0025973: Visualization, TKOpenGl - support EAGLContext as alternative to NSOpenGLContext
[occt.git] / src / Cocoa / Cocoa_Window.mm
1 // Created on: 2012-11-12
2 // Created by: Kirill GAVRILOV
3 // Copyright (c) 2012-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 #import <TargetConditionals.h>
17
18 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
19   #import <UIKit/UIKit.h>
20 #else
21   #import <Cocoa/Cocoa.h>
22 #endif
23
24 #include <Cocoa_Window.hxx>
25
26 #include <Cocoa_LocalPool.hxx>
27
28 #include <Image_AlienPixMap.hxx>
29 #include <Aspect_Convert.hxx>
30 #include <Aspect_WindowDefinitionError.hxx>
31
32 IMPLEMENT_STANDARD_HANDLE (Cocoa_Window, Aspect_Window)
33 IMPLEMENT_STANDARD_RTTIEXT(Cocoa_Window, Aspect_Window)
34
35 #if defined(__clang__) && (__clang_major__ >= 4) && __has_feature(objc_arc)
36   #define HAVE_OBJC_ARC
37 #endif
38
39 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
40   //
41 #else
42 static Standard_Integer getScreenBottom()
43 {
44   Cocoa_LocalPool aLocalPool;
45   NSArray* aScreens = [NSScreen screens];
46   if (aScreens == NULL || [aScreens count] == 0)
47   {
48     return 0;
49   }
50
51   NSScreen* aScreen = (NSScreen* )[aScreens objectAtIndex: 0];
52   NSDictionary* aDict = [aScreen deviceDescription];
53   NSNumber* aNumber = [aDict objectForKey: @"NSScreenNumber"];
54   if (aNumber == NULL
55   || [aNumber isKindOfClass: [NSNumber class]] == NO)
56   {
57     return 0;
58   }
59
60   CGDirectDisplayID aDispId = [aNumber unsignedIntValue];
61   CGRect aRect = CGDisplayBounds(aDispId);
62   return Standard_Integer(aRect.origin.y + aRect.size.height);
63 }
64 #endif
65
66 // =======================================================================
67 // function : Cocoa_Window
68 // purpose  :
69 // =======================================================================
70 Cocoa_Window::Cocoa_Window (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 : Aspect_Window (),
76 #if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
77   myHWindow (NULL),
78 #endif
79   myHView   (NULL),
80   myXLeft   (thePxLeft),
81   myYTop    (thePxTop),
82   myXRight  (thePxLeft + thePxWidth),
83   myYBottom (thePxTop + thePxHeight)
84 {
85 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
86   //
87 #else
88   if (thePxWidth <= 0 || thePxHeight <= 0)
89   {
90     Aspect_WindowDefinitionError::Raise ("Coordinate(s) out of range");
91   }
92   else if (NSApp == NULL)
93   {
94     Aspect_WindowDefinitionError::Raise ("Cocoa application should be instantiated before window");
95     return;
96   }
97
98   // convert top-bottom coordinates to bottom-top (Cocoa)
99   myYTop    = getScreenBottom() - myYBottom;
100   myYBottom = myYTop + thePxHeight;
101
102   Cocoa_LocalPool aLocalPool;
103   NSUInteger aWinStyle = NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask;
104   NSRect aRectNs = NSMakeRect (float(myXLeft), float(myYTop), float(thePxWidth), float(thePxHeight));
105   myHWindow = [[NSWindow alloc] initWithContentRect: aRectNs
106                                           styleMask: aWinStyle
107                                             backing: NSBackingStoreBuffered
108                                               defer: NO];
109   if (myHWindow == NULL)
110   {
111     Aspect_WindowDefinitionError::Raise ("Unable to create window");
112   }
113   myHView = [[myHWindow contentView] retain];
114
115   NSString* aTitleNs = [[NSString alloc] initWithUTF8String: theTitle];
116   [myHWindow setTitle: aTitleNs];
117   [aTitleNs release];
118
119   // do not destroy NSWindow on close - we didn't handle it!
120   [myHWindow setReleasedWhenClosed: NO];
121 #endif
122 }
123
124 // =======================================================================
125 // function : Cocoa_Window
126 // purpose  :
127 // =======================================================================
128 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
129 Cocoa_Window::Cocoa_Window (UIView* theViewNS)
130 : Aspect_Window(),
131 #else
132 Cocoa_Window::Cocoa_Window (NSView* theViewNS)
133 : Aspect_Window(),
134   myHWindow (NULL),
135 #endif
136   myHView   (NULL),
137   myXLeft   (0),
138   myYTop    (0),
139   myXRight  (512),
140   myYBottom (512)
141 {
142 #if defined(HAVE_OBJC_ARC)
143   myHView = theViewNS;
144 #else
145   myHView = [theViewNS retain];
146 #endif
147   DoResize();
148 }
149
150 // =======================================================================
151 // function : Destroy
152 // purpose  :
153 // =======================================================================
154 void Cocoa_Window::Destroy()
155 {
156 #if !defined(HAVE_OBJC_ARC)
157   Cocoa_LocalPool aLocalPool;
158 #endif
159 #if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
160   if (myHWindow != NULL)
161   {
162   #if !defined(HAVE_OBJC_ARC)
163     //[myHWindow close];
164     [myHWindow release];
165   #endif
166     myHWindow = NULL;
167   }
168 #endif
169   if (myHView != NULL)
170   {
171   #if !defined(HAVE_OBJC_ARC)
172     [myHView release];
173   #endif
174     myHView = NULL;
175   }
176 }
177
178 // =======================================================================
179 // function : SetHView
180 // purpose  :
181 // =======================================================================
182 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
183 void Cocoa_Window::SetHView (UIView* theView)
184 {
185 #else
186 void Cocoa_Window::SetHView (NSView* theView)
187 {
188   if (myHWindow != NULL)
189   {
190     [myHWindow setContentView: theView];
191   }
192 #endif
193
194 #if defined(HAVE_OBJC_ARC)
195   myHView = theView;
196 #else
197   if (myHView != NULL)
198   {
199     [myHView release];
200     myHView = NULL;
201   }
202   myHView = [theView retain];
203 #endif
204 }
205
206 // =======================================================================
207 // function : IsMapped
208 // purpose  :
209 // =======================================================================
210 Standard_Boolean Cocoa_Window::IsMapped() const
211 {
212   if (IsVirtual())
213   {
214     return Standard_True;
215   }
216
217 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
218   return myHView != NULL;
219 #else
220   return myHView != NULL
221    &&  [[myHView window] isVisible];
222 #endif
223 }
224
225 // =======================================================================
226 // function : Map
227 // purpose  :
228 // =======================================================================
229 void Cocoa_Window::Map() const
230 {
231   if (IsVirtual())
232   {
233     return;
234   }
235
236   if (myHView != NULL)
237   {
238   #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
239     //
240   #else
241     [[myHView window] orderFront: NULL];
242   #endif
243   }
244 }
245
246 // =======================================================================
247 // function : Unmap
248 // purpose  :
249 // =======================================================================
250 void Cocoa_Window::Unmap() const
251 {
252   if (myHView != NULL)
253   {
254   #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
255     //
256   #else
257     [[myHView window] orderOut: NULL];
258   #endif
259   }
260 }
261
262 // =======================================================================
263 // function : DoResize
264 // purpose  :
265 // =======================================================================
266 Aspect_TypeOfResize Cocoa_Window::DoResize() const
267 {
268   if (myHView == NULL)
269   {
270     return Aspect_TOR_UNKNOWN;
271   }
272
273 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
274   CGRect aBounds = [myHView bounds];
275 #else
276   NSRect aBounds = [myHView bounds];
277 #endif
278   Standard_Integer aMask = 0;
279   Aspect_TypeOfResize aMode = Aspect_TOR_UNKNOWN;
280
281   if (Abs ((Standard_Integer )aBounds.origin.x                         - myXLeft  ) > 2) aMask |= 1;
282   if (Abs ((Standard_Integer )(aBounds.origin.x + aBounds.size.width)  - myXRight ) > 2) aMask |= 2;
283   if (Abs ((Standard_Integer )aBounds.origin.y                         - myYTop   ) > 2) aMask |= 4;
284   if (Abs ((Standard_Integer )(aBounds.origin.y + aBounds.size.height) - myYBottom) > 2) aMask |= 8;
285   switch (aMask)
286   {
287     case 0:  aMode = Aspect_TOR_NO_BORDER;               break;
288     case 1:  aMode = Aspect_TOR_LEFT_BORDER;             break;
289     case 2:  aMode = Aspect_TOR_RIGHT_BORDER;            break;
290     case 4:  aMode = Aspect_TOR_TOP_BORDER;              break;
291     case 5:  aMode = Aspect_TOR_LEFT_AND_TOP_BORDER;     break;
292     case 6:  aMode = Aspect_TOR_TOP_AND_RIGHT_BORDER;    break;
293     case 8:  aMode = Aspect_TOR_BOTTOM_BORDER;           break;
294     case 9:  aMode = Aspect_TOR_BOTTOM_AND_LEFT_BORDER;  break;
295     case 10: aMode = Aspect_TOR_RIGHT_AND_BOTTOM_BORDER; break;
296     default: break;
297   }
298
299   *((Standard_Integer* )&myXLeft   ) = (Standard_Integer )aBounds.origin.x;
300   *((Standard_Integer* )&myXRight  ) = (Standard_Integer )(aBounds.origin.x + aBounds.size.width);
301   *((Standard_Integer* )&myYTop    ) = (Standard_Integer )aBounds.origin.y;
302   *((Standard_Integer* )&myYBottom ) = (Standard_Integer )(aBounds.origin.y + aBounds.size.height);
303   return aMode;
304 }
305
306 // =======================================================================
307 // function : DoMapping
308 // purpose  :
309 // =======================================================================
310 Standard_Boolean Cocoa_Window::DoMapping() const
311 {
312   return Standard_True;
313 }
314
315 // =======================================================================
316 // function : Ratio
317 // purpose  :
318 // =======================================================================
319 Quantity_Ratio Cocoa_Window::Ratio() const
320 {
321   if (myHView == NULL)
322   {
323     return 1.0;
324   }
325
326 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
327   CGRect aBounds = [myHView bounds];
328 #else
329   NSRect aBounds = [myHView bounds];
330 #endif
331   return Quantity_Ratio (aBounds.size.width / aBounds.size.height);
332 }
333
334 // =======================================================================
335 // function : Position
336 // purpose  :
337 // =======================================================================
338 void Cocoa_Window::Position (Standard_Integer& X1, Standard_Integer& Y1,
339                              Standard_Integer& X2, Standard_Integer& Y2) const
340 {
341 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
342   CGRect aBounds = [myHView bounds];
343   X1 = 0;
344   Y1 = 0;
345   X2 = (Standard_Integer )aBounds.size.width;
346   Y2 = (Standard_Integer )aBounds.size.height;
347 #else
348   NSWindow* aWindow = [myHView window];
349   NSRect aWindowRect = [aWindow frame];
350   X1 = (Standard_Integer) aWindowRect.origin.x;
351   Y1 = getScreenBottom() - (Standard_Integer) aWindowRect.origin.y - (Standard_Integer) aWindowRect.size.height;
352   X2 = X1 + (Standard_Integer) aWindowRect.size.width;
353   Y2 = Y1 + (Standard_Integer) aWindowRect.size.height;
354 #endif
355 }
356
357 // =======================================================================
358 // function : Size
359 // purpose  :
360 // =======================================================================
361 void Cocoa_Window::Size (Standard_Integer& theWidth,
362                          Standard_Integer& theHeight) const
363 {
364   if (myHView == NULL)
365   {
366     return;
367   }
368
369 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
370   CGRect aBounds = [myHView bounds];
371 #else
372   NSRect aBounds = [myHView bounds];
373 #endif
374   theWidth  = (Standard_Integer )aBounds.size.width;
375   theHeight = (Standard_Integer )aBounds.size.height;
376 }