1 // Created on: 2012-11-12
2 // Created by: Kirill GAVRILOV
3 // Copyright (c) 2012-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #import <TargetConditionals.h>
18 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
19 #import <UIKit/UIKit.h>
21 #import <Cocoa/Cocoa.h>
24 #include <Cocoa_Window.hxx>
26 #include <Cocoa_LocalPool.hxx>
28 #include <Image_AlienPixMap.hxx>
29 #include <Aspect_WindowDefinitionError.hxx>
31 IMPLEMENT_STANDARD_RTTIEXT(Cocoa_Window,Aspect_Window)
33 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
37 #if !defined(MAC_OS_X_VERSION_10_12) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12)
38 // replacements for macOS versions before 10.12
39 #define NSWindowStyleMaskResizable NSResizableWindowMask
40 #define NSWindowStyleMaskClosable NSClosableWindowMask
41 #define NSWindowStyleMaskTitled NSTitledWindowMask
44 static Standard_Integer getScreenBottom()
46 Cocoa_LocalPool aLocalPool;
47 NSArray* aScreens = [NSScreen screens];
48 if (aScreens == NULL || [aScreens count] == 0)
53 NSScreen* aScreen = (NSScreen* )[aScreens objectAtIndex: 0];
54 NSDictionary* aDict = [aScreen deviceDescription];
55 NSNumber* aNumber = [aDict objectForKey: @"NSScreenNumber"];
57 || [aNumber isKindOfClass: [NSNumber class]] == NO)
62 CGDirectDisplayID aDispId = [aNumber unsignedIntValue];
63 CGRect aRect = CGDisplayBounds(aDispId);
64 return Standard_Integer(aRect.origin.y + aRect.size.height);
68 //! Extension for Cocoa_Window::InvalidateContent().
69 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
70 @interface UIView (UIViewOcctAdditions)
71 - (void )invalidateContentOcct: (id )theSender;
73 @implementation UIView (UIViewOcctAdditions)
74 - (void )invalidateContentOcct: (id )theSender
77 [self setNeedsDisplay];
81 @interface NSView (NSViewOcctAdditions)
82 - (void )invalidateContentOcct: (id )theSender;
84 @implementation NSView (NSViewOcctAdditions)
85 - (void )invalidateContentOcct: (id )theSender
88 [self setNeedsDisplay: YES];
93 // =======================================================================
94 // function : Cocoa_Window
96 // =======================================================================
97 Cocoa_Window::Cocoa_Window (const Standard_CString theTitle,
98 const Standard_Integer thePxLeft,
99 const Standard_Integer thePxTop,
100 const Standard_Integer thePxWidth,
101 const Standard_Integer thePxHeight)
103 #if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
109 myXRight (thePxLeft + thePxWidth),
110 myYBottom (thePxTop + thePxHeight)
112 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
115 if (thePxWidth <= 0 || thePxHeight <= 0)
117 throw Aspect_WindowDefinitionError("Coordinate(s) out of range");
119 else if (NSApp == NULL)
121 throw Aspect_WindowDefinitionError("Cocoa application should be instantiated before window");
125 // convert top-bottom coordinates to bottom-top (Cocoa)
126 myYTop = getScreenBottom() - myYBottom;
127 myYBottom = myYTop + thePxHeight;
129 Cocoa_LocalPool aLocalPool;
130 NSUInteger aWinStyle = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable;
131 NSRect aRectNs = NSMakeRect (float(myXLeft), float(myYTop), float(thePxWidth), float(thePxHeight));
132 myHWindow = [[NSWindow alloc] initWithContentRect: aRectNs
134 backing: NSBackingStoreBuffered
136 if (myHWindow == NULL)
138 throw Aspect_WindowDefinitionError("Unable to create window");
140 // for the moment, OpenGL renderer is expected to output sRGB colorspace
141 [myHWindow setColorSpace: [NSColorSpace sRGBColorSpace]];
142 myHView = [[myHWindow contentView] retain];
144 NSString* aTitleNs = [[NSString alloc] initWithUTF8String: theTitle];
145 [myHWindow setTitle: aTitleNs];
148 // do not destroy NSWindow on close - we didn't handle it!
149 [myHWindow setReleasedWhenClosed: NO];
153 // =======================================================================
154 // function : Cocoa_Window
156 // =======================================================================
157 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
158 Cocoa_Window::Cocoa_Window (UIView* theViewNS)
161 Cocoa_Window::Cocoa_Window (NSView* theViewNS)
171 #if defined(HAVE_OBJC_ARC)
174 myHView = [theViewNS retain];
179 // =======================================================================
180 // function : ~Cocoa_Window
182 // =======================================================================
183 Cocoa_Window::~Cocoa_Window()
185 #if !defined(HAVE_OBJC_ARC)
186 Cocoa_LocalPool aLocalPool;
188 #if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
189 if (myHWindow != NULL)
191 #if !defined(HAVE_OBJC_ARC)
200 #if !defined(HAVE_OBJC_ARC)
207 // =======================================================================
208 // function : SetHView
210 // =======================================================================
211 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
212 void Cocoa_Window::SetHView (UIView* theView)
215 void Cocoa_Window::SetHView (NSView* theView)
217 if (myHWindow != NULL)
219 [myHWindow setContentView: theView];
223 #if defined(HAVE_OBJC_ARC)
231 myHView = [theView retain];
235 // =======================================================================
236 // function : IsMapped
238 // =======================================================================
239 Standard_Boolean Cocoa_Window::IsMapped() const
243 return Standard_True;
246 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
247 return myHView != NULL;
249 return myHView != NULL
250 && [[myHView window] isVisible];
254 // =======================================================================
257 // =======================================================================
258 void Cocoa_Window::Map() const
267 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
270 [[myHView window] orderFront: NULL];
275 // =======================================================================
278 // =======================================================================
279 void Cocoa_Window::Unmap() const
283 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
286 [[myHView window] orderOut: NULL];
291 // =======================================================================
292 // function : DoResize
294 // =======================================================================
295 Aspect_TypeOfResize Cocoa_Window::DoResize()
299 return Aspect_TOR_UNKNOWN;
302 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
303 CGRect aBounds = [myHView bounds];
305 NSRect aBounds = [myHView bounds];
307 Standard_Integer aMask = 0;
308 Aspect_TypeOfResize aMode = Aspect_TOR_UNKNOWN;
310 if (Abs ((Standard_Integer )aBounds.origin.x - myXLeft ) > 2) aMask |= 1;
311 if (Abs ((Standard_Integer )(aBounds.origin.x + aBounds.size.width) - myXRight ) > 2) aMask |= 2;
312 if (Abs ((Standard_Integer )aBounds.origin.y - myYTop ) > 2) aMask |= 4;
313 if (Abs ((Standard_Integer )(aBounds.origin.y + aBounds.size.height) - myYBottom) > 2) aMask |= 8;
316 case 0: aMode = Aspect_TOR_NO_BORDER; break;
317 case 1: aMode = Aspect_TOR_LEFT_BORDER; break;
318 case 2: aMode = Aspect_TOR_RIGHT_BORDER; break;
319 case 4: aMode = Aspect_TOR_TOP_BORDER; break;
320 case 5: aMode = Aspect_TOR_LEFT_AND_TOP_BORDER; break;
321 case 6: aMode = Aspect_TOR_TOP_AND_RIGHT_BORDER; break;
322 case 8: aMode = Aspect_TOR_BOTTOM_BORDER; break;
323 case 9: aMode = Aspect_TOR_BOTTOM_AND_LEFT_BORDER; break;
324 case 10: aMode = Aspect_TOR_RIGHT_AND_BOTTOM_BORDER; break;
328 myXLeft = (Standard_Integer )aBounds.origin.x;
329 myXRight = (Standard_Integer )(aBounds.origin.x + aBounds.size.width);
330 myYTop = (Standard_Integer )aBounds.origin.y;
331 myYBottom = (Standard_Integer )(aBounds.origin.y + aBounds.size.height);
335 // =======================================================================
336 // function : DoMapping
338 // =======================================================================
339 Standard_Boolean Cocoa_Window::DoMapping() const
341 return Standard_True;
344 // =======================================================================
347 // =======================================================================
348 Standard_Real Cocoa_Window::Ratio() const
355 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
356 CGRect aBounds = [myHView bounds];
358 NSRect aBounds = [myHView bounds];
360 return Standard_Real (aBounds.size.width / aBounds.size.height);
363 // =======================================================================
364 // function : Position
366 // =======================================================================
367 void Cocoa_Window::Position (Standard_Integer& X1, Standard_Integer& Y1,
368 Standard_Integer& X2, Standard_Integer& Y2) const
370 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
371 CGRect aBounds = [myHView bounds];
374 X2 = (Standard_Integer )aBounds.size.width;
375 Y2 = (Standard_Integer )aBounds.size.height;
377 NSWindow* aWindow = [myHView window];
378 NSRect aWindowRect = [aWindow frame];
379 X1 = (Standard_Integer) aWindowRect.origin.x;
380 Y1 = getScreenBottom() - (Standard_Integer) aWindowRect.origin.y - (Standard_Integer) aWindowRect.size.height;
381 X2 = X1 + (Standard_Integer) aWindowRect.size.width;
382 Y2 = Y1 + (Standard_Integer) aWindowRect.size.height;
386 // =======================================================================
389 // =======================================================================
390 void Cocoa_Window::Size (Standard_Integer& theWidth,
391 Standard_Integer& theHeight) const
398 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
399 CGRect aBounds = [myHView bounds];
401 NSRect aBounds = [myHView bounds];
403 theWidth = (Standard_Integer )aBounds.size.width;
404 theHeight = (Standard_Integer )aBounds.size.height;
407 // =======================================================================
408 // function : SetTitle
410 // =======================================================================
411 void Cocoa_Window::SetTitle (const TCollection_AsciiString& theTitle)
418 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
421 NSWindow* aWindow = [myHView window];
422 NSString* aTitleNS = [[NSString alloc] initWithUTF8String: theTitle.ToCString()];
423 [aWindow setTitle: aTitleNS];
428 // =======================================================================
429 // function : InvalidateContent
431 // =======================================================================
432 void Cocoa_Window::InvalidateContent (const Handle(Aspect_DisplayConnection)& )
439 if ([NSThread isMainThread])
441 #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
442 [myHView setNeedsDisplay];
444 [myHView setNeedsDisplay: YES];
449 [myHView performSelectorOnMainThread: @selector(invalidateContentOcct:)
455 // =======================================================================
456 // function : VirtualKeyFromNative
458 // =======================================================================
459 Aspect_VKey Cocoa_Window::VirtualKeyFromNative (Standard_Integer theKey)
463 case 0x00: return Aspect_VKey_A;
464 case 0x01: return Aspect_VKey_S;
465 case 0x02: return Aspect_VKey_D;
466 case 0x03: return Aspect_VKey_F;
467 case 0x04: return Aspect_VKey_H;
468 case 0x05: return Aspect_VKey_G;
469 case 0x06: return Aspect_VKey_Z;
470 case 0x07: return Aspect_VKey_X;
471 case 0x08: return Aspect_VKey_C;
472 case 0x09: return Aspect_VKey_V;
473 case 0x0A: return Aspect_VKey_UNKNOWN;
474 case 0x0B: return Aspect_VKey_B;
475 case 0x0C: return Aspect_VKey_Q;
476 case 0x0D: return Aspect_VKey_W;
477 case 0x0E: return Aspect_VKey_E;
478 case 0x0F: return Aspect_VKey_R;
479 case 0x10: return Aspect_VKey_Y;
480 case 0x11: return Aspect_VKey_T;
481 case 0x12: return Aspect_VKey_1;
482 case 0x13: return Aspect_VKey_2;
483 case 0x14: return Aspect_VKey_3;
484 case 0x15: return Aspect_VKey_4;
485 case 0x16: return Aspect_VKey_6;
486 case 0x17: return Aspect_VKey_5;
487 case 0x18: return Aspect_VKey_Plus;
488 case 0x19: return Aspect_VKey_9;
489 case 0x1A: return Aspect_VKey_7;
490 case 0x1B: return Aspect_VKey_Minus;
491 case 0x1C: return Aspect_VKey_8;
492 case 0x1D: return Aspect_VKey_0;
493 case 0x1E: return Aspect_VKey_BracketRight;
494 case 0x1F: return Aspect_VKey_O;
495 case 0x20: return Aspect_VKey_U;
496 case 0x21: return Aspect_VKey_BracketLeft;
497 case 0x22: return Aspect_VKey_I;
498 case 0x23: return Aspect_VKey_P;
499 case 0x24: return Aspect_VKey_Enter;
500 case 0x25: return Aspect_VKey_L;
501 case 0x26: return Aspect_VKey_J;
502 case 0x27: return Aspect_VKey_Apostrophe;
503 case 0x28: return Aspect_VKey_K;
504 case 0x29: return Aspect_VKey_Semicolon;
505 case 0x2A: return Aspect_VKey_Backslash;
506 case 0x2B: return Aspect_VKey_Comma; // 43, ',<'
507 case 0x2C: return Aspect_VKey_Slash; //ST_VK_OEM_2, // 44, '?/'
508 case 0x2D: return Aspect_VKey_N;
509 case 0x2E: return Aspect_VKey_M;
510 case 0x2F: return Aspect_VKey_Period; // 47, '.>'
511 case 0x30: return Aspect_VKey_Tab;
512 case 0x31: return Aspect_VKey_Space;
513 case 0x32: return Aspect_VKey_Tilde; // '~`'
514 case 0x33: return Aspect_VKey_Backspace;
515 case 0x34: return Aspect_VKey_UNKNOWN;
516 case 0x35: return Aspect_VKey_Escape;
517 case 0x36: return Aspect_VKey_UNKNOWN; // Aspect_VKey_Cmd, right Command
518 case 0x37: return Aspect_VKey_UNKNOWN; // Aspect_VKey_Cmd, left Command
519 case 0x38: return Aspect_VKey_Shift; // left shift
520 case 0x39: return Aspect_VKey_UNKNOWN;
521 case 0x3A: return Aspect_VKey_Alt; // left alt/option
522 case 0x3B: return Aspect_VKey_Control;
523 case 0x3C: return Aspect_VKey_Shift; // right shift
524 case 0x3D: return Aspect_VKey_Alt; // right alt/option
525 case 0x3E: return Aspect_VKey_UNKNOWN;
526 case 0x3F: return Aspect_VKey_UNKNOWN; // Aspect_VKey_Func, fn
538 case 0x4B: return Aspect_VKey_UNKNOWN;
539 case 0x4C: return Aspect_VKey_Enter; // fn + return
558 case 0x5F: return Aspect_VKey_UNKNOWN;
559 case 0x60: return Aspect_VKey_F5;
560 case 0x61: return Aspect_VKey_F6;
561 case 0x62: return Aspect_VKey_F7;
562 case 0x63: return Aspect_VKey_F3;
563 case 0x64: return Aspect_VKey_F8;
564 case 0x65: return Aspect_VKey_F9;
565 //case 0x66: return Aspect_VKey_UNKNOWN;
566 case 0x67: return Aspect_VKey_F11;
567 //case 0x68: return Aspect_VKey_UNKNOWN;
568 //case 0x69: return Aspect_VKey_UNKNOWN;
569 //case 0x6A: return Aspect_VKey_UNKNOWN;
570 //case 0x6B: return Aspect_VKey_UNKNOWN;
571 //case 0x6C: return Aspect_VKey_UNKNOWN;
572 case 0x6D: return Aspect_VKey_F10;
573 //case 0x6E: return Aspect_VKey_UNKNOWN;
574 case 0x6F: return Aspect_VKey_F12;
575 //case 0x70: return Aspect_VKey_UNKNOWN;
576 //case 0x71: return Aspect_VKey_UNKNOWN;
577 //case 0x72: return Aspect_VKey_UNKNOWN;
578 case 0x73: return Aspect_VKey_Home;
579 case 0x74: return Aspect_VKey_PageUp;
580 case 0x75: return Aspect_VKey_Delete;
581 case 0x76: return Aspect_VKey_F4;
582 case 0x77: return Aspect_VKey_End;
583 case 0x78: return Aspect_VKey_F2;
584 case 0x79: return Aspect_VKey_PageDown;
585 case 0x7A: return Aspect_VKey_F1;
586 case 0x7B: return Aspect_VKey_Left;
587 case 0x7C: return Aspect_VKey_Right;
588 case 0x7D: return Aspect_VKey_Down;
589 case 0x7E: return Aspect_VKey_Up;
590 case 0x7F: return Aspect_VKey_UNKNOWN;
592 return Aspect_VKey_UNKNOWN;