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