47d93dc608b69016ee0f4cf448518735ffb96efc
[occt.git] / src / Xw / Xw_Window.cxx
1 // Created on: 2013-04-06
2 // Created by: Kirill Gavrilov
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <Xw_Window.hxx>
17
18 #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__) && !defined(__EMSCRIPTEN__)
19
20 #include <Aspect_Convert.hxx>
21 #include <Aspect_ScrollDelta.hxx>
22 #include <Aspect_WindowDefinitionError.hxx>
23 #include <Aspect_WindowInputListener.hxx>
24 #include <Message.hxx>
25 #include <Message_Messenger.hxx>
26
27 //#include <X11/XF86keysym.h>
28
29 IMPLEMENT_STANDARD_RTTIEXT(Xw_Window, Aspect_Window)
30
31 // =======================================================================
32 // function : Xw_Window
33 // purpose  :
34 // =======================================================================
35 Xw_Window::Xw_Window (const Handle(Aspect_DisplayConnection)& theXDisplay,
36                       const Standard_CString theTitle,
37                       const Standard_Integer thePxLeft,
38                       const Standard_Integer thePxTop,
39                       const Standard_Integer thePxWidth,
40                       const Standard_Integer thePxHeight)
41 : Aspect_Window(),
42   myDisplay  (theXDisplay),
43   myXWindow  (0),
44   myFBConfig (NULL),
45   myXLeft    (thePxLeft),
46   myYTop     (thePxTop),
47   myXRight   (thePxLeft + thePxWidth),
48   myYBottom  (thePxTop + thePxHeight),
49   myIsOwnWin (Standard_True)
50 {
51   if (thePxWidth <= 0 || thePxHeight <= 0)
52   {
53     throw Aspect_WindowDefinitionError("Xw_Window, Coordinate(s) out of range");
54   }
55   else if (theXDisplay.IsNull())
56   {
57     throw Aspect_WindowDefinitionError("Xw_Window, X Display connection is undefined");
58   }
59
60   myFBConfig = theXDisplay->GetDefaultFBConfig();
61   XVisualInfo* aVisInfo = theXDisplay->GetDefaultVisualInfo();
62
63   Display* aDisp   = myDisplay->GetDisplay();
64   int      aScreen = DefaultScreen(aDisp);
65   Window   aParent = RootWindow   (aDisp, aScreen);
66
67
68   unsigned long aMask = 0;
69   XSetWindowAttributes aWinAttr;
70   memset(&aWinAttr, 0, sizeof(XSetWindowAttributes));
71   aWinAttr.event_mask = ExposureMask | StructureNotifyMask;
72   aMask |= CWEventMask;
73   if (aVisInfo != NULL)
74   {
75     aWinAttr.colormap = XCreateColormap(aDisp, aParent, aVisInfo->visual, AllocNone);
76   }
77   aWinAttr.border_pixel = 0;
78   aWinAttr.override_redirect = False;
79
80   myXWindow = XCreateWindow(aDisp, aParent,
81                             myXLeft, myYTop, thePxWidth, thePxHeight,
82                             0, aVisInfo != NULL ? aVisInfo->depth : CopyFromParent,
83                             InputOutput,
84                             aVisInfo != NULL ? aVisInfo->visual : CopyFromParent,
85                             CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &aWinAttr);
86   if (myXWindow == 0)
87   {
88     throw Aspect_WindowDefinitionError("Xw_Window, Unable to create window");
89   }
90
91   // if parent - desktop
92   XSizeHints aSizeHints;
93   aSizeHints.x      = myXLeft;
94   aSizeHints.y      = myYTop;
95   aSizeHints.flags  = PPosition;
96   aSizeHints.width  = thePxWidth;
97   aSizeHints.height = thePxHeight;
98   aSizeHints.flags |= PSize;
99   XSetStandardProperties (aDisp, myXWindow, theTitle, theTitle, None,
100                           NULL, 0, &aSizeHints);
101
102   /*XTextProperty aTitleProperty;
103   aTitleProperty.encoding = None;
104   char* aTitle = (char* )theTitle;
105   Xutf8TextListToTextProperty(aDisp, &aTitle, 1, XUTF8StringStyle, &aTitleProperty);
106   XSetWMName      (aDisp, myXWindow, &aTitleProperty);
107   XSetWMProperties(aDisp, myXWindow, &aTitleProperty, &aTitleProperty, NULL, 0, NULL, NULL, NULL);*/
108
109   XFlush (aDisp);
110 }
111
112 // =======================================================================
113 // function : Xw_Window
114 // purpose  :
115 // =======================================================================
116 Xw_Window::Xw_Window (const Handle(Aspect_DisplayConnection)& theXDisplay,
117                       const Window theXWin,
118                       const Aspect_FBConfig theFBConfig)
119 : Aspect_Window(),
120   myDisplay  (theXDisplay),
121   myXWindow  (theXWin),
122   myFBConfig (theFBConfig),
123   myXLeft    (0),
124   myYTop     (0),
125   myXRight   (512),
126   myYBottom  (512),
127   myIsOwnWin (Standard_False)
128 {
129   if (theXWin == 0)
130   {
131     throw Aspect_WindowDefinitionError("Xw_Window, given invalid X window");
132   }
133   else if (theXDisplay.IsNull())
134   {
135     throw Aspect_WindowDefinitionError("Xw_Window, X Display connection is undefined");
136   }
137
138   Display* aDisp = myDisplay->GetDisplay();
139
140   XWindowAttributes aWinAttr;
141   XGetWindowAttributes (aDisp, myXWindow, &aWinAttr);
142   XVisualInfo aVisInfoTmp;
143   aVisInfoTmp.visualid = aWinAttr.visual->visualid;
144   aVisInfoTmp.screen   = DefaultScreen (aDisp);
145   int aNbItems = 0;
146   XVisualInfo* aVisInfo = XGetVisualInfo (aDisp, VisualIDMask | VisualScreenMask, &aVisInfoTmp, &aNbItems);
147   if (aVisInfo == NULL)
148   {
149     throw Aspect_WindowDefinitionError("Xw_Window, Visual is unavailable");
150   }
151   XFree (aVisInfo);
152
153   DoResize();
154 }
155
156 // =======================================================================
157 // function : ~Xw_Window
158 // purpose  :
159 // =======================================================================
160 Xw_Window::~Xw_Window()
161 {
162   if (myIsOwnWin && myXWindow != 0 && !myDisplay.IsNull())
163   {
164     XDestroyWindow (myDisplay->GetDisplay(), myXWindow);
165   }
166 }
167
168 // =======================================================================
169 // function : XWindow
170 // purpose  :
171 // =======================================================================
172 Window Xw_Window::XWindow() const
173 {
174   return myXWindow;
175 }
176
177 // =======================================================================
178 // function : IsMapped
179 // purpose  :
180 // =======================================================================
181 Standard_Boolean Xw_Window::IsMapped() const
182 {
183   if (myXWindow == 0)
184   {
185     return false;
186   }
187   else if (IsVirtual())
188   {
189     return Standard_True;
190   }
191
192   XFlush (myDisplay->GetDisplay());
193   XWindowAttributes aWinAttr;
194   XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &aWinAttr);
195   return aWinAttr.map_state == IsUnviewable
196       || aWinAttr.map_state == IsViewable;
197 }
198
199 // =======================================================================
200 // function : Map
201 // purpose  :
202 // =======================================================================
203 void Xw_Window::Map() const
204 {
205   if (IsVirtual() || myXWindow == 0)
206   {
207     return;
208   }
209
210   XMapWindow (myDisplay->GetDisplay(), myXWindow);
211   XFlush (myDisplay->GetDisplay());
212 }
213
214 // =======================================================================
215 // function : Unmap
216 // purpose  :
217 // =======================================================================
218 void Xw_Window::Unmap() const
219 {
220   if (IsVirtual() || myXWindow == 0)
221   {
222     return;
223   }
224
225   XIconifyWindow (myDisplay->GetDisplay(), myXWindow, DefaultScreen(myDisplay->GetDisplay()));
226 }
227
228 // =======================================================================
229 // function : DoResize
230 // purpose  :
231 // =======================================================================
232 Aspect_TypeOfResize Xw_Window::DoResize()
233 {
234   if (IsVirtual() || myXWindow == 0)
235   {
236     return Aspect_TOR_UNKNOWN;
237   }
238
239   XFlush (myDisplay->GetDisplay());
240   XWindowAttributes aWinAttr;
241   XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &aWinAttr);
242   if (aWinAttr.map_state == IsUnmapped)
243   {
244     return Aspect_TOR_UNKNOWN;
245   }
246
247   Standard_Integer aMask = 0;
248   Aspect_TypeOfResize aMode = Aspect_TOR_UNKNOWN;
249
250   if (Abs (aWinAttr.x                     - myXLeft  ) > 2) aMask |= 1;
251   if (Abs ((aWinAttr.x + aWinAttr.width)  - myXRight ) > 2) aMask |= 2;
252   if (Abs (aWinAttr.y                     - myYTop   ) > 2) aMask |= 4;
253   if (Abs ((aWinAttr.y + aWinAttr.height) - myYBottom) > 2) aMask |= 8;
254   switch (aMask)
255   {
256     case 0:  aMode = Aspect_TOR_NO_BORDER;               break;
257     case 1:  aMode = Aspect_TOR_LEFT_BORDER;             break;
258     case 2:  aMode = Aspect_TOR_RIGHT_BORDER;            break;
259     case 4:  aMode = Aspect_TOR_TOP_BORDER;              break;
260     case 5:  aMode = Aspect_TOR_LEFT_AND_TOP_BORDER;     break;
261     case 6:  aMode = Aspect_TOR_TOP_AND_RIGHT_BORDER;    break;
262     case 8:  aMode = Aspect_TOR_BOTTOM_BORDER;           break;
263     case 9:  aMode = Aspect_TOR_BOTTOM_AND_LEFT_BORDER;  break;
264     case 10: aMode = Aspect_TOR_RIGHT_AND_BOTTOM_BORDER; break;
265     default: break;
266   }
267
268   myXLeft   = aWinAttr.x;
269   myXRight  = aWinAttr.x + aWinAttr.width;
270   myYTop    = aWinAttr.y;
271   myYBottom = aWinAttr.y + aWinAttr.height;
272   return aMode;
273 }
274
275 // =======================================================================
276 // function : DoMapping
277 // purpose  :
278 // =======================================================================
279 Standard_Boolean Xw_Window::DoMapping() const
280 {
281   return Standard_True; // IsMapped()
282 }
283
284 // =======================================================================
285 // function : Ratio
286 // purpose  :
287 // =======================================================================
288 Standard_Real Xw_Window::Ratio() const
289 {
290   if (IsVirtual() || myXWindow == 0)
291   {
292     return Standard_Real(myXRight - myXLeft) / Standard_Real(myYBottom - myYTop);
293   }
294
295   XFlush (myDisplay->GetDisplay());
296   XWindowAttributes aWinAttr;
297   XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &aWinAttr);
298   return Standard_Real(aWinAttr.width) / Standard_Real(aWinAttr.height);
299 }
300
301 // =======================================================================
302 // function : Position
303 // purpose  :
304 // =======================================================================
305 void Xw_Window::Position (Standard_Integer& theX1, Standard_Integer& theY1,
306                           Standard_Integer& theX2, Standard_Integer& theY2) const
307 {
308   if (IsVirtual() || myXWindow == 0)
309   {
310     theX1  = myXLeft;
311     theX2  = myXRight;
312     theY1  = myYTop;
313     theY2  = myYBottom;
314     return;
315   }
316
317   XFlush (myDisplay->GetDisplay());
318   XWindowAttributes anAttributes;
319   XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &anAttributes);
320   Window aChild;
321   XTranslateCoordinates (myDisplay->GetDisplay(), anAttributes.root, myXWindow,
322                          0, 0, &anAttributes.x, &anAttributes.y, &aChild);
323
324   theX1 = -anAttributes.x;
325   theX2 = theX1 + anAttributes.width;
326   theY1 = -anAttributes.y;
327   theY2 = theY1 + anAttributes.height;
328 }
329
330 // =======================================================================
331 // function : Size
332 // purpose  :
333 // =======================================================================
334 void Xw_Window::Size (Standard_Integer& theWidth,
335                       Standard_Integer& theHeight) const
336 {
337   if (IsVirtual() || myXWindow == 0)
338   {
339     theWidth  = myXRight - myXLeft;
340     theHeight = myYBottom - myYTop;
341     return;
342   }
343
344   XFlush (myDisplay->GetDisplay());
345   XWindowAttributes aWinAttr;
346   XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &aWinAttr);
347   theWidth  = aWinAttr.width;
348   theHeight = aWinAttr.height;
349 }
350
351 // =======================================================================
352 // function : SetTitle
353 // purpose  :
354 // =======================================================================
355 void Xw_Window::SetTitle (const TCollection_AsciiString& theTitle)
356 {
357   if (myXWindow != 0)
358   {
359     XStoreName (myDisplay->GetDisplay(), myXWindow, theTitle.ToCString());
360   }
361 }
362
363 // =======================================================================
364 // function : InvalidateContent
365 // purpose  :
366 // =======================================================================
367 void Xw_Window::InvalidateContent (const Handle(Aspect_DisplayConnection)& theDisp)
368 {
369   if (myXWindow == 0)
370   {
371     return;
372   }
373
374   const Handle(Aspect_DisplayConnection)& aDisp = !theDisp.IsNull() ? theDisp : myDisplay;
375   Display* aDispX = aDisp->GetDisplay();
376
377   XEvent anEvent;
378   memset (&anEvent, 0, sizeof(anEvent));
379   anEvent.type = Expose;
380   anEvent.xexpose.window = myXWindow;
381   XSendEvent (aDispX, myXWindow, False, ExposureMask, &anEvent);
382   XFlush (aDispX);
383 }
384
385 // =======================================================================
386 // function : VirtualKeyFromNative
387 // purpose  :
388 // =======================================================================
389 Aspect_VKey Xw_Window::VirtualKeyFromNative (unsigned long theKey)
390 {
391   if (theKey >= XK_0
392    && theKey <= XK_9)
393   {
394     return Aspect_VKey(theKey - XK_0 + Aspect_VKey_0);
395   }
396
397   if (theKey >= XK_A
398    && theKey <= XK_Z)
399   {
400     return Aspect_VKey(theKey - XK_A + Aspect_VKey_A);
401   }
402
403   if (theKey >= XK_a
404    && theKey <= XK_z)
405   {
406     return Aspect_VKey(theKey - XK_a + Aspect_VKey_A);
407   }
408
409   if (theKey >= XK_F1
410    && theKey <= XK_F24)
411   {
412     if (theKey <= XK_F12)
413     {
414       return Aspect_VKey(theKey - XK_F1 + Aspect_VKey_F1);
415     }
416     return Aspect_VKey_UNKNOWN;
417   }
418
419   switch (theKey)
420   {
421     case XK_space:
422       return Aspect_VKey_Space;
423     case XK_apostrophe:
424       return Aspect_VKey_Apostrophe;
425     case XK_comma:
426       return Aspect_VKey_Comma;
427     case XK_minus:
428       return Aspect_VKey_Minus;
429     case XK_period:
430       return Aspect_VKey_Period;
431     case XK_semicolon:
432       return Aspect_VKey_Semicolon;
433     case XK_equal:
434       return Aspect_VKey_Equal;
435     case XK_bracketleft:
436       return Aspect_VKey_BracketLeft;
437     case XK_backslash:
438       return Aspect_VKey_Backslash;
439     case XK_bracketright:
440       return Aspect_VKey_BracketRight;
441     case XK_BackSpace:
442       return Aspect_VKey_Backspace;
443     case XK_Tab:
444       return Aspect_VKey_Tab;
445     //case XK_Linefeed:
446     case XK_Return:
447     case XK_KP_Enter:
448       return Aspect_VKey_Enter;
449     //case XK_Pause:
450     //  return Aspect_VKey_Pause;
451     case XK_Escape:
452       return Aspect_VKey_Escape;
453     case XK_Home:
454       return Aspect_VKey_Home;
455     case XK_Left:
456       return Aspect_VKey_Left;
457     case XK_Up:
458       return Aspect_VKey_Up;
459     case XK_Right:
460       return Aspect_VKey_Right;
461     case XK_Down:
462       return Aspect_VKey_Down;
463     case XK_Prior:
464       return Aspect_VKey_PageUp;
465     case XK_Next:
466       return Aspect_VKey_PageDown;
467     case XK_End:
468       return Aspect_VKey_End;
469     //case XK_Insert:
470     //  return Aspect_VKey_Insert;
471     case XK_Menu:
472       return Aspect_VKey_Menu;
473     case XK_Num_Lock:
474       return Aspect_VKey_Numlock;
475     //case XK_KP_Delete:
476     //  return Aspect_VKey_NumDelete;
477     case XK_KP_Multiply:
478       return Aspect_VKey_NumpadMultiply;
479     case XK_KP_Add:
480       return Aspect_VKey_NumpadAdd;
481     //case XK_KP_Separator:
482     //  return Aspect_VKey_Separator;
483     case XK_KP_Subtract:
484       return Aspect_VKey_NumpadSubtract;
485     //case XK_KP_Decimal:
486     //  return Aspect_VKey_Decimal;
487     case XK_KP_Divide:
488       return Aspect_VKey_NumpadDivide;
489     case XK_Shift_L:
490     case XK_Shift_R:
491       return Aspect_VKey_Shift;
492     case XK_Control_L:
493     case XK_Control_R:
494       return Aspect_VKey_Control;
495     //case XK_Caps_Lock:
496     //  return Aspect_VKey_CapsLock;
497     case XK_Alt_L:
498     case XK_Alt_R:
499       return Aspect_VKey_Alt;
500     //case XK_Super_L:
501     //case XK_Super_R:
502     //  return Aspect_VKey_Super;
503     case XK_Delete:
504       return Aspect_VKey_Delete;
505
506     case 0x1008FF11: // XF86AudioLowerVolume
507       return Aspect_VKey_VolumeDown;
508     case 0x1008FF12: // XF86AudioMute
509       return Aspect_VKey_VolumeMute;
510     case 0x1008FF13: // XF86AudioRaiseVolume
511       return Aspect_VKey_VolumeUp;
512
513     case 0x1008FF14: // XF86AudioPlay
514       return Aspect_VKey_MediaPlayPause;
515     case 0x1008FF15: // XF86AudioStop
516       return Aspect_VKey_MediaStop;
517     case 0x1008FF16: // XF86AudioPrev
518       return Aspect_VKey_MediaPreviousTrack;
519     case 0x1008FF17: // XF86AudioNext
520       return Aspect_VKey_MediaNextTrack;
521
522     case 0x1008FF18: // XF86HomePage
523       return Aspect_VKey_BrowserHome;
524     case 0x1008FF26: // XF86Back
525       return Aspect_VKey_BrowserBack;
526     case 0x1008FF27: // XF86Forward
527       return Aspect_VKey_BrowserForward;
528     case 0x1008FF28: // XF86Stop
529       return Aspect_VKey_BrowserStop;
530     case 0x1008FF29: // XF86Refresh
531       return Aspect_VKey_BrowserRefresh;
532   }
533   return Aspect_VKey_UNKNOWN;
534 }
535
536 // =======================================================================
537 // function : ProcessMessage
538 // purpose  :
539 // =======================================================================
540 bool Xw_Window::ProcessMessage (Aspect_WindowInputListener& theListener,
541                                 XEvent& theMsg)
542 {
543   Display* aDisplay = myDisplay->GetDisplay();
544
545   // Handle event for the chosen display connection
546   switch (theMsg.type)
547   {
548     case ClientMessage:
549     {
550       if ((Atom)theMsg.xclient.data.l[0] == myDisplay->GetAtom (Aspect_XA_DELETE_WINDOW)
551        && theMsg.xclient.window == myXWindow)
552       {
553         theListener.ProcessClose();
554         return true;
555       }
556       return false;
557     }
558     case FocusIn:
559     case FocusOut:
560     {
561       if (theMsg.xfocus.window == myXWindow)
562       {
563         theListener.ProcessFocus (theMsg.type == FocusIn);
564       }
565       return true;
566     }
567     case Expose:
568     {
569       if (theMsg.xexpose.window == myXWindow)
570       {
571         theListener.ProcessExpose();
572       }
573
574       // remove all the ExposureMask and process them at once
575       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
576       {
577         if (!XCheckWindowEvent (aDisplay, myXWindow, ExposureMask, &theMsg))
578         {
579           break;
580         }
581       }
582
583       return true;
584     }
585     case ConfigureNotify:
586     {
587       // remove all the StructureNotifyMask and process them at once
588       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
589       {
590         if (!XCheckWindowEvent (aDisplay, myXWindow, StructureNotifyMask, &theMsg))
591         {
592           break;
593         }
594       }
595
596       if (theMsg.xconfigure.window == myXWindow)
597       {
598         theListener.ProcessConfigure (true);
599       }
600       return true;
601     }
602     case KeyPress:
603     case KeyRelease:
604     {
605       XKeyEvent*   aKeyEvent = (XKeyEvent* )&theMsg;
606       const KeySym aKeySym = XLookupKeysym (aKeyEvent, 0);
607       const Aspect_VKey aVKey = Xw_Window::VirtualKeyFromNative (aKeySym);
608       if (aVKey != Aspect_VKey_UNKNOWN)
609       {
610         const double aTimeStamp = theListener.EventTime();
611         if (theMsg.type == KeyPress)
612         {
613           theListener.KeyDown (aVKey, aTimeStamp);
614         }
615         else
616         {
617           theListener.KeyUp (aVKey, aTimeStamp);
618         }
619         theListener.ProcessInput();
620       }
621       return true;
622     }
623     case ButtonPress:
624     case ButtonRelease:
625     {
626       const Graphic3d_Vec2i aPos (theMsg.xbutton.x, theMsg.xbutton.y);
627       Aspect_VKeyFlags aFlags  = Aspect_VKeyFlags_NONE;
628       Aspect_VKeyMouse aButton = Aspect_VKeyMouse_NONE;
629       if (theMsg.xbutton.button == Button1) { aButton = Aspect_VKeyMouse_LeftButton; }
630       if (theMsg.xbutton.button == Button2) { aButton = Aspect_VKeyMouse_MiddleButton; }
631       if (theMsg.xbutton.button == Button3) { aButton = Aspect_VKeyMouse_RightButton; }
632
633       if ((theMsg.xbutton.state & ControlMask) != 0) { aFlags |= Aspect_VKeyFlags_CTRL; }
634       if ((theMsg.xbutton.state & ShiftMask)   != 0) { aFlags |= Aspect_VKeyFlags_SHIFT; }
635       if (theListener.Keys().IsKeyDown (Aspect_VKey_Alt))
636       {
637         aFlags |= Aspect_VKeyFlags_ALT;
638       }
639
640       if (theMsg.xbutton.button == Button4
641        || theMsg.xbutton.button == Button5)
642       {
643         if (theMsg.type != ButtonPress)
644         {
645           return true;
646         }
647
648         const double aDeltaF = (theMsg.xbutton.button == Button4 ? 1.0 : -1.0);
649         theListener.UpdateMouseScroll (Aspect_ScrollDelta (aPos, aDeltaF, aFlags));
650       }
651       else if (theMsg.type == ButtonPress)
652       {
653         theListener.PressMouseButton (aPos, aButton, aFlags, false);
654       }
655       else
656       {
657         theListener.ReleaseMouseButton (aPos, aButton, aFlags, false);
658       }
659       theListener.ProcessInput();
660       return true;
661     }
662     case MotionNotify:
663     {
664       if (theMsg.xmotion.window != myXWindow)
665       {
666         return false;
667       }
668
669       // remove all the ButtonMotionMask and process them at once
670       for (int aNbMaxEvents = XPending (aDisplay); aNbMaxEvents > 0; --aNbMaxEvents)
671       {
672         if (!XCheckWindowEvent (aDisplay, myXWindow, ButtonMotionMask | PointerMotionMask, &theMsg))
673         {
674           break;
675         }
676       }
677
678       Graphic3d_Vec2i aPos (theMsg.xmotion.x, theMsg.xmotion.y);
679       Aspect_VKeyMouse aButtons = Aspect_VKeyMouse_NONE;
680       Aspect_VKeyFlags aFlags   = Aspect_VKeyFlags_NONE;
681       if ((theMsg.xmotion.state & Button1Mask) != 0) { aButtons |= Aspect_VKeyMouse_LeftButton; }
682       if ((theMsg.xmotion.state & Button2Mask) != 0) { aButtons |= Aspect_VKeyMouse_MiddleButton; }
683       if ((theMsg.xmotion.state & Button3Mask) != 0) { aButtons |= Aspect_VKeyMouse_RightButton; }
684
685       if ((theMsg.xmotion.state & ControlMask) != 0) { aFlags |= Aspect_VKeyFlags_CTRL; }
686       if ((theMsg.xmotion.state & ShiftMask)   != 0) { aFlags |= Aspect_VKeyFlags_SHIFT; }
687       if (theListener.Keys().IsKeyDown (Aspect_VKey_Alt))
688       {
689         aFlags |= Aspect_VKeyFlags_ALT;
690       }
691
692       theListener.UpdateMousePosition (aPos, aButtons, aFlags, false);
693       theListener.ProcessInput();
694       return true;
695     }
696   }
697   return false;
698 }
699
700 #endif //  Win32 or Mac OS X