1/*========================================================================= 2 3Program: Visualization Toolkit 4Module: vtkCocoaRenderWindow.mm 5 6Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 7All rights reserved. 8See Copyright.txt or http://www.kitware.com/Copyright.htm for details. 9 10This software is distributed WITHOUT ANY WARRANTY; without even 11the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 12PURPOSE. See the above copyright notice for more information. 13 14=========================================================================*/ 15 16#include "vtkOpenGLRenderWindow.h" 17#import <Cocoa/Cocoa.h> 18#import "vtkCocoaMacOSXSDKCompatibility.h" // Needed to support old SDKs 19 20#import "vtkCocoaRenderWindow.h" 21#import "vtkRenderWindowInteractor.h" 22#import "vtkCommand.h" 23#import "vtkIdList.h" 24#import "vtkObjectFactory.h" 25#import "vtkRendererCollection.h" 26#import "vtkCocoaGLView.h" 27 28#import <vtksys/ios/sstream> 29 30vtkStandardNewMacro(vtkCocoaRenderWindow); 31 32//---------------------------------------------------------------------------- 33// This is a private class and an implementation detail, do not use it. 34// For fullscreen, an NSWindow that captures key events even when borderless 35@interface vtkCocoaFullScreenWindow : NSWindow 36{ 37} 38@end 39 40@implementation vtkCocoaFullScreenWindow 41- (BOOL)canBecomeKeyWindow 42{ 43 return YES; 44} 45@end 46 47//---------------------------------------------------------------------------- 48// This is a private class and an implementation detail, do not use it. 49// It manages the NSWindow of a "pure VTK application", 50// as opposed to a regular Mac app that happens to use VTK. 51//---------------------------------------------------------------------------- 52@interface vtkCocoaServer : NSObject 53{ 54 @private 55 vtkCocoaRenderWindow *_renWin; 56} 57 58// Designated initializer 59- (id)initWithRenderWindow:(vtkCocoaRenderWindow *)inRenderWindow; 60 61- (void)startObservations; 62- (void)stopObservations; 63 64@end 65 66//---------------------------------------------------------------------------- 67@implementation vtkCocoaServer 68 69//---------------------------------------------------------------------------- 70- (id)initWithRenderWindow:(vtkCocoaRenderWindow *)inRenderWindow 71{ 72 self = [super init]; 73 if (self) 74 { 75 _renWin = inRenderWindow; 76 } 77 return self; 78} 79 80//---------------------------------------------------------------------------- 81- (void)startObservations 82{ 83 assert(_renWin); 84 85 int windowCreated = _renWin->GetWindowCreated(); 86 NSWindow *win = reinterpret_cast<NSWindow *>(_renWin->GetRootWindow()); 87 if (windowCreated && win) 88 { 89 // Receive notifications of this, and only this, window's closing. 90 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 91 [nc addObserver:self 92 selector:@selector(windowWillClose:) 93 name:NSWindowWillCloseNotification 94 object:win]; 95 } 96 97 NSView *view = reinterpret_cast<NSView *>(_renWin->GetWindowId()); 98 int viewCreated = _renWin->GetViewCreated(); 99 if (viewCreated && view) 100 { 101 // Receive notifications of this, and only this, view's frame changing. 102 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 103 [nc addObserver:self 104 selector:@selector(viewFrameDidChange:) 105 name:NSViewFrameDidChangeNotification 106 object:view]; 107 } 108} 109 110//---------------------------------------------------------------------------- 111- (void)stopObservations 112{ 113 assert(_renWin); 114 115 int windowCreated = _renWin->GetWindowCreated(); 116 NSWindow *win = reinterpret_cast<NSWindow *>(_renWin->GetRootWindow()); 117 if (windowCreated && win) 118 { 119 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 120 [nc removeObserver:self 121 name:NSWindowWillCloseNotification 122 object:win]; 123 } 124 125 NSView *view = reinterpret_cast<NSView *>(_renWin->GetWindowId()); 126 int viewCreated = _renWin->GetViewCreated(); 127 if (viewCreated && view) 128 { 129 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 130 [nc removeObserver:self 131 name:NSViewFrameDidChangeNotification 132 object:view]; 133 } 134} 135 136//---------------------------------------------------------------------------- 137- (void)windowWillClose:(NSNotification *)aNotification 138{ 139 // We should only get here if it was us that created the NSWindow. 140 assert(_renWin); 141 assert(_renWin->GetWindowCreated()); 142 143 // We should only have observed our own NSWindow. 144 assert([aNotification object] == _renWin->GetRootWindow()); 145 (void)aNotification; 146 147 // Stop observing because the window is closing. 148 [self stopObservations]; 149 150 // The NSWindow is closing, so prevent anyone from accidentally using it. 151 _renWin->SetRootWindow(NULL); 152 153 // Tell interactor to stop the NSApplication's run loop 154 vtkRenderWindowInteractor *interactor = _renWin->GetInteractor(); 155 if (interactor) 156 { 157 interactor->TerminateApp(); 158 } 159} 160 161//---------------------------------------------------------------------------- 162- (void)viewFrameDidChange:(NSNotification *)aNotification 163{ 164 // We should only get here if it was us that created the NSView. 165 assert(_renWin); 166 assert(_renWin->GetViewCreated()); 167 168 // We should only have observed our own NSView. 169 assert([aNotification object] == _renWin->GetWindowId()); 170 (void)aNotification; 171 172 // Retrieve the Interactor. 173 vtkRenderWindowInteractor *interactor = _renWin->GetInteractor(); 174 if (!interactor || !interactor->GetEnabled()) 175 { 176 return; 177 } 178 179 // Get the NSView's new frame size. 180 NSView *view = reinterpret_cast<NSView *>(_renWin->GetWindowId()); 181 assert(view); 182 NSRect frameRect = [view frame]; 183 int width = (int)round(NSWidth(frameRect)); 184 int height = (int)round(NSHeight(frameRect)); 185 186 // Get the interactor's current cache of the size. 187 int size[2]; 188 interactor->GetSize(size); 189 190 if (width != size[0] || height != size[1]) 191 { 192 // Send ConfigureEvent from the Interactor. 193 interactor->UpdateSize(width, height); 194 interactor->InvokeEvent(vtkCommand::ConfigureEvent, NULL); 195 } 196} 197 198@end 199 200//---------------------------------------------------------------------------- 201vtkCocoaRenderWindow::vtkCocoaRenderWindow() 202{ 203 // First, create the cocoa objects manager. The dictionary is empty so 204 // essentially all objects are initialized to NULL. 205 NSMutableDictionary *cocoaManager = [NSMutableDictionary dictionary]; 206 207 // SetCocoaManager works like an Obj-C setter, so do like Obj-C and 208 // init the ivar to null first. 209 this->CocoaManager = NULL; 210 this->SetCocoaManager(reinterpret_cast<void *>(cocoaManager)); 211 [cocoaManager self]; // prevent premature collection under GC. 212 213 this->WindowCreated = 0; 214 this->ViewCreated = 0; 215 this->SetWindowName("Visualization Toolkit - Cocoa"); 216 this->CursorHidden = 0; 217 this->ForceMakeCurrent = 0; 218 this->Capabilities = 0; 219 this->OnScreenInitialized = 0; 220 this->OffScreenInitialized = 0; 221} 222 223//---------------------------------------------------------------------------- 224vtkCocoaRenderWindow::~vtkCocoaRenderWindow() 225{ 226 if (this->CursorHidden) 227 { 228 this->ShowCursor(); 229 } 230 this->Finalize(); 231 232 vtkRenderer *ren; 233 vtkCollectionSimpleIterator rit; 234 this->Renderers->InitTraversal(rit); 235 while ( (ren = this->Renderers->GetNextRenderer(rit)) ) 236 { 237 ren->SetRenderWindow(NULL); 238 } 239 240 delete[] this->Capabilities; 241 this->Capabilities = 0; 242 243 this->SetContextId(NULL); 244 this->SetPixelFormat(NULL); 245 this->SetCocoaServer(NULL); 246 this->SetRootWindow(NULL); 247 this->SetWindowId(NULL); 248 this->SetParentId(NULL); 249 250 // Release the cocoa object manager. 251 this->SetCocoaManager(NULL); 252} 253 254//---------------------------------------------------------------------------- 255void vtkCocoaRenderWindow::Finalize() 256{ 257 if(this->OffScreenInitialized) 258 { 259 this->OffScreenInitialized = 0; 260 this->DestroyOffScreenWindow(); 261 } 262 if(this->OnScreenInitialized) 263 { 264 this->OnScreenInitialized = 0; 265 this->DestroyWindow(); 266 } 267} 268 269//---------------------------------------------------------------------------- 270void vtkCocoaRenderWindow::DestroyWindow() 271{ 272 // finish OpenGL rendering 273 if (this->OwnContext && this->GetContextId()) 274 { 275 this->MakeCurrent(); 276 277 // tell each of the renderers that this render window/graphics context 278 // is being removed (the RendererCollection is removed by vtkRenderWindow's 279 // destructor) 280 vtkCollectionSimpleIterator rsit; 281 vtkRenderer *ren; 282 for ( this->Renderers->InitTraversal(rsit); 283 (ren = this->Renderers->GetNextRenderer(rsit));) 284 { 285 ren->SetRenderWindow(NULL); 286 ren->SetRenderWindow(this); 287 } 288 } 289 this->SetContextId(NULL); 290 this->SetPixelFormat(NULL); 291 292 vtkCocoaServer *server = (vtkCocoaServer *)this->GetCocoaServer(); 293 [server stopObservations]; 294 this->SetCocoaServer(NULL); 295 296 // If we created it, close the NSWindow. 297 if (this->WindowCreated) 298 { 299 NSWindow *window = (NSWindow*)this->GetRootWindow(); 300 [window close]; 301 } 302 303 this->SetWindowId(NULL); 304 this->SetParentId(NULL); 305 this->SetRootWindow(NULL); 306 this->WindowCreated = 0; 307 this->ViewCreated = 0; 308} 309 310//---------------------------------------------------------------------------- 311void vtkCocoaRenderWindow::SetWindowName( const char * _arg ) 312{ 313 vtkWindow::SetWindowName(_arg); 314 if (this->GetRootWindow()) 315 { 316 NSString *winTitleStr = [NSString stringWithUTF8String:_arg]; 317 318 [(NSWindow*)this->GetRootWindow() setTitle:winTitleStr]; 319 } 320} 321 322//---------------------------------------------------------------------------- 323bool vtkCocoaRenderWindow::InitializeFromCurrentContext() 324{ 325 NSOpenGLContext *currentContext = [NSOpenGLContext currentContext]; 326 if (currentContext != NULL) 327 { 328 NSView *currentView = [currentContext view]; 329 if (currentView != NULL) 330 { 331 NSWindow *window = [currentView window]; 332 this->SetWindowId(currentView); 333 this->SetRootWindow(window); 334 this->SetContextId((void*)currentContext); 335 this->OpenGLInit(); 336 this->OwnContext = 0; 337 return true; 338 } 339 } 340 return false; 341} 342 343//---------------------------------------------------------------------------- 344int vtkCocoaRenderWindow::GetEventPending() 345{ 346 return 0; 347} 348 349//---------------------------------------------------------------------------- 350// Initialize the rendering process. 351void vtkCocoaRenderWindow::Start() 352{ 353 this->Initialize(); 354 355 // set the current window 356 this->MakeCurrent(); 357} 358 359//---------------------------------------------------------------------------- 360void vtkCocoaRenderWindow::MakeCurrent() 361{ 362 if (this->GetContextId()) 363 { 364 [(NSOpenGLContext*)this->GetContextId() makeCurrentContext]; 365 } 366} 367 368// ---------------------------------------------------------------------------- 369// Description: 370// Tells if this window is the current OpenGL context for the calling thread. 371bool vtkCocoaRenderWindow::IsCurrent() 372{ 373 bool result=false; 374 if(this->GetContextId()!=0) 375 { 376 result=static_cast<NSOpenGLContext *>(this->GetContextId())== 377 [NSOpenGLContext currentContext]; 378 } 379 return result; 380} 381 382//---------------------------------------------------------------------------- 383bool vtkCocoaRenderWindow::IsDrawable() 384{ 385 // you must initialize it first 386 // else it always evaluates false 387 this->Initialize(); 388 389 // first check that window is valid 390 NSView *theView = (NSView*)this->GetWindowId(); 391 bool win =[[theView window] windowNumber]>0; 392 393 // then check that the drawable is valid 394 NSOpenGLContext *context = (NSOpenGLContext *)this->GetContextId(); 395 bool ok = [context view] != nil; 396 return win && ok; 397} 398 399//---------------------------------------------------------------------------- 400void vtkCocoaRenderWindow::UpdateContext() 401{ 402 if (this->GetContextId()) 403 { 404 [(NSOpenGLContext*)this->GetContextId() update]; 405 } 406} 407 408//---------------------------------------------------------------------------- 409const char* vtkCocoaRenderWindow::ReportCapabilities() 410{ 411 this->MakeCurrent(); 412 413 const char* glVendor = (const char*) glGetString(GL_VENDOR); 414 const char* glRenderer = (const char*) glGetString(GL_RENDERER); 415 const char* glVersion = (const char*) glGetString(GL_VERSION); 416 const char* glExtensions = (const char*) glGetString(GL_EXTENSIONS); 417 418 vtksys_ios::ostringstream strm; 419 strm << "OpenGL vendor string: " << glVendor 420 << "\nOpenGL renderer string: " << glRenderer 421 << "\nOpenGL version string: " << glVersion 422 << "\nOpenGL extensions: " << glExtensions << endl; 423 424 // Obtain the OpenGL context in order to keep track of the current screen. 425 NSOpenGLContext* context = (NSOpenGLContext*)this->GetContextId(); 426 GLint currentScreen = [context currentVirtualScreen]; 427 428 // The NSOpenGLPixelFormat can only be queried for one particular 429 // attribute at a time. Just make repeated queries to get the 430 // pertinent settings. 431 NSOpenGLPixelFormat* pixelFormat = (NSOpenGLPixelFormat*)this->GetPixelFormat(); 432 strm << "PixelFormat Descriptor:" << endl; 433 GLint pfd = 0; 434 [pixelFormat getValues: &pfd forAttribute: NSOpenGLPFAColorSize forVirtualScreen: currentScreen]; 435 strm << " colorSize: " << pfd << endl; 436 437 [pixelFormat getValues: &pfd forAttribute: NSOpenGLPFAAlphaSize forVirtualScreen: currentScreen]; 438 strm << " alphaSize: " << pfd << endl; 439 440 [pixelFormat getValues: &pfd forAttribute: NSOpenGLPFAStencilSize forVirtualScreen: currentScreen]; 441 strm << " stencilSize: " << pfd << endl; 442 443 [pixelFormat getValues: &pfd forAttribute: NSOpenGLPFADepthSize forVirtualScreen: currentScreen]; 444 strm << " depthSize: " << pfd << endl; 445 446 [pixelFormat getValues: &pfd forAttribute: NSOpenGLPFAAccumSize forVirtualScreen: currentScreen]; 447 strm << " accumSize: " << pfd << endl; 448 449 [pixelFormat getValues: &pfd forAttribute: NSOpenGLPFADoubleBuffer forVirtualScreen: currentScreen]; 450 strm << " double buffer: " << (pfd == 0 ? "No" : "Yes") << endl; 451 452 [pixelFormat getValues: &pfd forAttribute: NSOpenGLPFAStereo forVirtualScreen: currentScreen]; 453 strm << " stereo: " << (pfd == 0 ? "No" : "Yes") << endl; 454 455 [pixelFormat getValues: &pfd forAttribute: NSOpenGLPFAStencilSize forVirtualScreen: currentScreen]; 456 strm << " stencil: " << pfd << endl; 457 458 [pixelFormat getValues: &pfd forAttribute: NSOpenGLPFAAccelerated forVirtualScreen: currentScreen]; 459 strm << " hardware acceleration:: " << (pfd == 0 ? "No" : "Yes") << endl; 460 461 delete[] this->Capabilities; 462 463 size_t len = strm.str().length() + 1; 464 this->Capabilities = new char[len]; 465 strlcpy(this->Capabilities, strm.str().c_str(), len); 466 467 return this->Capabilities; 468} 469 470//---------------------------------------------------------------------------- 471int vtkCocoaRenderWindow::SupportsOpenGL() 472{ 473 this->MakeCurrent(); 474 if (!this->GetContextId() || !this->GetPixelFormat()) 475 { 476 return 0; 477 } 478 return 1; 479} 480 481//---------------------------------------------------------------------------- 482int vtkCocoaRenderWindow::IsDirect() 483{ 484 this->MakeCurrent(); 485 if (!this->GetContextId() || !this->GetPixelFormat()) 486 { 487 return 0; 488 } 489 return 1; 490} 491 492//---------------------------------------------------------------------------- 493void vtkCocoaRenderWindow::SetSize(int* a) 494{ 495 this->SetSize( a[0], a[1] ); 496} 497 498//---------------------------------------------------------------------------- 499void vtkCocoaRenderWindow::SetSize(int x, int y) 500{ 501 static int resizing = 0; 502 503 if ((this->Size[0] != x) || (this->Size[1] != y) || (this->GetParentId())) 504 { 505 this->Modified(); 506 this->Size[0] = x; 507 this->Size[1] = y; 508 if (this->GetParentId() && this->GetWindowId() && this->Mapped) 509 { 510 // Set the NSView size, not the window size. 511 if (!resizing) 512 { 513 resizing = 1; 514 NSView *theView = (NSView*)this->GetWindowId(); 515 NSRect viewRect = [theView frame]; 516 CGFloat oldHeight = NSHeight(viewRect); 517 CGFloat height = (CGFloat)y; 518 CGFloat width = (CGFloat)x; 519 CGFloat xpos = NSMinX(viewRect); 520 CGFloat ypos = NSMinY(viewRect) - (height - oldHeight); 521 NSRect theRect = NSMakeRect(xpos, ypos, width, height); 522 [theView setFrame:theRect]; 523 [theView setNeedsDisplay:YES]; 524 resizing = 0; 525 } 526 } 527 else if (this->GetRootWindow() && this->Mapped) 528 { 529 if (!resizing) 530 { 531 resizing = 1; 532 NSSize theSize = NSMakeSize((CGFloat)x, (CGFloat)y); 533 [(NSWindow*)this->GetRootWindow() setContentSize:theSize]; 534 resizing = 0; 535 } 536 } 537 } 538} 539 540//---------------------------------------------------------------------------- 541void vtkCocoaRenderWindow::SetForceMakeCurrent() 542{ 543 this->ForceMakeCurrent = 1; 544} 545 546//---------------------------------------------------------------------------- 547void vtkCocoaRenderWindow::SetPosition(int* a) 548{ 549 this->SetPosition( a[0], a[1] ); 550} 551 552//---------------------------------------------------------------------------- 553void vtkCocoaRenderWindow::SetPosition(int x, int y) 554{ 555 static int resizing = 0; 556 557 if ((this->Position[0] != x) || (this->Position[1] != y) 558 || (this->GetParentId())) 559 { 560 this->Modified(); 561 this->Position[0] = x; 562 this->Position[1] = y; 563 if (this->GetParentId() && this->GetWindowId() && this->Mapped) 564 { 565 // Set the NSView position relative to the parent 566 if (!resizing) 567 { 568 resizing = 1; 569 NSRect parentRect = [(NSView*)this->GetParentId() frame]; 570 NSView *theView = (NSView*)this->GetWindowId(); 571 NSRect viewRect = [theView frame]; 572 CGFloat parentHeight = NSHeight(parentRect); 573 CGFloat height = NSHeight(viewRect); 574 CGFloat xpos = (CGFloat)x; 575 CGFloat ypos = parentHeight - height - (CGFloat)y; 576 NSPoint origin = NSMakePoint(xpos,ypos); 577 [theView setFrameOrigin:origin]; 578 [theView setNeedsDisplay:YES]; 579 resizing = 0; 580 } 581 } 582 else if (this->GetRootWindow() && this->Mapped) 583 { 584 if (!resizing) 585 { 586 resizing = 1; 587 NSPoint origin = NSMakePoint((CGFloat)x, (CGFloat)y); 588 [(NSWindow*)this->GetRootWindow() setFrameOrigin:origin]; 589 resizing = 0; 590 } 591 } 592 } 593} 594 595//---------------------------------------------------------------------------- 596// End the rendering process and display the image. 597void vtkCocoaRenderWindow::Frame() 598{ 599 this->MakeCurrent(); 600 601 if (!this->AbortRender && this->DoubleBuffer && this->SwapBuffers) 602 { 603 [(NSOpenGLContext*)this->GetContextId() flushBuffer]; 604 } 605 else 606 { 607 glFlush(); 608 } 609} 610 611//---------------------------------------------------------------------------- 612// Update system if needed due to stereo rendering. 613void vtkCocoaRenderWindow::StereoUpdate() 614{ 615 // if stereo is on and it wasn't before 616 if (this->StereoRender && (!this->StereoStatus)) 617 { 618 switch (this->StereoType) 619 { 620 case VTK_STEREO_CRYSTAL_EYES: 621 this->StereoStatus = 1; 622 break; 623 case VTK_STEREO_RED_BLUE: 624 this->StereoStatus = 1; 625 break; 626 case VTK_STEREO_ANAGLYPH: 627 this->StereoStatus = 1; 628 break; 629 case VTK_STEREO_DRESDEN: 630 this->StereoStatus = 1; 631 break; 632 case VTK_STEREO_INTERLACED: 633 this->StereoStatus = 1; 634 break; 635 case VTK_STEREO_CHECKERBOARD: 636 this->StereoStatus = 1; 637 break; 638 case VTK_STEREO_SPLITVIEWPORT_HORIZONTAL: 639 this->StereoStatus = 1; 640 break; 641 } 642 } 643 else if ((!this->StereoRender) && this->StereoStatus) 644 { 645 switch (this->StereoType) 646 { 647 case VTK_STEREO_CRYSTAL_EYES: 648 this->StereoStatus = 0; 649 break; 650 case VTK_STEREO_RED_BLUE: 651 this->StereoStatus = 0; 652 break; 653 case VTK_STEREO_ANAGLYPH: 654 this->StereoStatus = 0; 655 break; 656 case VTK_STEREO_DRESDEN: 657 this->StereoStatus = 0; 658 break; 659 case VTK_STEREO_INTERLACED: 660 this->StereoStatus = 0; 661 break; 662 case VTK_STEREO_CHECKERBOARD: 663 this->StereoStatus = 0; 664 break; 665 case VTK_STEREO_SPLITVIEWPORT_HORIZONTAL: 666 this->StereoStatus = 0; 667 break; 668 } 669 } 670} 671 672//---------------------------------------------------------------------------- 673// Specify various window parameters. 674void vtkCocoaRenderWindow::WindowConfigure() 675{ 676 // this is all handled by the desiredVisualInfo method 677} 678 679//---------------------------------------------------------------------------- 680void vtkCocoaRenderWindow::SetupPixelFormat(void*, void*, int, int, int) 681{ 682 vtkErrorMacro(<< "vtkCocoaRenderWindow::SetupPixelFormat - IMPLEMENT"); 683} 684 685//---------------------------------------------------------------------------- 686void vtkCocoaRenderWindow::SetupPalette(void*) 687{ 688 vtkErrorMacro(<< "vtkCocoaRenderWindow::SetupPalette - IMPLEMENT"); 689} 690 691//---------------------------------------------------------------------------- 692// Initialize the window for rendering. 693void vtkCocoaRenderWindow::CreateAWindow() 694{ 695 static unsigned count = 1; 696 697 // As vtk is both crossplatform and a library, we don't know if it is being 698 // used in a 'regular Cocoa application' or as a 'pure vtk application'. 699 // By the former I mean a regular Cocoa application that happens to have 700 // a vtkCocoaGLView, by the latter I mean an application that only uses 701 // vtk APIs (which happen to use Cocoa as an implementation detail). 702 // Specifically, we can't know if NSApplicationMain() was ever called 703 // (which is usually done in main()), nor whether the NSApplication exists. 704 // 705 // So here we call +sharedApplication which will create the NSApplication 706 // if it does not exist. If it does exist, this does nothing. 707 // We are not actually interested in the return value. 708 // This call is intentionally delayed until this CreateAWindow call 709 // to prevent Cocoa-window related stuff from happening in scenarios 710 // where vtkRenderWindows are created but never shown. 711 (void)[NSApplication sharedApplication]; 712 713 // create an NSWindow only if neither an NSView nor an NSWindow have 714 // been specified already. This is the case for a 'pure vtk application'. 715 // If you are using vtk in a 'regular Mac application' you should call 716 // SetRootWindow() and SetWindowId() so that a window is not created here. 717 if (!this->GetRootWindow() && !this->GetWindowId() && !this->GetParentId()) 718 { 719 NSWindow* theWindow = nil; 720 721#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 722 NSScreen *screen = [NSScreen mainScreen]; 723 if (this->FullScreen && screen) 724 { 725 NSRect ctRect = [screen frame]; 726 this->Size[0] = (int)round(NSWidth(ctRect)); 727 this->Size[1] = (int)round(NSHeight(ctRect)); 728 729 theWindow = [[vtkCocoaFullScreenWindow alloc] 730 initWithContentRect:ctRect 731 styleMask:NSBorderlessWindowMask 732 backing:NSBackingStoreBuffered 733 defer:NO]; 734 735 // This will hide the menu and the dock 736 [theWindow setLevel:NSMainMenuWindowLevel+1]; 737 // This will show the menu and the dock 738 //[theWindow setLevel:NSFloatingWindowLevel]; 739 } 740 else 741#endif 742 { 743 if ((this->Size[0]+this->Size[1]) == 0) 744 { 745 this->Size[0] = 300; 746 this->Size[1] = 300; 747 } 748 if ((this->Position[0]+this->Position[1]) == 0) 749 { 750 this->Position[0] = 50; 751 this->Position[1] = 50; 752 } 753 754 NSRect ctRect = NSMakeRect((CGFloat)this->Position[0], 755 (CGFloat)this->Position[1], 756 (CGFloat)this->Size[0], 757 (CGFloat)this->Size[1]); 758 759 theWindow = [[NSWindow alloc] 760 initWithContentRect:ctRect 761 styleMask:NSTitledWindowMask | 762 NSClosableWindowMask | 763 NSMiniaturizableWindowMask | 764 NSResizableWindowMask 765 backing:NSBackingStoreBuffered 766 defer:NO]; 767 } 768 769 if (!theWindow) 770 { 771 vtkErrorMacro("Could not create window, serious error!"); 772 return; 773 } 774 775 this->SetRootWindow(theWindow); 776 this->WindowCreated = 1; 777 778 // makeKeyAndOrderFront: will show the window 779 // we don't want this if offscreen was requested 780 if(!this->OffScreenRendering) 781 { 782 [theWindow makeKeyAndOrderFront:nil]; 783 [theWindow setAcceptsMouseMovedEvents:YES]; 784 } 785 } 786 // create a view if one has not been specified 787 if (!this->GetWindowId()) 788 { 789 if (this->GetParentId()) 790 { 791 NSView *parent = (NSView*)this->GetParentId(); 792 NSRect parentRect = [parent frame]; 793 CGFloat parentHeight = NSHeight(parentRect); 794 CGFloat parentWidth = NSWidth(parentRect); 795 CGFloat width = (CGFloat)this->Size[0]; 796 CGFloat height = (CGFloat)this->Size[1]; 797 CGFloat x = (CGFloat)this->Position[0]; 798 CGFloat y = parentHeight - height - (CGFloat)this->Position[1]; 799 800 // A whole bunch of sanity checks: frame must be inside parent 801 if (x > parentWidth - 1) { x = parentWidth - 1; }; 802 if (y > parentHeight - 1) { y = parentHeight - 1; }; 803 if (x < 0.0) { x = 0.0; } 804 if (y < 0.0) { y = 0.0; } 805 if (x + width > parentWidth) { width = parentWidth - x; } 806 if (y + height > parentWidth) { height = parentHeight - y; } 807 808 // Don't use vtkCocoaGLView, because if we are in Tk (which is what 809 // SetParentId() was added for) then the Tk superview handles the events. 810 NSRect glRect = NSMakeRect(x, y, width, height); 811 NSView *glView = [[NSView alloc] initWithFrame:glRect]; 812 [parent addSubview:glView]; 813 this->SetWindowId(glView); 814 this->ViewCreated = 1; 815#if VTK_OBJC_IS_MRR 816 [glView release]; 817#endif 818 } 819 else 820 { 821 NSRect glRect = NSMakeRect(0.0, 0.0, 822 (CGFloat)this->Size[0], 823 (CGFloat)this->Size[1]); 824 825 // Create a vtkCocoaGLView. 826 vtkCocoaGLView *glView = [[vtkCocoaGLView alloc] initWithFrame:glRect]; 827 [(NSWindow*)this->GetRootWindow() setContentView:glView]; 828 this->SetWindowId(glView); 829 this->ViewCreated = 1; 830 [glView setVTKRenderWindow:this]; 831#if VTK_OBJC_IS_MRR 832 [glView release]; 833#endif 834 } 835 } 836 837 this->CreateGLContext(); 838 839 // Change the window title, but only if it was created by vtk 840 if (this->WindowCreated) 841 { 842 NSString *winName = [NSString stringWithFormat:@"Visualization Toolkit - Cocoa #%u", count++]; 843 this->SetWindowName([winName cStringUsingEncoding:NSASCIIStringEncoding]); 844 } 845 846 // the error "invalid drawable" in the console from this call can appear 847 // but only early in the app's lifetime (ie sometime during launch) 848 // IMPORTANT: this is necessary to update the context here in case of 849 // hardware offscreen rendering 850 NSOpenGLContext* context = (NSOpenGLContext*)this->GetContextId(); 851 [context setView:(NSView*)this->GetWindowId()]; 852 853 [context update]; 854 855 this->MakeCurrent(); 856 857 // wipe out any existing display lists 858 vtkRenderer *renderer = NULL; 859 vtkCollectionSimpleIterator rsit; 860 861 for ( this->Renderers->InitTraversal(rsit); 862 (renderer = this->Renderers->GetNextRenderer(rsit));) 863 { 864 renderer->SetRenderWindow(0); 865 renderer->SetRenderWindow(this); 866 } 867 this->OpenGLInit(); 868 this->Mapped = 1; 869 870 // Now that the NSView and NSWindow exist, the vtkCocoaServer can start its observations. 871 vtkCocoaServer *server = [[vtkCocoaServer alloc] initWithRenderWindow:this]; 872 this->SetCocoaServer(reinterpret_cast<void *>(server)); 873 [server startObservations]; 874#if VTK_OBJC_IS_MRR 875 [server release]; 876#endif 877} 878 879//---------------------------------------------------------------------------- 880void vtkCocoaRenderWindow::CreateGLContext() 881{ 882 // keep trying to get different pixelFormats until successful 883 NSOpenGLPixelFormat *pixelFormat = nil; 884 while (pixelFormat == nil) 885 { 886 int i = 0; 887 NSOpenGLPixelFormatAttribute attribs[20]; 888 889 attribs[i++] = NSOpenGLPFAAccelerated; 890 attribs[i++] = NSOpenGLPFADepthSize; 891 attribs[i++] = (NSOpenGLPixelFormatAttribute)32; 892 893 if (this->MultiSamples != 0) 894 { 895 attribs[i++] = NSOpenGLPFASampleBuffers; 896 attribs[i++] = (NSOpenGLPixelFormatAttribute)1; 897 attribs[i++] = NSOpenGLPFASamples; 898 attribs[i++] = (NSOpenGLPixelFormatAttribute)(this->MultiSamples); 899 attribs[i++] = NSOpenGLPFAMultisample; 900 } 901 902 if (this->DoubleBuffer != 0) 903 { 904 attribs[i++] = NSOpenGLPFADoubleBuffer; 905 } 906 907 attribs[i++] = (NSOpenGLPixelFormatAttribute)0; 908 909 // make sure that size of array was not exceeded 910 assert(sizeof(NSOpenGLPixelFormatAttribute)*i < sizeof(attribs)); 911 912 pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs]; 913 914 if (pixelFormat == nil) 915 { 916 if (this->MultiSamples == 0) 917 { 918 // after trying with no multisamples, we are done 919 break; 920 } 921 else if (this->MultiSamples < 4) 922 { 923 // next time try with no multisamples 924 this->MultiSamples = 0; 925 } 926 else 927 { 928 this->MultiSamples /= 2; 929 } 930 } 931 } 932 933 NSOpenGLContext *context = [[NSOpenGLContext alloc] 934 initWithFormat:pixelFormat 935 shareContext:nil]; 936 937 // This syncs the OpenGL context to the VBL to prevent tearing 938 GLint one = 1; 939 [context setValues:&one forParameter:NSOpenGLCPSwapInterval]; 940 941 this->SetPixelFormat((void*)pixelFormat); 942 this->SetContextId((void*)context); 943 944 [pixelFormat self]; // prevent premature collection under GC. 945 [context self]; // prevent premature collection under GC. 946 947#if VTK_OBJC_IS_MRR 948 [pixelFormat release]; 949 [context release]; 950#endif 951} 952 953//---------------------------------------------------------------------------- 954// Initialize the rendering window. 955void vtkCocoaRenderWindow::Initialize () 956{ 957 if(this->OffScreenRendering) 958 { 959 // destroy on screen 960 if(this->OnScreenInitialized) 961 { 962 this->DestroyWindow(); 963 this->OnScreenInitialized = 0; 964 } 965 // create off screen 966 if(!this->OffScreenInitialized) 967 { 968 int width=((this->Size[0]>0) ? this->Size[0] : 300); 969 int height=((this->Size[1]>0) ? this->Size[1] : 300); 970 if(!this->CreateHardwareOffScreenWindow(width,height)) 971 { 972 // no other offscreen mode available, do on screen rendering 973 this->CreateAWindow(); 974 } 975 this->OffScreenInitialized = 1; 976 } 977 } 978 else 979 { 980 // destroy off screen 981 if(this->OffScreenInitialized) 982 { 983 this->DestroyOffScreenWindow(); 984 } 985 // create on screen 986 if(!this->OnScreenInitialized) 987 { 988 this->OnScreenInitialized = 1; 989 this->CreateAWindow(); 990 } 991 } 992 if((this->OnScreenInitialized) && (this->Mapped)) 993 { 994 // the error "invalid drawable" in the console from this call can appear 995 // but only early in the app's lifetime (ie sometime during launch) 996 // IMPORTANT: this is necessary to update the context here in case of 997 // onscreen rendering 998 NSOpenGLContext* context = (NSOpenGLContext*)this->GetContextId(); 999 [context setView:(NSView*)this->GetWindowId()]; 1000 1001 [context update]; 1002 } 1003} 1004 1005//----------------------------------------------------------------------------- 1006void vtkCocoaRenderWindow::DestroyOffScreenWindow() 1007{ 1008 if(this->OffScreenUseFrameBuffer) 1009 { 1010 this->DestroyHardwareOffScreenWindow(); 1011 } 1012 else 1013 { 1014 // on screen 1015 this->DestroyWindow(); 1016 } 1017} 1018 1019//---------------------------------------------------------------------------- 1020// Get the current size of the window. 1021int *vtkCocoaRenderWindow::GetSize() 1022{ 1023 // if we aren't mapped then just return the ivar 1024 if (!this->Mapped) 1025 { 1026 return this->Superclass::GetSize(); 1027 } 1028 1029 // We want to return the size of 'the window'. But the term 'window' 1030 // is overloaded. It's really the NSView that vtk draws into, so we 1031 // return its size. 1032 NSView* view = (NSView*)this->GetWindowId(); 1033 if (view) 1034 { 1035 NSRect frameRect = [view frame]; 1036 this->Size[0] = (int)round(NSWidth(frameRect)); 1037 this->Size[1] = (int)round(NSHeight(frameRect)); 1038 } 1039 return this->Superclass::GetSize(); 1040} 1041 1042//---------------------------------------------------------------------------- 1043// Get the current size of the screen in pixels. 1044int *vtkCocoaRenderWindow::GetScreenSize() 1045{ 1046 NSOpenGLContext* context = (NSOpenGLContext*)this->GetContextId(); 1047 GLint currentScreen = [context currentVirtualScreen]; 1048 1049 NSScreen* screen = [[NSScreen screens] objectAtIndex:currentScreen]; 1050 NSRect screenRect = [screen frame]; 1051 1052 this->Size[0] = (int)round(NSWidth(screenRect)); 1053 this->Size[1] = (int)round(NSHeight(screenRect)); 1054 1055 return this->Size; 1056} 1057 1058//---------------------------------------------------------------------------- 1059// Get the position in screen coordinates of the window. 1060int *vtkCocoaRenderWindow::GetPosition() 1061{ 1062 // if we aren't mapped then just return the ivar 1063 if (!this->Mapped) 1064 { 1065 return this->Position; 1066 } 1067 1068 if (this->GetParentId() && this->GetWindowId()) 1069 { 1070 // Get display position of the NSView within its parent 1071 NSRect parentRect = [(NSView*)this->GetParentId() frame]; 1072 NSRect viewFrameRect = [(NSView*)this->GetWindowId() frame]; 1073 this->Position[0] = int(round(NSMinX(viewFrameRect))); 1074 this->Position[1] = int(round((NSHeight(parentRect) 1075 - NSHeight(viewFrameRect) 1076 - NSMinY(viewFrameRect)))); 1077 } 1078 else 1079 { 1080 // We want to return the position of 'the window'. But the term 'window' 1081 // is overloaded. In this case, it's the position of the NSWindow itself 1082 // on the screen that we return. We don't much care where the NSView is 1083 // within the NSWindow. 1084 NSWindow *window = (NSWindow*)this->GetRootWindow(); 1085 if (window) 1086 { 1087 NSRect winFrameRect = [window frame]; 1088 this->Position[0] = (int)NSMinX(winFrameRect); 1089 this->Position[1] = (int)NSMinY(winFrameRect); 1090 } 1091 } 1092 1093 return this->Position; 1094} 1095 1096//---------------------------------------------------------------------------- 1097// Change the window to fill the entire screen. 1098void vtkCocoaRenderWindow::SetFullScreen(int arg) 1099{ 1100 if (this->FullScreen == arg) 1101 { 1102 return; 1103 } 1104 1105 if (!this->Mapped) 1106 { 1107 this->FullScreen = arg; 1108 return; 1109 } 1110 1111 // set the mode 1112 this->FullScreen = arg; 1113 if (this->FullScreen <= 0) 1114 { 1115 this->Position[0] = this->OldScreen[0]; 1116 this->Position[1] = this->OldScreen[1]; 1117 this->Size[0] = this->OldScreen[2]; 1118 this->Size[1] = this->OldScreen[3]; 1119 this->Borders = this->OldScreen[4]; 1120 } 1121 else 1122 { 1123 // if window already up get its values 1124 if (this->GetRootWindow()) 1125 { 1126 int* pos = this->GetPosition(); 1127 this->OldScreen[0] = pos[0]; 1128 this->OldScreen[1] = pos[1]; 1129 1130 this->OldScreen[4] = this->Borders; 1131 this->PrefFullScreen(); 1132 } 1133 } 1134 1135 // remap the window 1136 this->WindowRemap(); 1137 1138 this->Modified(); 1139} 1140 1141//---------------------------------------------------------------------------- 1142// 1143// Set the variable that indicates that we want a stereo capable window 1144// be created. This method can only be called before a window is realized. 1145// 1146void vtkCocoaRenderWindow::SetStereoCapableWindow(int capable) 1147{ 1148 if (this->GetContextId() == 0) 1149 { 1150 vtkRenderWindow::SetStereoCapableWindow(capable); 1151 } 1152 else 1153 { 1154 vtkWarningMacro(<< "Requesting a StereoCapableWindow must be performed " 1155 << "before the window is realized, i.e. before a render."); 1156 } 1157} 1158 1159//---------------------------------------------------------------------------- 1160// Set the preferred window size to full screen. 1161void vtkCocoaRenderWindow::PrefFullScreen() 1162{ 1163 int *size = this->GetScreenSize(); 1164 vtkWarningMacro(<< "Can only set FullScreen before showing window: " 1165 << size[0] << 'x' << size[1] << "."); 1166} 1167 1168//---------------------------------------------------------------------------- 1169// Remap the window. 1170void vtkCocoaRenderWindow::WindowRemap() 1171{ 1172 vtkWarningMacro(<< "Can't remap the window."); 1173 // Acquire the display and capture the screen. 1174 // Create the full-screen window. 1175 // Add the context. 1176} 1177 1178//---------------------------------------------------------------------------- 1179void vtkCocoaRenderWindow::PrintSelf(ostream& os, vtkIndent indent) 1180{ 1181 this->Superclass::PrintSelf(os,indent); 1182 1183 os << indent << "MultiSamples: " << this->MultiSamples << endl; 1184 os << indent << "CocoaManager: " << this->GetCocoaManager() << endl; 1185 os << indent << "RootWindow (NSWindow): " << this->GetRootWindow() << endl; 1186 os << indent << "WindowId (NSView): " << this->GetWindowId() << endl; 1187 os << indent << "ParentId: " << this->GetParentId() << endl; 1188 os << indent << "ContextId: " << this->GetContextId() << endl; 1189 os << indent << "PixelFormat: " << this->GetPixelFormat() << endl; 1190 os << indent << "WindowCreated: " << (this->GetWindowCreated() ? "Yes" : "No") << endl; 1191 os << indent << "ViewCreated: " << (this->GetViewCreated() ? "Yes" : "No") << endl; 1192} 1193 1194//---------------------------------------------------------------------------- 1195int vtkCocoaRenderWindow::GetDepthBufferSize() 1196{ 1197 if ( this->Mapped ) 1198 { 1199 GLint size = 0; 1200 glGetIntegerv( GL_DEPTH_BITS, &size ); 1201 return (int) size; 1202 } 1203 else 1204 { 1205 vtkDebugMacro(<< "Window is not mapped yet!" ); 1206 return 24; 1207 } 1208} 1209 1210//---------------------------------------------------------------------------- 1211// Returns the NSWindow* associated with this vtkRenderWindow. 1212void *vtkCocoaRenderWindow::GetRootWindow() 1213{ 1214 NSMutableDictionary *manager = 1215 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1216 return reinterpret_cast<void *>([manager objectForKey:@"RootWindow"]); 1217} 1218 1219//---------------------------------------------------------------------------- 1220// Sets the NSWindow* associated with this vtkRenderWindow. 1221void vtkCocoaRenderWindow::SetRootWindow(void *arg) 1222{ 1223 if (arg != NULL) 1224 { 1225 NSMutableDictionary *manager = 1226 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1227 [manager setObject:reinterpret_cast<id>(arg) 1228 forKey:@"RootWindow"]; 1229 } 1230 else 1231 { 1232 NSMutableDictionary *manager = 1233 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1234 [manager removeObjectForKey:@"RootWindow"]; 1235 } 1236} 1237 1238//---------------------------------------------------------------------------- 1239// Returns the NSView* associated with this vtkRenderWindow. 1240void *vtkCocoaRenderWindow::GetWindowId() 1241{ 1242 NSMutableDictionary *manager = 1243 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1244 return reinterpret_cast<void *>([manager objectForKey:@"WindowId"]); 1245} 1246 1247//---------------------------------------------------------------------------- 1248// Sets the NSView* associated with this vtkRenderWindow. 1249void vtkCocoaRenderWindow::SetWindowId(void *arg) 1250{ 1251 if (arg != NULL) 1252 { 1253 NSMutableDictionary *manager = 1254 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1255 [manager setObject:reinterpret_cast<id>(arg) 1256 forKey:@"WindowId"]; 1257 } 1258 else 1259 { 1260 NSMutableDictionary *manager = 1261 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1262 [manager removeObjectForKey:@"WindowId"]; 1263 } 1264} 1265 1266//---------------------------------------------------------------------------- 1267// Returns the NSView* that is the parent of this vtkRenderWindow. 1268void *vtkCocoaRenderWindow::GetParentId() 1269{ 1270 NSMutableDictionary *manager = 1271 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1272 return reinterpret_cast<void *>([manager objectForKey:@"ParentId"]); 1273} 1274 1275//---------------------------------------------------------------------------- 1276// Sets the NSView* that this vtkRenderWindow should use as a parent. 1277void vtkCocoaRenderWindow::SetParentId(void *arg) 1278{ 1279 if (arg != NULL) 1280 { 1281 NSMutableDictionary *manager = 1282 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1283 [manager setObject:reinterpret_cast<id>(arg) 1284 forKey:@"ParentId"]; 1285 } 1286 else 1287 { 1288 NSMutableDictionary *manager = 1289 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1290 [manager removeObjectForKey:@"ParentId"]; 1291 } 1292} 1293 1294//---------------------------------------------------------------------------- 1295// Sets the NSOpenGLContext* associated with this vtkRenderWindow. 1296void vtkCocoaRenderWindow::SetContextId(void *contextId) 1297{ 1298 if (contextId != NULL) 1299 { 1300 NSMutableDictionary *manager = 1301 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1302 [manager setObject:reinterpret_cast<id>(contextId) 1303 forKey:@"ContextId"]; 1304 } 1305 else 1306 { 1307 NSMutableDictionary *manager = 1308 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1309 [manager removeObjectForKey:@"ContextId"]; 1310 } 1311} 1312 1313//---------------------------------------------------------------------------- 1314// Returns the NSOpenGLContext* associated with this vtkRenderWindow. 1315void *vtkCocoaRenderWindow::GetContextId() 1316{ 1317 NSMutableDictionary *manager = 1318 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1319 return reinterpret_cast<void *>([manager objectForKey:@"ContextId"]); 1320} 1321 1322//---------------------------------------------------------------------------- 1323// Sets the NSOpenGLPixelFormat* associated with this vtkRenderWindow. 1324void vtkCocoaRenderWindow::SetPixelFormat(void *pixelFormat) 1325{ 1326 if (pixelFormat != NULL) 1327 { 1328 NSMutableDictionary *manager = 1329 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1330 [manager setObject:reinterpret_cast<id>(pixelFormat) 1331 forKey:@"PixelFormat"]; 1332 } 1333 else 1334 { 1335 NSMutableDictionary *manager = 1336 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1337 [manager removeObjectForKey:@"PixelFormat"]; 1338 } 1339} 1340 1341//---------------------------------------------------------------------------- 1342// Returns the NSOpenGLPixelFormat* associated with this vtkRenderWindow. 1343void *vtkCocoaRenderWindow::GetPixelFormat() 1344{ 1345 NSMutableDictionary *manager = 1346 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1347 return reinterpret_cast<void *>([manager objectForKey:@"PixelFormat"]); 1348} 1349 1350//---------------------------------------------------------------------------- 1351void vtkCocoaRenderWindow::SetCocoaServer(void *server) 1352{ 1353 if (server != NULL) 1354 { 1355 NSMutableDictionary *manager = 1356 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1357 [manager setObject:reinterpret_cast<vtkCocoaServer *>(server) 1358 forKey:@"CocoaServer"]; 1359 } 1360 else 1361 { 1362 NSMutableDictionary *manager = 1363 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1364 [manager removeObjectForKey:@"CocoaServer"]; 1365 } 1366} 1367 1368//---------------------------------------------------------------------------- 1369void *vtkCocoaRenderWindow::GetCocoaServer() 1370{ 1371 NSMutableDictionary *manager = 1372 reinterpret_cast<NSMutableDictionary *>(this->GetCocoaManager()); 1373 return reinterpret_cast<void *>([manager objectForKey:@"CocoaServer"]); 1374} 1375 1376//---------------------------------------------------------------------------- 1377void vtkCocoaRenderWindow::SetCocoaManager(void *manager) 1378{ 1379 NSMutableDictionary *currentCocoaManager = 1380 reinterpret_cast<NSMutableDictionary *>(this->CocoaManager); 1381 NSMutableDictionary *newCocoaManager = 1382 reinterpret_cast<NSMutableDictionary *>(manager); 1383 1384 if (currentCocoaManager != newCocoaManager) 1385 { 1386 // Why not use Cocoa's retain and release? Without garbage collection 1387 // (GC), the two are equivalent anyway because of 'toll free bridging', 1388 // so no problem there. With GC, retain and release do nothing, but 1389 // CFRetain and CFRelease still manipulate the internal reference count. 1390 // We need that, since we are not using strong references (we don't want 1391 // it collected out from under us!). 1392 if (currentCocoaManager) 1393 { 1394 CFRelease(currentCocoaManager); 1395 } 1396 if (newCocoaManager) 1397 { 1398 this->CocoaManager = const_cast<void *>(CFRetain (newCocoaManager)); 1399 } 1400 else 1401 { 1402 this->CocoaManager = NULL; 1403 } 1404 } 1405} 1406 1407//---------------------------------------------------------------------------- 1408void vtkCocoaRenderWindow::SetWindowInfo(char *info) 1409{ 1410 // The paramater is an ASCII string of a decimal number representing 1411 // a pointer to the window. Convert it back to a pointer. 1412 ptrdiff_t tmp = 0; 1413 if (info) 1414 { 1415 (void)sscanf(info, "%tu", &tmp); 1416 } 1417 1418 this->SetWindowId (reinterpret_cast<void *>(tmp)); 1419} 1420 1421//---------------------------------------------------------------------------- 1422void vtkCocoaRenderWindow::SetParentInfo(char *info) 1423{ 1424 // The paramater is an ASCII string of a decimal number representing 1425 // a pointer to the window. Convert it back to a pointer. 1426 ptrdiff_t tmp = 0; 1427 if (info) 1428 { 1429 (void)sscanf(info, "%tu", &tmp); 1430 } 1431 1432 this->SetParentId (reinterpret_cast<void *>(tmp)); 1433} 1434 1435//---------------------------------------------------------------------------- 1436void *vtkCocoaRenderWindow::GetCocoaManager() 1437{ 1438 return this->CocoaManager; 1439} 1440 1441//---------------------------------------------------------------------------- 1442void vtkCocoaRenderWindow::HideCursor() 1443{ 1444 if (this->CursorHidden) 1445 { 1446 return; 1447 } 1448 this->CursorHidden = 1; 1449 1450 [NSCursor hide]; 1451} 1452 1453//---------------------------------------------------------------------------- 1454void vtkCocoaRenderWindow::ShowCursor() 1455{ 1456 if (!this->CursorHidden) 1457 { 1458 return; 1459 } 1460 this->CursorHidden = 0; 1461 1462 [NSCursor unhide]; 1463} 1464 1465// --------------------------------------------------------------------------- 1466int vtkCocoaRenderWindow::GetViewCreated() 1467{ 1468 return this->ViewCreated; 1469} 1470 1471// --------------------------------------------------------------------------- 1472int vtkCocoaRenderWindow::GetWindowCreated() 1473{ 1474 return this->WindowCreated; 1475} 1476 1477//---------------------------------------------------------------------------- 1478void vtkCocoaRenderWindow::SetCursorPosition(int x, int y) 1479{ 1480 // The given coordinates are from the bottom left of the view. 1481 NSPoint newViewPoint = NSMakePoint (x, y); 1482 1483 // Convert to screen coordinates. 1484 NSView *view = (NSView *)this->GetWindowId(); 1485 if (view) 1486 { 1487 NSPoint screenPoint = [view convertPoint:newViewPoint toView:nil]; 1488 CGPoint newCursorPosition = NSPointToCGPoint(screenPoint); 1489 1490 // Move the cursor there. 1491 (void)CGWarpMouseCursorPosition (newCursorPosition); 1492 } 1493} 1494 1495//---------------------------------------------------------------------------- 1496void vtkCocoaRenderWindow::SetCurrentCursor(int shape) 1497{ 1498 if (this->InvokeEvent(vtkCommand::CursorChangedEvent, &shape)) 1499 { 1500 return; 1501 } 1502 this->Superclass::SetCurrentCursor(shape); 1503 NSCursor* cursor = nil; 1504 switch (shape) 1505 { 1506 case VTK_CURSOR_DEFAULT: 1507 case VTK_CURSOR_ARROW: 1508 cursor = [NSCursor arrowCursor]; 1509 break; 1510 case VTK_CURSOR_SIZENS: 1511 cursor = [NSCursor resizeUpDownCursor]; 1512 break; 1513 case VTK_CURSOR_SIZEWE: 1514 cursor = [NSCursor resizeLeftRightCursor]; 1515 break; 1516 case VTK_CURSOR_HAND: 1517 cursor = [NSCursor pointingHandCursor]; 1518 break; 1519 case VTK_CURSOR_CROSSHAIR: 1520 cursor = [NSCursor crosshairCursor]; 1521 break; 1522 1523 // NSCursor does not have cursors for these. 1524 case VTK_CURSOR_SIZENE: 1525 case VTK_CURSOR_SIZESW: 1526 case VTK_CURSOR_SIZENW: 1527 case VTK_CURSOR_SIZESE: 1528 case VTK_CURSOR_SIZEALL: 1529 cursor = [NSCursor arrowCursor]; 1530 break; 1531 } 1532 1533 [cursor set]; 1534} 1535