ecba86f9468815fa970a1f0a33311f4f7a73a74e
[blender.git] / intern / ghost / intern / GHOST_WindowX11.cpp
1 /**
2  * $Id$
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30  */
31
32 #include "GHOST_WindowX11.h"
33 #include "GHOST_SystemX11.h"
34 #include "STR_String.h"
35 #include "GHOST_Debug.h"
36
37 // For standard X11 cursors
38 #include <X11/cursorfont.h>
39 #include <X11/Xatom.h>
40
41 // For obscure full screen mode stuuf
42 // lifted verbatim from blut.
43
44 typedef struct {
45         long flags;
46         long functions;
47         long decorations;
48         long input_mode;
49 } MotifWmHints;
50
51 #define MWM_HINTS_DECORATIONS         (1L << 1)
52
53 GLXContext GHOST_WindowX11::s_firstContext = NULL;
54
55 GHOST_WindowX11::
56 GHOST_WindowX11(
57         GHOST_SystemX11 *system,
58         Display * display,
59         const STR_String& title, 
60         GHOST_TInt32 left,
61         GHOST_TInt32 top,
62         GHOST_TUns32 width,     
63         GHOST_TUns32 height,
64         GHOST_TWindowState state,
65         GHOST_TDrawingContextType type,
66         const bool stereoVisual
67 ) :
68         GHOST_Window(title,left,top,width,height,state,type,stereoVisual),
69         m_context(NULL),
70         m_display(display),
71         m_system (system),
72         m_valid_setup (false),
73         m_invalid_window(false),
74         m_empty_cursor(None),
75         m_custom_cursor(None)
76 {
77         
78         // Set up the minimum atrributes that we require and see if
79         // X can find us a visual matching those requirements.
80
81         int attributes[40], i = 0;
82
83         if(m_stereoVisual)
84                 attributes[i++] = GLX_STEREO;
85
86         attributes[i++] = GLX_RGBA;
87         attributes[i++] = GLX_DOUBLEBUFFER;     
88         attributes[i++] = GLX_RED_SIZE;   attributes[i++] = 1;
89         attributes[i++] = GLX_BLUE_SIZE;  attributes[i++] = 1;
90         attributes[i++] = GLX_GREEN_SIZE; attributes[i++] = 1;
91         attributes[i++] = GLX_DEPTH_SIZE; attributes[i++] = 1;
92         attributes[i] = None;
93         
94         m_visual = glXChooseVisual(m_display, DefaultScreen(m_display), attributes);
95
96         if (m_visual == NULL) {
97                 // barf : no visual meeting these requirements could be found.
98                 return;
99         }
100
101         // Create a bunch of attributes needed to create an X window.
102
103
104         // First create a colormap for the window and visual. 
105         // This seems pretty much a legacy feature as we are in rgba mode anyway.
106
107         XSetWindowAttributes xattributes;
108         memset(&xattributes, 0, sizeof(xattributes));
109
110         xattributes.colormap= XCreateColormap(
111                 m_display, 
112                 RootWindow(m_display, m_visual->screen),
113                 m_visual->visual,
114                 AllocNone
115         );
116
117         xattributes.border_pixel= 0;
118
119         // Specify which events we are interested in hearing.   
120
121         xattributes.event_mask= 
122                 ExposureMask | StructureNotifyMask | 
123                 KeyPressMask | KeyReleaseMask |
124                 EnterWindowMask | LeaveWindowMask |
125                 ButtonPressMask | ButtonReleaseMask |
126                 PointerMotionMask | FocusChangeMask;
127
128         // create the window!
129
130         m_window = 
131                 XCreateWindow(
132                         m_display, 
133                         RootWindow(m_display, m_visual->screen), 
134                         left,
135                         top,
136                         width,
137                         height,
138                         0, // no border.
139                         m_visual->depth,
140                         InputOutput, 
141                         m_visual->visual,
142                         CWBorderPixel|CWColormap|CWEventMask, 
143                         &xattributes
144                 );
145
146         // Are we in fullscreen mode - then include
147         // some obscure blut code to remove decorations.
148
149         if (state == GHOST_kWindowStateFullScreen) {
150
151                 MotifWmHints hints;
152                 Atom atom;
153                                         
154                 atom = XInternAtom(m_display, "_MOTIF_WM_HINTS", False);
155                 
156                 if (atom == None) {
157                         GHOST_PRINT("Could not intern X atom for _MOTIF_WM_HINTS.\n");
158                 } else {
159                         hints.flags = MWM_HINTS_DECORATIONS;
160                         hints.decorations = 0;  /* Absolutely no decorations. */
161                         // other hints.decorations make no sense
162                         // you can't select individual decorations
163
164                         XChangeProperty(m_display, m_window,
165                                 atom, atom, 32,
166                                 PropModeReplace, (unsigned char *) &hints, 4);
167                 }
168         } else if (state == GHOST_kWindowStateMaximized) {
169                 // With this, xprop should report the following just after launch
170                 // _NET_WM_STATE(ATOM) = _NET_WM_STATE_MAXIMIZED_VERT, _NET_WM_STATE_MAXIMIZED_HORZ
171                 // After demaximization the right side is empty, though (maybe not the most correct then?)
172                 Atom state, atomh, atomv;
173
174                 state = XInternAtom(m_display, "_NET_WM_STATE", False);
175                 atomh = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
176                 atomv = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_VERT", False);
177                 if (state == None ) {
178                         GHOST_PRINT("Atom _NET_WM_STATE requested but not avaliable nor created.\n");
179                 } else {
180                         XChangeProperty(m_display, m_window,
181                                 state, XA_ATOM, 32,
182                                 PropModeAppend, (unsigned char *) &atomh, 1);
183                         XChangeProperty(m_display, m_window,
184                                 state, XA_ATOM, 32,
185                                 PropModeAppend, (unsigned char *) &atomv, 1);
186                 }
187         }
188         
189         // Create some hints for the window manager on how
190         // we want this window treated. 
191
192         XSizeHints * xsizehints = XAllocSizeHints();
193         xsizehints->flags = USPosition | USSize;
194         xsizehints->x = left;
195         xsizehints->y = top;
196         xsizehints->width = width;
197         xsizehints->height = height;
198         XSetWMNormalHints(m_display, m_window, xsizehints);
199         XFree(xsizehints);
200
201         XClassHint * xclasshint = XAllocClassHint();
202         int len = title.Length() +1 ;
203         char *wmclass = (char *)malloc(sizeof(char) * len);
204         strncpy(wmclass, (const char*)title, sizeof(char) * len);
205         xclasshint->res_name = wmclass;
206         xclasshint->res_class = wmclass;
207         XSetClassHint(m_display, m_window, xclasshint);
208         free(wmclass);
209         XFree(xclasshint);
210
211         setTitle(title);
212
213         initXInputDevices();
214
215         // now set up the rendering context.
216         if (installDrawingContext(type) == GHOST_kSuccess) {
217                 m_valid_setup = true;
218                 GHOST_PRINT("Created window\n");
219         }
220
221         XMapWindow(m_display, m_window);
222         GHOST_PRINT("Mapped window\n");
223
224         XFlush(m_display);
225 }
226
227 /* 
228         Dummy function to get around IO Handler exiting if device invalid
229         Basically it will not crash blender now if you have a X device that 
230         is configured but not plugged in.
231
232 */
233 static int ApplicationErrorHandler(Display *display, XErrorEvent *theEvent) {
234         fprintf(stderr, "Ignoring Xlib error: error code %d request code %d\n",
235                 theEvent->error_code, theEvent->request_code) ;
236
237         /* No exit! - but keep lint happy */
238         return 0 ;
239 }
240
241 void GHOST_WindowX11::initXInputDevices()
242 {
243         static XErrorHandler old_handler = (XErrorHandler) 0 ;
244         XExtensionVersion *version = XGetExtensionVersion(m_display, INAME);
245
246         if(version && (version != (XExtensionVersion*)NoSuchExtension)) {
247                 if(version->present) {
248                         int device_count;
249                         XDeviceInfo* device_info = XListInputDevices(m_display, &device_count);
250                         m_xtablet.StylusDevice = 0;
251                         m_xtablet.EraserDevice = 0;
252                         m_xtablet.CommonData.Active= 0;
253
254                         /* Install our error handler to override Xlib's termination behavior */
255                         old_handler = XSetErrorHandler(ApplicationErrorHandler) ;
256
257                         for(int i=0; i<device_count; ++i) {
258                                 if(!strcasecmp(device_info[i].name, "stylus")) {
259                                         m_xtablet.StylusID= device_info[i].id;
260                                         m_xtablet.StylusDevice = XOpenDevice(m_display, m_xtablet.StylusID);
261
262                                         if (m_xtablet.StylusDevice != NULL) {
263                                                 /* Find how many pressure levels tablet has */
264                                                 XAnyClassPtr ici = device_info[i].inputclassinfo;
265                                                 for(int j=0; j<m_xtablet.StylusDevice->num_classes; ++j) {
266                                                         if(ici->c_class==ValuatorClass) {
267                                                                 XValuatorInfo* xvi = (XValuatorInfo*)ici;
268                                                                 m_xtablet.PressureLevels = xvi->axes[2].max_value;
269                                                         
270                                                                 /* this is assuming that the tablet has the same tilt resolution in both
271                                                                  * positive and negative directions. It would be rather weird if it didn't.. */
272                                                                 m_xtablet.XtiltLevels = xvi->axes[3].max_value;
273                                                                 m_xtablet.YtiltLevels = xvi->axes[4].max_value;
274                                                                 break;
275                                                         }
276                                                 
277                                                         ici = (XAnyClassPtr)(((char *)ici) + ici->length);
278                                                 }
279                                         } else {
280                                                 m_xtablet.StylusID= 0;
281                                         }
282                                 }
283                                 if(!strcasecmp(device_info[i].name, "eraser")) {
284                                         m_xtablet.EraserID= device_info[i].id;
285                                         m_xtablet.EraserDevice = XOpenDevice(m_display, m_xtablet.EraserID);
286                                         if (m_xtablet.EraserDevice == NULL) m_xtablet.EraserID= 0;
287                                 }
288                         }
289
290                         /* Restore handler */
291                         (void) XSetErrorHandler(old_handler) ;
292
293                         XFreeDeviceList(device_info);
294
295
296                         XEventClass xevents[10], ev;
297                         int dcount = 0;
298
299                         if(m_xtablet.StylusDevice) {
300                                 DeviceMotionNotify(m_xtablet.StylusDevice, m_xtablet.MotionEvent, ev);
301                                 if(ev) xevents[dcount++] = ev;
302                                 ProximityIn(m_xtablet.StylusDevice, m_xtablet.ProxInEvent, ev);
303                                 if(ev) xevents[dcount++] = ev;
304                                 ProximityOut(m_xtablet.StylusDevice, m_xtablet.ProxOutEvent, ev);
305                                 if(ev) xevents[dcount++] = ev;
306                         }
307                         if(m_xtablet.EraserDevice) {
308                                 DeviceMotionNotify(m_xtablet.EraserDevice, m_xtablet.MotionEvent, ev);
309                                 if(ev) xevents[dcount++] = ev;
310                                 ProximityIn(m_xtablet.EraserDevice, m_xtablet.ProxInEvent, ev);
311                                 if(ev) xevents[dcount++] = ev;
312                                 ProximityOut(m_xtablet.EraserDevice, m_xtablet.ProxOutEvent, ev);
313                                 if(ev) xevents[dcount++] = ev;
314                         }
315
316                         XSelectExtensionEvent(m_display, m_window, xevents, dcount);
317                 }
318                 XFree(version);
319         }
320 }       
321
322
323         Window 
324 GHOST_WindowX11::
325 getXWindow(
326 ){
327         return m_window;
328 }       
329
330         bool 
331 GHOST_WindowX11::
332 getValid(
333 ) const {
334         return m_valid_setup;
335 }
336
337         void 
338 GHOST_WindowX11::
339 setTitle(
340         const STR_String& title
341 ){
342         XStoreName(m_display,m_window,title);
343         XFlush(m_display);
344 }
345
346         void 
347 GHOST_WindowX11::
348 getTitle(
349         STR_String& title
350 ) const {
351         char *name = NULL;
352         
353         XFetchName(m_display,m_window,&name);
354         title= name?name:"untitled";
355         XFree(name);
356 }
357         
358         void 
359 GHOST_WindowX11::
360 getWindowBounds(
361         GHOST_Rect& bounds
362 ) const {
363                 // Getting the window bounds under X11 is not
364                 // really supported (nor should it be desired).
365         getClientBounds(bounds);
366 }
367
368         void 
369 GHOST_WindowX11::
370 getClientBounds(
371         GHOST_Rect& bounds
372 ) const {
373         Window root_return;
374         int x_return,y_return;
375         unsigned int w_return,h_return,border_w_return,depth_return;
376         GHOST_TInt32 screen_x, screen_y;
377         
378         XGetGeometry(m_display,m_window,&root_return,&x_return,&y_return,
379                 &w_return,&h_return,&border_w_return,&depth_return);
380
381         clientToScreen(0, 0, screen_x, screen_y);
382         
383         bounds.m_l = screen_x;
384         bounds.m_r = bounds.m_l + w_return;
385         bounds.m_t = screen_y;
386         bounds.m_b = bounds.m_t + h_return;
387
388 }
389
390         GHOST_TSuccess 
391 GHOST_WindowX11::
392 setClientWidth(
393         GHOST_TUns32 width
394 ){      
395         XWindowChanges values;
396         unsigned int value_mask= CWWidth;               
397         values.width = width;
398         XConfigureWindow(m_display,m_window,value_mask,&values);
399
400         return GHOST_kSuccess;
401 }
402
403         GHOST_TSuccess 
404 GHOST_WindowX11::
405 setClientHeight(
406         GHOST_TUns32 height
407 ){
408         XWindowChanges values;
409         unsigned int value_mask= CWHeight;              
410         values.height = height;
411         XConfigureWindow(m_display,m_window,value_mask,&values);
412         return GHOST_kSuccess;
413
414 }
415
416         GHOST_TSuccess 
417 GHOST_WindowX11::
418 setClientSize(
419         GHOST_TUns32 width,
420         GHOST_TUns32 height
421 ){
422         XWindowChanges values;
423         unsigned int value_mask= CWWidth | CWHeight;            
424         values.width = width;
425         values.height = height;
426         XConfigureWindow(m_display,m_window,value_mask,&values);
427         return GHOST_kSuccess;
428
429 }       
430
431         void 
432 GHOST_WindowX11::
433 screenToClient(
434         GHOST_TInt32 inX,
435         GHOST_TInt32 inY,
436         GHOST_TInt32& outX,
437         GHOST_TInt32& outY
438 ) const {
439         // not sure about this one!
440
441         int ax,ay;
442         Window temp;
443
444         XTranslateCoordinates(
445                         m_display,
446                         RootWindow(m_display, m_visual->screen),
447                         m_window,
448                         inX,
449                         inY,
450                         &ax,
451                         &ay,
452                         &temp
453                 );
454         outX = ax;
455         outY = ay;
456 }
457                  
458         void 
459 GHOST_WindowX11::
460 clientToScreen(
461         GHOST_TInt32 inX,
462         GHOST_TInt32 inY,
463         GHOST_TInt32& outX,
464         GHOST_TInt32& outY
465 ) const {
466         int ax,ay;
467         Window temp;
468
469         XTranslateCoordinates(
470                         m_display,
471                         m_window,
472                         RootWindow(m_display, m_visual->screen),
473                         inX,
474                         inY,
475                         &ax,
476                         &ay,
477                         &temp
478                 );
479         outX = ax;
480         outY = ay;
481 }
482
483
484         GHOST_TWindowState 
485 GHOST_WindowX11::
486 getState(
487 ) const {
488         //FIXME 
489         return GHOST_kWindowStateNormal;
490 }
491
492         GHOST_TSuccess 
493 GHOST_WindowX11::
494 setState(
495         GHOST_TWindowState state
496 ){
497         //TODO
498
499         if (state == (int)getState()) {
500                 return GHOST_kSuccess;
501         } else {
502                 return GHOST_kFailure;
503         }
504
505 }
506
507 #include <iostream>
508 using namespace std;
509
510         GHOST_TSuccess 
511 GHOST_WindowX11::
512 setOrder(
513         GHOST_TWindowOrder order
514 ){
515         if (order == GHOST_kWindowOrderTop) {
516                 XWindowAttributes attr;   
517                 Atom atom;
518
519                 /* We use both XRaiseWindow and _NET_ACTIVE_WINDOW, since some
520                    window managers ignore the former (e.g. kwin from kde) and others
521                    don't implement the latter (e.g. fluxbox pre 0.9.9) */
522
523                 XRaiseWindow(m_display, m_window);
524
525                 atom = XInternAtom(m_display, "_NET_ACTIVE_WINDOW", True);
526
527                 if (atom != None) {
528                         Window root;
529                         XEvent xev;
530                         long eventmask;
531
532                         xev.xclient.type = ClientMessage;
533                         xev.xclient.serial = 0;
534                         xev.xclient.send_event = True;
535                         xev.xclient.window = m_window;
536                         xev.xclient.message_type = atom;
537
538                         xev.xclient.format = 32;
539                         xev.xclient.data.l[0] = 0;
540                         xev.xclient.data.l[1] = 0;
541                         xev.xclient.data.l[2] = 0;
542                         xev.xclient.data.l[3] = 0;
543                         xev.xclient.data.l[4] = 0;
544
545                         root = RootWindow(m_display, m_visual->screen),
546                         eventmask = SubstructureRedirectMask | SubstructureNotifyMask;
547
548                         XSendEvent(m_display, root, False, eventmask, &xev);
549                 }
550
551                 XGetWindowAttributes(m_display, m_window, &attr);
552
553                 /* iconized windows give bad match error */
554                 if (attr.map_state == IsViewable)
555                         XSetInputFocus(m_display, m_window, RevertToPointerRoot,
556                                                  CurrentTime);
557                 XFlush(m_display);
558         } else if (order == GHOST_kWindowOrderBottom) {
559                 XLowerWindow(m_display,m_window);
560                 XFlush(m_display);
561         } else {
562                 return GHOST_kFailure;
563         }
564         
565         return GHOST_kSuccess;
566 }
567
568         GHOST_TSuccess 
569 GHOST_WindowX11::
570 swapBuffers(
571 ){
572         if (getDrawingContextType() == GHOST_kDrawingContextTypeOpenGL) {
573                 glXSwapBuffers(m_display,m_window);
574                 return GHOST_kSuccess;
575         } else {
576                 return GHOST_kFailure;
577         }
578 }
579
580         GHOST_TSuccess 
581 GHOST_WindowX11::
582 activateDrawingContext(
583 ){
584         if (m_context !=NULL) {
585                 glXMakeCurrent(m_display, m_window,m_context);                                          
586                 return GHOST_kSuccess;
587         } 
588         return GHOST_kFailure;
589 }
590
591         GHOST_TSuccess 
592 GHOST_WindowX11::
593 invalidate(
594 ){
595         
596         // So the idea of this function is to generate an expose event
597         // for the window.
598         // Unfortunately X does not handle expose events for you and 
599         // it is the client's job to refresh the dirty part of the window.
600         // We need to queue up invalidate calls and generate GHOST events 
601         // for them in the system.
602
603         // We implement this by setting a boolean in this class to concatenate 
604         // all such calls into a single event for this window.
605
606         // At the same time we queue the dirty windows in the system class
607         // and generate events for them at the next processEvents call.
608
609         if (m_invalid_window == false) {
610                 m_system->addDirtyWindow(this);
611                 m_invalid_window = true;
612         } 
613  
614         return GHOST_kSuccess;
615 }
616
617 /**
618  * called by the X11 system implementation when expose events
619  * for the window have been pushed onto the GHOST queue
620  */
621  
622         void
623 GHOST_WindowX11::
624 validate(
625 ){
626         m_invalid_window = false;
627 }       
628  
629  
630 /**
631  * Destructor.
632  * Closes the window and disposes resources allocated.
633  */
634
635 GHOST_WindowX11::
636 ~GHOST_WindowX11(
637 ){
638         std::map<unsigned int, Cursor>::iterator it = m_standard_cursors.begin();
639         for (; it != m_standard_cursors.end(); it++) {
640                 XFreeCursor(m_display, it->second);
641         }
642
643         if (m_empty_cursor) {
644                 XFreeCursor(m_display, m_empty_cursor);
645         }
646         if (m_custom_cursor) {
647                 XFreeCursor(m_display, m_custom_cursor);
648         }
649         
650         if (m_context) {
651                 if (m_context == s_firstContext) {
652                         s_firstContext = NULL;
653                 }
654                 glXDestroyContext(m_display, m_context);
655         }
656         XDestroyWindow(m_display, m_window);
657         XFree(m_visual);
658 }
659
660
661
662
663 /**
664  * Tries to install a rendering context in this window.
665  * @param type  The type of rendering context installed.
666  * @return Indication as to whether installation has succeeded.
667  */
668         GHOST_TSuccess 
669 GHOST_WindowX11::
670 installDrawingContext(
671         GHOST_TDrawingContextType type
672 ){
673         // only support openGL for now.
674         GHOST_TSuccess success;
675         switch (type) {
676         case GHOST_kDrawingContextTypeOpenGL:
677                 m_context = glXCreateContext(m_display, m_visual, s_firstContext, True);
678                 if (m_context !=NULL) {
679                         if (!s_firstContext) {
680                                 s_firstContext = m_context;
681                         }
682                         glXMakeCurrent(m_display, m_window,m_context);                                          
683                         success = GHOST_kSuccess;
684                 } else {
685                         success = GHOST_kFailure;
686                 }
687
688                 break;
689
690         case GHOST_kDrawingContextTypeNone:
691                 success = GHOST_kSuccess;
692                 break;
693
694         default:
695                 success = GHOST_kFailure;
696         }
697         return success;
698 }
699
700
701
702 /**
703  * Removes the current drawing context.
704  * @return Indication as to whether removal has succeeded.
705  */
706         GHOST_TSuccess 
707 GHOST_WindowX11::
708 removeDrawingContext(
709 ){
710         GHOST_TSuccess success;
711
712         if (m_context != NULL) {
713                 glXDestroyContext(m_display, m_context);
714                 success = GHOST_kSuccess;
715         } else {
716                 success = GHOST_kFailure;
717         }
718         return success; 
719 }
720
721
722         Cursor
723 GHOST_WindowX11::
724 getStandardCursor(
725         GHOST_TStandardCursor g_cursor
726 ){
727         unsigned int xcursor_id;
728
729 #define GtoX(gcurs, xcurs)      case gcurs: xcursor_id = xcurs
730         switch (g_cursor) {
731         GtoX(GHOST_kStandardCursorRightArrow, XC_arrow); break;
732         GtoX(GHOST_kStandardCursorLeftArrow, XC_top_left_arrow); break;
733         GtoX(GHOST_kStandardCursorInfo, XC_hand1); break;
734         GtoX(GHOST_kStandardCursorDestroy, XC_pirate); break;
735         GtoX(GHOST_kStandardCursorHelp, XC_question_arrow); break; 
736         GtoX(GHOST_kStandardCursorCycle, XC_exchange); break;
737         GtoX(GHOST_kStandardCursorSpray, XC_spraycan); break;
738         GtoX(GHOST_kStandardCursorWait, XC_watch); break;
739         GtoX(GHOST_kStandardCursorText, XC_xterm); break;
740         GtoX(GHOST_kStandardCursorCrosshair, XC_crosshair); break;
741         GtoX(GHOST_kStandardCursorUpDown, XC_sb_v_double_arrow); break;
742         GtoX(GHOST_kStandardCursorLeftRight, XC_sb_h_double_arrow); break;
743         GtoX(GHOST_kStandardCursorTopSide, XC_top_side); break;
744         GtoX(GHOST_kStandardCursorBottomSide, XC_bottom_side); break;
745         GtoX(GHOST_kStandardCursorLeftSide, XC_left_side); break;
746         GtoX(GHOST_kStandardCursorRightSide, XC_right_side); break;
747         GtoX(GHOST_kStandardCursorTopLeftCorner, XC_top_left_corner); break;
748         GtoX(GHOST_kStandardCursorTopRightCorner, XC_top_right_corner); break;
749         GtoX(GHOST_kStandardCursorBottomRightCorner, XC_bottom_right_corner); break;
750         GtoX(GHOST_kStandardCursorBottomLeftCorner, XC_bottom_left_corner); break;
751         GtoX(GHOST_kStandardCursorPencil, XC_pencil); break;
752         default:
753                 xcursor_id = 0;
754         }
755 #undef GtoX
756
757         if (xcursor_id) {
758                 Cursor xcursor = m_standard_cursors[xcursor_id];
759                 
760                 if (!xcursor) {
761                         xcursor = XCreateFontCursor(m_display, xcursor_id);
762
763                         m_standard_cursors[xcursor_id] = xcursor;
764                 }
765                 
766                 return xcursor;
767         } else {
768                 return None;
769         }
770 }
771
772         Cursor 
773 GHOST_WindowX11::
774 getEmptyCursor(
775 ) {
776         if (!m_empty_cursor) {
777                 Pixmap blank;
778                 XColor dummy;
779                 char data[1] = {0};
780                         
781                 /* make a blank cursor */
782                 blank = XCreateBitmapFromData (
783                         m_display, 
784                         RootWindow(m_display,DefaultScreen(m_display)),
785                         data, 1, 1
786                 );
787
788                 m_empty_cursor = XCreatePixmapCursor(m_display, blank, blank, &dummy, &dummy, 0, 0);
789                 XFreePixmap(m_display, blank);
790         }
791
792         return m_empty_cursor;
793 }
794
795         GHOST_TSuccess
796 GHOST_WindowX11::
797 setWindowCursorVisibility(
798         bool visible
799 ){
800         Cursor xcursor;
801         
802         if (visible) {
803                 xcursor = getStandardCursor( getCursorShape() );
804         } else {
805                 xcursor = getEmptyCursor();
806         }
807
808         XDefineCursor(m_display, m_window, xcursor);
809         XFlush(m_display);
810         
811         return GHOST_kSuccess;
812 }
813
814         GHOST_TSuccess
815 GHOST_WindowX11::
816 setWindowCursorShape(
817         GHOST_TStandardCursor shape
818 ){
819         Cursor xcursor = getStandardCursor( shape );
820         
821         XDefineCursor(m_display, m_window, xcursor);
822         XFlush(m_display);
823
824         return GHOST_kSuccess;
825 }
826
827         GHOST_TSuccess
828 GHOST_WindowX11::
829 setWindowCustomCursorShape(
830         GHOST_TUns8 bitmap[16][2], 
831         GHOST_TUns8 mask[16][2], 
832         int hotX, 
833         int hotY
834 ){
835
836 setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*)mask, 
837                                                                         16, 16, hotX, hotY, 0, 1);
838         return GHOST_kSuccess;
839 }
840
841         GHOST_TSuccess
842 GHOST_WindowX11::
843 setWindowCustomCursorShape(     
844         GHOST_TUns8 *bitmap, 
845         GHOST_TUns8 *mask, 
846         int sizex, 
847         int sizey, 
848         int hotX, 
849         int hotY, 
850         int fg_color, 
851         int bg_color
852 ){
853         Pixmap bitmap_pix, mask_pix;
854         XColor fg, bg;
855         
856         if(XAllocNamedColor(m_display, DefaultColormap(m_display, DefaultScreen(m_display)),
857                 "White", &fg, &fg) == 0) return GHOST_kFailure;
858         if(XAllocNamedColor(m_display, DefaultColormap(m_display, DefaultScreen(m_display)),
859                 "Black", &bg, &bg) == 0) return GHOST_kFailure;
860
861         if (m_custom_cursor) {
862                 XFreeCursor(m_display, m_custom_cursor);
863         }
864
865         bitmap_pix = XCreateBitmapFromData(m_display, m_window, (char*) bitmap, sizex, sizey);
866         mask_pix = XCreateBitmapFromData(m_display, m_window, (char*) mask, sizex, sizey);
867                 
868         m_custom_cursor = XCreatePixmapCursor(m_display, bitmap_pix, mask_pix, &fg, &bg, hotX, hotY);
869         XDefineCursor(m_display, m_window, m_custom_cursor);
870         XFlush(m_display);
871         
872         XFreePixmap(m_display, bitmap_pix);
873         XFreePixmap(m_display, mask_pix);
874
875         return GHOST_kSuccess;
876 }
877
878 /*
879
880 void glutCustomCursor(char *data1, char *data2, int size)
881 {
882         Pixmap source, mask;
883         Cursor cursor;
884         XColor fg, bg;
885         
886         if(XAllocNamedColor(__glutDisplay, DefaultColormap(__glutDisplay, __glutScreen),
887                 "White", &fg, &fg) == 0) return;
888         if(XAllocNamedColor(__glutDisplay, DefaultColormap(__glutDisplay, __glutScreen),
889                 "Red", &bg, &bg) == 0) return;
890
891
892         source= XCreateBitmapFromData(__glutDisplay, xdraw, data2, size, size);
893         mask= XCreateBitmapFromData(__glutDisplay, xdraw, data1, size, size);
894                 
895         cursor= XCreatePixmapCursor(__glutDisplay, source, mask, &fg, &bg, 7, 7);
896                 
897         XFreePixmap(__glutDisplay, source);
898         XFreePixmap(__glutDisplay, mask);
899                 
900         XDefineCursor(__glutDisplay, xdraw, cursor);
901 }
902
903 */