b811c5e1e33fd9010d994ddd5d7d61a397ef1abc
[occt.git] / src / Xw / Xw_Window.cxx
1 // Created on: 2013-04-06
2 // Created by: Kirill Gavrilov
3 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <Xw_Window.hxx>
17
18 #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__)
19
20 #include <Aspect_Convert.hxx>
21 #include <Aspect_WindowDefinitionError.hxx>
22 #include <Message.hxx>
23 #include <Message_Messenger.hxx>
24
25 #if defined(HAVE_EGL) || defined(HAVE_GLES2)
26   #include <EGL/egl.h>
27   #ifndef EGL_OPENGL_ES3_BIT
28     #define EGL_OPENGL_ES3_BIT 0x00000040
29   #endif
30 #else
31   #include <GL/glx.h>
32
33 namespace
34 {
35
36   //! Search for RGBA double-buffered visual with stencil buffer.
37   static int TheDoubleBuffVisual[] =
38   {
39     GLX_RGBA,
40     GLX_DEPTH_SIZE, 16,
41     GLX_STENCIL_SIZE, 1,
42     GLX_DOUBLEBUFFER,
43     None
44   };
45
46   //! Search for RGBA double-buffered visual with stencil buffer.
47   static int TheDoubleBuffFBConfig[] =
48   {
49     GLX_X_RENDERABLE,  True,
50     GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
51     GLX_RENDER_TYPE,   GLX_RGBA_BIT,
52     GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
53     GLX_DEPTH_SIZE,    16,
54     GLX_STENCIL_SIZE,  1,
55     GLX_DOUBLEBUFFER,  True,
56     None
57   };
58
59 }
60
61 #endif
62
63 IMPLEMENT_STANDARD_RTTIEXT(Xw_Window, Aspect_Window)
64
65 // =======================================================================
66 // function : Xw_Window
67 // purpose  :
68 // =======================================================================
69 Xw_Window::Xw_Window (const Handle(Aspect_DisplayConnection)& theXDisplay,
70                       const Standard_CString theTitle,
71                       const Standard_Integer thePxLeft,
72                       const Standard_Integer thePxTop,
73                       const Standard_Integer thePxWidth,
74                       const Standard_Integer thePxHeight,
75                       const Aspect_FBConfig  theFBConfig)
76 : Aspect_Window(),
77   myDisplay  (theXDisplay),
78   myXWindow  (0),
79   myFBConfig (theFBConfig),
80   myXLeft    (thePxLeft),
81   myYTop     (thePxTop),
82   myXRight   (thePxLeft + thePxWidth),
83   myYBottom  (thePxTop + thePxHeight),
84   myIsOwnWin (Standard_True)
85 {
86   if (thePxWidth <= 0 || thePxHeight <= 0)
87   {
88     throw Aspect_WindowDefinitionError("Xw_Window, Coordinate(s) out of range");
89   }
90   else if (theXDisplay.IsNull())
91   {
92     throw Aspect_WindowDefinitionError("Xw_Window, X Display connection is undefined");
93     return;
94   }
95
96   Display* aDisp   = myDisplay->GetDisplay();
97   int      aScreen = DefaultScreen(aDisp);
98   Window   aParent = RootWindow   (aDisp, aScreen);
99   XVisualInfo* aVisInfo = NULL;
100
101 #if defined(HAVE_EGL) || defined(HAVE_GLES2)
102   EGLDisplay anEglDisplay = eglGetDisplay (aDisp);
103   EGLint aVerMajor = 0; EGLint aVerMinor = 0;
104   XVisualInfo aVisInfoTmp; memset (&aVisInfoTmp, 0, sizeof(aVisInfoTmp));
105   if (anEglDisplay != EGL_NO_DISPLAY
106    && eglInitialize (anEglDisplay, &aVerMajor, &aVerMinor) == EGL_TRUE)
107   {
108     EGLint aConfigAttribs[] =
109     {
110       EGL_RED_SIZE,     8,
111       EGL_GREEN_SIZE,   8,
112       EGL_BLUE_SIZE,    8,
113       EGL_ALPHA_SIZE,   0,
114       EGL_DEPTH_SIZE,   24,
115       EGL_STENCIL_SIZE, 8,
116     #if defined(HAVE_GLES2)
117       EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
118     #else
119       EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
120     #endif
121       EGL_NONE
122     };
123
124     EGLint aNbConfigs = 0;
125     void* anEglConfig = NULL;
126     for (Standard_Integer aGlesVer = 3; aGlesVer >= 2; --aGlesVer)
127     {
128     #if defined(GL_ES_VERSION_2_0)
129       aConfigAttribs[6 * 2 + 1] = aGlesVer == 3 ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_ES2_BIT;
130     #else
131       if (aGlesVer == 2)
132       {
133         break;
134       }
135     #endif
136
137       if (eglChooseConfig (anEglDisplay, aConfigAttribs, &anEglConfig, 1, &aNbConfigs) == EGL_TRUE
138        && anEglConfig != NULL)
139       {
140         break;
141       }
142       eglGetError();
143
144       aConfigAttribs[4 * 2 + 1] = 16; // try config with smaller depth buffer
145       if (eglChooseConfig (anEglDisplay, aConfigAttribs, &anEglConfig, 1, &aNbConfigs) == EGL_TRUE
146        && anEglConfig != NULL)
147       {
148         break;
149       }
150       eglGetError();
151     }
152
153     if (anEglConfig != NULL
154      && eglGetConfigAttrib (anEglDisplay, anEglConfig, EGL_NATIVE_VISUAL_ID, (EGLint* )&aVisInfoTmp.visualid) == EGL_TRUE)
155     {
156       int aNbVisuals = 0;
157       aVisInfoTmp.screen = DefaultScreen (aDisp);
158       aVisInfo = XGetVisualInfo (aDisp, VisualIDMask | VisualScreenMask, &aVisInfoTmp, &aNbVisuals);
159     }
160   }
161   if (aVisInfo == NULL)
162   {
163     Message::DefaultMessenger()->Send ("Warning: cannot choose Visual using EGL while creating Xw_Window", Message_Warning);
164   }
165 #else
166   int aDummy = 0;
167   if (!glXQueryExtension (myDisplay->GetDisplay(), &aDummy, &aDummy))
168   {
169     throw Aspect_WindowDefinitionError("Xw_Window, GLX extension is unavailable");
170     return;
171   }
172   if (myFBConfig == NULL)
173   {
174     // FBConfigs were added in GLX version 1.3
175     int aGlxMajor = 0;
176     int aGlxMinor = 0;
177     const bool hasFBCfg = glXQueryVersion (aDisp, &aGlxMajor, &aGlxMinor)
178                        && ((aGlxMajor == 1 && aGlxMinor >= 3) || (aGlxMajor > 1));
179     if (hasFBCfg)
180     {
181       int aFBCount = 0;
182       GLXFBConfig* aFBCfgList = NULL;
183       if (hasFBCfg)
184       {
185         aFBCfgList = glXChooseFBConfig (aDisp, aScreen, TheDoubleBuffFBConfig, &aFBCount);
186       }
187       if(aFBCfgList != NULL
188       && aFBCount >= 1)
189       {
190         myFBConfig = aFBCfgList[0];
191         aVisInfo   = glXGetVisualFromFBConfig (aDisp, myFBConfig);
192       }
193       XFree (aFBCfgList);
194     }
195   }
196
197   if (aVisInfo == NULL)
198   {
199     aVisInfo = glXChooseVisual (aDisp, aScreen, TheDoubleBuffVisual);
200   }
201   if (aVisInfo == NULL)
202   {
203     throw Aspect_WindowDefinitionError("Xw_Window, couldn't find compatible Visual (RGBA, double-buffered)");
204     return;
205   }
206 #endif
207
208   unsigned long aMask = 0;
209   XSetWindowAttributes aWinAttr;
210   memset(&aWinAttr, 0, sizeof(XSetWindowAttributes));
211   aWinAttr.event_mask = ExposureMask | StructureNotifyMask;
212   aMask |= CWEventMask;
213   if (aVisInfo != NULL)
214   {
215     aWinAttr.colormap = XCreateColormap(aDisp, aParent, aVisInfo->visual, AllocNone);
216   }
217   aWinAttr.border_pixel = 0;
218   aWinAttr.override_redirect = False;
219
220   myXWindow = XCreateWindow(aDisp, aParent,
221                             myXLeft, myYTop, thePxWidth, thePxHeight,
222                             0, aVisInfo != NULL ? aVisInfo->depth : CopyFromParent,
223                             InputOutput,
224                             aVisInfo != NULL ? aVisInfo->visual : CopyFromParent,
225                             CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &aWinAttr);
226   if (aVisInfo != NULL)
227   {
228     XFree (aVisInfo);
229     aVisInfo = NULL;
230   }
231   if (myXWindow == 0)
232   {
233     throw Aspect_WindowDefinitionError("Xw_Window, Unable to create window");
234     return;
235   }
236
237   // if parent - desktop
238   XSizeHints aSizeHints;
239   aSizeHints.x      = myXLeft;
240   aSizeHints.y      = myYTop;
241   aSizeHints.flags  = PPosition;
242   aSizeHints.width  = thePxWidth;
243   aSizeHints.height = thePxHeight;
244   aSizeHints.flags |= PSize;
245   XSetStandardProperties (aDisp, myXWindow, theTitle, theTitle, None,
246                           NULL, 0, &aSizeHints);
247
248   /*XTextProperty aTitleProperty;
249   aTitleProperty.encoding = None;
250   char* aTitle = (char* )theTitle;
251   Xutf8TextListToTextProperty(aDisp, &aTitle, 1, XUTF8StringStyle, &aTitleProperty);
252   XSetWMName      (aDisp, myXWindow, &aTitleProperty);
253   XSetWMProperties(aDisp, myXWindow, &aTitleProperty, &aTitleProperty, NULL, 0, NULL, NULL, NULL);*/
254
255   XFlush (aDisp);
256 }
257
258 // =======================================================================
259 // function : Xw_Window
260 // purpose  :
261 // =======================================================================
262 Xw_Window::Xw_Window (const Handle(Aspect_DisplayConnection)& theXDisplay,
263                       const Window theXWin,
264                       const Aspect_FBConfig theFBConfig)
265 : Aspect_Window(),
266   myDisplay  (theXDisplay),
267   myXWindow  (theXWin),
268   myFBConfig (theFBConfig),
269   myXLeft    (0),
270   myYTop     (0),
271   myXRight   (512),
272   myYBottom  (512),
273   myIsOwnWin (Standard_False)
274 {
275   if (theXWin == 0)
276   {
277     throw Aspect_WindowDefinitionError("Xw_Window, given invalid X window");
278     return;
279   }
280   else if (theXDisplay.IsNull())
281   {
282     throw Aspect_WindowDefinitionError("Xw_Window, X Display connection is undefined");
283     return;
284   }
285 #if !defined(HAVE_EGL) && !defined(HAVE_GLES2)
286   int aDummy = 0;
287   if (!glXQueryExtension (myDisplay->GetDisplay(), &aDummy, &aDummy))
288   {
289     myXWindow = 0;
290     throw Aspect_WindowDefinitionError("Xw_Window, GLX extension is unavailable");
291     return;
292   }
293 #endif
294
295   Display* aDisp = myDisplay->GetDisplay();
296
297   XWindowAttributes aWinAttr;
298   XGetWindowAttributes (aDisp, myXWindow, &aWinAttr);
299   XVisualInfo aVisInfoTmp;
300   aVisInfoTmp.visualid = aWinAttr.visual->visualid;
301   aVisInfoTmp.screen   = DefaultScreen (aDisp);
302   int aNbItems = 0;
303   XVisualInfo* aVisInfo = XGetVisualInfo (aDisp, VisualIDMask | VisualScreenMask, &aVisInfoTmp, &aNbItems);
304   if (aVisInfo == NULL)
305   {
306     throw Aspect_WindowDefinitionError("Xw_Window, Visual is unavailable");
307     return;
308   }
309   XFree (aVisInfo);
310
311   DoResize();
312 }
313
314 // =======================================================================
315 // function : ~Xw_Window
316 // purpose  :
317 // =======================================================================
318 Xw_Window::~Xw_Window()
319 {
320   if (myIsOwnWin && myXWindow != 0 && !myDisplay.IsNull())
321   {
322     XDestroyWindow (myDisplay->GetDisplay(), myXWindow);
323   }
324 }
325
326 // =======================================================================
327 // function : XWindow
328 // purpose  :
329 // =======================================================================
330 Window Xw_Window::XWindow() const
331 {
332   return myXWindow;
333 }
334
335 // =======================================================================
336 // function : IsMapped
337 // purpose  :
338 // =======================================================================
339 Standard_Boolean Xw_Window::IsMapped() const
340 {
341   if (myXWindow == 0)
342   {
343     return false;
344   }
345   else if (IsVirtual())
346   {
347     return Standard_True;
348   }
349
350   XFlush (myDisplay->GetDisplay());
351   XWindowAttributes aWinAttr;
352   XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &aWinAttr);
353   return aWinAttr.map_state == IsUnviewable
354       || aWinAttr.map_state == IsViewable;
355 }
356
357 // =======================================================================
358 // function : Map
359 // purpose  :
360 // =======================================================================
361 void Xw_Window::Map() const
362 {
363   if (IsVirtual() || myXWindow == 0)
364   {
365     return;
366   }
367
368   XMapWindow (myDisplay->GetDisplay(), myXWindow);
369   XFlush (myDisplay->GetDisplay());
370 }
371
372 // =======================================================================
373 // function : Unmap
374 // purpose  :
375 // =======================================================================
376 void Xw_Window::Unmap() const
377 {
378   if (IsVirtual() || myXWindow == 0)
379   {
380     return;
381   }
382
383   XIconifyWindow (myDisplay->GetDisplay(), myXWindow, DefaultScreen(myDisplay->GetDisplay()));
384 }
385
386 // =======================================================================
387 // function : DoResize
388 // purpose  :
389 // =======================================================================
390 Aspect_TypeOfResize Xw_Window::DoResize() const
391 {
392   if (myXWindow == 0)
393   {
394     return Aspect_TOR_UNKNOWN;
395   }
396
397   XFlush (myDisplay->GetDisplay());
398   XWindowAttributes aWinAttr;
399   XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &aWinAttr);
400   if (aWinAttr.map_state == IsUnmapped)
401   {
402     return Aspect_TOR_UNKNOWN;
403   }
404
405   Standard_Integer aMask = 0;
406   Aspect_TypeOfResize aMode = Aspect_TOR_UNKNOWN;
407
408   if (Abs (aWinAttr.x                     - myXLeft  ) > 2) aMask |= 1;
409   if (Abs ((aWinAttr.x + aWinAttr.width)  - myXRight ) > 2) aMask |= 2;
410   if (Abs (aWinAttr.y                     - myYTop   ) > 2) aMask |= 4;
411   if (Abs ((aWinAttr.y + aWinAttr.height) - myYBottom) > 2) aMask |= 8;
412   switch (aMask)
413   {
414     case 0:  aMode = Aspect_TOR_NO_BORDER;               break;
415     case 1:  aMode = Aspect_TOR_LEFT_BORDER;             break;
416     case 2:  aMode = Aspect_TOR_RIGHT_BORDER;            break;
417     case 4:  aMode = Aspect_TOR_TOP_BORDER;              break;
418     case 5:  aMode = Aspect_TOR_LEFT_AND_TOP_BORDER;     break;
419     case 6:  aMode = Aspect_TOR_TOP_AND_RIGHT_BORDER;    break;
420     case 8:  aMode = Aspect_TOR_BOTTOM_BORDER;           break;
421     case 9:  aMode = Aspect_TOR_BOTTOM_AND_LEFT_BORDER;  break;
422     case 10: aMode = Aspect_TOR_RIGHT_AND_BOTTOM_BORDER; break;
423     default: break;
424   }
425
426   *((Standard_Integer* )&myXLeft   ) = aWinAttr.x;
427   *((Standard_Integer* )&myXRight  ) = aWinAttr.x + aWinAttr.width;
428   *((Standard_Integer* )&myYTop    ) = aWinAttr.y;
429   *((Standard_Integer* )&myYBottom ) = aWinAttr.y + aWinAttr.height;
430   return aMode;
431 }
432
433 // =======================================================================
434 // function : DoMapping
435 // purpose  :
436 // =======================================================================
437 Standard_Boolean Xw_Window::DoMapping() const
438 {
439   return Standard_True; // IsMapped()
440 }
441
442 // =======================================================================
443 // function : Ratio
444 // purpose  :
445 // =======================================================================
446 Standard_Real Xw_Window::Ratio() const
447 {
448   if (myXWindow == 0)
449   {
450     return 1.0;
451   }
452
453   XFlush (myDisplay->GetDisplay());
454   XWindowAttributes aWinAttr;
455   XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &aWinAttr);
456   return Standard_Real(aWinAttr.width) / Standard_Real(aWinAttr.height);
457 }
458
459 // =======================================================================
460 // function : Position
461 // purpose  :
462 // =======================================================================
463 void Xw_Window::Position (Standard_Integer& X1, Standard_Integer& Y1,
464                           Standard_Integer& X2, Standard_Integer& Y2) const
465 {
466   if (myXWindow == 0)
467   {
468     return;
469   }
470
471   XFlush (myDisplay->GetDisplay());
472   XWindowAttributes anAttributes;
473   XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &anAttributes);
474   Window aChild;
475   XTranslateCoordinates (myDisplay->GetDisplay(), anAttributes.root, myXWindow,
476                          0, 0, &anAttributes.x, &anAttributes.y, &aChild);
477
478   X1 = -anAttributes.x;
479   X2 = X1 + anAttributes.width;
480   Y1 = -anAttributes.y;
481   Y2 = Y1 + anAttributes.height;
482 }
483
484 // =======================================================================
485 // function : Size
486 // purpose  :
487 // =======================================================================
488 void Xw_Window::Size (Standard_Integer& theWidth,
489                       Standard_Integer& theHeight) const
490 {
491   if (myXWindow == 0)
492   {
493     return;
494   }
495
496   XFlush (myDisplay->GetDisplay());
497   XWindowAttributes aWinAttr;
498   XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &aWinAttr);
499   theWidth  = aWinAttr.width;
500   theHeight = aWinAttr.height;
501 }
502
503 // =======================================================================
504 // function : InvalidateContent
505 // purpose  :
506 // =======================================================================
507 void Xw_Window::InvalidateContent (const Handle(Aspect_DisplayConnection)& theDisp)
508 {
509   if (myXWindow == 0)
510   {
511     return;
512   }
513
514   const Handle(Aspect_DisplayConnection)& aDisp = !theDisp.IsNull() ? theDisp : myDisplay;
515   Display* aDispX = aDisp->GetDisplay();
516
517   XEvent anEvent;
518   memset (&anEvent, 0, sizeof(anEvent));
519   anEvent.type = Expose;
520   anEvent.xexpose.window = myXWindow;
521   XSendEvent (aDispX, myXWindow, False, ExposureMask, &anEvent);
522   XFlush (aDispX);
523 }
524
525 #endif //  Win32 or Mac OS X