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