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