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