ecere/gui/drivers/XInterface: Preventing dialog windows from showing up in taskbar
[sdk] / ecere / src / gui / drivers / XInterface.ec
1 namespace gui::drivers;
2
3 import "instance"
4 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D) && !defined(ECERE_NOGL)
5 import "OpenGLDisplayDriver"
6 #endif
7
8 #if (defined(__unix__) || defined(__APPLE__)) && !defined(ECERE_MINIGLX)
9
10 #undef __BLOCKS__
11 default:
12 #define uint _uint
13 #define property _property
14 #define new _new
15 #define class _class
16
17 #ifdef __linux__
18 #include <linux/joystick.h>
19 #endif
20 #include <sys/param.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <sys/select.h>
24
25 //#include <stdio.h>
26 //#include <stdlib.h>
27 //#include <string.h>
28
29 #define Window    X11Window
30 #define Cursor    X11Cursor
31 #define Font      X11Font
32 #define Display   X11Display
33 #define Time      X11Time
34 #define KeyCode   X11KeyCode
35 #define Picture   X11Picture
36 #define Bool      X11Bool
37
38 #define _XTYPEDEF_BOOL
39 typedef int X11Bool;
40
41 #include <X11/Xatom.h>
42 #include <X11/Xlib.h>
43 #include <X11/Xresource.h>
44 #include <X11/Xutil.h>
45 #include <X11/XKBlib.h>
46 #include <X11/keysym.h>
47 #include <X11/cursorfont.h>
48 #include <fcntl.h>
49 #if !defined(ECERE_NO3D) && !defined(ECERE_NOGL)
50 #include <GL/glx.h>
51 #endif
52 #include <X11/extensions/Xrender.h>
53 #include <X11/extensions/XShm.h>
54
55 #undef Bool
56 #undef Picture
57 #undef Window
58 #undef Cursor
59 #undef Font
60 #undef Display
61 #undef Time
62 #undef KeyCode
63 #undef uint
64
65 #undef new
66 #undef property
67 #undef class
68 private:
69
70 import "Interface"
71 import "XDisplayDriver"
72
73 // These are the events we care about
74 #define EVENT_MASK StructureNotifyMask | \
75       ButtonPressMask | ButtonReleaseMask | PointerMotionMask | \
76       KeyPressMask | KeyReleaseMask | ExposureMask | FocusChangeMask | \
77       PropertyChangeMask
78
79 void * xGlobalDisplay;
80 static XIM im;
81 // static XIC ic;
82 static XContext windowContext;
83 static Window lastActive;
84
85 static char * clipBoardData;
86
87 static Thread /* xThread, */ timerThread;
88 static bool xTerminate;
89 static Semaphore xSemaphore { };
90 static Mutex xMutex { };
91 static bool fullScreenMode;
92 static int desktopX = 0, desktopY = 0, desktopW = 0, desktopH = 0;
93 X11Window confineWindow;
94 static X11Cursor nullCursor;
95 static X11Window capturedWindow = None;
96 static Window restrictedWindow = null;
97 static bool gotAnXEvent = false;
98 static XEvent xEvent;
99 static int joystickFD[4];
100 static X11Window activeWindow;
101 static X11Cursor systemCursors[SystemCursor];
102
103 static enum NETWMStateAction { remove = 0, add = 1, toggle = 2 };
104
105 static enum AtomIdents
106 {
107    clipboard, multiple, targets, utf8_string, wm_delete_window, wm_hints, wm_name, wm_protocols, wm_state, wm_take_focus, wm_transient_for,
108    _motif_wm_hints,
109    _net_active_window, _net_current_desktop, _net_number_of_desktops, _net_wm_icon, _net_wm_name, _net_wm_pid,
110    _net_wm_state, _net_wm_state_demands_attention, _net_wm_state_hidden, _net_wm_user_time, _net_wm_window_type,
111    _net_wm_window_type_desktop, _net_wm_window_type_dialog, _net_wm_window_type_dock, _net_wm_window_type_dropdown_menu,
112    _net_wm_window_type_menu, _net_wm_window_type_normal, _net_wm_window_type_popup_menu, _net_wm_window_type_splash,
113    _net_wm_window_type_toolbar, _net_wm_window_type_utility, _net_workarea, _net_frame_extents, _net_request_frame_extents,
114    _net_wm_state_maximized_vert, _net_wm_state_maximized_horz, _net_wm_state_modal, app_selection, _net_supported,
115    _net_wm_state_skip_taskbar
116 };
117
118 static Atom atoms[AtomIdents];
119 static bool atomsSupported[AtomIdents];
120
121 static const char *atomNames[AtomIdents] = {
122    "CLIPBOARD", //clipboard
123    "MULTIPLE", //multiple
124    "TARGETS", //targets
125    "UTF8_STRING", //utf8_string
126    "WM_DELETE_WINDOW", //wm_delete_window
127    "WM_HINTS", //wm_hints
128    "WM_NAME", //wm_name
129    "WM_PROTOCOLS", //wm_protocols
130    "WM_STATE", //wm_state
131    "WM_TAKE_FOCUS", //wm_take_focus
132    "WM_TRANSIENT_FOR", //wm_transient_for
133    "_MOTIF_WM_HINTS", //_motif_wm_hints
134    "_NET_ACTIVE_WINDOW", //_net_active_window
135    "_NET_CURRENT_DESKTOP", //_net_current_desktop
136    "_NET_NUMBER_OF_DESKTOPS", //_net_number_of_desktops
137    "_NET_WM_ICON", //_net_wm_icon
138    "_NET_WM_NAME", //_net_wm_name
139    "_NET_WM_PID", //_net_wm_pid
140    "_NET_WM_STATE", //_net_wm_state
141    "_NET_WM_STATE_DEMANDS_ATTENTION", //_net_wm_state_demands_attention
142    "_NET_WM_STATE_HIDDEN", //_net_wm_state_hidden
143    "_NET_WM_USER_TIME", //_net_wm_user_time
144    "_NET_WM_WINDOW_TYPE", //_net_wm_window_type
145    "_NET_WM_WINDOW_TYPE_DESKTOP", //_net_wm_window_type_desktop
146    "_NET_WM_WINDOW_TYPE_DIALOG", //_net_wm_window_type_dialog
147    "_NET_WM_WINDOW_TYPE_DOCK", //_net_wm_window_type_dock
148    "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", //_net_wm_window_type_dropdown_menu
149    "_NET_WM_WINDOW_TYPE_MENU", //_net_wm_window_type_menu
150    "_NET_WM_WINDOW_TYPE_NORMAL", //_net_wm_window_type_normal
151    "_NET_WM_WINDOW_TYPE_POPUP_MENU", //_net_wm_window_type_popup_menu
152    "_NET_WM_WINDOW_TYPE_SPLASH", //_net_wm_window_type_splash
153    "_NET_WM_WINDOW_TYPE_TOOLBAR", //_net_wm_window_type_toolbar
154    "_NET_WM_WINDOW_TYPE_UTILITY", //_net_wm_window_type_utility
155    "_NET_WORKAREA",  //_net_workarea
156    "_NET_FRAME_EXTENTS", // _net_frame_extents
157    "_NET_REQUEST_FRAME_EXTENTS", // _net_request_frame_extents
158    "_NET_WM_STATE_MAXIMIZED_VERT", // _net_wm_state_maximized_vert
159    "_NET_WM_STATE_MAXIMIZED_HORZ", // _net_wm_state_maximized_horz
160    "_NET_WM_STATE_MODAL", // _net_wm_state_modal
161    "APP_SELECTION",
162    "_NET_SUPPORTED",
163    "_NET_WM_STATE_SKIP_TASKBAR"
164 };
165 /*
166 _NET_WM_STATE_STICKY, ATOM
167 _NET_WM_STATE_MAXIMIZED_VERT, ATOM
168 _NET_WM_STATE_MAXIMIZED_HORZ, ATOM
169 _NET_WM_STATE_SHADED, ATOM
170 _NET_WM_STATE_SKIP_PAGER, ATOM
171 _NET_WM_STATE_HIDDEN, ATOM
172 _NET_WM_STATE_FULLSCREEN, ATOM
173 _NET_WM_STATE_ABOVE, ATOM
174 _NET_WM_STATE_BELOW, ATOM
175 _NET_WM_STATE_DEMANDS_ATTENTION, ATOM
176 */
177
178 static bool autoRepeatDetectable;
179 static bool setICPosition;
180 int xSystemDepth;
181 PixelFormat xSystemPixelFormat;
182 Visual * xSystemVisual;
183 bool xSharedMemory;
184
185 static void SetNETWMState(X11Window windowHandle, bool throughRoot, NETWMStateAction action, Atom atom1, Atom atom2)
186 {
187    if(atomsSupported[_net_wm_state])
188    {
189       int format;
190       unsigned long count, fill;
191       Atom type;
192       char * data = null;
193       uint state = WithdrawnState;
194
195       /*if(XGetWindowProperty(xGlobalDisplay, windowHandle, atoms[wm_state], 0, 3, False,
196                  atoms[wm_state], &type, &format, &count, &fill, &data) == Success && count)
197       {
198          state = *(uint *)data;
199          XFree(data);
200       } */
201       if(!throughRoot) //state == WithdrawnState)
202       {
203          // We need to handle modifying these ourselves for withdrawn windows...
204          if(action == add)
205          {
206             Atom values[2] = { atom1, atom2 };
207             XChangeProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_state], XA_ATOM,
208                32, PropModeAppend, (byte *)values, atom2 ? 2 : 1);
209          }
210          else if(XGetWindowProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_state], 0, 32, False,
211              XA_ATOM, &type, &format, &count, &fill, &data) == Success)
212          {
213             Atom * values = (Atom *) data;
214             int i;
215             for (i = 0; i < count; i++)
216             {
217                if(values[i] == atom1 || (atom2 && values[i] == atom2))
218                {
219                   if(i < count - 1)
220                      memmove(values + i, values + i + 1, sizeof(Atom) * (count - i - 1));
221                   count--;
222                   i--;
223                }
224             }
225             XChangeProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_state], XA_ATOM, 32, PropModeReplace, (byte *)values, (int)count);
226             XFree(data);
227          }
228       }
229       else
230       {
231          XClientMessageEvent event = { 0 };
232          event.type = ClientMessage;
233          event.message_type = atoms[_net_wm_state];
234          event.display = xGlobalDisplay;
235          event.serial = 0;
236          event.window = windowHandle;
237          event.send_event = 1;
238          event.format = 32;
239          event.data.l[0] = action;
240          event.data.l[1] = atom1;
241          event.data.l[2] = atom2;
242          XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false,
243             SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
244       }
245    }
246
247 }
248
249 static X11Time timeStamp;
250
251 class XWindowData : struct
252 {
253 public:
254    XVisualInfo * visual;
255    XIC ic;
256    bool laterFocus;
257    // Decorations Size
258    Box decor;
259    bool gotFrameExtents;
260 };
261
262 bool XGetBorderWidths(Window window, Box box)
263 {
264    XWindowData windowData = window.windowData;
265    if(windowData)
266    {
267       if(window.state == maximized)
268          box = { 0, 0, 0, 0 };
269       else
270          box = windowData.decor;
271       return true;
272    }
273    return false;
274 }
275
276 static Visual * FindFullColorVisual(X11Display *dpy, int * depth)
277 {
278    XVisualInfo vinfo;
279    XVisualInfo *vinfo_ret;
280    int numitems;
281
282    vinfo._class = TrueColor;
283    vinfo_ret = XGetVisualInfo(dpy, VisualClassMask, &vinfo, &numitems);
284    if(numitems)
285    {
286       int maxdepth = 0;
287       while(numitems > 0)
288       {
289          if(vinfo_ret[numitems-1].depth > maxdepth)
290             maxdepth = vinfo_ret[numitems-1].depth;
291          numitems--;
292       }
293       XFree((void *) vinfo_ret);
294       if(maxdepth >= 16)
295       {
296          if(XMatchVisualInfo(dpy, DefaultScreen(dpy), maxdepth, TrueColor, &vinfo))
297          {
298             *depth = maxdepth;
299             return vinfo.visual;
300          }
301       }
302    }
303    return null;
304 }
305
306 static void RepositionDesktop(bool updateChildren)
307 {
308    int x = 0, y = 0;
309    int w, h;
310    Screen * x_screen = XDefaultScreenOfDisplay(xGlobalDisplay);
311    X11Window x_root;
312    int current = 0;
313    char *data = null;
314    int format;
315    unsigned long len, fill;
316    Atom type;
317    static double lastTime = 0, time;
318
319    time = GetTime();
320    if(desktopW && desktopH && time - lastTime < 1.5) return;
321    lastTime = time;
322
323    w = XDisplayWidth(xGlobalDisplay, DefaultScreen(xGlobalDisplay));
324    h = XDisplayHeight(xGlobalDisplay, DefaultScreen(xGlobalDisplay));
325    x_root = XRootWindowOfScreen(x_screen);
326
327    if(atomsSupported[_net_number_of_desktops])
328    {
329       if(XGetWindowProperty(xGlobalDisplay, x_root, atoms[_net_number_of_desktops], 0, 1, False,
330                             XA_CARDINAL, &type, &format, &len, &fill,
331                             &data) != Success)
332       {
333          printf("cant get xa desktops property\n");
334       }
335
336       if(data)
337       {
338          int desktops = 0;
339          desktops = (int)*(long *)data;
340
341          //printf("_NET_NUMBER_OF_DESKTOPS is %d\n", desktops);
342
343          XFree(data);
344          data = null;
345       }
346    }
347
348    if(atomsSupported[_net_current_desktop])
349    {
350       if(XGetWindowProperty(xGlobalDisplay, x_root, atoms[_net_current_desktop], 0, 1, False,
351                             XA_CARDINAL, &type, &format, &len, &fill,
352                             &data) != Success)
353       {
354          printf("cant get xa current property\n");
355       }
356
357       if(data)
358       {
359          current = (int)*(long *)data;
360          XFree(data);
361          data = null;
362
363          //printf("_NET_CURRENT_DESKTOP is %d\n", current);
364       }
365    }
366    if(atomsSupported[_net_workarea])
367    {
368       long *workareas;
369
370       if(XGetWindowProperty(xGlobalDisplay, x_root, atoms[_net_workarea], 0, (4 * 32),
371                             False, AnyPropertyType, &type, &format, &len,
372                             &fill, &data) != Success)
373       {
374          //printf("warning\n");
375       }
376
377       /*
378       if(type == None || format == 0)
379          printf("warning\n");
380
381       if(fill)
382          printf("warning\n");
383
384       if(len % 4)
385          printf("warning\n");
386       */
387
388       if(data)
389       {
390          workareas = (long *)data;
391
392          x = (int)workareas[current * 4];
393          y = (int)workareas[current * 4 + 1];
394          w = (int)workareas[current * 4 + 2];
395          h = (int)workareas[current * 4 + 3];
396
397          //printf("_NET_WORKAREA is x = %d, y = %d, w = %d, h = %d\n", x, y, w, h);
398          XFree(data);
399          data = null;
400       }
401       //   printf("Work Area width: %d, height %d\n", w, h);
402    }
403
404    if(desktopX != x || desktopY != y || desktopW != w || desktopH != h)
405    {
406       guiApp.SetDesktopPosition(x, y, w, h, updateChildren);
407       desktopX = x;
408       desktopY = y;
409       desktopW = w;
410       desktopH = h;
411    }
412 }
413
414 /****************************************************************************
415    /// PRIVATE UTILITY FUNCTIONS /////////////
416 ****************************************************************************/
417 // --- Keyboard Input ---
418 #define KEYCODE_HOME    0x59
419 #define KEYCODE_UP      0x5A
420 #define KEYCODE_PGUP    0x5B
421 #define KEYCODE_LEFT    0x5C
422 #define KEYCODE_RIGHT   0x5E
423 #define KEYCODE_END     0x5F
424 #define KEYCODE_DOWN    0x60
425 #define KEYCODE_PGDWN   0x61
426 #define KEYCODE_INS     0x62
427 #define KEYCODE_DEL     0x63
428 #define KEYCODE_SLASH   0x68
429
430 default:
431 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit;
432 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp;
433 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown;
434 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit;
435 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove;
436 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick;
437 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown;
438 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp;
439 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick;
440 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown;
441 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp;
442 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick;
443 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown;
444 extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp;
445 private:
446
447 static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEvent * event)
448 {
449    bool result = true;
450    Key code;
451    unichar ch = 0;
452    KeySym keysym = NoSymbol;
453    Status status;
454    int buflength = 0;
455    static long bufsize = 16;
456    static char *buf = NULL;
457    XWindowData windowData = window.windowData;
458    Key key = 0;
459
460    if(window.destroyed) return result;
461
462    // Logf("Got 0x%x (%d)\n", keyCode, key);
463
464    // Translate the key code
465    /*
466    key = key - 8;
467    //Logf("Got 0x%x (%d)\n", key, key);
468
469    switch(key)
470    {
471       case KEYCODE_HOME: key = home; break;
472       case KEYCODE_UP: key = up; break;
473       case KEYCODE_PGUP: key = pageUp; break;
474       case KEYCODE_LEFT: key = left; break;
475       case KEYCODE_RIGHT: key = right; break;
476       case KEYCODE_END: key = end; break;
477       case KEYCODE_DOWN: key = down; break;
478       case KEYCODE_PGDWN: key = pageDown; break;
479       case KEYCODE_INS: key = insert; break;
480       case KEYCODE_DEL: key = del; break;
481       case KEYCODE_SLASH: key = keyPadSlash; break;
482    }
483
484    ch = (byte)Interface::TranslateKey(key, event->state & ShiftMask);
485    */
486 /*
487    if(release)
488       Logf("Key up:   %3d (%2x)\n", key, key);
489    else
490       Logf("Key down: %3d (%2x)\n", key, key);
491 */
492
493    if(!buf)
494       buf = malloc((uint)bufsize);
495    if(windowData && windowData.ic)
496    {
497       buflength = XmbLookupString(windowData.ic, event, buf, (int)bufsize, &keysym, &status);
498       if (status == XBufferOverflow)
499       {
500          buf = realloc(buf, (uint)(bufsize = buflength));
501          buflength = XmbLookupString(windowData.ic, event, buf, (int)bufsize, &keysym, &status);
502       }
503       if(status != XLookupKeySym && status != XLookupBoth && release == 1)
504          keysym = XLookupKeysym(event, 0);
505    }
506    else
507    {
508       keysym = XLookupKeysym(event, 0);
509    }
510
511    // printf("Got keysym %d (%x)\n", keysym, keysym);
512    if(keysym != NoSymbol) //status == XLookupKeySym || status == XLookupBoth)
513    {
514       switch(keysym)
515       {
516          case XK_BackSpace:   key = backSpace; break;
517          case XK_ISO_Left_Tab: key = tab; break;
518          case XK_Tab:         key = tab; break;
519          // case XK_Linefeed:
520          // case XK_Clear:
521          case XK_Return:      key = enter; break;
522          case XK_Pause:       key = pauseBreak; break;
523          case XK_Scroll_Lock: key = scrollLock; break;
524          case XK_Sys_Req:     key = printScreen; break;
525          case XK_Escape:      key = escape; break;
526          case XK_Delete:      key = del; break;
527
528          case XK_Home:        key = home; break;
529          case XK_Left:        key = left; break;
530          case XK_Up:          key = up; break;
531          case XK_Right:       key = right; break;
532          case XK_Down:        key = down; break;
533          // case XK_Prior:
534          case XK_Page_Up:     key = pageUp; break;
535          // case XK_Next:
536          case XK_Page_Down:   key = pageDown; break;
537          case XK_End:         key = end; break;
538          // case XK_Begin:
539
540          // case XK_Select:
541          // case XK_Print:
542          // case XK_Execute:
543          case XK_Insert:      key = insert; break;
544          // case XK_Undo:
545          // case XK_Redo:
546          // case XK_Menu:
547          // case XK_Find:
548          // case XK_Cancel:
549 #ifdef __APPLE__
550          case XK_Help:     key = insert; break;
551 #endif
552          case XK_Break:    key = Key { pauseBreak, ctrl = true }; break;
553 #ifdef __APPLE__
554          case XK_Mode_switch: key = leftAlt; break;
555 #endif
556          // case XK_script_switch:
557          case XK_Num_Lock:    key = numLock; break;
558
559          // case XK_KP_Space:
560          // case XK_KP_Tab:
561          case XK_KP_Enter:    key = keyPadEnter; break;
562          // case XK_KP_F1:
563          // case XK_KP_F2:
564          // case XK_KP_F3:
565          // case XK_KP_F4:
566          case XK_KP_Home:     key = keyPadHome; break;
567          case XK_KP_Left:     key = keyPadLeft; break;
568          case XK_KP_Up:       key = keyPadUp; break;
569          case XK_KP_Right:    key = keyPadRight; break;
570          case XK_KP_Down:     key = keyPadDown; break;
571          // case XK_KP_Prior:
572          case XK_KP_Page_Up:  key = keyPadPageUp; break;
573          // case XK_KP_Next:
574          case XK_KP_Page_Down:key = keyPadPageDown; break;
575          case XK_KP_End:      key = keyPadEnd; break;
576          // case XK_KP_Begin:
577          case XK_KP_Insert:   key = keyPadInsert; break;
578          case XK_KP_Delete:   key = keyPadDelete; break;
579          // case XK_KP_Equal:
580          case XK_KP_Multiply: key = keyPadStar; break;
581          case XK_KP_Add:      key = keyPadPlus; break;
582          case XK_KP_Separator:key = keyPadDelete; break;
583          case XK_KP_Subtract: key = keyPadMinus; break;
584          // case XK_KP_Decimal:
585          case XK_KP_Divide:   key = keyPadSlash; break;
586
587          case XK_KP_0:  key = keyPad0; break;
588          case XK_KP_1:  key = keyPad1; break;
589          case XK_KP_2:  key = keyPad2; break;
590          case XK_KP_3:  key = keyPad3; break;
591          case XK_KP_4:  key = keyPad4; break;
592          case XK_KP_5:  key = keyPad5; break;
593          case XK_KP_6:  key = keyPad6; break;
594          case XK_KP_7:  key = keyPad7; break;
595          case XK_KP_8:  key = keyPad8; break;
596          case XK_KP_9:  key = keyPad9; break;
597
598          case XK_F1: key = f1; break;
599          case XK_F2: key = f2; break;
600          case XK_F3: key = f3; break;
601          case XK_F4: key = f4; break;
602          case XK_F5: key = f5; break;
603          case XK_F6: key = f6; break;
604          case XK_F7: key = f7; break;
605          case XK_F8: key = f8; break;
606          case XK_F9: key = f9; break;
607          case XK_F10: key = f10; break;
608          case XK_F11: key = f11; break;
609          //case XK_L1:
610          case XK_F12: key = f12; break;
611          /*
612          case XK_L2:
613          case XK_F13:
614          case XK_L3:
615          case XK_F14:
616          case XK_L4:
617          case XK_F15:
618          case XK_L5:
619          case XK_F16:
620          case XK_L6:
621          case XK_F17:
622          case XK_L7:
623          case XK_F18:
624          case XK_L8:
625          case XK_F19:
626          case XK_L9:
627          case XK_F20:
628          case XK_L10:
629          case XK_F21:
630          case XK_R1:
631          case XK_F22:
632          case XK_R2:
633          case XK_F23:
634          case XK_R3:
635          case XK_F24:
636          case XK_R4:
637          case XK_F25:
638          case XK_R5:
639          case XK_F26:
640          case XK_R6:
641          case XK_F27:
642          case XK_R7:
643          case XK_F28:
644          case XK_R8:
645          case XK_F29:
646          case XK_R9:
647          case XK_F30:
648          case XK_R10:
649          case XK_F31:
650          case XK_R11:
651          case XK_F32:
652          case XK_R12:
653          case XK_F33:
654          case XK_R13:
655          case XK_F34:
656          case XK_R14:
657          case XK_F35:
658          case XK_R15:
659          */
660          case XK_Shift_L: key = leftShift; break;
661          case XK_Shift_R: key = rightShift; break;
662          case XK_Control_L: key = leftControl; break;
663          case XK_Control_R: key = rightControl; break;
664          case XK_Caps_Lock: key = capsLock; break;
665          // case XK_Shift_Lock:
666          // case XK_Meta_L:
667          // case XK_Meta_R:
668          case XK_Alt_L: key = leftAlt; break;
669          case XK_Alt_R: key = rightAlt; break;
670          // case XK_Super_L:
671          // case XK_Super_R:
672          // case XK_Hyper_L:
673          // case XK_Hyper_R:
674
675          case XK_space: key = space; break;
676          case XK_exclam: key = bang; break;
677          case XK_quotedbl: key = doubleQuote; break;
678          case XK_numbersign: key = pound; break;
679          case XK_dollar: key = dollar; break;
680          case XK_percent: key = percent; break;
681          case XK_ampersand: key = ampersand; break;
682          case XK_apostrophe: key = quote; break;
683          // case XK_quoteright: key = quote; break;
684          case XK_parenleft: key = leftParanthesis; break;
685          case XK_parenright: key = rightParanthesis; break;
686          case XK_asterisk: key = star; break;
687          case XK_plus: key = plus; break;
688          case XK_comma: key = comma; break;
689          case XK_minus: key = minus; break;
690          case XK_period: key = period; break;
691          case XK_slash: key = slash; break;
692          case XK_0: key = k0; break;
693          case XK_1: key = k1; break;
694          case XK_2: key = k2; break;
695          case XK_3: key = k3; break;
696          case XK_4: key = k4; break;
697          case XK_5: key = k5; break;
698          case XK_6: key = k6; break;
699          case XK_7: key = k7; break;
700          case XK_8: key = k8; break;
701          case XK_9: key = k9; break;
702          case XK_colon: key = colon; break;
703          case XK_semicolon: key = semicolon; break;
704          case XK_less: key = smallerThan; break;
705          case XK_equal: key = equal; break;
706          case XK_greater: key = greaterThan; break;
707          case XK_question: key = questionMark; break;
708          case XK_at: key = ampersand; break;
709          case XK_A: key = a; break;
710          case XK_B: key = b; break;
711          case XK_C: key = c; break;
712          case XK_D: key = d; break;
713          case XK_E: key = e; break;
714          case XK_F: key = f; break;
715          case XK_G: key = g; break;
716          case XK_H: key = h; break;
717          case XK_I: key = i; break;
718          case XK_J: key = j; break;
719          case XK_K: key = k; break;
720          case XK_L: key = l; break;
721          case XK_M: key = m; break;
722          case XK_N: key = n; break;
723          case XK_O: key = o; break;
724          case XK_P: key = p; break;
725          case XK_Q: key = q; break;
726          case XK_R: key = r; break;
727          case XK_S: key = s; break;
728          case XK_T: key = t; break;
729          case XK_U: key = u; break;
730          case XK_V: key = v; break;
731          case XK_W: key = w; break;
732          case XK_X: key = x; break;
733          case XK_Y: key = y; break;
734          case XK_Z: key = z; break;
735          case XK_bracketleft: key = leftBracket; break;
736          case XK_backslash: key = backSlash; break;
737          case XK_bracketright: key = rightBracket; break;
738          case XK_asciicircum: key = circumflex; break;
739          case XK_underscore: key = underscore; break;
740          // case XK_grave: key = backQuote; break;
741          case XK_quoteleft: key = backQuote; break;
742          case XK_a: key = a; break;
743          case XK_b: key = b; break;
744          case XK_c: key = c; break;
745          case XK_d: key = d; break;
746          case XK_e: key = e; break;
747          case XK_f: key = f; break;
748          case XK_g: key = g; break;
749          case XK_h: key = h; break;
750          case XK_i: key = i; break;
751          case XK_j: key = j; break;
752          case XK_k: key = k; break;
753          case XK_l: key = l; break;
754          case XK_m: key = m; break;
755          case XK_n: key = n; break;
756          case XK_o: key = o; break;
757          case XK_p: key = p; break;
758          case XK_q: key = q; break;
759          case XK_r: key = r; break;
760          case XK_s: key = s; break;
761          case XK_t: key = t; break;
762          case XK_u: key = u; break;
763          case XK_v: key = v; break;
764          case XK_w: key = w; break;
765          case XK_x: key = x; break;
766          case XK_y: key = y; break;
767          case XK_z: key = z; break;
768          case XK_braceleft: key = leftBracket; break;
769          case XK_bar: key = pipe; break;
770          case XK_braceright: key = rightBracket; break;
771          case XK_asciitilde: key = tilde; break;
772       }
773    }
774    if(!windowData.ic)
775    {
776       ch = (byte)Interface::TranslateKey(key, event->state & ShiftMask);
777       // 127 is delete, we don't treat that as a character (Use (SmartKey)key == del)
778       if(ch == 128 || ch == 127) ch = 0;
779    }
780    code = key;
781    if(keysym == XK_ISO_Left_Tab)
782       code.shift = true;
783    if(key != leftShift && key != rightShift && event->state & ShiftMask)
784       code.shift = true;
785    if(key != leftControl && key != rightControl && event->state & ControlMask)
786       code.ctrl = true;
787    if(key != leftAlt && key != rightAlt && event->state & Mod1Mask)
788       code.alt = true;
789
790 #ifdef __APPLE__
791    if(key != leftAlt && key != rightAlt && event->state & (1<<13))
792    {
793       code.alt = true;
794       /*buflength = 0;
795       ch = 0;*/
796    }
797 #endif
798
799    // Logf("Key Message: %s, keysym: 0x%x, key: %d state: %d, ch: %c\n", release ? ((release == 2) ? "REPEAT" : "KeyRelease") : "KeyPress", keysym, key, event->state, (byte)ch);
800
801    incref window;
802    if(release == 1)
803    {
804       int numBytes;
805       if(windowData && windowData.ic) ch = buflength ? UTF8GetChar(buf, &numBytes) : 0;
806       if(ch == 127) ch = 0;
807       // printf("Release! %d %d %d\n", keysym, code, ch);
808       result = window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, code, ch);
809    }
810    else
811    {
812       int c;
813       if(release == 0)
814       {
815          if(windowData.ic && buflength)
816          {
817             for(c = 0; c<buflength;)
818             {
819                int numBytes;
820                ch = UTF8GetChar(buf + c, &numBytes);
821                if(ch == 127) ch = 0;
822                result = window.KeyMessage((c == 0) ?
823                   __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown : __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit,
824                   (c == 0) ? code : 0, ch);
825                c += numBytes;
826                if(!numBytes) c = buflength;
827             }
828          }
829          else
830             result = window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, code, ch);
831       }
832       else if(key<128)
833       {
834          if(buflength && windowData.ic)
835             for(c = 0; c<buflength;)
836             {
837                int numBytes;
838                ch = UTF8GetChar(buf + c, &numBytes);
839                if(ch == 127) ch = 0;
840                result = window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, code, ch);
841                c += numBytes;
842                if(!numBytes) c = buflength;
843             }
844          else
845             result = window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, code, ch);
846       }
847    }
848    delete window;
849
850    return result;
851 }
852 /*
853 static uint E_CALL XEventThread(void * data)
854 {
855    for(;;)
856    {
857       XEvent e;
858       xSemaphore.Wait();
859       if(xTerminate) break;
860       if(!gotAnXEvent)
861       {
862          XPeekEvent(xGlobalDisplay, &e);
863          gotAnXEvent = true;
864          guiApp.SignalEvent();
865       }
866    }
867    return 0;
868 }
869 */
870
871 static X11Bool EventChecker(void *display, XEvent *event, char * data)
872 {
873    return (!data || (event->type == (int) data)) && event->type != NoExpose && event->type != GraphicsExpose;
874 }
875
876 static X11Bool ConfigureNotifyChecker(void *display, XConfigureEvent *event, char * data)
877 {
878    return (!data || (event->window == (X11Window) data)) && event->type == ConfigureNotify;
879 }
880
881 static enum FrameExtentSupport { unknown, working, broken };
882
883 static FrameExtentSupport frameExtentSupported;
884 static Time frameExtentRequest;
885 static X11Window frameExtentWindow;
886
887 static uint timerDelay = MAXINT;
888 #define RESOLUTION   (18.2 * 100)
889 static uint XTimerThread(Thread thread)
890 {
891    int s = ConnectionNumber(xGlobalDisplay);
892    /*
893    Time lastTime, thisTime;
894    lastTime = GetTime();
895    */
896    for(;;)
897    {
898       //int result;
899       //bool waitSemaphore = false;
900       fd_set readSet, writeSet, exceptSet;
901       struct timeval tv = { (timerDelay == MAXINT) ? 0 : (timerDelay / 1000000), (timerDelay == MAXINT) ? (int)(1000000 / 18.2) : (timerDelay % 1000000) };
902
903       if(xTerminate) break;
904       FD_ZERO(&readSet);
905       FD_ZERO(&writeSet);
906       FD_ZERO(&exceptSet);
907       FD_SET(s, &readSet);
908       FD_SET(s, &exceptSet);
909       xMutex.Wait();
910       if(select(s + 1, &readSet, null, null, &tv))
911       {
912          if(FD_ISSET(s, &readSet))
913             gotAnXEvent = true;
914       }
915       if(frameExtentSupported == unknown && frameExtentRequest && GetTime() - frameExtentRequest > 1)
916       {
917          XPropertyEvent event = { 0 };
918          event.type = PropertyNotify;
919          event.state = PropertyNewValue;
920          event.atom = atoms[_net_frame_extents];
921          event.display = xGlobalDisplay;
922          event.serial = 0;
923          event.window = frameExtentWindow;
924          event.send_event = 1;
925
926          frameExtentSupported = broken;
927
928          XSendEvent(xGlobalDisplay, frameExtentWindow, bool::false,
929             PropertyChangeMask, (union _XEvent *)&event);
930       }
931       xMutex.Release();
932       guiApp.SignalEvent();
933       xSemaphore.Wait();
934
935 #if 0
936       XEvent e;
937       Sleep(1.0 / RESOLUTION);
938       thisTime = GetTime();
939       if(xTerminate) break;
940       if(thisTime - lastTime > (1.0 / 18.2))
941       {
942          guiApp.SignalEvent();
943          lastTime = thisTime;
944       }
945       else
946       {
947          xMutex.Wait();
948          if(!gotAnXEvent)
949          {
950             XLockDisplay(xGlobalDisplay);
951             if(XCheckIfEvent(xGlobalDisplay, &xEvent, EventChecker, null))
952             {
953                gotAnXEvent = true;
954                guiApp.SignalEvent();
955             }
956             XUnlockDisplay(xGlobalDisplay);
957          }
958          xMutex.Release();
959       }
960 #endif
961    }
962    return 0;
963 }
964
965 static int MyXErrorHandler(X11Display * display, XErrorEvent * event)
966 {
967    char buffer[1024];
968    if(xGlobalDisplay)
969       XGetErrorText(xGlobalDisplay, event->error_code, buffer, sizeof(buffer));
970 #ifdef _DEBUG
971    Logf("X Error: %s\n", buffer);
972 #endif
973    return 0;
974 }
975
976 static int MyXIOErrorHandler(X11Display * display)
977 {
978    Log("X IO Error\n");
979    return 0;
980 }
981
982 // Motif Hints (to get rid of the decorations)
983 #define MWM_HINTS_FUNCTIONS   (1L << 0)
984 #define MWM_HINTS_DECORATIONS (1L << 1)
985 #define MWM_HINTS_INPUT_MODE  (1L << 2)
986 #define MWM_HINTS_STATUS      (1L << 3)
987
988 #define MWM_DECOR_ALL         (1L << 0)
989 #define MWM_DECOR_BORDER      (1L << 1)
990 #define MWM_DECOR_RESIZEH     (1L << 2)
991 #define MWM_DECOR_TITLE       (1L << 3)
992 #define MWM_DECOR_MENU        (1L << 4)
993 #define MWM_DECOR_MINIMIZE    (1L << 5)
994 #define MWM_DECOR_MAXIMIZE    (1L << 6)
995
996 #define MWM_FUNC_ALL (1L << 0)
997 #define MWM_FUNC_RESIZE (1L << 1)
998 #define MWM_FUNC_MOVE (1L << 2)
999 #define MWM_FUNC_MINIMIZE (1L << 3)
1000 #define MWM_FUNC_MAXIMIZE (1L << 4)
1001 #define MWM_FUNC_CLOSE (1L << 5)
1002
1003 struct MWM_Hints
1004 {
1005   unsigned long flags;
1006   unsigned long functions;
1007   unsigned long decorations;
1008   long inputMode;
1009   unsigned long status;
1010 };
1011
1012 static void WaitForViewableWindow(Window window)
1013 {
1014    //int attempts = 0;
1015    //Logf("Wait for viewable %s\n", window.name);
1016    XFlush(xGlobalDisplay);
1017    //while(attempts++ < 40)
1018    while(true)
1019    {
1020       XWindowAttributes attributes = { 0 };
1021       int result;
1022       if(!XGetWindowAttributes(xGlobalDisplay, (X11Window)window.windowHandle, &attributes))
1023          break;
1024       if(attributes.map_state == IsViewable)
1025          break;
1026       else
1027          Sleep(1.0 / RESOLUTION);
1028    }
1029 }
1030
1031 static bool RequestFrameExtents(X11Window windowHandle)
1032 {
1033    if(frameExtentSupported != broken)
1034    {
1035       // Request decoration frame extents
1036       XClientMessageEvent event = { 0 };
1037       event.type = ClientMessage;
1038       event.message_type = atoms[_net_request_frame_extents];
1039       event.display = xGlobalDisplay;
1040       event.serial = 0;
1041       event.window = windowHandle;
1042       event.send_event = 1;
1043       event.format = 32;
1044
1045       if(frameExtentSupported == unknown && !frameExtentRequest)
1046       {
1047          frameExtentRequest = GetTime();
1048          frameExtentWindow = windowHandle;
1049       }
1050
1051       XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false,
1052          SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
1053       return true;
1054    }
1055    return false;
1056 }
1057
1058 static bool GetFrameExtents(Window window, bool update)
1059 {
1060    XWindowData windowData = window.windowData;
1061    bool result = false;
1062    int format;
1063    unsigned long len, fill;
1064    Atom type;
1065    char * data = null;
1066
1067    if(XGetWindowProperty(xGlobalDisplay, (X11Window)window.windowHandle,
1068       atoms[_net_frame_extents], 0, 4,
1069        False, XA_CARDINAL, &type, &format, &len,
1070        &fill, &data) == Success && data)
1071    {
1072       long *extents = (long *)data;
1073       bool change = extents[0] != windowData.decor.left ||
1074                     extents[1] != windowData.decor.right ||
1075                     extents[2] != windowData.decor.top ||
1076                     extents[3] != windowData.decor.bottom;
1077
1078       bool hadFrameExtents = windowData.gotFrameExtents;
1079       Box oldDecor = windowData.decor;
1080
1081       frameExtentSupported = working;
1082       frameExtentWindow = 0;
1083       frameExtentRequest = 0;
1084
1085       if(!hadFrameExtents || extents[0] || extents[1] || extents[2] || extents[3])
1086       {
1087          windowData.decor =
1088          {
1089             left = (int)extents[0], right  = (int)extents[1],
1090             top  = (int)extents[2], bottom = (int)extents[3]
1091          };
1092          windowData.gotFrameExtents = true;
1093          if(update && change && ((Window)window).clientSize.w > 0)
1094          {
1095             int x = window.position.x, y = window.position.y, w = window.size.w, h = window.size.h;
1096             if(!hadFrameExtents && window.state != maximized)
1097             {
1098                window.ComputeAnchors(
1099                   window.normalAnchor,
1100                   window.normalSizeAnchor,
1101                   &x, &y, &w, &h);
1102             }
1103             else
1104             {
1105                x += windowData.decor.left - oldDecor.left;
1106                y += windowData.decor.top - oldDecor.top;
1107
1108                w += windowData.decor.left - oldDecor.left + windowData.decor.right - oldDecor.right;
1109                h += windowData.decor.top - oldDecor.top   + windowData.decor.bottom - oldDecor.bottom;
1110             }
1111
1112             if(window.state != maximized)
1113             {
1114                window.Position(x, y, w, h, true, true, true, true, false, !hadFrameExtents && window.state != maximized);
1115                XInterface::UpdateRootWindow(window);
1116             }
1117          }
1118          result = true;
1119       }
1120       XFree(data);
1121    }
1122    return result;
1123 }
1124
1125 static bool WaitForFrameExtents(Window window)
1126 {
1127    int attempts = 0;
1128    //XFlush(xGlobalDisplay);
1129    while(attempts++ < 10)
1130    {
1131       if(GetFrameExtents(window, false)) return true;
1132       Sleep(1.0 / RESOLUTION);
1133    }
1134    return false;
1135 }
1136
1137 /****************************************************************************
1138    /// DRIVER IMPLEMENTATION /////////////
1139 ****************************************************************************/
1140
1141 /*static */class HiResTimer : Thread
1142 {
1143    bool terminate;
1144    uint delay;
1145
1146    void Stop()
1147    {
1148       if(started)
1149       {
1150          terminate = true;
1151          Wait();
1152       }
1153    }
1154
1155    uint Main()
1156    {
1157       while(!terminate)
1158       {
1159          //usleep(delay);
1160          // Sleep(delay / 1000000.0);
1161          struct timeval tv = { delay / 1000000, delay % 1000000 };
1162          select(0,null,null,null, &tv);
1163          guiApp.SignalEvent();
1164       }
1165       return 0;
1166    }
1167 };
1168
1169 static HiResTimer hiResTimer { };
1170
1171 default:
1172
1173 #include <sys/ipc.h>
1174 #include <sys/shm.h>
1175 #include <signal.h>
1176 #include <locale.h>
1177
1178
1179 private:
1180
1181 #ifndef SHM_STAT
1182 #define SHM_STAT  13
1183 #define SHM_INFO  14
1184 #endif
1185
1186 static int terminatePid;
1187
1188 static void SigIntHandler(int value)
1189 {
1190    // printf("SigHandler %d\n", getpid());
1191    if(!terminatePid || terminatePid == getpid())
1192    {
1193       terminateX++;
1194       terminatePid = getpid();
1195       // printf("terminateX now equals %d\n", terminateX);
1196       if(guiApp && guiApp.semaphore)
1197          guiApp.semaphore.Release();
1198    }
1199    /*
1200    struct shmid_ds info;
1201    int maxid = shmctl (0, SHM_INFO, &info);
1202    int pid = getpgrp();
1203    int thisPid = getpid();
1204    //if(thisPid == pid)
1205    /-*
1206    {
1207       if(maxid >= 0)
1208       {
1209          int id;
1210          for(id = 0; id <= maxid; id++)
1211          {
1212             struct shmid_ds shmseg;
1213             int shmid;
1214             if((shmid = shmctl(id, SHM_STAT, &shmseg)) >= 0)
1215             {
1216                if(shmseg.shm_cpid == pid || shmseg.shm_cpid == thisPid)
1217                {
1218                   printf("%d (%d) belongs to us (%d)\n", shmid, id, shmseg.shm_cpid);
1219                   shmctl(shmid, IPC_RMID, 0);
1220                }
1221             }
1222          }
1223       }
1224       exit(0);
1225    }
1226    */
1227    /*else if(guiApp.desktop)
1228       guiApp.desktop.Destroy(0);*/
1229 }
1230
1231 class XInterface : Interface
1232 {
1233    class_property(name) = "X";
1234
1235    // --- User Interface System ---
1236    bool Initialize()
1237    {
1238       setlocale(LC_ALL, "en_US.UTF-8");
1239       XInitThreads();
1240       XSupportsLocale();
1241       XSetLocaleModifiers("");
1242       XSetErrorHandler(MyXErrorHandler);
1243       XSetIOErrorHandler(MyXIOErrorHandler);
1244 #ifndef __APPLE__
1245       signal(SIGINT, SigIntHandler);
1246 #endif
1247       xTerminate = false;
1248       xGlobalDisplay = XOpenDisplay(null);
1249       // XSynchronize(xGlobalDisplay, True);
1250       frameExtentSupported = unknown;
1251
1252       joystickFD[0] = open("/dev/js0", O_RDONLY);
1253       joystickFD[1] = open("/dev/js1", O_RDONLY);
1254       joystickFD[2] = open("/dev/js2", O_RDONLY);
1255       joystickFD[3] = open("/dev/js3", O_RDONLY);
1256
1257       systemCursors[iBeam]    = XCreateFontCursor(xGlobalDisplay, XC_xterm);
1258       systemCursors[cross]    = XCreateFontCursor(xGlobalDisplay, XC_tcross);
1259       systemCursors[moving]   = XCreateFontCursor(xGlobalDisplay, XC_fleur);
1260       systemCursors[sizeNESW] = XCreateFontCursor(xGlobalDisplay, XC_bottom_left_corner);
1261       systemCursors[sizeNS]   = XCreateFontCursor(xGlobalDisplay, XC_sb_v_double_arrow);
1262       systemCursors[sizeNWSE] = XCreateFontCursor(xGlobalDisplay, XC_bottom_right_corner);
1263       systemCursors[sizeWE]   = XCreateFontCursor(xGlobalDisplay, XC_sb_h_double_arrow);
1264       systemCursors[hand]     = XCreateFontCursor(xGlobalDisplay, XC_hand2);
1265       systemCursors[arrow]    = XCreateFontCursor(xGlobalDisplay, XC_left_ptr);
1266
1267       if(xGlobalDisplay)
1268       {
1269          XWindowAttributes attributes = { 0 };
1270          XGetWindowAttributes(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), &attributes);
1271          xSystemDepth = attributes.depth;
1272          xSystemVisual = attributes.visual;
1273          switch(xSystemDepth)
1274          {
1275             case 32: case 24: xSystemPixelFormat = pixelFormat888; break;
1276             case 16:
1277             case 15:
1278             {
1279                XVisualInfo vinfo;
1280                XVisualInfo *vinfo_ret;
1281                int numitems = 0;
1282
1283                vinfo.visualid = XVisualIDFromVisual(xSystemVisual);
1284                vinfo_ret = XGetVisualInfo(xGlobalDisplay, VisualIDMask, &vinfo, &numitems);
1285                if(numitems)
1286                {
1287                   xSystemPixelFormat = (vinfo_ret->green_mask == 0x3E0) ? pixelFormat555 : pixelFormat565;
1288                   /*
1289                   if(GetXRenderFormat(xSystemPixelFormat, 0))
1290                   {
1291                      // printf("Got X Render format %d\n", xSystemPixelFormat);
1292                      break;
1293                   }
1294                   else
1295                      printf("No X Format?\n");
1296                   xSystemPixelFormat = (xSystemPixelFormat == pixelFormat555) ? pixelFormat565 : pixelFormat555;
1297                   vinfo = *vinfo_ret;
1298                   // vinfo._class = DirectColor;
1299                   vinfo.visualid = 0;
1300                   vinfo.bits_per_rgb = 5;
1301                   vinfo.depth = xSystemDepth;
1302                   vinfo.green_mask = (xSystemPixelFormat == pixelFormat555) ? 0x3E0 : 0x7E0;
1303                   vinfo.red_mask   = (xSystemPixelFormat == pixelFormat555) ? 0x7C00 : 0xF800;
1304                   XFree((void *) vinfo_ret);
1305                   if(XMatchVisualInfo(xGlobalDisplay, DefaultScreen(xGlobalDisplay), vinfo.depth, vinfo._class, &vinfo))
1306                   //vinfo_ret = XGetVisualInfo(xGlobalDisplay, VisualDepthMask|VisualRedMaskMask|VisualGreenMaskMask|VisualBlueMaskMask, &vinfo, &numitems);
1307                   //if(vinfo_ret)
1308                   {
1309                      //vinfo = *vinfo_ret;
1310                      if(GetXRenderFormat(xSystemPixelFormat, 0))
1311                      {
1312                         // printf("Got X Render format %d (second try)\n", xSystemPixelFormat);
1313                         // printf("red mask: %x, green mask: %x, blue mask: %x\n", vinfo.red_mask,vinfo.green_mask, vinfo.blue_mask);
1314                      }
1315                      xSystemVisual = vinfo.visual;
1316                   }
1317                   else
1318                      printf("Could not get a 555 visual\n");
1319                   */
1320                }
1321                break;
1322             }
1323          }
1324          // printf("Got a depth of %d\n", xSystemDepth);
1325
1326          {
1327             int major, minor, pixmaps;
1328             xSharedMemory = XShmQueryExtension(xGlobalDisplay) && XShmQueryVersion(xGlobalDisplay, &major, &minor, &pixmaps) && pixmaps;
1329          }
1330
1331          // printf("Opening IM\n");
1332          im = XOpenIM(xGlobalDisplay, null, null, null);
1333          // if(im)
1334          {
1335             XColor fore = { 0 }, back = { 0 };
1336             Pixmap pixmap = XCreatePixmap(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), 1, 1, 1);
1337             Pixmap mask = XCreatePixmap(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), 1, 1, 1);
1338             XSetWindowAttributes attributes = { 0 };
1339
1340             XkbSetDetectableAutoRepeat(xGlobalDisplay, True, &autoRepeatDetectable);
1341
1342             XInternAtoms(xGlobalDisplay, (char**)atomNames, AtomIdents::enumSize, False, atoms);
1343
1344             // Check which atoms are supported by the WM
1345             {
1346                int format;
1347                unsigned long count, fill;
1348                Atom type;
1349                Atom * data;
1350
1351                if(XGetWindowProperty(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), atoms[_net_supported],
1352                   0, 10000, False, XA_ATOM, &type, &format, &count, &fill, (void *)&data) == Success)
1353                {
1354                   int i;
1355                   for (i = 0; i < count; i++)
1356                   {
1357                      AtomIdents j;
1358                      for(j = 0; j < AtomIdents::enumSize; j++)
1359                      {
1360                         if(atoms[j] == data[i])
1361                         {
1362                            atomsSupported[j] = true;
1363                            break;
1364                         }
1365                      }
1366                   }
1367                   XFree(data);
1368                }
1369             }
1370
1371             {
1372                Atom protocols[2] = { atoms[wm_delete_window], atoms[wm_take_focus] };
1373
1374                XSetWMProtocols(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), protocols, 2);
1375             }
1376
1377             /*
1378             if(atomsSupported[_net_workarea])
1379                printf("Warning: _NET_WORKAREA extension not supported\n");
1380             */
1381
1382             attributes.override_redirect = True;
1383             if(!windowContext)
1384             {
1385                windowContext = XUniqueContext();
1386             }
1387
1388             nullCursor = XCreatePixmapCursor(xGlobalDisplay, pixmap, mask, &fore, &back, 0, 0);
1389             confineWindow = XCreateWindow(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay),
1390                0,0,1,1,0, CopyFromParent, InputOnly, xSystemVisual /*CopyFromParent*/, CWOverrideRedirect, &attributes);
1391
1392
1393             // IM initialization
1394             {
1395                /*ic = XCreateIC(im, XNInputStyle,
1396                   XIMPreeditNothing | XIMStatusNothing,
1397                   // XIMPreeditNone | XIMStatusNone | XIMPreeditPosition | XIMStatusArea | XIMPreeditArea | XIMStatusArea | XIMPreeditNothing | XIMStatusNothing,
1398                   XNClientWindow, confineWindow, XNFocusWindow, confineWindow, 0);
1399                   */
1400
1401                /*
1402                XIMStyles *IMcando;
1403                XIMStyle  clientCanDo;
1404                XIMStyle  styleWeWillUse = null;
1405                int i;
1406                XVaNestedList arglist;
1407                unsigned long imEventMask;
1408
1409                XGetImValues(im, XNQueryInputStyle, &IMcando, null);
1410                XSetICFocus(ic);
1411                clientCanDo =
1412                   XIMPreeditNone | XIMStatusNone |
1413                   XIMPreeditPosition | XIMStatusArea |
1414                   XIMPreeditArea | XIMStatusArea |
1415                   XIMPreeditNothing | XIMStatusNothing;
1416
1417                for(i=0; i<IMcando->count_styles; i++)
1418                {
1419                    XIMStyle tmpStyle;
1420                    tmpStyle = IMcando->support_styles[i];
1421                    if ( ((tmpStyle & clientCanDo) == tmpStyle) && prefer(tmpStyle, styleWeWillUse) )
1422                      styleWeWillUse = tmpStyle;
1423                }
1424                if(styleWeWillUse = null)
1425                    exit_with_error();
1426                XFree(IMcando);
1427
1428                arglist = XVaCreateNestedList(0, XNFontSet, fontset,
1429                                           XNForeground,
1430                                           WhitePixel(xGlobalDisplay, screen),
1431                                           XNBackground,
1432                                           BlackPixel(xGlobalDisplay, screen),
1433                                           NULL);
1434                ic = XCreateIC(im, XNInputStyle, styleWeWillUse,
1435                              XNClientWindow, window, XNFocusWindow, window,
1436                              XNStatusAttributes, arglist,
1437                              XNPreeditAttributes, arglist, NULL);
1438                XFree(arglist);
1439                if (ic == null)
1440                    exit_with_error();
1441
1442                XGetWindowAttributes(xGlobalDisplay, win, &winAtts);
1443                XGetICValues(ic, XNFilterEvents, &imEventMask, null);
1444                imEventMask |= winAtts.your_event_mask;
1445                XSelectInput(xGlobalDisplay, window, imEventMask);
1446                XSetICFocus(ic);
1447                */
1448             }
1449
1450             xMutex.Wait();
1451             timerThread = Thread { };
1452             incref timerThread;
1453             timerThread.Main = XTimerThread;
1454             timerThread.Create();
1455
1456             return true;
1457          }
1458       }
1459       return false;
1460    }
1461
1462    void Terminate()
1463    {
1464       XEvent e = { 0 };
1465       xTerminate = true;
1466
1467       // WHY WAS THIS COMMENTED HERE?
1468       // Probably because it was causing crashes, the proper fix should now be in DestroyRootWindow
1469       delete lastActive;
1470
1471       xMutex.Release();
1472       xSemaphore.Release();
1473
1474       timerThread.Wait();
1475       delete timerThread;
1476       hiResTimer.Stop();
1477
1478       XFreeCursor(xGlobalDisplay, systemCursors[iBeam]);
1479       XFreeCursor(xGlobalDisplay, systemCursors[cross]);
1480       XFreeCursor(xGlobalDisplay, systemCursors[moving]);
1481       XFreeCursor(xGlobalDisplay, systemCursors[sizeNESW]);
1482       XFreeCursor(xGlobalDisplay, systemCursors[sizeNS]);
1483       XFreeCursor(xGlobalDisplay, systemCursors[sizeNWSE]);
1484       XFreeCursor(xGlobalDisplay, systemCursors[sizeWE]);
1485       XFreeCursor(xGlobalDisplay, systemCursors[hand]);
1486       XFreeCursor(xGlobalDisplay, systemCursors[arrow]);
1487
1488       //XPutBackEvent(xGlobalDisplay, &e);
1489       // xThread.Wait();
1490       // delete xThread;
1491
1492       /*if(windowData && windowData.ic)
1493       {
1494          XDestroyIC(windowData.ic);
1495          windowData.ic = null;
1496       }*/
1497       if(im)
1498       {
1499          XCloseIM(im);
1500          im = null;
1501       }
1502       XCloseDisplay(xGlobalDisplay);
1503       xGlobalDisplay = null;
1504
1505       if(joystickFD[0] != -1) close(joystickFD[0]);
1506       if(joystickFD[1] != -1) close(joystickFD[1]);
1507       if(joystickFD[2] != -1) close(joystickFD[2]);
1508       if(joystickFD[3] != -1) close(joystickFD[3]);
1509    }
1510
1511    #define DBLCLICK_DELAY  300   // 0.3 second
1512    #define DBLCLICK_DELTA  1
1513
1514    bool ProcessInput(bool processAll)
1515    {
1516       bool eventAvailable = false;
1517       XEvent e;
1518
1519       if(!fullScreenMode) RepositionDesktop(true);
1520       //xMutex.Wait();
1521 //*      XLockDisplay(xGlobalDisplay);
1522       while(!xTerminate && (/*gotAnXEvent || */XCheckIfEvent(xGlobalDisplay, &e, EventChecker, null)))
1523       {
1524          Window window = null;
1525          XAnyEvent * thisEvent = (XAnyEvent *)&e;
1526          // printf("Got an event: %d\n", thisEvent->type);
1527
1528          //if(gotAnXEvent) { thisEvent = (XAnyEvent *)&xEvent; gotAnXEvent = false; }
1529
1530          if(im && XFilterEvent((union _XEvent *)thisEvent, None))
1531             continue;
1532          eventAvailable = true;
1533          XFindContext(xGlobalDisplay, thisEvent->window, windowContext, (XPointer *) &window);
1534          if(window)
1535          {
1536             XWindowData windowData = window.windowData;
1537             static uint lastKeyCode = 0;
1538             switch(thisEvent->type)
1539             {
1540                case KeyPress:
1541                {
1542                   XKeyEvent * event = (XKeyEvent *) thisEvent;
1543                   incref window;
1544                   timeStamp = event->time;
1545                   if(!window.active)
1546                   {
1547                      Window modalRoot = window.FindModal();
1548                      XWindowData windowData;
1549
1550                      activeWindow = (X11Window)window.windowHandle;
1551
1552                      if(!window.parent || window != window.parent.activeChild)
1553                      {
1554                         if(modalRoot)
1555                            modalRoot.ExternalActivate(true, true, window, null);
1556                         else
1557                            window.ExternalActivate(true, true, window, null); // lastActive);
1558                         windowData = modalRoot ? modalRoot.windowData : window.windowData;
1559                         if(windowData && windowData.ic)
1560                         {
1561                            // XSetICValues(ic, XNClientWindow, window.windowHandle, XNFocusWindow, window.windowHandle, 0);
1562                            XSetICFocus(windowData.ic);
1563                         }
1564                      }
1565                   }
1566                   //*XUnlockDisplay(xGlobalDisplay);
1567                   ProcessKeyMessage(window, event->keycode, (event->keycode == lastKeyCode) ? 2 : 0, event);
1568                   //*if(xGlobalDisplay) XLockDisplay(xGlobalDisplay);
1569                   lastKeyCode = event->keycode;
1570                   delete window;
1571                   break;
1572                }
1573                case KeyRelease:
1574                {
1575                   XKeyEvent * event = (XKeyEvent *) thisEvent;
1576                   XEvent nextEvent;
1577                   lastKeyCode = 0;
1578                   timeStamp = event->time;
1579                   if(!autoRepeatDetectable && XCheckIfEvent(xGlobalDisplay, (XEvent *)&nextEvent, EventChecker, (void *)KeyPress))
1580                   {
1581                      if(im && XFilterEvent(&nextEvent, None))
1582                         break;
1583
1584                      if(((XKeyEvent *)&nextEvent)->keycode == event->keycode)
1585                      {
1586                         //*XUnlockDisplay(xGlobalDisplay);
1587                         ProcessKeyMessage(window, event->keycode, 2, event);
1588                      }
1589                      else
1590                      {
1591                         //*XUnlockDisplay(xGlobalDisplay);
1592                         // printf("Keycode not the same :(\n");
1593                         ProcessKeyMessage(window, event->keycode, 1, event);
1594                         ProcessKeyMessage(window, ((XKeyEvent *)&nextEvent)->keycode, 0, (XKeyEvent *)&nextEvent);
1595                      }
1596                   }
1597                   else
1598                   {
1599                      //*XUnlockDisplay(xGlobalDisplay);
1600                      // printf("No KeyPress ahead\n");
1601                      ProcessKeyMessage(window, event->keycode, 1, event);
1602                   }
1603                   //*if(xGlobalDisplay) XLockDisplay(xGlobalDisplay);
1604                   break;
1605                }
1606                case ButtonPress:
1607                {
1608                   XButtonEvent * event = (XButtonEvent *) thisEvent;
1609
1610                   static double lastTime[3];
1611                   static Window lastWindow[3];
1612                   static Point lastPos[3];
1613
1614                   Modifiers keyFlags = 0;
1615                   bool doubleClick;
1616                   uint button, buttonDouble, whichButton;
1617                   uint buttonMask;
1618                   int x = event->x_root, y = event->y_root;
1619                   timeStamp = event->time;
1620                   if(event->button == Button1)
1621                   {
1622                      // Force a raise on click here to deal with confused active state preventing to bring the window up
1623                      if(!atomsSupported[_net_active_window] && !window.isRemote)
1624                         XRaiseWindow(xGlobalDisplay, (X11Window)window.windowHandle);
1625                      XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToPointerRoot, CurrentTime);
1626                      button = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown;
1627                      buttonDouble = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick;
1628                      whichButton = 0;
1629                      buttonMask = Button1Mask;
1630                      keyFlags.left = true;
1631                   }
1632                   else if(event->button == Button3)
1633                   {
1634                      button = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown;
1635                      buttonDouble = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick;
1636                      whichButton = 2;
1637                      buttonMask = Button3Mask;
1638                      keyFlags.right = true;
1639                   }
1640                   else
1641                   {
1642                      button = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown;
1643                      buttonDouble = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick;
1644                      whichButton = 1;
1645                      buttonMask = Button2Mask;
1646                      keyFlags.middle = true;
1647                   }
1648                   if(event->state & buttonMask)
1649                      break;
1650
1651                   doubleClick = event->time - lastTime[whichButton] < DBLCLICK_DELAY &&
1652                      window == lastWindow[whichButton] &&
1653                      Abs(event->x_root - lastPos[whichButton].x) < DBLCLICK_DELTA &&
1654                      Abs(event->y_root - lastPos[whichButton].y) < DBLCLICK_DELTA;
1655                   lastTime[whichButton] = doubleClick ? 0 : event->time;
1656                   lastWindow[whichButton] = window;
1657                   lastPos[whichButton].x = event->x_root;
1658                   lastPos[whichButton].y = event->y_root;
1659
1660                   if(event->state & ShiftMask)     keyFlags.shift = true;
1661                   if(event->state & ControlMask)   keyFlags.ctrl = true;
1662                   if(event->state & Mod1Mask)      keyFlags.alt = true;
1663                   if(event->state & Button1Mask)   keyFlags.left = true;
1664                   if(event->state & Button2Mask)   keyFlags.middle = true;
1665                   if(event->state & Button3Mask)   keyFlags.right = true;
1666                   //*XUnlockDisplay(xGlobalDisplay);
1667
1668                   incref window;
1669                   if(event->button == Button4 || event->button == Button5)
1670                   {
1671                      window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, (event->button == Button4) ? wheelUp : wheelDown, 0);
1672                   }
1673                   else
1674                   {
1675                      if(doubleClick)
1676                      {
1677                         if(!window.MouseMessage(buttonDouble, x, y, &keyFlags, false, true))
1678                         {
1679                            //*if(xGlobalDisplay) XLockDisplay(xGlobalDisplay);
1680                            delete window;
1681                            break;
1682                         }
1683                      }
1684                      window.MouseMessage(button, x, y, &keyFlags, false, /*doubleClick? false : */true);
1685                   }
1686                   //*if(xGlobalDisplay) XLockDisplay(xGlobalDisplay);
1687                   delete window;
1688                   break;
1689                }
1690                case ButtonRelease:
1691                {
1692                   Modifiers keyFlags = 0;
1693                   XButtonEvent * event = (XButtonEvent *) thisEvent;
1694                   uint button;
1695                   uint buttonMask;
1696                   int x = event->x_root, y = event->y_root;
1697                   if(event->button == Button1)
1698                   {
1699                      button = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp;
1700                      buttonMask = Button1Mask;
1701                   }
1702                   else if(event->button == Button3)
1703                   {
1704                      button = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp;
1705                      buttonMask = Button3Mask;
1706                   }
1707                   else
1708                   {
1709                      button = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp;
1710                      buttonMask = Button2Mask;
1711                   }
1712                   timeStamp = event->time;
1713                   if(!(event->state & buttonMask)) break;
1714                   if(event->state & ShiftMask)     keyFlags.shift = true;
1715                   if(event->state & ControlMask)   keyFlags.ctrl = true;
1716                   if(event->state & Mod1Mask)      keyFlags.alt = true;
1717                   if(event->state & Button1Mask)   keyFlags.left = true;
1718                   if(event->state & Button2Mask)   keyFlags.middle = true;
1719                   if(event->state & Button3Mask)   keyFlags.right = true;
1720                   if(guiApp.windowCaptured && guiApp.windowCaptured != window)
1721                   {
1722                      // X hasn't noticed the capture yet, so fix it!
1723                      x += window.absPosition.x;
1724                      y += window.absPosition.y;
1725                      window = guiApp.windowCaptured.rootWindow;
1726                      x -= window.absPosition.x;
1727                      y -= window.absPosition.y;
1728                   }
1729                   //*XUnlockDisplay(xGlobalDisplay);
1730                   incref window;
1731                   window.MouseMessage(button, x, y, &keyFlags, false, false);
1732                   delete window;
1733                   //*if(xGlobalDisplay) XLockDisplay(xGlobalDisplay);
1734                   break;
1735                }
1736                case MotionNotify:
1737                {
1738                   static uint lastTime = 0;
1739                   XMotionEvent * event = (XMotionEvent *) thisEvent;
1740                   while(XCheckIfEvent(xGlobalDisplay, (XEvent *)thisEvent, EventChecker, (void *)MotionNotify));
1741                   // if(event->time - lastTime > 15)
1742                   {
1743                      Modifiers keyFlags = 0;
1744                      timeStamp = event->time;
1745                      // int x = event->x_root, y = event->y_root;
1746
1747                      if(event->state & ShiftMask)     keyFlags.shift = true;
1748                      if(event->state & ControlMask)   keyFlags.ctrl = true;
1749                      if(event->state & Mod1Mask)      keyFlags.alt = true;
1750                      if(event->state & Button1Mask)   keyFlags.left = true;
1751                      if(event->state & Button2Mask)   keyFlags.middle = true;
1752                      if(event->state & Button3Mask)   keyFlags.right = true;
1753                      //*XUnlockDisplay(xGlobalDisplay);
1754                      incref window;
1755                      window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove,
1756                         event->x_root, event->y_root, &keyFlags, false, false);
1757                      delete window;
1758                      //*if(xGlobalDisplay) XLockDisplay(xGlobalDisplay);
1759                      lastTime = (uint)event->time;
1760                   }
1761                   break;
1762                }
1763                case Expose:
1764                {
1765                   XExposeEvent * event = (XExposeEvent *) thisEvent;
1766                   Box box;
1767                   box.left = event->x;
1768                   box.top = event->y;
1769                   box.right = box.left + event->width - 1;
1770                   box.bottom = box.top + event->height - 1;
1771                   window.UpdateDirty(box);
1772                   break;
1773                }
1774                case SelectionRequest:
1775                {
1776                   XSelectionRequestEvent *req = (XSelectionRequestEvent *) thisEvent;
1777                   XEvent respond;
1778                   if(req->target == atoms[targets] && clipBoardData)
1779                   {
1780                      Atom * supportedTargets = new Atom[4];
1781                      supportedTargets[0] = atoms[targets];
1782                      supportedTargets[1] = atoms[multiple];
1783                      supportedTargets[2] = XA_STRING;
1784                      supportedTargets[3] = atoms[utf8_string];
1785                      XChangeProperty(xGlobalDisplay,req->requestor, req->_property,
1786                         XA_ATOM,32,PropModeReplace, (byte *) supportedTargets, 4*sizeof(Atom));
1787                      respond.xselection._property = req->_property;
1788                      delete supportedTargets;
1789                   }
1790                   else if((req->target == XA_STRING || req->target == atoms[utf8_string]) && clipBoardData)
1791                   {
1792                      Atom _property = (req->_property == None) ? req->target : req->_property;
1793                      XChangeProperty(xGlobalDisplay,req->requestor, _property,
1794                         req->target/*req->_property*/,8,PropModeReplace, (byte *) clipBoardData, strlen(clipBoardData));
1795                      respond.xselection._property = _property;
1796                   }
1797                   else
1798                      respond.xselection._property = None;
1799
1800                   respond.xselection.type = SelectionNotify;
1801                   respond.xselection.display = req->display;
1802                   respond.xselection.requestor = req->requestor;
1803                   respond.xselection.selection =req->selection;
1804                   respond.xselection.target = req->target;
1805                   respond.xselection.time = CurrentTime;
1806                   XSendEvent(xGlobalDisplay, req->requestor,0,0,&respond);
1807                   break;
1808                }
1809                case SelectionClear:
1810                {
1811                   delete clipBoardData;
1812                   break;
1813                }
1814                case FocusIn:
1815                {
1816                   if(activeWindow != (X11Window)window.windowHandle)
1817                   {
1818                      XFocusChangeEvent *event = (XFocusChangeEvent *) thisEvent;
1819                      Window modalRoot = window.FindModal();
1820                      XWindowData windowData;
1821
1822                      activeWindow = (X11Window)window.windowHandle;
1823
1824                      if(window.parent && window == window.parent.activeChild) break;
1825                      incref window;
1826                      //if(window.creationActivation == activate)
1827                      {
1828                         if(modalRoot)
1829                            modalRoot.ExternalActivate(true, true, window, null); // lastActive);
1830                         else
1831                            window.ExternalActivate(true, true, window, null); // lastActive);
1832                      }
1833                      windowData = modalRoot ? modalRoot.windowData : window.windowData;
1834                      if(windowData && windowData.ic)
1835                      {
1836                         // XSetICValues(ic, XNClientWindow, window.windowHandle, XNFocusWindow, window.windowHandle, 0);
1837                         XSetICFocus(windowData.ic);
1838                      }
1839                      //delete lastActive;
1840                      //lastActive = window;
1841                      //incref lastActive;
1842                      delete window;
1843                   }
1844                   break;
1845                }
1846                case FocusOut:
1847                {
1848 #ifdef _DEBUG
1849                   //printf("Processing a FocusOut Event for %s (%x)\n", window._class.name, window);
1850 #endif
1851
1852                   if(XCheckTypedWindowEvent(xGlobalDisplay, thisEvent->window, FocusIn, (XEvent *)thisEvent))
1853                   {
1854                      break;
1855                   }
1856                   if(thisEvent->window == activeWindow)
1857                      activeWindow = (X11Window)null;
1858 #if 0
1859                   if(XCheckTypedEvent(xGlobalDisplay, FocusIn, (XEvent *)thisEvent))
1860                   {
1861                      if(XCheckTypedWindowEvent(xGlobalDisplay, thisEvent->window, FocusOut, (XEvent *)thisEvent))
1862                      {
1863                         XFocusChangeEvent *event = (XFocusChangeEvent *) thisEvent;
1864
1865                         XFindContext(xGlobalDisplay, thisEvent->window, windowContext, (XPointer *) &window);
1866                         if(window)
1867                         {
1868                            Window windowCopy = window;
1869                            XWindowData windowData;
1870                            if(windowCopy == windowCopy.parent.activeChild) break;
1871                            incref windowCopy;
1872                            windowCopy.ExternalActivate(true, true,  windowCopy, lastActive);
1873
1874                            windowData = windowCopy.windowData;
1875                            if(windowData && windowData.ic)
1876                               XSetICFocus(windowData.ic);
1877
1878                            delete lastActive;
1879                            lastActive = windowCopy;
1880                            incref lastActive;
1881                            delete windowCopy;
1882                         }
1883
1884                         // XFindContext(xGlobalDisplay, thisEvent->window, windowContext, (XPointer *) &window);
1885                         if(window)
1886                         {
1887                            if(window != window.parent.activeChild) break;
1888                            incref window;
1889                            window.ExternalActivate(false, true,  window, lastActive);
1890                            delete window;
1891                         }
1892                      }
1893                      else
1894                      {
1895                         XWindowData windowData;
1896                         XFindContext(xGlobalDisplay, thisEvent->window, windowContext, (XPointer *) &window);
1897
1898                         if(window)
1899                         {
1900                            XFocusChangeEvent *event = (XFocusChangeEvent *) thisEvent;
1901                            Window modalRoot = window.FindModal();
1902
1903                            incref window;
1904                            if(modalRoot)
1905                            {
1906                               modalRoot.ExternalActivate(true, true, window, lastActive);
1907                            }
1908                            else
1909                            {
1910                               window.ExternalActivate(true, true, window, lastActive);
1911                            }
1912                            windowData = modalRoot ? modalRoot.windowData : window.windowData;
1913                            if(windowData && windowData.ic)
1914                               XSetICFocus(windowData.ic);
1915
1916                            delete lastActive;
1917                            lastActive = window;
1918                            incref lastActive;
1919                            delete window;
1920                         }
1921                      }
1922                   }
1923                   else
1924 #endif
1925                   {
1926                      XFocusChangeEvent *event = (XFocusChangeEvent *) thisEvent;
1927                      if(window != window.parent.activeChild && window != guiApp.interimWindow) break;
1928                      incref window;
1929
1930 #ifdef _DEBUG
1931                      //printf("Deactivating %s\n", window._class.name);
1932 #endif
1933
1934                      if(!window.ExternalActivate(false, true, window, null /*lastActive*/))
1935                      {
1936                         XCheckTypedEvent(xGlobalDisplay, /*thisEvent->window, */ButtonPress, (XEvent *)thisEvent);
1937                      }
1938
1939                      //delete lastActive;
1940                      /*
1941                      lastActive = window;
1942                      incref lastActive;
1943                      */
1944                      delete window;
1945                   }
1946                   break;
1947                }
1948                case ConfigureNotify:
1949                {
1950                   XConfigureEvent * event = (XConfigureEvent *) thisEvent;
1951                   bool unmaximized = false;
1952                   if(!window.visible) break;
1953                   while(XCheckIfEvent(xGlobalDisplay, (XEvent *)thisEvent, (void *)ConfigureNotifyChecker, (void *)window.windowHandle));
1954                   //if(event->x - desktopX != window.position.x || event->y - desktopY != window.position.y || event->width != window.size.w || event->height != window.size.h)
1955
1956                   if(atomsSupported[_net_wm_state]) //window.nativeDecorations)
1957                   {
1958                      int format;
1959                      unsigned long len, fill;
1960                      Atom type;
1961                      char * data = null;
1962                      if(XGetWindowProperty(xGlobalDisplay, (X11Window)window.systemHandle, atoms[_net_wm_state], 0, 32, False,
1963                             XA_ATOM, &type, &format, &len, &fill, &data) == Success)
1964                      {
1965                         bool maxVert = false, maxHorz = false, isMinimized = false;
1966                         Atom * hints = (Atom *)data;
1967                         int c;
1968                         for(c = 0; c < len && hints[c]; c++)
1969                         {
1970                            if(hints[c] == atoms[_net_wm_state_maximized_vert])
1971                               maxVert = true;
1972                            else if(hints[c] == atoms[_net_wm_state_maximized_horz])
1973                               maxHorz = true;
1974                            else if(hints[c] == atoms[_net_wm_state_hidden])
1975                               isMinimized = true;
1976                         }
1977                         XFree(data);
1978
1979                         if(maxVert && maxHorz)
1980                         {
1981                            if(window.state != maximized)
1982                            {
1983                               *&window.state = maximized;
1984                               if(!window.nativeDecorations)
1985                                  window.CreateSystemChildren();
1986                            }
1987                         }
1988                         else if(isMinimized)
1989                         {
1990                            if(window.state != minimized)
1991                            {
1992                               *&window.state = minimized;
1993                               if(!window.nativeDecorations)
1994                                  window.CreateSystemChildren();
1995                            }
1996                         }
1997                         else if(window.state != normal)
1998                         {
1999                            if(window.state == maximized)
2000                               unmaximized = true;
2001                            *&window.state = normal;
2002                            if(!window.nativeDecorations)
2003                               window.CreateSystemChildren();
2004                         }
2005                      }
2006                   }
2007                   {
2008                      bool offset = false;
2009                      int x, y, w, h;
2010                      if(unmaximized && window.nativeDecorations)
2011                      {
2012                         if(window.nativeDecorations && RequestFrameExtents((X11Window)window.windowHandle))
2013                            WaitForFrameExtents(window);
2014
2015                         // Ensure we set the normal size anchor when un-maximizing
2016                         window.ComputeAnchors(window.normalAnchor, window.normalSizeAnchor, &x, &y, &w, &h);
2017                      }
2018                      else
2019                      {
2020                         x = event->x;
2021                         y = event->y;
2022                         w = event->width, h = event->height;
2023
2024                         //if(event->send_event)
2025                         {
2026                            X11Window rootChild;
2027                            int rootX, rootY;
2028                            XTranslateCoordinates(xGlobalDisplay, event->window,
2029                               RootWindow(xGlobalDisplay, DefaultScreen(xGlobalDisplay)), 0, 0,
2030                               &rootX, &rootY, &rootChild);
2031
2032                            if(x != rootX || y != rootY)
2033                            {
2034                               /*if(event->send_event)
2035                                  offset = true;*/
2036                               x = rootX;
2037                               y = rootY;
2038                            }
2039                         }
2040
2041                         x -= desktopX;
2042                         y -= desktopY;
2043
2044                         if(window.nativeDecorations && window.state != maximized)
2045                         {
2046                            x -= windowData.decor.left;
2047                            y -= windowData.decor.top;
2048                            w += windowData.decor.left + windowData.decor.right;
2049                            h += windowData.decor.top + windowData.decor.bottom;
2050
2051                            /*
2052                            x -= window.clientStart.x;
2053                            y -= window.clientStart.y - (window.hasMenuBar ? skinMenuHeight : 0);
2054                            w += window.size.w - window.clientSize.w;
2055                            h += window.size.h - window.clientSize.h;
2056                            */
2057                         }
2058                      }
2059
2060                      window.Position(x, y, w, h, true, true, true, true, false, unmaximized);
2061
2062                      // Break the anchors for moveable/resizable windows
2063                      // Avoid doing this if the translation wasn't in sync as it will cause the window to move around
2064                      if(!unmaximized && !offset && window.style.fixed && window.state == normal)
2065                      {
2066                         window.normalAnchor = Anchor
2067                         {
2068                            left = x + windowData.decor.left,
2069                            top = y + windowData.decor.top
2070                         };
2071                         window.normalSizeAnchor =
2072                            SizeAnchor { { window.clientSize.w, window.clientSize.h }, isClientW = true, isClientH = true };
2073                      }
2074                   }
2075                   break;
2076                }
2077                case ClientMessage:
2078                {
2079                   XClientMessageEvent * event = (XClientMessageEvent *) thisEvent;
2080
2081                   if(event->data.l[0] == atoms[wm_delete_window])
2082                   {
2083                      window.Destroy(0);
2084                   }
2085
2086                   if(event->data.l[0] == atoms[wm_take_focus])
2087                   {
2088                      Window modalRoot;
2089                      XWindowData windowData;
2090                      bool laterFocus;
2091                      activeWindow = (X11Window)window.windowHandle;
2092
2093                      timeStamp = (X11Time)event->data.l[1];
2094
2095                      windowData = window.windowData;
2096                      laterFocus = windowData.laterFocus;
2097                      windowData.laterFocus = true;
2098
2099 #ifdef _DEBUG
2100                      //printf("Processing a ClientMessage WM_TAKE_FOCUS Event for %s (%x)\n", window._class.name, window);
2101 #endif
2102                      if(guiApp.interimWindow && guiApp.interimWindow.created && window != guiApp.interimWindow) break; //window == window.parent.activeChild) break;
2103                      // if(window == window.parent.activeChild) break;
2104                      incref window;
2105
2106                      {
2107                         XEvent checkEvent;
2108                         //XFlush(xGlobalDisplay);
2109                         while(XCheckTypedEvent(xGlobalDisplay, FocusOut, &checkEvent))
2110                         {
2111                            XFocusChangeEvent *event = (XFocusChangeEvent *) &checkEvent;
2112                            Window window;
2113                            XFindContext(xGlobalDisplay, event->window, windowContext, (XPointer *) &window);
2114                            if(window != window.parent.activeChild) break;
2115                            incref window;
2116
2117       #ifdef _DEBUG
2118                            //printf("Found a FocusOut ahead, deactivating %s (%d)\n", window._class.name, window);
2119       #endif
2120
2121                            if(!window.ExternalActivate(false, true, window, null /*lastActive*/))
2122                            {
2123                               XCheckTypedEvent(xGlobalDisplay, /*thisEvent->window, */ButtonPress, (XEvent *)thisEvent);
2124                            }
2125                            delete lastActive;
2126                            delete window;
2127                         }
2128                      }
2129
2130                      modalRoot = window.FindModal();
2131                      windowData = modalRoot ? modalRoot.windowData : window.windowData;
2132                      if(windowData)
2133                      {
2134                         if(laterFocus || (modalRoot ? modalRoot : window).creationActivation == activate)
2135                         {
2136                            if(modalRoot)
2137                            {
2138                               XRaiseWindow(xGlobalDisplay, (X11Window)modalRoot.windowHandle);
2139                               WaitForViewableWindow(modalRoot);
2140                               if(atomsSupported[_net_active_window])
2141                               {
2142                                  XClientMessageEvent event = { 0 };
2143                                  event.type = ClientMessage;
2144                                  event.message_type = atoms[_net_active_window];
2145                                  event.display = xGlobalDisplay;
2146                                  event.serial = 0;
2147                                  event.window = (X11Window)modalRoot.windowHandle;
2148                                  event.send_event = 1;
2149                                  event.format = 32;
2150                                  event.data.l[0] = /*0*/ 1;
2151                                  event.data.l[1] = timeStamp;
2152                                  event.data.l[2] = activeWindow;
2153                                  /*
2154                                  event.data.l[2] = activeWindow; //guiApp.desktop.activeChild.windowHandle;
2155                                  */
2156 #ifdef _DEBUG
2157                                  //printf("(ClientMessage - %s) Setting _NET_ACTIVE_WINDOW for %s (%x)\n", window._class.name, modalRoot._class.name, modalRoot);
2158 #endif
2159
2160                                  XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false, SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
2161                                  XSetInputFocus(xGlobalDisplay, (X11Window)modalRoot.windowHandle, RevertToPointerRoot, timeStamp);
2162
2163                                  //XFlush(xGlobalDisplay);
2164                                  //printf("Done.\n");
2165                               }
2166                            }
2167                            else
2168                            {
2169                               XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToPointerRoot, timeStamp);
2170                               window.ExternalActivate(true, true, window, null); // lastActive);
2171                               if(windowData && windowData.ic)
2172                               {
2173                                  // XSetICValues(ic, XNClientWindow, window.windowHandle, XNFocusWindow, window.windowHandle, 0);
2174                                  //XSetICFocus(windowData.ic);
2175                               }
2176                            }
2177                         }
2178                         windowData.laterFocus = true;
2179                         delete lastActive;
2180                         lastActive = window;
2181                         incref lastActive;
2182                      }
2183                      delete window;
2184                   }
2185                   break;
2186                }
2187                case PropertyNotify:
2188                {
2189                   XWindowData windowData = window.windowData;
2190                   XPropertyEvent * event = (XPropertyEvent *) thisEvent;
2191                   if(event->atom == atoms[_net_frame_extents] &&
2192                     event->state == PropertyNewValue && windowData)
2193                   {
2194                      if(!GetFrameExtents(window, true))
2195                         windowData.gotFrameExtents = true; // Unsupported?
2196                   }
2197                   break;
2198                }
2199             }
2200             if(!processAll) break;
2201          }
2202       }
2203       //*if(xGlobalDisplay) XUnlockDisplay(xGlobalDisplay);
2204       //xMutex.Release();
2205       if(!eventAvailable)
2206          return false;
2207       return true;
2208    }
2209
2210    void Wait()
2211    {
2212       gotAnXEvent = false;
2213       xMutex.Release();
2214       xSemaphore.Release();
2215       guiApp.WaitEvent();
2216       xMutex.Wait();
2217    }
2218
2219    void Lock(Window window)
2220    {
2221       //*XLockDisplay(xGlobalDisplay);
2222    }
2223
2224    void Unlock(Window window)
2225    {
2226       //*XUnlockDisplay(xGlobalDisplay);
2227    }
2228
2229    char ** GraphicsDrivers(int * numDrivers)
2230    {
2231       static char *graphicsDrivers[] = { "X", "OpenGL" };
2232       *numDrivers = sizeof(graphicsDrivers) / sizeof(char *);
2233       return (char **)graphicsDrivers;
2234    }
2235
2236    void GetCurrentMode(bool * fullScreen, int * resolution, int * colorDepth, int * refreshRate)
2237    {
2238       *fullScreen = fullScreenMode;
2239    }
2240
2241    void EnsureFullScreen(bool *fullScreen)
2242    {
2243
2244    }
2245
2246    bool ScreenMode(bool fullScreen, int resolution, int colorDepth, int refreshRate, bool * textMode)
2247    {
2248       bool result = true;
2249
2250       fullScreenMode = fullScreen;
2251
2252       if(fullScreen)
2253       {
2254
2255       }
2256       else
2257       {
2258          static bool firstTime = true;
2259          firstTime = false;
2260          desktopX = desktopY = desktopW = desktopH = 0;
2261
2262          RepositionDesktop(false);
2263       }
2264       return result;
2265    }
2266
2267    // --- Window Creation ---
2268    void * CreateRootWindow(Window window)
2269    {
2270       X11Window windowHandle;
2271       XSetWindowAttributes attributes = { 0 };
2272       XVisualInfo * visualInfo = null;
2273       int depth;
2274       Visual * visual;
2275       XIC ic = null;
2276       unsigned long mask = EVENT_MASK;
2277
2278       // Old WM (e.g. TWM), use built-in decorations
2279       if(!atomsSupported[_net_wm_state])
2280          window.nativeDecorations = false;
2281       attributes.override_redirect = (window.interim || (!atomsSupported[_net_wm_state] && !window.nativeDecorations)) ? True : False;
2282       attributes.event_mask = EVENT_MASK;
2283       //printf("%s\n", guiApp.defaultDisplayDriver);
2284 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D) && !defined(ECERE_NOGL)
2285       if(window.dispDriver == class(OpenGLDisplayDriver) || !strcmp(guiApp.defaultDisplayDriver, "OpenGL"))
2286       {
2287          int samples;
2288          bool alpha = true;
2289          for(samples = 4;; samples /= 2)
2290          {
2291             bool found = false;
2292             int attrib[30] =
2293             {
2294                GLX_RENDER_TYPE, GLX_RGBA_BIT,
2295                GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
2296                GLX_DOUBLEBUFFER, True,
2297                GLX_DEPTH_SIZE, 1,
2298                GLX_RED_SIZE, 1,
2299                GLX_GREEN_SIZE, 1,
2300                GLX_BLUE_SIZE, 1
2301             };
2302             int numAttribs = 14;
2303
2304             GLXFBConfig *fbconfigs = null, fbconfig;
2305             int numfbconfigs;
2306             int i;
2307             //printf("Samples = %d, alpha = %d\n", samples, alpha);
2308             if(alpha)
2309             {
2310                attrib[numAttribs++] = GLX_ALPHA_SIZE;
2311                attrib[numAttribs++] = 1;
2312             }
2313             if(samples)
2314             {
2315                attrib[numAttribs++] = GLX_SAMPLE_BUFFERS_ARB;
2316                attrib[numAttribs++] = GL_TRUE;
2317                attrib[numAttribs++] = GLX_SAMPLES_ARB;
2318                attrib[numAttribs++] = samples;
2319             }
2320             attrib[numAttribs] = None;
2321
2322             // visualInfo = glXChooseVisual(xGlobalDisplay, DefaultScreen(xGlobalDisplay), attrib);
2323
2324             //printf("Trying %d samples...\n", samples);
2325             fbconfigs = glXChooseFBConfig(xGlobalDisplay, DefaultScreen(xGlobalDisplay), attrib, &numfbconfigs);
2326             if(fbconfigs)
2327             {
2328                for (i = 0; i < numfbconfigs; i++)
2329                {
2330                   XRenderPictFormat * format;
2331                   visualInfo = glXGetVisualFromFBConfig(xGlobalDisplay, fbconfigs[i]);
2332                   if (!visualInfo) continue;
2333                   if(window.alphaBlend)
2334                   {
2335                      format = XRenderFindVisualFormat(xGlobalDisplay, visualInfo->visual);
2336                      if (!format) { XFree(visualInfo); continue; }
2337                      if(format->direct.alphaMask > 0)
2338                      {
2339                         //printf("Found what we're looking for (alphaBlend)\n");
2340                         fbconfig = fbconfigs[i];
2341                         found = true;
2342                         break;
2343                      }
2344                   }
2345                   else
2346                   {
2347                      //printf("Found what we're looking for\n");
2348                      found = true;
2349                      break;
2350                   }
2351                }
2352                if (i == numfbconfigs)
2353                {
2354                   fbconfig = fbconfigs[0];
2355                   visualInfo = glXGetVisualFromFBConfig(xGlobalDisplay, fbconfig);
2356                }
2357             }
2358             if(fbconfigs)
2359                XFree(fbconfigs);
2360             if(found || (!samples && !alpha))
2361             {
2362                //printf("Stopping now\n");
2363                break;
2364             }
2365             else
2366                XFree(visualInfo);
2367             if(samples == 1) samples = 0;
2368             else if(!samples) alpha = false;
2369          }
2370       }
2371       if(!visualInfo)
2372       {
2373          int attrList[] =
2374          {
2375             GLX_USE_GL, GLX_DEPTH_SIZE, 1,
2376             GLX_RGBA,
2377             GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
2378             GLX_DOUBLEBUFFER,
2379             None
2380          };
2381          visualInfo = glXChooseVisual(xGlobalDisplay, DefaultScreen(xGlobalDisplay), attrList);
2382       }
2383 #endif
2384       depth = visualInfo ? visualInfo->depth : (window.alphaBlend ? 32 : xSystemDepth);
2385       visual = visualInfo ? visualInfo->visual : (window.alphaBlend ? FindFullColorVisual (xGlobalDisplay, &depth) : xSystemVisual);
2386       // printf("visual: %d, depth: %d\n", visual, depth);
2387
2388       if(visual)
2389       {
2390          attributes.colormap = XCreateColormap(xGlobalDisplay, XRootWindow(xGlobalDisplay, DefaultScreen(xGlobalDisplay)), visual, AllocNone);
2391          attributes.border_pixel = 0;
2392       }
2393       else
2394          return null;
2395
2396       if(fullScreenMode)
2397       {
2398          windowHandle = XCreateWindow(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay),
2399             0,0,guiApp.desktop.size.w,guiApp.desktop.size.h,0, depth, InputOutput, visual ? visual : CopyFromParent,
2400             CWEventMask | (visual ? (CWColormap | CWBorderPixel) : 0)/*| CWOverrideRedirect*/, &attributes);
2401       }
2402       /*
2403          Unsupported for now...
2404       else if(window.systemParent)
2405       {
2406
2407       }
2408       */
2409       else
2410       {
2411          if(window.windowHandle)
2412             windowHandle = (X11Window)window.windowHandle;
2413          else
2414          {
2415             X11Window parentWindow = (X11Window)null;
2416             int x = window.position.x + desktopX, y = window.position.y + desktopY;
2417             int w = window.state == normal ? Max(1, window.size.w) : Max(1, window.normalSizeAnchor.size.w);
2418             int h = window.state == normal ? Max(1, window.size.h) : Max(1, window.normalSizeAnchor.size.h);
2419             MinMaxValue smw = 0, smh = 0;
2420             MinMaxValue minW = window.minSize.w, minH = window.minSize.h;
2421             window.OnResizing((int *)&minW, (int *)&minH);
2422
2423             // To fix jumping message boxes on Cinnamon:
2424             if(window.state == normal && (minW > window.minSize.w || minH > window.minSize.w))
2425                window.ComputeAnchors(window.normalAnchor, window.normalSizeAnchor, &x, &y, &w, &h);
2426
2427             window.SetWindowMinimum(&smw, &smh);
2428             minW = Max(minW, smw);
2429             minH = Max(minH, smh);
2430
2431             if(!window.nativeDecorations && window.state != normal)
2432             {
2433                w += window.size.w - window.clientSize.w;
2434                h += window.size.h - window.clientSize.h;
2435             }
2436
2437             if(window.master.rootWindow && window.master.rootWindow != guiApp.desktop && (window._isModal || window.style.interim))
2438             {
2439                Window master = window.master;
2440                Window rootWindow = master.rootWindow;
2441
2442                parentWindow = rootWindow.is3D ? (X11Window)rootWindow.parent.windowHandle : (X11Window)rootWindow.windowHandle;
2443
2444                // parentWindow = window.master.rootWindow.is3D ? window.master.rootWindow.parent.windowHandle : window.master.rootWindow.windowHandle;
2445             }
2446             if(window.style.showInTaskBar)
2447                parentWindow = (X11Window)null;
2448
2449             windowHandle = XCreateWindow(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay),
2450                x, y, w, h,
2451                0, depth, InputOutput, visual ? visual : CopyFromParent,
2452                CWEventMask | CWOverrideRedirect | (visual ? (CWColormap | CWBorderPixel) : 0), &attributes);
2453
2454             if(parentWindow && (window.interim || window.isModal))
2455             {
2456                //printf("Setting WM_TRANSIENT_FOR of %s to %s\n", window._class.name, window.master.rootWindow._class.name);
2457                XSetTransientForHint(xGlobalDisplay, windowHandle, parentWindow);
2458                //XFlush(xGlobalDisplay);
2459                //printf("Done.\n");
2460                //XChangeProperty(xGlobalDisplay, windowHandle, atoms[wm_transient_for], XA_WINDOW, 32, PropModeReplace, (unsigned char*)&parentWindow, 1);
2461                if(window.isModal)
2462                   SetNETWMState(windowHandle, false, add, atoms[_net_wm_state_modal], 0);
2463             }
2464
2465             {
2466                Atom hints[4];
2467                int count;
2468                if(parentWindow && window.interim)
2469                {
2470                   hints[0] = atoms[_net_wm_window_type_dropdown_menu];
2471                   hints[1] = atoms[_net_wm_window_type_popup_menu];
2472                   hints[2] = atoms[_net_wm_window_type_menu];
2473                   count = 3;
2474                }
2475                else if(parentWindow)
2476                {
2477                   hints[0] = atoms[_net_wm_window_type_normal];
2478                   SetNETWMState(windowHandle, false, add, atoms[_net_wm_state_skip_taskbar], 0);
2479
2480                   // Some WMs won't show a close button if dialog is set
2481                   // Additionally, this casues jumping of all dialog windows on Cinnamon
2482                   //hints[0] = atoms[_net_wm_window_type_dialog];
2483                   count = 1;
2484                }
2485                else
2486                {
2487                   hints[0] = atoms[_net_wm_window_type_normal];
2488                   count = 1;
2489                };
2490                XChangeProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_window_type], XA_ATOM, 32,
2491                   PropModeReplace, (unsigned char*)&hints, count);
2492
2493                {
2494                   XWMHints xwmHints;
2495                   xwmHints.flags = InputHint;
2496                   xwmHints.input = 0;
2497                   XSetWMHints(xGlobalDisplay, windowHandle, &xwmHints);
2498                }
2499                {
2500                   Atom protocols[2] = { atoms[wm_delete_window], atoms[wm_take_focus] };
2501                   XSetWMProtocols(xGlobalDisplay, windowHandle, protocols, 2);
2502                }
2503
2504                // Set Normal hints for minimum/maximum size
2505                {
2506                   XSizeHints hints = { 0 };
2507                   hints.min_width = minW;
2508                   hints.min_height = minH;
2509                   hints.flags |= PMinSize;
2510
2511                   if(window.maxSize.w < MAXINT || window.minSize.h < MAXINT)
2512                   {
2513                      hints.max_width = window.maxSize.w;
2514                      hints.max_height = window.maxSize.h;
2515                      hints.flags |= PMaxSize;
2516                   }
2517                   hints.x = x;
2518                   hints.y = y;
2519                   hints.flags |= PPosition;
2520
2521                   hints.width = w;
2522                   hints.height = h;
2523                   hints.flags |= PSize;
2524
2525                   XSetWMNormalHints(xGlobalDisplay, windowHandle, &hints);
2526                }
2527             }
2528          }
2529       }
2530
2531       if(!ic && im)
2532       {
2533          char fontString[1024] = "--helvetica-*-r-*-*-*-120-*-*-*-*-*-*,-misc-fixed-*-r-*-*-*-130-*-*-*-*-*-*";
2534          XPoint cursor_location = { 0, 0 };
2535          char **missing_charsets;
2536          int num_missing_charsets = 0;
2537          char *default_string;
2538          XFontSet fontset;
2539          XRectangle area = { 0, 0,  400, 400 };
2540          XVaNestedList argList;
2541
2542          // sprintf(fontString, "-*-%s-*-r-*-*-*-%d-*-*-*-*-*-*", "Helvetica" /*window.font.faceName*/, (int)(window.font.size * 20));
2543          fontset = XCreateFontSet(xGlobalDisplay, fontString, &missing_charsets, &num_missing_charsets, &default_string);
2544          argList = XVaCreateNestedList(0,
2545                                        XNSpotLocation, &cursor_location,
2546                                        //XNArea, &area,
2547                                        XNFontSet, fontset,/*
2548                                        XNForeground,
2549                                        WhitePixel(xGlobalDisplay, DefaultScreen(xGlobalDisplay)),
2550                                        XNBackground,
2551                                        BlackPixel(xGlobalDisplay, DefaultScreen(xGlobalDisplay)),*/
2552                                        NULL);
2553          ic = XCreateIC(im, XNInputStyle,
2554             XIMStatusNothing | XIMPreeditPosition,
2555             XNPreeditAttributes, argList,
2556             XNClientWindow, windowHandle, XNFocusWindow, windowHandle, NULL);
2557          XFree(argList);
2558          // Should we free the fontset or not?
2559          // XFreeFontSet(xGlobalDisplay, fontset);
2560          if(ic)
2561             setICPosition = true;
2562          else
2563             ic = XCreateIC(im, XNInputStyle, XIMStatusNothing | XIMPreeditNothing, XNClientWindow, windowHandle, XNFocusWindow, windowHandle, null);
2564       }
2565       if(ic)
2566       {
2567          XGetICValues(ic, XNFilterEvents, &mask, NULL);
2568          mask |= EVENT_MASK;
2569       }
2570       /*
2571       XSelectInput(xGlobalDisplay, windowHandle, mask);
2572
2573       if(capturedWindow == None && !restrictedWindow)
2574       {
2575          XGrabPointer(xGlobalDisplay, (X11Window)windowHandle, False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync,
2576             GrabModeAsync, restrictedWindow ? confineWindow : None, fullScreenMode ? nullCursor : None, CurrentTime);
2577          XUngrabPointer(xGlobalDisplay, CurrentTime);
2578       }
2579       */
2580
2581       {
2582          if ( atoms[_motif_wm_hints] != None )
2583          {
2584             MWM_Hints hints
2585             {
2586                (window.nativeDecorations ? 0 : MWM_HINTS_DECORATIONS)|MWM_HINTS_FUNCTIONS,
2587                (window.hasClose ? MWM_FUNC_CLOSE : 0) |
2588                (window.hasMaximize ? MWM_FUNC_MAXIMIZE : 0) |
2589                (window.hasMinimize ? MWM_FUNC_MINIMIZE : 0) |
2590                ((window.moveable || ((BorderBits)window.borderStyle).fixed) ? MWM_FUNC_MOVE : 0) |
2591                (((BorderBits)window.borderStyle).sizable ? MWM_FUNC_RESIZE : 0),
2592                 0, 0, 0
2593             };
2594             XChangeProperty(xGlobalDisplay, windowHandle, atoms[_motif_wm_hints], atoms[_motif_wm_hints], 32,
2595                PropModeReplace, (unsigned char*)&hints, 5);
2596          }
2597
2598          // *** We set this for ourselves, so don't check atomsSupported !!! ***
2599          if(atoms[_net_wm_pid])
2600          {
2601             int pid = getpid();
2602             // printf("Setting _NET_WM_PID to %d\n", pid);
2603             XChangeProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_pid], XA_CARDINAL, 32,
2604                PropModeReplace, (unsigned char*)&pid, 1);
2605          }
2606       }
2607
2608       /*
2609       {
2610          Atom protocolsAtom = XInternAtom(xGlobalDisplay, "WM_PROTOCOLS", False);
2611          if ( protocolsAtom != None )
2612          {
2613             MWM_Hints hints = { MWM_HINTS_DECORATIONS|MWM_HINTS_FUNCTIONS, 0, 0, 0, 0 };
2614             XChangeProperty(xGlobalDisplay, windowHandle, atoms[_motif_wm_hints], atoms[_motif_wm_hints], 32,
2615                PropModeReplace, (unsigned char*)&hints, sizeof(hints)/4);
2616          }
2617       }*/
2618       // XFlush(xGlobalDisplay);
2619       window.windowData = XWindowData { visualInfo, ic };
2620
2621       XSaveContext(xGlobalDisplay, windowHandle, windowContext, (XPointer)window);
2622
2623       XSelectInput(xGlobalDisplay, windowHandle, mask);
2624
2625       if(capturedWindow == None && !restrictedWindow)
2626       {
2627          XGrabPointer(xGlobalDisplay, (X11Window)windowHandle, False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync,
2628             GrabModeAsync, restrictedWindow ? confineWindow : None, fullScreenMode ? nullCursor : None, CurrentTime);
2629          XUngrabPointer(xGlobalDisplay, CurrentTime);
2630       }
2631
2632       if(!window.nativeDecorations || !RequestFrameExtents(windowHandle))
2633          ((XWindowData)window.windowData).gotFrameExtents = true;
2634
2635       return (void *)windowHandle;
2636    }
2637
2638    void DestroyRootWindow(Window window)
2639    {
2640       XEvent event;
2641
2642       XDeleteContext(xGlobalDisplay, (XID)window, windowContext);
2643       XSaveContext(xGlobalDisplay, (X11Window)window.windowHandle, windowContext, null);
2644       XDestroyWindow(xGlobalDisplay, (X11Window)window.windowHandle);
2645       XSync(xGlobalDisplay, 0);
2646       while(XCheckWindowEvent(xGlobalDisplay, (X11Window)window.windowHandle, 0xFFFFFFFF, &event));
2647       window.windowHandle = null;
2648       if(window.windowData)
2649       {
2650          XWindowData windowData = window.windowData;
2651          XFree(windowData.visual);
2652          if(windowData && windowData.ic)
2653             XDestroyIC(windowData.ic);
2654          delete windowData;
2655          // printf("Setting windowData for %s to null\n", window._class.name);
2656          window.windowData = null;
2657       }
2658       if(lastActive == window)
2659          delete lastActive;
2660    }
2661
2662    // -- Window manipulation ---
2663
2664    void SetRootWindowCaption(Window window, char * name)
2665    {
2666       if(window.windowHandle)
2667       {
2668          XChangeProperty(xGlobalDisplay, (X11Window)window.windowHandle, atoms[_net_wm_name],
2669             atoms[utf8_string], 8, PropModeReplace, (byte *)name, name ? strlen(name) : 0);
2670          XChangeProperty(xGlobalDisplay, (X11Window)window.windowHandle, atoms[wm_name],
2671             atoms[utf8_string], 8, PropModeReplace, (byte *)name, name ? strlen(name) : 0);
2672       }
2673    }
2674
2675    void PositionRootWindow(Window window, int x, int y, int w, int h, bool move, bool resize)
2676    {
2677       //Logf("Position root window %s\n", window.name);
2678       if(window.windowHandle && (!window.parent || !window.parent.display))
2679       {
2680          bool visible = window.visible;
2681          if(window.visible && window.created)
2682             XMapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
2683          if(window.state == minimized && atomsSupported[_net_wm_state]) return;
2684
2685          if(window.nativeDecorations)
2686          {
2687             XWindowData windowData = window.windowData;
2688
2689             // Was commenting this out was part of #700/#795 fix, but this causes jumping of e.g. About box after getting frame extents PropertyNotify
2690
2691                // && window.state != maximized -- required for Cinnamon on Mint 14/15
2692             if(!windowData.gotFrameExtents && window.state != maximized)
2693             {
2694                if(WaitForFrameExtents(window))
2695                {
2696                   x += windowData.decor.left;
2697                   y += windowData.decor.top ;
2698
2699                   w += windowData.decor.left + windowData.decor.right;
2700                   h += windowData.decor.top  + windowData.decor.bottom;
2701                }
2702             }
2703
2704             x -= windowData.decor.left;
2705             y -= windowData.decor.top;
2706
2707             w -= windowData.decor.left + windowData.decor.right;
2708             h -= windowData.decor.top + windowData.decor.bottom;
2709
2710             // Tweak for first unmaximize on Unity on Ubuntu 11.10
2711             /*if(window.state == maximized && (desktopX + w > desktopW || desktopY + h > desktopH))
2712             {
2713                w -= 40;
2714                h -= 40;
2715             }*/
2716          }
2717
2718          x += desktopX;
2719          y += desktopY;
2720
2721          if(!atomsSupported[_net_wm_state] || window.state != maximized)
2722          {
2723             if(move && resize)
2724                XMoveResizeWindow(xGlobalDisplay, (X11Window)window.windowHandle, x, y, w, h);
2725             else if(move)
2726                XMoveWindow(xGlobalDisplay, (X11Window)window.windowHandle, x, y);
2727             else if(resize)
2728                XResizeWindow(xGlobalDisplay, (X11Window)window.windowHandle, w, h);
2729
2730             // Reset min/max for fixed size windows on WMs not looking at MWM_FUNC_RESIZE (e.g. Cinnamon)
2731             if(window.style.fixed && !window.style.sizable)
2732             {
2733                XSizeHints hints = { 0 };
2734                long supplied;
2735                XGetWMNormalHints(xGlobalDisplay, (X11Window)window.windowHandle, &hints, &supplied);
2736                hints.min_width = hints.max_width = w;
2737                hints.min_height = hints.max_height = h;
2738                hints.flags |= PMinSize|PMaxSize;
2739                XSetWMNormalHints(xGlobalDisplay, (X11Window)window.windowHandle, &hints);
2740             }
2741          }
2742       }
2743    }
2744
2745    void OrderRootWindow(Window window, bool topMost)
2746    {
2747
2748    }
2749
2750    void SetRootWindowColor(Window window)
2751    {
2752
2753    }
2754
2755    void OffsetWindow(Window window, int * x, int * y)
2756    {
2757
2758    }
2759
2760    void UpdateRootWindow(Window window)
2761    {
2762       if(!window.parent || !window.parent.display)
2763       {
2764          if(window.visible)
2765          {
2766             Box box = window.box;
2767             box.left -= window.clientStart.x;
2768             box.top -= window.clientStart.y;
2769             box.right -= window.clientStart.x;
2770             box.bottom -= window.clientStart.y;
2771             // Logf("Update root window %s\n", window.name);
2772             window.Update(null);
2773             box.left   += window.clientStart.x;
2774             box.top    += window.clientStart.y;
2775             box.right  += window.clientStart.x;
2776             box.bottom += window.clientStart.y;
2777             window.UpdateDirty(box);
2778          }
2779       }
2780    }
2781
2782    void SetRootWindowState(Window window, WindowState state, bool visible)
2783    {
2784       // Old WM (e.g. TWM), use built-in decorations
2785       if(!atomsSupported[_net_wm_state])
2786          window.nativeDecorations = false;
2787       if(!window.parent || !window.parent.display)
2788       {
2789          //Logf("Set root window state %d %s\n", state, window.name);
2790          if(visible)
2791          {
2792             XMapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
2793             WaitForViewableWindow(window);
2794             if(window.creationActivation == activate && state != minimized)
2795                ActivateRootWindow(window);
2796
2797             if(state == minimized && atomsSupported[_net_wm_state])
2798             {
2799                uint iconic = IconicState;
2800
2801                // SetNETWMState(window.windowHandle, true, add, atoms[_net_wm_state_hidden], null);
2802                /*
2803                XChangeProperty(xGlobalDisplay, window.windowHandle, atoms[wm_state], XA_CARDINAL, 32,
2804                   PropModeReplace, &iconic, 1);
2805                */
2806
2807                /*
2808                XClientMessageEvent event = { 0 };
2809                event.type = ClientMessage;
2810                event.message_type = atoms[wm_state];
2811                event.display = xGlobalDisplay;
2812                event.window = window.windowHandle;
2813                event.send_event = 1;
2814                event.format = 32;
2815                event.data.l[0] = IconicState;
2816                XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false, SubstructureRedirectMask | SubstructureNotifyMask, &event);
2817                */
2818
2819                // printf("Attempting to minimize %s\n", window._class.name);
2820                XIconifyWindow(xGlobalDisplay, (X11Window)window.windowHandle, DefaultScreen(xGlobalDisplay));
2821             }
2822             else
2823             {
2824                //((XWindowData)window.windowData).gotFrameExtents && (!window.nativeDecorations || window.state == state))
2825                if(!atomsSupported[_net_wm_state] || (!((XWindowData)window.windowData).gotFrameExtents && window.state == maximized))
2826                {
2827                   // Running this block avoids the initial IDE maximized->unmaximized flicker
2828                   //if(window.state != maximized || !atomsSupported[_net_wm_state] || window.nativeDecorations)
2829                   {
2830                      int x = window.position.x;
2831                      int y = window.position.y;
2832                      int w = window.size.w;
2833                      int h = window.size.h;
2834
2835                      if(window.nativeDecorations)
2836                      {
2837                         XWindowData windowData = window.windowData;
2838                         x -= windowData.decor.left;
2839                         y -= windowData.decor.top;
2840
2841                         w -= windowData.decor.left + windowData.decor.right;
2842                         h -= windowData.decor.top + windowData.decor.bottom;
2843                      }
2844                      x += desktopX;
2845                      y += desktopY;
2846
2847                      XMoveResizeWindow(xGlobalDisplay,
2848                         (X11Window)window.windowHandle,
2849                         x, y, w, h);
2850                   }
2851                   UpdateRootWindow(window);
2852                }
2853                if(atomsSupported[_net_wm_state])
2854                {
2855                   // Maximize / Restore the window
2856                   SetNETWMState((X11Window)window.windowHandle, true, state == maximized ? add: remove,
2857                      atoms[_net_wm_state_maximized_vert], atoms[_net_wm_state_maximized_horz]);
2858                   if(state == maximized)
2859                   {
2860                      // Prevent the code in ConfigureNotify to think the window has been unmaximized
2861                      // if the Window Manager hasn't set the hints yet.
2862                      XFlush(xGlobalDisplay);
2863                      Sleep(0.01);
2864                   }
2865                }
2866             }
2867          }
2868          else
2869             XUnmapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
2870          //XFlush(xGlobalDisplay);
2871       }
2872    }
2873
2874    void FlashRootWindow(Window window)
2875    {
2876       // printf("Attempting to flash root window\n");
2877       SetNETWMState((X11Window)window.windowHandle, true, add, atoms[_net_wm_state_demands_attention], 0);
2878    }
2879
2880    void ActivateRootWindow(Window window)
2881    {
2882       if(!window.parent || !window.parent.display)
2883       {
2884          if(!window.style.hidden && window.created)
2885          {
2886             //printf("Activate root window %s\n", window._class.name);
2887             XRaiseWindow(xGlobalDisplay, (X11Window)window.windowHandle);
2888             XMapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
2889             WaitForViewableWindow(window);
2890             if(atomsSupported[_net_active_window])
2891             {
2892                XClientMessageEvent event = { 0 };
2893                event.type = ClientMessage;
2894                event.message_type = atoms[_net_active_window];
2895                event.display = xGlobalDisplay;
2896                event.serial = 0;
2897                event.window = (X11Window)window.windowHandle;
2898                event.send_event = 1;
2899                event.format = 32;
2900                event.data.l[0] = /*0*/ 1;
2901                event.data.l[1] = timeStamp;
2902                event.data.l[2] = activeWindow; //guiApp.desktop.activeChild.windowHandle;
2903
2904 #ifdef _DEBUG
2905                //printf("(ActivateRootWindow) Setting _NET_ACTIVE_WINDOW for %s (%x)\n", window._class.name, window);
2906 #endif
2907
2908                XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false, SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
2909 //#if defined(__APPLE__)
2910                XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToPointerRoot, CurrentTime);
2911 //#endif
2912             }
2913             else
2914                XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToPointerRoot, CurrentTime);
2915          }
2916       }
2917    }
2918
2919    // --- Mouse-based window movement ---
2920
2921    void StartMoving(Window window, int x, int y, bool fromKeyBoard)
2922    {
2923
2924    }
2925
2926    void StopMoving(Window window)
2927    {
2928
2929    }
2930
2931    // -- Mouse manipulation ---
2932
2933    void GetMousePosition(int *x, int *y)
2934    {
2935       X11Window rootWindow, childWindow;
2936       int mx, my;
2937       unsigned int state;
2938       ((GuiApplication)__thisModule.application).Lock();
2939       //XLockDisplay(xGlobalDisplay);
2940       XQueryPointer(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), &childWindow,
2941          &rootWindow, x, y, &mx, &my, &state);
2942       //XUnlockDisplay(xGlobalDisplay);
2943       ((GuiApplication)__thisModule.application).Unlock();
2944    }
2945
2946    void SetMousePosition(int x, int y)
2947    {
2948
2949    }
2950
2951    void SetMouseRange(Window window, Box box)
2952    {
2953       ((GuiApplication)__thisModule.application).Lock();
2954       //XLockDisplay(xGlobalDisplay);
2955       if(box && box.left > 0 && box.top > 0 &&
2956          box.right < guiApp.desktop.clientSize.w - 1 && box.bottom < guiApp.desktop.clientSize.h - 1)
2957       {
2958          if(!window.parent || !window.parent.display)
2959          {
2960             XMoveResizeWindow(xGlobalDisplay, confineWindow, box.left /*+ desktopX*/, box.top /*+ desktopY*/,
2961                box.right - box.left + 1, box.bottom - box.top + 1);
2962
2963             if(!restrictedWindow)
2964                XMapWindow(xGlobalDisplay, confineWindow);
2965
2966             XGrabPointer(xGlobalDisplay, (X11Window) window.rootWindow.windowHandle, False,
2967                ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync,
2968                GrabModeAsync, confineWindow, fullScreenMode ? nullCursor : None, CurrentTime);
2969
2970             restrictedWindow = window;
2971          }
2972       }
2973       else if(restrictedWindow)
2974       {
2975          if(capturedWindow != None)
2976          {
2977             XGrabPointer(xGlobalDisplay, (X11Window)capturedWindow,
2978                False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync,
2979                GrabModeAsync, None, fullScreenMode ? nullCursor : None, CurrentTime);
2980          }
2981          else
2982             XUngrabPointer(xGlobalDisplay, CurrentTime);
2983
2984          if(restrictedWindow)
2985             XUnmapWindow(xGlobalDisplay, confineWindow);
2986
2987          restrictedWindow = null;
2988       }
2989       //XUnlockDisplay(xGlobalDisplay);
2990       ((GuiApplication)__thisModule.application).Unlock();
2991    }
2992
2993    void SetMouseCapture(Window window)
2994    {
2995       //*XLockDisplay(xGlobalDisplay);
2996       if(window)
2997       {
2998          if(!window.parent || !window.parent.display)
2999          {
3000             XGrabPointer(xGlobalDisplay, (X11Window)window.windowHandle,
3001                False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync,
3002                GrabModeAsync, restrictedWindow ? confineWindow : None, fullScreenMode ? nullCursor : None, CurrentTime);
3003
3004             capturedWindow = (X11Window) window.windowHandle;
3005          }
3006       }
3007       else if(capturedWindow != None)
3008       {
3009          if(restrictedWindow)
3010             XGrabPointer(xGlobalDisplay, (X11Window) restrictedWindow.rootWindow.windowHandle, False,
3011                ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync,
3012                GrabModeAsync, confineWindow, fullScreenMode ? nullCursor : None, CurrentTime);
3013          else
3014             XUngrabPointer(xGlobalDisplay, CurrentTime);
3015          capturedWindow = None;
3016       }
3017       //*XUnlockDisplay(xGlobalDisplay);
3018    }
3019
3020    // -- Mouse cursor ---
3021
3022    void SetMouseCursor(Window window, int cursor)
3023    {
3024       if(window.rootWindow.windowHandle)
3025          XDefineCursor(xGlobalDisplay, (X11Window) window.rootWindow.windowHandle,
3026             cursor == -1 ? (X11Cursor)0 : systemCursors[(SystemCursor)cursor]);
3027    }
3028
3029    // --- Caret ---
3030
3031    void SetCaret(int x, int y, int size)
3032    {
3033       Window caretOwner = guiApp.caretOwner;
3034       Window window = caretOwner ? caretOwner.rootWindow : null;
3035       if(window && window.windowData && setICPosition)
3036       {
3037          XWindowData windowData = window.windowData;
3038          if(windowData && windowData.ic)
3039          {
3040             XPoint cursor_location =
3041             {
3042                (short)(caretOwner.caretPos.x - caretOwner.scroll.x + caretOwner.absPosition.x - window.absPosition.x),
3043                (short)(caretOwner.caretPos.y - caretOwner.scroll.y + caretOwner.absPosition.y - window.absPosition.y)
3044             };
3045             XVaNestedList argList = XVaCreateNestedList(0, XNSpotLocation, &cursor_location, NULL);
3046             XSetICValues(windowData.ic, XNPreeditAttributes, argList, 0);
3047          }
3048       }
3049    }
3050
3051    void ClearClipboard()
3052    {
3053       //*XLockDisplay(xGlobalDisplay);
3054       if(clipBoardData)
3055       {
3056          delete clipBoardData;
3057          XSetSelectionOwner(xGlobalDisplay, atoms[clipboard], None, CurrentTime);
3058       }
3059       //*XUnlockDisplay(xGlobalDisplay);
3060    }
3061
3062    bool AllocateClipboard(ClipBoard clipBoard, uint size)
3063    {
3064       bool result = false;
3065       if((clipBoard.text = new0 byte[size]))
3066          result = true;
3067       return result;
3068    }
3069
3070    bool SaveClipboard(ClipBoard clipBoard)
3071    {
3072       bool result = false;
3073       //*XLockDisplay(xGlobalDisplay);
3074       if(clipBoard.text)
3075       {
3076          Window rootWindow = guiApp.desktop;
3077          if(!fullScreenMode)
3078          {
3079             for(rootWindow = rootWindow.children.first;
3080                rootWindow && !rootWindow.windowHandle;
3081                rootWindow = rootWindow.next);
3082          }
3083          if(clipBoardData)
3084             delete clipBoardData;
3085          else if(rootWindow)
3086             XSetSelectionOwner(xGlobalDisplay, atoms[clipboard],
3087                (X11Window) rootWindow.windowHandle, CurrentTime);
3088          clipBoardData = clipBoard.text;
3089          clipBoard.text = null;
3090          result = true;
3091       }
3092       //*XUnlockDisplay(xGlobalDisplay);
3093       return result;
3094    }
3095
3096    bool LoadClipboard(ClipBoard clipBoard)
3097    {
3098       bool result = false;
3099
3100       //*XLockDisplay(xGlobalDisplay);
3101       // The data is inside this client...
3102       if(clipBoardData)
3103       {
3104          clipBoard.text = new char[strlen(clipBoardData)+1];
3105          strcpy(clipBoard.text, clipBoardData);
3106          result = true;
3107       }
3108       // The data is with another client...
3109       else
3110       {
3111          Window rootWindow = guiApp.desktop;
3112          if(!fullScreenMode)
3113          {
3114             for(rootWindow = rootWindow.children.first;
3115                rootWindow && !rootWindow.windowHandle;
3116                rootWindow = rootWindow.next);
3117          }
3118          if(rootWindow)
3119          {
3120             Atom selAtom = atoms[clipboard];
3121             X11Window owner = XGetSelectionOwner(xGlobalDisplay, selAtom);
3122             if(owner != None)
3123             {
3124                Atom atom;
3125                for(atom = atoms[utf8_string]; atom; atom = ((atom == atoms[utf8_string]) ? XA_STRING : 0))
3126                {
3127                   XEvent e;
3128                   XConvertSelection(xGlobalDisplay, selAtom, atom, atoms[app_selection] /*None*/, (X11Window) rootWindow.windowHandle, CurrentTime);
3129                   XIfEvent(xGlobalDisplay, (XEvent *) &e, EventChecker, (void *)SelectionNotify);
3130                   if(e.type == SelectionNotify)
3131                   {
3132                      XSelectionEvent * selection = (XSelectionEvent *) &e;
3133                      //printf("Got a SelectionNotify with %d (%s)\n", selection->_property, XGetAtomName(xGlobalDisplay, selection->_property));
3134                      byte *data = null;
3135                      unsigned long len, size = 0, dummy;
3136                      Atom type;
3137                      int format;
3138                      XGetWindowProperty(xGlobalDisplay, (X11Window) rootWindow.windowHandle, selection->_property ? selection->_property : atom, 0, 0, False, AnyPropertyType, &type, &format, &len, &size, &data);
3139                      if(data)
3140                      {
3141                         XFree(data);
3142                         data = null;
3143                      }
3144                      if(size > 0)
3145                      {
3146                         if(XGetWindowProperty(xGlobalDisplay, (X11Window) rootWindow.windowHandle, selection->_property ? selection->_property : atom, 0, size, False,
3147                               AnyPropertyType, &type,&format,&len, &dummy, &data) == Success)
3148                         {
3149                            clipBoard.text = new char[size+1];
3150                            strncpy(clipBoard.text, data, size);
3151                            clipBoard.text[size] = '\0';
3152                            XFree(data);
3153                            result = true;
3154                            break;
3155                         }
3156                      }
3157                   }
3158                }
3159             }
3160          }
3161       }
3162       //*XUnlockDisplay(xGlobalDisplay);
3163       return result;
3164    }
3165
3166    void UnloadClipboard(ClipBoard clipBoard)
3167    {
3168       delete clipBoard.text;
3169    }
3170
3171    // --- State based input ---
3172
3173    bool AcquireInput(Window window, bool state)
3174    {
3175       return false;
3176    }
3177
3178    bool GetMouseState(MouseButtons * buttons, int * x, int * y)
3179    {
3180       bool result = false;
3181       if(x) *x = 0;
3182       if(y) *y = 0;
3183       return result;
3184    }
3185
3186    bool GetJoystickState(int device, Joystick joystick)
3187    {
3188       bool result = false;
3189    #if defined(__linux__)
3190       if(joystick && device < 4)
3191       {
3192          struct JS_DATA_TYPE js = { 0 };
3193          memset(joystick, 0, sizeof(Joystick));
3194          if(joystickFD[device] && read(joystickFD[device], &js, JS_RETURN) == JS_RETURN)
3195          {
3196             joystick.buttons = js.buttons;
3197             joystick.x = js.x - 128;
3198             joystick.y = js.y - 128;
3199             result = true;
3200          }
3201       }
3202    #endif
3203       return result;
3204    }
3205
3206    bool GetKeyState(Key key)
3207    {
3208       int keyState = 0;
3209       return keyState;
3210    }
3211
3212    void SetTimerResolution(uint hertz)
3213    {
3214       timerDelay = hertz ? (1000000 / hertz) : MAXINT;
3215       /*
3216       hiResTimer.Stop();
3217       if(hertz)
3218       {
3219          hiResTimer.delay = 1000000 / hertz;
3220          hiResTimer.Create();
3221       }
3222       */
3223    }
3224
3225    bool SetIcon(Window window, BitmapResource resource)
3226    {
3227       if(resource)
3228       {
3229          Bitmap bitmap { };
3230          if(bitmap.Load(resource.fileName, null, null))
3231          {
3232             unsigned long * icon = new unsigned long[2 + bitmap.width * bitmap.height];
3233             bitmap.Convert(null, pixelFormat888, null);
3234             icon[0] = bitmap.width;
3235             icon[1] = bitmap.height;
3236             if(sizeof(long) != sizeof(uint32))
3237             {
3238                int c;
3239                for(c = 0; c < bitmap.width * bitmap.height; c++)
3240                   icon[c+2] = ((uint32 *)bitmap.picture)[c];
3241             }
3242             else
3243                memcpy(icon + 2, bitmap.picture, bitmap.width * bitmap.height * sizeof(uint32));
3244             XChangeProperty(xGlobalDisplay, (X11Window)window.windowHandle, atoms[_net_wm_icon],
3245               XA_CARDINAL,32,PropModeReplace, (byte *)icon, 2+bitmap.width*bitmap.height);
3246             delete icon;
3247          }
3248          delete bitmap;
3249       }
3250       return true;
3251    }
3252 }
3253
3254 default dllexport void * __attribute__((stdcall)) IS_XGetDisplay()
3255 {
3256    return xGlobalDisplay;
3257 }
3258
3259 default dllexport void * __attribute__((stdcall)) IS_XGetWindow(Window window)
3260 {
3261    return window.windowHandle ? window.windowHandle : window.rootWindow.windowHandle;
3262 }
3263
3264 #endif