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