7ae3a25c744bd413275c578d8884386e42de9f99
[occt.git] / src / ViewerTest / ViewerTest_EventManager.cxx
1 // Created on: 1998-08-27
2 // Created by: Robert COUBLANC
3 // Copyright (c) 1998-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <ViewerTest_EventManager.hxx>
18
19 #include <AIS_AnimationCamera.hxx>
20 #include <Aspect_DisplayConnection.hxx>
21 #include <AIS_InteractiveContext.hxx>
22 #include <AIS_Shape.hxx>
23 #include <Aspect_Grid.hxx>
24 #include <Draw.hxx>
25 #include <Message.hxx>
26 #include <ViewerTest_ContinuousRedrawer.hxx>
27 #include <ViewerTest_V3dView.hxx>
28 #include <ViewerTest.hxx>
29
30 #if defined(_WIN32)
31   //
32 #elif defined(HAVE_XLIB)
33   #include <Xw_Window.hxx>
34   #include <X11/Xlib.h>
35   #include <X11/Xutil.h>
36 #elif defined(__EMSCRIPTEN__)
37   #include <Wasm_Window.hxx>
38   #include <emscripten.h>
39   #include <emscripten/html5.h>
40
41   //! Callback flushing events and redrawing the WebGL canvas.
42   static void onWasmRedrawView (void* )
43   {
44     Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
45     const Handle(V3d_View)& aView = ViewerTest::CurrentView();
46     const Handle(AIS_InteractiveContext)& aCtx = ViewerTest::GetAISContext();
47     if (!aViewCtrl.IsNull() && !aView.IsNull() && !aCtx.IsNull())
48     {
49       aViewCtrl->ProcessExpose();
50     }
51   }
52 #endif
53
54 Standard_IMPORT Standard_Boolean Draw_Interprete (const char* theCommand);
55
56 IMPLEMENT_STANDARD_RTTIEXT(ViewerTest_EventManager,Standard_Transient)
57
58 //=======================================================================
59 //function : GlobalViewAnimation
60 //purpose  :
61 //=======================================================================
62 const Handle(AIS_AnimationCamera)& ViewerTest_EventManager::GlobalViewAnimation()
63 {
64   static Handle(AIS_AnimationCamera) THE_CAMERA_ANIM = new AIS_AnimationCamera ("ViewerTest_EventManager_ViewAnimation", Handle(V3d_View)());
65   THE_CAMERA_ANIM->SetOwnDuration (0.5);
66   return THE_CAMERA_ANIM;
67 }
68
69 //=======================================================================
70 //function : ViewerTest_EventManager
71 //purpose  :
72 //=======================================================================
73 ViewerTest_EventManager::ViewerTest_EventManager (const Handle(V3d_View)&               theView,
74                                                   const Handle(AIS_InteractiveContext)& theCtx)
75 : myCtx  (theCtx),
76   myView (theView),
77   myToPickPnt (Standard_False),
78   myIsTmpContRedraw (Standard_False),
79   myUpdateRequests (0)
80 {
81   myViewAnimation = GlobalViewAnimation();
82
83   addActionHotKeys (Aspect_VKey_NavForward,        Aspect_VKey_W, Aspect_VKey_W | Aspect_VKeyFlags_SHIFT);
84   addActionHotKeys (Aspect_VKey_NavBackward ,      Aspect_VKey_S, Aspect_VKey_S | Aspect_VKeyFlags_SHIFT);
85   addActionHotKeys (Aspect_VKey_NavSlideLeft,      Aspect_VKey_A, Aspect_VKey_A | Aspect_VKeyFlags_SHIFT);
86   addActionHotKeys (Aspect_VKey_NavSlideRight,     Aspect_VKey_D, Aspect_VKey_D | Aspect_VKeyFlags_SHIFT);
87   addActionHotKeys (Aspect_VKey_NavRollCCW,        Aspect_VKey_Q, Aspect_VKey_Q | Aspect_VKeyFlags_SHIFT);
88   addActionHotKeys (Aspect_VKey_NavRollCW,         Aspect_VKey_E, Aspect_VKey_E | Aspect_VKeyFlags_SHIFT);
89
90   addActionHotKeys (Aspect_VKey_NavSpeedIncrease,  Aspect_VKey_Plus,  Aspect_VKey_Plus  | Aspect_VKeyFlags_SHIFT,
91                                                    Aspect_VKey_Equal,
92                                                    Aspect_VKey_NumpadAdd, Aspect_VKey_NumpadAdd | Aspect_VKeyFlags_SHIFT);
93   addActionHotKeys (Aspect_VKey_NavSpeedDecrease,  Aspect_VKey_Minus, Aspect_VKey_Minus | Aspect_VKeyFlags_SHIFT,
94                                                    Aspect_VKey_NumpadSubtract, Aspect_VKey_NumpadSubtract | Aspect_VKeyFlags_SHIFT);
95
96   addActionHotKeys (Aspect_VKey_NavLookUp,         Aspect_VKey_Up);
97   addActionHotKeys (Aspect_VKey_NavLookDown,       Aspect_VKey_Down);
98   addActionHotKeys (Aspect_VKey_NavLookLeft,       Aspect_VKey_Left);
99   addActionHotKeys (Aspect_VKey_NavLookRight,      Aspect_VKey_Right);
100   addActionHotKeys (Aspect_VKey_NavSlideLeft,      Aspect_VKey_Left  | Aspect_VKeyFlags_SHIFT);
101   addActionHotKeys (Aspect_VKey_NavSlideRight,     Aspect_VKey_Right | Aspect_VKeyFlags_SHIFT);
102   addActionHotKeys (Aspect_VKey_NavSlideUp,        Aspect_VKey_Up    | Aspect_VKeyFlags_SHIFT);
103   addActionHotKeys (Aspect_VKey_NavSlideDown,      Aspect_VKey_Down  | Aspect_VKeyFlags_SHIFT);
104
105   // window could be actually not yet set to the View
106   //SetupWindowCallbacks (theView->Window());
107 }
108
109 //=======================================================================
110 //function : ~ViewerTest_EventManager
111 //purpose  :
112 //=======================================================================
113 ViewerTest_EventManager::~ViewerTest_EventManager()
114 {
115   if (!myViewAnimation.IsNull()
116     && myViewAnimation->View() == myView)
117   {
118     myViewAnimation->Stop();
119     myViewAnimation->SetView (Handle(V3d_View)());
120   }
121 }
122
123 // =======================================================================
124 // function : UpdateMouseClick
125 // purpose  :
126 // =======================================================================
127 bool ViewerTest_EventManager::UpdateMouseClick (const Graphic3d_Vec2i& thePoint,
128                                                 Aspect_VKeyMouse theButton,
129                                                 Aspect_VKeyFlags theModifiers,
130                                                 bool theIsDoubleClick)
131 {
132   if (theIsDoubleClick && !myView.IsNull() && !myCtx.IsNull())
133   {
134     FitAllAuto (myCtx, myView);
135     return true;
136   }
137   return AIS_ViewController::UpdateMouseClick (thePoint, theButton, theModifiers, theIsDoubleClick);
138 }
139
140 //=======================================================================
141 //function : UpdateMouseButtons
142 //purpose  :
143 //=======================================================================
144 bool ViewerTest_EventManager::UpdateMouseButtons (const Graphic3d_Vec2i& thePoint,
145                                                   Aspect_VKeyMouse theButtons,
146                                                   Aspect_VKeyFlags theModifiers,
147                                                   bool theIsEmulated)
148 {
149   SetAllowRotation (!ViewerTest_V3dView::IsCurrentViewIn2DMode());
150
151   if (theButtons == Aspect_VKeyMouse_LeftButton)
152   {
153     if (myToPickPnt && (theModifiers & Aspect_VKeyFlags_CTRL) != 0)
154     {
155       Graphic3d_Vec3d anXYZ;
156       myView->Convert (thePoint.x(), thePoint.y(), anXYZ.x(), anXYZ.y(), anXYZ.z());
157       Draw::Set (myPickPntArgVec[0].ToCString(), anXYZ.x());
158       Draw::Set (myPickPntArgVec[1].ToCString(), anXYZ.y());
159       Draw::Set (myPickPntArgVec[2].ToCString(), anXYZ.z());
160       myToPickPnt = false;
161     }
162   }
163
164   return AIS_ViewController::UpdateMouseButtons (thePoint, theButtons, theModifiers, theIsEmulated);
165 }
166
167 //==============================================================================
168 //function : ProcessExpose
169 //purpose  :
170 //==============================================================================
171 void ViewerTest_EventManager::ProcessExpose()
172 {
173   if (!myView.IsNull())
174   {
175     FlushViewEvents (myCtx, myView, true);
176   }
177 }
178
179 //==============================================================================
180 //function : handleViewRedraw
181 //purpose  :
182 //==============================================================================
183 void ViewerTest_EventManager::handleViewRedraw (const Handle(AIS_InteractiveContext)& theCtx,
184                                                 const Handle(V3d_View)& theView)
185 {
186   myUpdateRequests = 0;
187   AIS_ViewController::handleViewRedraw (theCtx, theView);
188
189   // On non-Windows platforms Aspect_Window::InvalidateContent() from rendering thread does not work as expected
190   // as in Tcl event loop the new message might go to sleep with new event remaining in queue.
191   // As a workaround - use dedicated background thread to ping Tcl event loop.
192   if (myToAskNextFrame)
193   {
194     ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
195     if (!myIsTmpContRedraw
196      && (!aRedrawer.IsStarted() || aRedrawer.IsPaused()))
197     {
198       myIsTmpContRedraw = true;
199     #if !defined(_WIN32) && !defined(__EMSCRIPTEN__)
200       aRedrawer.Start (theView, 60.0);
201     #endif
202     }
203
204     // ask more frames
205     ++myUpdateRequests;
206   #if defined(__EMSCRIPTEN__)
207     emscripten_async_call (onWasmRedrawView, this, 0);
208   #endif
209   }
210   else if (myIsTmpContRedraw)
211   {
212     myIsTmpContRedraw = false;
213   #ifndef _WIN32
214     ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
215     aRedrawer.Pause();
216   #endif
217   }
218 }
219
220 //==============================================================================
221 //function : ProcessConfigure
222 //purpose  :
223 //==============================================================================
224 void ViewerTest_EventManager::ProcessConfigure (bool theIsResized)
225 {
226   if (!myView.IsNull())
227   {
228     if (!theIsResized
229      // track window moves to reverse stereo pair
230      && myView->RenderingParams().StereoMode != Graphic3d_StereoMode_RowInterlaced
231      && myView->RenderingParams().StereoMode != Graphic3d_StereoMode_ColumnInterlaced
232      && myView->RenderingParams().StereoMode != Graphic3d_StereoMode_ChessBoard)
233     {
234       return;
235     }
236
237     myView->Window()->DoResize();
238     myView->MustBeResized();
239     myView->Invalidate();
240     FlushViewEvents (myCtx, myView, true);
241   }
242 }
243
244 //==============================================================================
245 //function : ProcessInput
246 //purpose  :
247 //==============================================================================
248 void ViewerTest_EventManager::ProcessInput()
249 {
250   if (myView.IsNull())
251   {
252     return;
253   }
254
255 #if defined(__EMSCRIPTEN__)
256   // Queue onWasmRedrawView() callback to redraw canvas after all user input is flushed by browser.
257   // Redrawing viewer on every single message would be a pointless waste of resources,
258   // as user will see only the last drawn frame due to WebGL implementation details.
259   if (++myUpdateRequests == 1)
260   {
261   #if defined(__EMSCRIPTEN__)
262     emscripten_async_call (onWasmRedrawView, this, 0);
263   #endif
264   }
265 #else
266   // handle synchronously
267   ProcessExpose();
268 #endif
269 }
270
271 // =======================================================================
272 // function : navigationKeyModifierSwitch
273 // purpose  :
274 // =======================================================================
275 bool ViewerTest_EventManager::navigationKeyModifierSwitch (unsigned int theModifOld,
276                                                            unsigned int theModifNew,
277                                                            double       theTimeStamp)
278 {
279   bool hasActions = false;
280   for (unsigned int aKeyIter = 0; aKeyIter < Aspect_VKey_ModifiersLower; ++aKeyIter)
281   {
282     if (!myKeys.IsKeyDown (aKeyIter))
283     {
284       continue;
285     }
286
287     Aspect_VKey anActionOld = Aspect_VKey_UNKNOWN, anActionNew = Aspect_VKey_UNKNOWN;
288     myNavKeyMap.Find (aKeyIter | theModifOld, anActionOld);
289     myNavKeyMap.Find (aKeyIter | theModifNew, anActionNew);
290     if (anActionOld == anActionNew)
291     {
292       continue;
293     }
294
295     if (anActionOld != Aspect_VKey_UNKNOWN)
296     {
297       myKeys.KeyUp (anActionOld, theTimeStamp);
298     }
299     if (anActionNew != Aspect_VKey_UNKNOWN)
300     {
301       hasActions = true;
302       myKeys.KeyDown (anActionNew, theTimeStamp);
303     }
304   }
305   return hasActions;
306 }
307
308 //=======================================================================
309 //function : KeyDown
310 //purpose  :
311 //=======================================================================
312 void ViewerTest_EventManager::KeyDown (Aspect_VKey theKey,
313                                        double theTime,
314                                        double thePressure)
315 {
316   const unsigned int aModifOld = myKeys.Modifiers();
317   AIS_ViewController::KeyDown (theKey, theTime, thePressure);
318
319   const unsigned int aModifNew = myKeys.Modifiers();
320   if (aModifNew != aModifOld
321    && navigationKeyModifierSwitch (aModifOld, aModifNew, theTime))
322   {
323     // modifier key just pressed
324   }
325
326   Aspect_VKey anAction = Aspect_VKey_UNKNOWN;
327   if (myNavKeyMap.Find (theKey | myKeys.Modifiers(), anAction)
328   &&  anAction != Aspect_VKey_UNKNOWN)
329   {
330     AIS_ViewController::KeyDown (anAction, theTime, thePressure);
331   }
332 }
333
334 //=======================================================================
335 //function : KeyUp
336 //purpose  :
337 //=======================================================================
338 void ViewerTest_EventManager::KeyUp (Aspect_VKey theKey,
339                                      double theTime)
340 {
341   const unsigned int aModifOld = myKeys.Modifiers();
342   AIS_ViewController::KeyUp (theKey, theTime);
343
344   Aspect_VKey anAction = Aspect_VKey_UNKNOWN;
345   if (myNavKeyMap.Find (theKey | myKeys.Modifiers(), anAction)
346   &&  anAction != Aspect_VKey_UNKNOWN)
347   {
348     AIS_ViewController::KeyUp (anAction, theTime);
349     ProcessKeyPress (anAction);
350   }
351
352   const unsigned int aModifNew = myKeys.Modifiers();
353   if (aModifNew != aModifOld
354    && navigationKeyModifierSwitch (aModifOld, aModifNew, theTime))
355   {
356     // modifier key released
357   }
358
359   ProcessKeyPress (theKey | aModifNew);
360 }
361
362 //==============================================================================
363 //function : ProcessKeyPress
364 //purpose  :
365 //==============================================================================
366 void ViewerTest_EventManager::ProcessKeyPress (Aspect_VKey theKey)
367 {
368   if (myCtx.IsNull()
369    || myView.IsNull())
370   {
371     return;
372   }
373
374   switch (theKey)
375   {
376     case Aspect_VKey_Backspace: // AXO
377     {
378       if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
379       {
380         myView->SetProj(V3d_XposYnegZpos);
381       }
382       break;
383     }
384     case Aspect_VKey_F:
385     {
386       if (myCtx->NbSelected() > 0)
387       {
388         myCtx->FitSelected (myView);
389       }
390       else
391       {
392         myView->FitAll();
393       }
394       break;
395     }
396     case Aspect_VKey_H: // HLR
397     {
398       std::cout << "HLR\n";
399       myView->SetComputedMode (!myView->ComputedMode());
400       myView->Redraw();
401       break;
402     }
403     case Aspect_VKey_P: // Type of HLR
404     {
405       myCtx->DefaultDrawer()->SetTypeOfHLR (myCtx->DefaultDrawer()->TypeOfHLR() == Prs3d_TOH_Algo
406                                           ? Prs3d_TOH_PolyAlgo
407                                           : Prs3d_TOH_Algo);
408       if (myCtx->NbSelected() == 0)
409       {
410         AIS_ListOfInteractive aListOfShapes;
411         myCtx->DisplayedObjects (aListOfShapes);
412         for (AIS_ListIteratorOfListOfInteractive anIter (aListOfShapes); anIter.More(); anIter.Next())
413         {
414           if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (anIter.Value()))
415           {
416             aShape->SetTypeOfHLR (aShape->TypeOfHLR() == Prs3d_TOH_PolyAlgo
417                                 ? Prs3d_TOH_Algo
418                                 : Prs3d_TOH_PolyAlgo);
419             myCtx->Redisplay (aShape, Standard_False);
420           }
421         }
422       }
423       else
424       {
425         for (myCtx->InitSelected(); myCtx->MoreSelected(); myCtx->NextSelected())
426         {
427           if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (myCtx->SelectedInteractive()))
428           {
429             aShape->SetTypeOfHLR (aShape->TypeOfHLR() == Prs3d_TOH_PolyAlgo
430                                 ? Prs3d_TOH_Algo
431                                 : Prs3d_TOH_PolyAlgo);
432             myCtx->Redisplay (aShape, Standard_False);
433           }
434         }
435       }
436       myCtx->UpdateCurrentViewer();
437       break;
438     }
439     case Aspect_VKey_S | Aspect_VKeyFlags_CTRL:
440     case Aspect_VKey_W | Aspect_VKeyFlags_CTRL:
441     {
442       Standard_Integer aDispMode = AIS_Shaded;
443       if (theKey == (Aspect_VKey_S | Aspect_VKeyFlags_CTRL))
444       {
445         aDispMode = AIS_Shaded;
446         std::cout << "setup Shaded display mode\n";
447       }
448       else
449       {
450         aDispMode = AIS_WireFrame;
451         std::cout << "setup WireFrame display mode\n";
452       }
453
454       if (myCtx->NbSelected() == 0)
455       {
456         myCtx->SetDisplayMode (aDispMode, true);
457       }
458       else
459       {
460         for (myCtx->InitSelected(); myCtx->MoreSelected(); myCtx->NextSelected())
461         {
462           myCtx->SetDisplayMode (myCtx->SelectedInteractive(), aDispMode, false);
463         }
464         myCtx->UpdateCurrentViewer();
465       }
466       break;
467     }
468     case Aspect_VKey_U: // Unset display mode
469     {
470       std::cout << "reset display mode to defaults\n";
471       if (myCtx->NbSelected() == 0)
472       {
473         myCtx->SetDisplayMode (AIS_WireFrame, true);
474       }
475       else
476       {
477         for (myCtx->InitSelected(); myCtx->MoreSelected(); myCtx->NextSelected())
478         {
479           myCtx->UnsetDisplayMode (myCtx->SelectedInteractive(), false);
480         }
481         myCtx->UpdateCurrentViewer();
482       }
483       break;
484     }
485     case Aspect_VKey_T:
486     {
487       if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
488       {
489         myView->SetProj (V3d_TypeOfOrientation_Zup_Top);
490       }
491       break;
492     }
493     case Aspect_VKey_B:
494     {
495       if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
496       {
497         myView->SetProj (V3d_TypeOfOrientation_Zup_Bottom);
498       }
499       break;
500     }
501     case Aspect_VKey_L:
502     {
503       if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
504       {
505         myView->SetProj (V3d_TypeOfOrientation_Zup_Left);
506       }
507       break;
508     }
509     case Aspect_VKey_R:
510     {
511       if (!ViewerTest_V3dView::IsCurrentViewIn2DMode())
512       {
513         myView->SetProj (V3d_TypeOfOrientation_Zup_Right);
514       }
515       break;
516     }
517     case Aspect_VKey_Comma:
518     {
519       myCtx->HilightNextDetected (myView);
520       break;
521     }
522     case Aspect_VKey_Period:
523     {
524       myCtx->HilightPreviousDetected (myView);
525       break;
526     }
527     case Aspect_VKey_Slash:
528     case Aspect_VKey_NumpadDivide:
529     {
530       Handle(Graphic3d_Camera) aCamera = myView->Camera();
531       if (aCamera->IsStereo())
532       {
533         aCamera->SetIOD (aCamera->GetIODType(), aCamera->IOD() - 0.01);
534         myView->Redraw();
535       }
536       break;
537     }
538     case Aspect_VKey_NumpadMultiply:
539     {
540       Handle(Graphic3d_Camera) aCamera = myView->Camera();
541       if (aCamera->IsStereo())
542       {
543         aCamera->SetIOD (aCamera->GetIODType(), aCamera->IOD() + 0.01);
544         myView->Redraw();
545       }
546       break;
547     }
548     case Aspect_VKey_Delete:
549     {
550       if (!myCtx.IsNull()
551         && myCtx->NbSelected() > 0)
552       {
553         Draw_Interprete ("verase");
554       }
555       break;
556     }
557     case Aspect_VKey_Escape:
558     {
559       if (!myCtx.IsNull()
560         && ViewerTest_EventManager::ToCloseViewOnEscape())
561       {
562         Draw_Interprete (ViewerTest_EventManager::ToExitOnCloseView() ? "exit" : "vclose");
563       }
564       break;
565     }
566     case Aspect_VKey_NavSpeedDecrease:
567     case Aspect_VKey_NavSpeedIncrease:
568     {
569       // handle slide speed
570       float aNewSpeed = theKey == Aspect_VKey_NavSpeedDecrease
571                       ? myWalkSpeedRelative * 0.5f
572                       : myWalkSpeedRelative * 2.0f;
573       if (aNewSpeed >= 0.00001f
574        && aNewSpeed <= 10.0f)
575       {
576         if (Abs (aNewSpeed - 0.1f) < 0.001f)
577         {
578           aNewSpeed = 0.1f;
579         }
580         myWalkSpeedRelative = aNewSpeed;
581       }
582       break;
583     }
584   }
585
586   if (theKey >= Aspect_VKey_0
587    && theKey <= Aspect_VKey_7)
588   {
589     const Standard_Integer aSelMode = theKey - Aspect_VKey_0;
590     bool toEnable = true;
591     if (!myCtx.IsNull())
592     {
593       AIS_ListOfInteractive aPrsList;
594       myCtx->DisplayedObjects (aPrsList);
595       for (AIS_ListOfInteractive::Iterator aPrsIter (aPrsList); aPrsIter.More() && toEnable; aPrsIter.Next())
596       {
597         TColStd_ListOfInteger aModes;
598         myCtx->ActivatedModes (aPrsIter.Value(), aModes);
599         for (TColStd_ListOfInteger::Iterator aModeIter (aModes); aModeIter.More() && toEnable; aModeIter.Next())
600         {
601           if (aModeIter.Value() == aSelMode)
602           {
603             toEnable = false;
604           }
605         }
606       }
607     }
608     TCollection_AsciiString aCmd = TCollection_AsciiString ("vselmode ") + aSelMode + (toEnable ? " 1" : " 0");
609     Draw_Interprete (aCmd.ToCString());
610   }
611 }
612
613 #if defined(__EMSCRIPTEN__)
614 //! Handle browser window resize event.
615 static EM_BOOL onResizeCallback (int theEventType, const EmscriptenUiEvent* theEvent, void* )
616 {
617   Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
618   if (!aViewCtrl.IsNull()
619    && !ViewerTest::CurrentView().IsNull())
620   {
621     Handle(Wasm_Window) aWindow = Handle(Wasm_Window)::DownCast (ViewerTest::CurrentView()->Window());
622     return aWindow->ProcessUiEvent (*aViewCtrl, theEventType, theEvent) ? EM_TRUE : EM_FALSE;
623   }
624   return EM_FALSE;
625 }
626
627 //! Update canvas bounding rectangle.
628 EM_JS(void, occJSUpdateBoundingClientRect, (), {
629   Module._myCanvasRect = Module.canvas.getBoundingClientRect();
630 });
631
632 //! Get canvas bounding top.
633 EM_JS(int, occJSGetBoundingClientTop, (), {
634   return Math.round(Module._myCanvasRect.top);
635 });
636
637 //! Get canvas bounding left.
638 EM_JS(int, occJSGetBoundingClientLeft, (), {
639   return Math.round(Module._myCanvasRect.left);
640 });
641
642 //! Handle mouse input event.
643 static EM_BOOL onWasmMouseCallback (int theEventType, const EmscriptenMouseEvent* theEvent, void* )
644 {
645   Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
646   if (!aViewCtrl.IsNull()
647    && !ViewerTest::CurrentView().IsNull())
648   {
649     Handle(Wasm_Window) aWindow = Handle(Wasm_Window)::DownCast (ViewerTest::CurrentView()->Window());
650     if (theEventType == EMSCRIPTEN_EVENT_MOUSEMOVE
651      || theEventType == EMSCRIPTEN_EVENT_MOUSEUP)
652     {
653       // these events are bound to EMSCRIPTEN_EVENT_TARGET_WINDOW, and coordinates should be converted
654       occJSUpdateBoundingClientRect();
655       EmscriptenMouseEvent anEvent = *theEvent;
656       anEvent.targetX -= occJSGetBoundingClientLeft();
657       anEvent.targetY -= occJSGetBoundingClientTop();
658       return aWindow->ProcessMouseEvent (*aViewCtrl, theEventType, &anEvent) ? EM_TRUE : EM_FALSE;
659     }
660
661     return aWindow->ProcessMouseEvent (*aViewCtrl, theEventType, theEvent) ? EM_TRUE : EM_FALSE;
662   }
663   return EM_FALSE;
664 }
665
666 //! Handle mouse wheel event.
667 static EM_BOOL onWasmWheelCallback (int theEventType, const EmscriptenWheelEvent* theEvent, void* )
668 {
669   Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
670   if (!aViewCtrl.IsNull()
671    && !ViewerTest::CurrentView().IsNull())
672   {
673     Handle(Wasm_Window) aWindow = Handle(Wasm_Window)::DownCast (ViewerTest::CurrentView()->Window());
674     return aWindow->ProcessWheelEvent (*aViewCtrl, theEventType, theEvent) ? EM_TRUE : EM_FALSE;
675   }
676   return EM_FALSE;
677 }
678
679 //! Handle touch input event.
680 static EM_BOOL onWasmTouchCallback (int theEventType, const EmscriptenTouchEvent* theEvent, void* )
681 {
682   Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
683   if (!aViewCtrl.IsNull()
684    && !ViewerTest::CurrentView().IsNull())
685   {
686     Handle(Wasm_Window) aWindow = Handle(Wasm_Window)::DownCast (ViewerTest::CurrentView()->Window());
687     return aWindow->ProcessTouchEvent (*aViewCtrl, theEventType, theEvent) ? EM_TRUE : EM_FALSE;
688   }
689   return EM_FALSE;
690 }
691
692 //! Handle keyboard input event.
693 static EM_BOOL onWasmKeyCallback (int theEventType, const EmscriptenKeyboardEvent* theEvent, void* )
694 {
695   Handle(ViewerTest_EventManager) aViewCtrl = ViewerTest::CurrentEventManager();
696   if (!aViewCtrl.IsNull()
697    && !ViewerTest::CurrentView().IsNull())
698   {
699     Handle(Wasm_Window) aWindow = Handle(Wasm_Window)::DownCast (ViewerTest::CurrentView()->Window());
700     aWindow->ProcessKeyEvent (*aViewCtrl, theEventType, theEvent);
701     return EM_TRUE;
702   }
703   return EM_FALSE;
704 }
705 #endif
706
707 // ==============================================================================
708 // function : SetupWindowCallbacks
709 // purpose  :
710 // ==============================================================================
711 void ViewerTest_EventManager::SetupWindowCallbacks (const Handle(Aspect_Window)& theWin)
712 {
713 #ifdef _WIN32
714   (void )theWin;
715 #elif defined(HAVE_XLIB)
716   // X11
717   Window anXWin = (Window )theWin->NativeHandle();
718   Display* anXDisplay = (Display* )theWin->DisplayConnection()->GetDisplayAspect();
719   XSynchronize (anXDisplay, 1);
720
721   // X11 : For keyboard on SUN
722   XWMHints aWmHints;
723   memset (&aWmHints, 0, sizeof(aWmHints));
724   aWmHints.flags = InputHint;
725   aWmHints.input = 1;
726   XSetWMHints (anXDisplay, anXWin, &aWmHints);
727
728   XSelectInput (anXDisplay, anXWin,
729                 ExposureMask | KeyPressMask | KeyReleaseMask
730               | ButtonPressMask | ButtonReleaseMask
731               | StructureNotifyMask
732               | PointerMotionMask
733               | Button1MotionMask | Button2MotionMask
734               | Button3MotionMask | FocusChangeMask);
735   Atom aDeleteWindowAtom = theWin->DisplayConnection()->GetAtom (Aspect_XA_DELETE_WINDOW);
736   XSetWMProtocols (anXDisplay, anXWin, &aDeleteWindowAtom, 1);
737
738   XSynchronize (anXDisplay, 0);
739 #elif defined(__EMSCRIPTEN__)
740   Handle(Wasm_Window) aWindow = Handle(Wasm_Window)::DownCast (theWin);
741   if (aWindow->CanvasId().IsEmpty()
742    || aWindow->CanvasId() == "#")
743   {
744     Message::SendFail ("Error: unable registering callbacks to Module.canvas");
745     return;
746   }
747
748   const char* aTargetId = aWindow->CanvasId().ToCString();
749   const EM_BOOL toUseCapture = EM_TRUE;
750   void* anOpaque = NULL; //this; // unused
751
752   // make sure to clear previously set listeners (e.g. created by another ViewerTest_EventManager instance)
753   emscripten_html5_remove_all_event_listeners();
754
755   // resize event implemented only for a window by browsers,
756   // so that if web application changes canvas size by other means it should use another way to tell OCCT about resize
757   emscripten_set_resize_callback     (EMSCRIPTEN_EVENT_TARGET_WINDOW, anOpaque, toUseCapture, onResizeCallback);
758
759   // bind these events to window to track mouse movements outside of canvas
760   //emscripten_set_mouseup_callback    (aTargetId, anOpaque, toUseCapture, onWasmMouseCallback);
761   //emscripten_set_mousemove_callback  (aTargetId, anOpaque, toUseCapture, onWasmMouseCallback);
762   //emscripten_set_mouseleave_callback (aTargetId, anOpaque, toUseCapture, onWasmMouseCallback);
763   emscripten_set_mouseup_callback    (EMSCRIPTEN_EVENT_TARGET_WINDOW, anOpaque, toUseCapture, onWasmMouseCallback);
764   emscripten_set_mousemove_callback  (EMSCRIPTEN_EVENT_TARGET_WINDOW, anOpaque, toUseCapture, onWasmMouseCallback);
765
766   emscripten_set_mousedown_callback  (aTargetId, anOpaque, toUseCapture, onWasmMouseCallback);
767   emscripten_set_dblclick_callback   (aTargetId, anOpaque, toUseCapture, onWasmMouseCallback);
768   emscripten_set_click_callback      (aTargetId, anOpaque, toUseCapture, onWasmMouseCallback);
769   emscripten_set_mouseenter_callback (aTargetId, anOpaque, toUseCapture, onWasmMouseCallback);
770   emscripten_set_wheel_callback      (aTargetId, anOpaque, toUseCapture, onWasmWheelCallback);
771
772   emscripten_set_touchstart_callback (aTargetId, anOpaque, toUseCapture, onWasmTouchCallback);
773   emscripten_set_touchend_callback   (aTargetId, anOpaque, toUseCapture, onWasmTouchCallback);
774   emscripten_set_touchmove_callback  (aTargetId, anOpaque, toUseCapture, onWasmTouchCallback);
775   emscripten_set_touchcancel_callback(aTargetId, anOpaque, toUseCapture, onWasmTouchCallback);
776
777   // keyboard input requires a focusable element or EMSCRIPTEN_EVENT_TARGET_WINDOW
778   emscripten_set_keydown_callback    (aTargetId, anOpaque, toUseCapture, onWasmKeyCallback);
779   emscripten_set_keyup_callback      (aTargetId, anOpaque, toUseCapture, onWasmKeyCallback);
780 #else
781   (void )theWin;
782 #endif
783 }