|
Blender
V2.59
|
00001 00030 #include <Cocoa/Cocoa.h> 00031 00032 #ifndef MAC_OS_X_VERSION_10_6 00033 //Use of the SetSystemUIMode function (64bit compatible) 00034 #include <Carbon/Carbon.h> 00035 #endif 00036 00037 #include <OpenGL/gl.h> 00038 /***** Multithreaded opengl code : uncomment for enabling 00039 #include <OpenGL/OpenGL.h> 00040 */ 00041 00042 00043 #include "GHOST_WindowCocoa.h" 00044 #include "GHOST_SystemCocoa.h" 00045 #include "GHOST_Debug.h" 00046 00047 00048 #pragma mark Cocoa window delegate object 00049 /* live resize ugly patch 00050 extern "C" { 00051 struct bContext; 00052 typedef struct bContext bContext; 00053 bContext* ghostC; 00054 extern int wm_window_timer(const bContext *C); 00055 extern void wm_window_process_events(const bContext *C); 00056 extern void wm_event_do_handlers(bContext *C); 00057 extern void wm_event_do_notifiers(bContext *C); 00058 extern void wm_draw_update(bContext *C); 00059 };*/ 00060 @interface CocoaWindowDelegate : NSObject 00061 #ifdef MAC_OS_X_VERSION_10_6 00062 <NSWindowDelegate> 00063 #endif 00064 { 00065 GHOST_SystemCocoa *systemCocoa; 00066 GHOST_WindowCocoa *associatedWindow; 00067 } 00068 00069 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa; 00070 - (void)windowWillClose:(NSNotification *)notification; 00071 - (void)windowDidBecomeKey:(NSNotification *)notification; 00072 - (void)windowDidResignKey:(NSNotification *)notification; 00073 - (void)windowDidExpose:(NSNotification *)notification; 00074 - (void)windowDidResize:(NSNotification *)notification; 00075 - (void)windowDidMove:(NSNotification *)notification; 00076 - (void)windowWillMove:(NSNotification *)notification; 00077 @end 00078 00079 @implementation CocoaWindowDelegate : NSObject 00080 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa 00081 { 00082 systemCocoa = sysCocoa; 00083 associatedWindow = winCocoa; 00084 } 00085 00086 - (void)windowWillClose:(NSNotification *)notification 00087 { 00088 systemCocoa->handleWindowEvent(GHOST_kEventWindowClose, associatedWindow); 00089 } 00090 00091 - (void)windowDidBecomeKey:(NSNotification *)notification 00092 { 00093 systemCocoa->handleWindowEvent(GHOST_kEventWindowActivate, associatedWindow); 00094 } 00095 00096 - (void)windowDidResignKey:(NSNotification *)notification 00097 { 00098 systemCocoa->handleWindowEvent(GHOST_kEventWindowDeactivate, associatedWindow); 00099 } 00100 00101 - (void)windowDidExpose:(NSNotification *)notification 00102 { 00103 systemCocoa->handleWindowEvent(GHOST_kEventWindowUpdate, associatedWindow); 00104 } 00105 00106 - (void)windowDidMove:(NSNotification *)notification 00107 { 00108 systemCocoa->handleWindowEvent(GHOST_kEventWindowMove, associatedWindow); 00109 } 00110 00111 - (void)windowWillMove:(NSNotification *)notification 00112 { 00113 systemCocoa->handleWindowEvent(GHOST_kEventWindowMove, associatedWindow); 00114 } 00115 00116 - (void)windowDidResize:(NSNotification *)notification 00117 { 00118 #ifdef MAC_OS_X_VERSION_10_6 00119 //if (![[notification object] inLiveResize]) { 00120 //Send event only once, at end of resize operation (when user has released mouse button) 00121 #endif 00122 systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, associatedWindow); 00123 #ifdef MAC_OS_X_VERSION_10_6 00124 //} 00125 #endif 00126 /* Live resize ugly patch. Needed because live resize runs in a modal loop, not letting main loop run 00127 if ([[notification object] inLiveResize]) { 00128 systemCocoa->dispatchEvents(); 00129 wm_window_timer(ghostC); 00130 wm_event_do_handlers(ghostC); 00131 wm_event_do_notifiers(ghostC); 00132 wm_draw_update(ghostC); 00133 }*/ 00134 } 00135 @end 00136 00137 #pragma mark NSWindow subclass 00138 //We need to subclass it to tell that even borderless (fullscreen), it can become key (receive user events) 00139 @interface CocoaWindow: NSWindow 00140 { 00141 GHOST_SystemCocoa *systemCocoa; 00142 GHOST_WindowCocoa *associatedWindow; 00143 GHOST_TDragnDropTypes m_draggedObjectType; 00144 } 00145 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa; 00146 - (GHOST_SystemCocoa*)systemCocoa; 00147 @end 00148 @implementation CocoaWindow 00149 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa 00150 { 00151 systemCocoa = sysCocoa; 00152 associatedWindow = winCocoa; 00153 } 00154 - (GHOST_SystemCocoa*)systemCocoa 00155 { 00156 return systemCocoa; 00157 } 00158 00159 -(BOOL)canBecomeKeyWindow 00160 { 00161 return YES; 00162 } 00163 00164 //The drag'n'drop dragging destination methods 00165 - (NSDragOperation)draggingEntered:(id < NSDraggingInfo >)sender 00166 { 00167 NSPoint mouseLocation = [sender draggingLocation]; 00168 NSPasteboard *draggingPBoard = [sender draggingPasteboard]; 00169 00170 if ([[draggingPBoard types] containsObject:NSTIFFPboardType]) m_draggedObjectType = GHOST_kDragnDropTypeBitmap; 00171 else if ([[draggingPBoard types] containsObject:NSFilenamesPboardType]) m_draggedObjectType = GHOST_kDragnDropTypeFilenames; 00172 else if ([[draggingPBoard types] containsObject:NSStringPboardType]) m_draggedObjectType = GHOST_kDragnDropTypeString; 00173 else return NSDragOperationNone; 00174 00175 associatedWindow->setAcceptDragOperation(TRUE); //Drag operation is accepted by default 00176 systemCocoa->handleDraggingEvent(GHOST_kEventDraggingEntered, m_draggedObjectType, associatedWindow, mouseLocation.x, mouseLocation.y, nil); 00177 return NSDragOperationCopy; 00178 } 00179 00180 - (BOOL)wantsPeriodicDraggingUpdates 00181 { 00182 return NO; //No need to overflow blender event queue. Events shall be sent only on changes 00183 } 00184 00185 - (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender 00186 { 00187 NSPoint mouseLocation = [sender draggingLocation]; 00188 00189 systemCocoa->handleDraggingEvent(GHOST_kEventDraggingUpdated, m_draggedObjectType, associatedWindow, mouseLocation.x, mouseLocation.y, nil); 00190 return associatedWindow->canAcceptDragOperation()?NSDragOperationCopy:NSDragOperationNone; 00191 } 00192 00193 - (void)draggingExited:(id < NSDraggingInfo >)sender 00194 { 00195 systemCocoa->handleDraggingEvent(GHOST_kEventDraggingExited, m_draggedObjectType, associatedWindow, 0, 0, nil); 00196 m_draggedObjectType = GHOST_kDragnDropTypeUnknown; 00197 } 00198 00199 - (BOOL)prepareForDragOperation:(id < NSDraggingInfo >)sender 00200 { 00201 if (associatedWindow->canAcceptDragOperation()) 00202 return YES; 00203 else 00204 return NO; 00205 } 00206 00207 - (BOOL)performDragOperation:(id < NSDraggingInfo >)sender 00208 { 00209 NSPoint mouseLocation = [sender draggingLocation]; 00210 NSPasteboard *draggingPBoard = [sender draggingPasteboard]; 00211 NSImage *droppedImg; 00212 id data; 00213 00214 switch (m_draggedObjectType) { 00215 case GHOST_kDragnDropTypeBitmap: 00216 if([NSImage canInitWithPasteboard:draggingPBoard]) { 00217 droppedImg = [[NSImage alloc]initWithPasteboard:draggingPBoard]; 00218 data = droppedImg; //[draggingPBoard dataForType:NSTIFFPboardType]; 00219 } 00220 else return NO; 00221 break; 00222 case GHOST_kDragnDropTypeFilenames: 00223 data = [draggingPBoard propertyListForType:NSFilenamesPboardType]; 00224 break; 00225 case GHOST_kDragnDropTypeString: 00226 data = [draggingPBoard stringForType:NSStringPboardType]; 00227 break; 00228 default: 00229 return NO; 00230 break; 00231 } 00232 systemCocoa->handleDraggingEvent(GHOST_kEventDraggingDropDone, m_draggedObjectType, associatedWindow, mouseLocation.x, mouseLocation.y, (void*)data); 00233 return YES; 00234 } 00235 00236 @end 00237 00238 00239 00240 #pragma mark NSOpenGLView subclass 00241 //We need to subclass it in order to give Cocoa the feeling key events are trapped 00242 @interface CocoaOpenGLView : NSOpenGLView 00243 { 00244 GHOST_SystemCocoa *systemCocoa; 00245 GHOST_WindowCocoa *associatedWindow; 00246 } 00247 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa; 00248 @end 00249 @implementation CocoaOpenGLView 00250 00251 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa 00252 { 00253 systemCocoa = sysCocoa; 00254 associatedWindow = winCocoa; 00255 } 00256 00257 - (BOOL)acceptsFirstResponder 00258 { 00259 return YES; 00260 } 00261 00262 //The trick to prevent Cocoa from complaining (beeping) 00263 - (void)keyDown:(NSEvent *)theEvent 00264 {} 00265 00266 #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 00267 //Cmd+key are handled differently before 10.5 00268 - (BOOL)performKeyEquivalent:(NSEvent *)theEvent 00269 { 00270 NSString *chars = [theEvent charactersIgnoringModifiers]; 00271 00272 if ([chars length] <1) 00273 return NO; 00274 00275 //Let cocoa handle menu shortcuts 00276 switch ([chars characterAtIndex:0]) { 00277 case 'q': 00278 case 'w': 00279 case 'h': 00280 case 'm': 00281 case '<': 00282 case '>': 00283 case '~': 00284 case '`': 00285 return NO; 00286 default: 00287 return YES; 00288 } 00289 } 00290 #endif 00291 00292 - (BOOL)isOpaque 00293 { 00294 return YES; 00295 } 00296 00297 - (void) drawRect:(NSRect)rect 00298 { 00299 if ([self inLiveResize]) 00300 { 00301 //Don't redraw while in live resize 00302 } 00303 else 00304 { 00305 [super drawRect:rect]; 00306 systemCocoa->handleWindowEvent(GHOST_kEventWindowUpdate, associatedWindow); 00307 } 00308 } 00309 00310 @end 00311 00312 00313 #pragma mark initialization / finalization 00314 00315 NSOpenGLContext* GHOST_WindowCocoa::s_firstOpenGLcontext = nil; 00316 00317 GHOST_WindowCocoa::GHOST_WindowCocoa( 00318 GHOST_SystemCocoa *systemCocoa, 00319 const STR_String& title, 00320 GHOST_TInt32 left, 00321 GHOST_TInt32 bottom, 00322 GHOST_TUns32 width, 00323 GHOST_TUns32 height, 00324 GHOST_TWindowState state, 00325 GHOST_TDrawingContextType type, 00326 const bool stereoVisual, const GHOST_TUns16 numOfAASamples 00327 ) : 00328 GHOST_Window(width, height, state, GHOST_kDrawingContextTypeNone, stereoVisual, numOfAASamples), 00329 m_customCursor(0) 00330 { 00331 NSOpenGLPixelFormatAttribute pixelFormatAttrsWindow[40]; 00332 NSOpenGLPixelFormat *pixelFormat = nil; 00333 int i; 00334 00335 m_systemCocoa = systemCocoa; 00336 m_fullScreen = false; 00337 00338 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00339 00340 //Creates the window 00341 NSRect rect; 00342 NSSize minSize; 00343 00344 rect.origin.x = left; 00345 rect.origin.y = bottom; 00346 rect.size.width = width; 00347 rect.size.height = height; 00348 00349 m_window = [[CocoaWindow alloc] initWithContentRect:rect 00350 styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask 00351 backing:NSBackingStoreBuffered defer:NO]; 00352 if (m_window == nil) { 00353 [pool drain]; 00354 return; 00355 } 00356 00357 [m_window setSystemAndWindowCocoa:systemCocoa windowCocoa:this]; 00358 00359 //Forbid to resize the window below the blender defined minimum one 00360 minSize.width = 320; 00361 minSize.height = 240; 00362 [m_window setContentMinSize:minSize]; 00363 00364 setTitle(title); 00365 00366 00367 // Pixel Format Attributes for the windowed NSOpenGLContext 00368 i=0; 00369 pixelFormatAttrsWindow[i++] = NSOpenGLPFADoubleBuffer; 00370 00371 // Guarantees the back buffer contents to be valid after a call to NSOpenGLContext object’s flushBuffer 00372 // needed for 'Draw Overlap' drawing method 00373 pixelFormatAttrsWindow[i++] = NSOpenGLPFABackingStore; 00374 00375 pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccelerated; 00376 //pixelFormatAttrsWindow[i++] = NSOpenGLPFAAllowOfflineRenderers,; // Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway 00377 00378 pixelFormatAttrsWindow[i++] = NSOpenGLPFADepthSize; 00379 pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32; 00380 00381 00382 if (stereoVisual) pixelFormatAttrsWindow[i++] = NSOpenGLPFAStereo; 00383 00384 if (numOfAASamples>0) { 00385 // Multisample anti-aliasing 00386 pixelFormatAttrsWindow[i++] = NSOpenGLPFAMultisample; 00387 00388 pixelFormatAttrsWindow[i++] = NSOpenGLPFASampleBuffers; 00389 pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 1; 00390 00391 pixelFormatAttrsWindow[i++] = NSOpenGLPFASamples; 00392 pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) numOfAASamples; 00393 00394 pixelFormatAttrsWindow[i++] = NSOpenGLPFANoRecovery; 00395 } 00396 00397 pixelFormatAttrsWindow[i] = (NSOpenGLPixelFormatAttribute) 0; 00398 00399 pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttrsWindow]; 00400 00401 00402 //Fall back to no multisampling if Antialiasing init failed 00403 if (pixelFormat == nil) { 00404 i=0; 00405 pixelFormatAttrsWindow[i++] = NSOpenGLPFADoubleBuffer; 00406 00407 // Guarantees the back buffer contents to be valid after a call to NSOpenGLContext object’s flushBuffer 00408 // needed for 'Draw Overlap' drawing method 00409 pixelFormatAttrsWindow[i++] = NSOpenGLPFABackingStore; 00410 00411 pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccelerated; 00412 //pixelFormatAttrsWindow[i++] = NSOpenGLPFAAllowOfflineRenderers,; // Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway 00413 00414 pixelFormatAttrsWindow[i++] = NSOpenGLPFADepthSize; 00415 pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32; 00416 00417 if (stereoVisual) pixelFormatAttrsWindow[i++] = NSOpenGLPFAStereo; 00418 00419 pixelFormatAttrsWindow[i] = (NSOpenGLPixelFormatAttribute) 0; 00420 00421 pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttrsWindow]; 00422 00423 } 00424 00425 if (numOfAASamples>0) { //Set m_numOfAASamples to the actual value 00426 GLint gli; 00427 [pixelFormat getValues:&gli forAttribute:NSOpenGLPFASamples forVirtualScreen:0]; 00428 if (m_numOfAASamples != (GHOST_TUns16)gli) { 00429 m_numOfAASamples = (GHOST_TUns16)gli; 00430 printf("GHOST_Window could be created with anti-aliasing of only %i samples\n",m_numOfAASamples); 00431 } 00432 } 00433 00434 //Creates the OpenGL View inside the window 00435 m_openGLView = [[CocoaOpenGLView alloc] initWithFrame:rect 00436 pixelFormat:pixelFormat]; 00437 00438 [m_openGLView setSystemAndWindowCocoa:systemCocoa windowCocoa:this]; 00439 00440 [pixelFormat release]; 00441 00442 m_openGLContext = [m_openGLView openGLContext]; //This context will be replaced by the proper one just after 00443 00444 [m_window setContentView:m_openGLView]; 00445 [m_window setInitialFirstResponder:m_openGLView]; 00446 00447 [m_window setReleasedWhenClosed:NO]; //To avoid bad pointer exception in case of user closing the window 00448 00449 [m_window makeKeyAndOrderFront:nil]; 00450 00451 setDrawingContextType(type); 00452 updateDrawingContext(); 00453 activateDrawingContext(); 00454 00455 m_tablet.Active = GHOST_kTabletModeNone; 00456 00457 CocoaWindowDelegate *windowDelegate = [[CocoaWindowDelegate alloc] init]; 00458 [windowDelegate setSystemAndWindowCocoa:systemCocoa windowCocoa:this]; 00459 [m_window setDelegate:windowDelegate]; 00460 00461 [m_window setAcceptsMouseMovedEvents:YES]; 00462 00463 [m_window registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, 00464 NSStringPboardType, NSTIFFPboardType, nil]]; 00465 00466 if (state == GHOST_kWindowStateFullScreen) 00467 setState(GHOST_kWindowStateFullScreen); 00468 00469 [pool drain]; 00470 } 00471 00472 00473 GHOST_WindowCocoa::~GHOST_WindowCocoa() 00474 { 00475 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00476 00477 if (m_customCursor) { 00478 [m_customCursor release]; 00479 m_customCursor = nil; 00480 } 00481 00482 [m_openGLView release]; 00483 00484 if (m_window) { 00485 [m_window close]; 00486 [[m_window delegate] release]; 00487 [m_window release]; 00488 m_window = nil; 00489 } 00490 00491 //Check for other blender opened windows and make the frontmost key 00492 NSArray *windowsList = [NSApp orderedWindows]; 00493 if ([windowsList count]) { 00494 [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil]; 00495 } 00496 [pool drain]; 00497 } 00498 00499 #pragma mark accessors 00500 00501 bool GHOST_WindowCocoa::getValid() const 00502 { 00503 return (m_window != 0); 00504 } 00505 00506 void* GHOST_WindowCocoa::getOSWindow() const 00507 { 00508 return (void*)m_window; 00509 } 00510 00511 void GHOST_WindowCocoa::setTitle(const STR_String& title) 00512 { 00513 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setTitle(): window invalid") 00514 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00515 00516 NSString *windowTitle = [[NSString alloc] initWithCString:title encoding:NSUTF8StringEncoding]; 00517 00518 //Set associated file if applicable 00519 if (windowTitle && [windowTitle hasPrefix:@"Blender"]) 00520 { 00521 NSRange fileStrRange; 00522 NSString *associatedFileName; 00523 int len; 00524 00525 fileStrRange.location = [windowTitle rangeOfString:@"["].location+1; 00526 len = [windowTitle rangeOfString:@"]"].location - fileStrRange.location; 00527 00528 if (len >0) 00529 { 00530 fileStrRange.length = len; 00531 associatedFileName = [windowTitle substringWithRange:fileStrRange]; 00532 [m_window setTitle:[associatedFileName lastPathComponent]]; 00533 00534 //Blender used file open/save functions converte file names into legal URL ones 00535 associatedFileName = [associatedFileName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 00536 @try { 00537 [m_window setRepresentedFilename:associatedFileName]; 00538 } 00539 @catch (NSException * e) { 00540 printf("\nInvalid file path given in window title"); 00541 } 00542 } 00543 else { 00544 [m_window setTitle:windowTitle]; 00545 [m_window setRepresentedFilename:@""]; 00546 } 00547 00548 } else { 00549 [m_window setTitle:windowTitle]; 00550 [m_window setRepresentedFilename:@""]; 00551 } 00552 00553 00554 [windowTitle release]; 00555 [pool drain]; 00556 } 00557 00558 00559 void GHOST_WindowCocoa::getTitle(STR_String& title) const 00560 { 00561 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getTitle(): window invalid") 00562 00563 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00564 00565 NSString *windowTitle = [m_window title]; 00566 00567 if (windowTitle != nil) { 00568 title = [windowTitle UTF8String]; 00569 } 00570 00571 [pool drain]; 00572 } 00573 00574 00575 void GHOST_WindowCocoa::getWindowBounds(GHOST_Rect& bounds) const 00576 { 00577 NSRect rect; 00578 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getWindowBounds(): window invalid") 00579 00580 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00581 00582 NSRect screenSize = [[m_window screen] visibleFrame]; 00583 00584 rect = [m_window frame]; 00585 00586 bounds.m_b = screenSize.size.height - (rect.origin.y -screenSize.origin.y); 00587 bounds.m_l = rect.origin.x -screenSize.origin.x; 00588 bounds.m_r = rect.origin.x-screenSize.origin.x + rect.size.width; 00589 bounds.m_t = screenSize.size.height - (rect.origin.y + rect.size.height -screenSize.origin.y); 00590 00591 [pool drain]; 00592 } 00593 00594 00595 void GHOST_WindowCocoa::getClientBounds(GHOST_Rect& bounds) const 00596 { 00597 NSRect rect; 00598 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getClientBounds(): window invalid") 00599 00600 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00601 00602 if (!m_fullScreen) 00603 { 00604 NSRect screenSize = [[m_window screen] visibleFrame]; 00605 00606 //Max window contents as screen size (excluding title bar...) 00607 NSRect contentRect = [CocoaWindow contentRectForFrameRect:screenSize 00608 styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)]; 00609 00610 rect = [m_window contentRectForFrameRect:[m_window frame]]; 00611 00612 bounds.m_b = contentRect.size.height - (rect.origin.y -contentRect.origin.y); 00613 bounds.m_l = rect.origin.x -contentRect.origin.x; 00614 bounds.m_r = rect.origin.x-contentRect.origin.x + rect.size.width; 00615 bounds.m_t = contentRect.size.height - (rect.origin.y + rect.size.height -contentRect.origin.y); 00616 } 00617 else { 00618 NSRect screenSize = [[m_window screen] frame]; 00619 00620 bounds.m_b = screenSize.origin.y + screenSize.size.height; 00621 bounds.m_l = screenSize.origin.x; 00622 bounds.m_r = screenSize.origin.x + screenSize.size.width; 00623 bounds.m_t = screenSize.origin.y; 00624 } 00625 [pool drain]; 00626 } 00627 00628 00629 GHOST_TSuccess GHOST_WindowCocoa::setClientWidth(GHOST_TUns32 width) 00630 { 00631 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientWidth(): window invalid") 00632 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00633 GHOST_Rect cBnds, wBnds; 00634 getClientBounds(cBnds); 00635 if (((GHOST_TUns32)cBnds.getWidth()) != width) { 00636 NSSize size; 00637 size.width=width; 00638 size.height=cBnds.getHeight(); 00639 [m_window setContentSize:size]; 00640 } 00641 [pool drain]; 00642 return GHOST_kSuccess; 00643 } 00644 00645 00646 GHOST_TSuccess GHOST_WindowCocoa::setClientHeight(GHOST_TUns32 height) 00647 { 00648 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientHeight(): window invalid") 00649 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00650 GHOST_Rect cBnds, wBnds; 00651 getClientBounds(cBnds); 00652 if (((GHOST_TUns32)cBnds.getHeight()) != height) { 00653 NSSize size; 00654 size.width=cBnds.getWidth(); 00655 size.height=height; 00656 [m_window setContentSize:size]; 00657 } 00658 [pool drain]; 00659 return GHOST_kSuccess; 00660 } 00661 00662 00663 GHOST_TSuccess GHOST_WindowCocoa::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) 00664 { 00665 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientSize(): window invalid") 00666 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00667 GHOST_Rect cBnds, wBnds; 00668 getClientBounds(cBnds); 00669 if ((((GHOST_TUns32)cBnds.getWidth()) != width) || 00670 (((GHOST_TUns32)cBnds.getHeight()) != height)) { 00671 NSSize size; 00672 size.width=width; 00673 size.height=height; 00674 [m_window setContentSize:size]; 00675 } 00676 [pool drain]; 00677 return GHOST_kSuccess; 00678 } 00679 00680 00681 GHOST_TWindowState GHOST_WindowCocoa::getState() const 00682 { 00683 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getState(): window invalid") 00684 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00685 GHOST_TWindowState state; 00686 if (m_fullScreen) { 00687 state = GHOST_kWindowStateFullScreen; 00688 } 00689 else if ([m_window isMiniaturized]) { 00690 state = GHOST_kWindowStateMinimized; 00691 } 00692 else if ([m_window isZoomed]) { 00693 state = GHOST_kWindowStateMaximized; 00694 } 00695 else { 00696 state = GHOST_kWindowStateNormal; 00697 } 00698 [pool drain]; 00699 return state; 00700 } 00701 00702 00703 void GHOST_WindowCocoa::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const 00704 { 00705 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::screenToClient(): window invalid") 00706 00707 screenToClientIntern(inX, inY, outX, outY); 00708 00709 /* switch y to match ghost convention */ 00710 GHOST_Rect cBnds; 00711 getClientBounds(cBnds); 00712 outY = (cBnds.getHeight() - 1) - outY; 00713 } 00714 00715 00716 void GHOST_WindowCocoa::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const 00717 { 00718 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::clientToScreen(): window invalid") 00719 00720 /* switch y to match ghost convention */ 00721 GHOST_Rect cBnds; 00722 getClientBounds(cBnds); 00723 inY = (cBnds.getHeight() - 1) - inY; 00724 00725 clientToScreenIntern(inX, inY, outX, outY); 00726 } 00727 00728 void GHOST_WindowCocoa::screenToClientIntern(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const 00729 { 00730 NSPoint screenCoord; 00731 NSPoint baseCoord; 00732 00733 screenCoord.x = inX; 00734 screenCoord.y = inY; 00735 00736 baseCoord = [m_window convertScreenToBase:screenCoord]; 00737 00738 outX = baseCoord.x; 00739 outY = baseCoord.y; 00740 } 00741 00742 void GHOST_WindowCocoa::clientToScreenIntern(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const 00743 { 00744 NSPoint screenCoord; 00745 NSPoint baseCoord; 00746 00747 baseCoord.x = inX; 00748 baseCoord.y = inY; 00749 00750 screenCoord = [m_window convertBaseToScreen:baseCoord]; 00751 00752 outX = screenCoord.x; 00753 outY = screenCoord.y; 00754 } 00755 00756 00757 NSScreen* GHOST_WindowCocoa::getScreen() 00758 { 00759 return [m_window screen]; 00760 } 00761 00762 00768 GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state) 00769 { 00770 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setState(): window invalid") 00771 switch (state) { 00772 case GHOST_kWindowStateMinimized: 00773 [m_window miniaturize:nil]; 00774 break; 00775 case GHOST_kWindowStateMaximized: 00776 [m_window zoom:nil]; 00777 break; 00778 00779 case GHOST_kWindowStateFullScreen: 00780 if (!m_fullScreen) 00781 { 00782 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00783 00784 //This status change needs to be done before Cocoa call to enter fullscreen mode 00785 //to give window delegate hint not to forward its deactivation to ghost wm that doesn't know view/window difference 00786 m_fullScreen = true; 00787 00788 #ifdef MAC_OS_X_VERSION_10_6 00789 //10.6 provides Cocoa functions to autoshow menu bar, and to change a window style 00790 //Hide menu & dock if needed 00791 if ([[m_window screen] isEqual:[[NSScreen screens] objectAtIndex:0]]) 00792 { 00793 [NSApp setPresentationOptions:(NSApplicationPresentationHideDock | NSApplicationPresentationAutoHideMenuBar)]; 00794 } 00795 //Make window borderless and enlarge it 00796 [m_window setStyleMask:NSBorderlessWindowMask]; 00797 [m_window setFrame:[[m_window screen] frame] display:YES]; 00798 [m_window makeFirstResponder:m_openGLView]; 00799 #else 00800 //With 10.5, we need to create a new window to change its style to borderless 00801 //Hide menu & dock if needed 00802 if ([[m_window screen] isEqual:[[NSScreen screens] objectAtIndex:0]]) 00803 { 00804 //Cocoa function in 10.5 does not allow to set the menu bar in auto-show mode [NSMenu setMenuBarVisible:NO]; 00805 //One of the very few 64bit compatible Carbon function 00806 SetSystemUIMode(kUIModeAllHidden,kUIOptionAutoShowMenuBar); 00807 } 00808 //Create a fullscreen borderless window 00809 CocoaWindow *tmpWindow = [[CocoaWindow alloc] 00810 initWithContentRect:[[m_window screen] frame] 00811 styleMask:NSBorderlessWindowMask 00812 backing:NSBackingStoreBuffered 00813 defer:YES]; 00814 //Copy current window parameters 00815 [tmpWindow setTitle:[m_window title]]; 00816 [tmpWindow setRepresentedFilename:[m_window representedFilename]]; 00817 [tmpWindow setReleasedWhenClosed:NO]; 00818 [tmpWindow setAcceptsMouseMovedEvents:YES]; 00819 [tmpWindow setDelegate:[m_window delegate]]; 00820 [tmpWindow setSystemAndWindowCocoa:[m_window systemCocoa] windowCocoa:this]; 00821 [tmpWindow registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, 00822 NSStringPboardType, NSTIFFPboardType, nil]]; 00823 00824 //Assign the openGL view to the new window 00825 [tmpWindow setContentView:m_openGLView]; 00826 00827 //Show the new window 00828 [tmpWindow makeKeyAndOrderFront:m_openGLView]; 00829 //Close and release old window 00830 [m_window setDelegate:nil]; // To avoid the notification of "window closed" event 00831 [m_window close]; 00832 [m_window release]; 00833 m_window = tmpWindow; 00834 #endif 00835 00836 //Tell WM of view new size 00837 m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this); 00838 00839 [pool drain]; 00840 } 00841 break; 00842 case GHOST_kWindowStateNormal: 00843 default: 00844 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00845 if (m_fullScreen) 00846 { 00847 m_fullScreen = false; 00848 00849 //Exit fullscreen 00850 #ifdef MAC_OS_X_VERSION_10_6 00851 //Show again menu & dock if needed 00852 if ([[m_window screen] isEqual:[NSScreen mainScreen]]) 00853 { 00854 [NSApp setPresentationOptions:NSApplicationPresentationDefault]; 00855 } 00856 //Make window normal and resize it 00857 [m_window setStyleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)]; 00858 [m_window setFrame:[[m_window screen] visibleFrame] display:YES]; 00859 //TODO for 10.6 only : window title is forgotten after the style change 00860 [m_window makeFirstResponder:m_openGLView]; 00861 #else 00862 //With 10.5, we need to create a new window to change its style to borderless 00863 //Show menu & dock if needed 00864 if ([[m_window screen] isEqual:[NSScreen mainScreen]]) 00865 { 00866 //Cocoa function in 10.5 does not allow to set the menu bar in auto-show mode [NSMenu setMenuBarVisible:YES]; 00867 SetSystemUIMode(kUIModeNormal, 0); //One of the very few 64bit compatible Carbon function 00868 } 00869 //Create a fullscreen borderless window 00870 CocoaWindow *tmpWindow = [[CocoaWindow alloc] 00871 initWithContentRect:[[m_window screen] frame] 00872 styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask) 00873 backing:NSBackingStoreBuffered 00874 defer:YES]; 00875 //Copy current window parameters 00876 [tmpWindow setTitle:[m_window title]]; 00877 [tmpWindow setRepresentedFilename:[m_window representedFilename]]; 00878 [tmpWindow setReleasedWhenClosed:NO]; 00879 [tmpWindow setAcceptsMouseMovedEvents:YES]; 00880 [tmpWindow setDelegate:[m_window delegate]]; 00881 [tmpWindow setSystemAndWindowCocoa:[m_window systemCocoa] windowCocoa:this]; 00882 [tmpWindow registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, 00883 NSStringPboardType, NSTIFFPboardType, nil]]; 00884 //Forbid to resize the window below the blender defined minimum one 00885 [tmpWindow setContentMinSize:NSMakeSize(320, 240)]; 00886 00887 //Assign the openGL view to the new window 00888 [tmpWindow setContentView:m_openGLView]; 00889 00890 //Show the new window 00891 [tmpWindow makeKeyAndOrderFront:nil]; 00892 //Close and release old window 00893 [m_window setDelegate:nil]; // To avoid the notification of "window closed" event 00894 [m_window close]; 00895 [m_window release]; 00896 m_window = tmpWindow; 00897 #endif 00898 00899 //Tell WM of view new size 00900 m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this); 00901 } 00902 else if ([m_window isMiniaturized]) 00903 [m_window deminiaturize:nil]; 00904 else if ([m_window isZoomed]) 00905 [m_window zoom:nil]; 00906 [pool drain]; 00907 break; 00908 } 00909 00910 return GHOST_kSuccess; 00911 } 00912 00913 GHOST_TSuccess GHOST_WindowCocoa::setModifiedState(bool isUnsavedChanges) 00914 { 00915 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00916 00917 [m_window setDocumentEdited:isUnsavedChanges]; 00918 00919 [pool drain]; 00920 return GHOST_Window::setModifiedState(isUnsavedChanges); 00921 } 00922 00923 00924 00925 GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order) 00926 { 00927 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00928 00929 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setOrder(): window invalid") 00930 if (order == GHOST_kWindowOrderTop) { 00931 [m_window makeKeyAndOrderFront:nil]; 00932 } 00933 else { 00934 NSArray *windowsList; 00935 00936 [m_window orderBack:nil]; 00937 00938 //Check for other blender opened windows and make the frontmost key 00939 windowsList = [NSApp orderedWindows]; 00940 if ([windowsList count]) { 00941 [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil]; 00942 } 00943 } 00944 00945 [pool drain]; 00946 return GHOST_kSuccess; 00947 } 00948 00949 #pragma mark Drawing context 00950 00951 /*#define WAIT_FOR_VSYNC 1*/ 00952 00953 GHOST_TSuccess GHOST_WindowCocoa::swapBuffers() 00954 { 00955 if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { 00956 if (m_openGLContext != nil) { 00957 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00958 [m_openGLContext flushBuffer]; 00959 [pool drain]; 00960 return GHOST_kSuccess; 00961 } 00962 } 00963 return GHOST_kFailure; 00964 } 00965 00966 GHOST_TSuccess GHOST_WindowCocoa::updateDrawingContext() 00967 { 00968 if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { 00969 if (m_openGLContext != nil) { 00970 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00971 [m_openGLContext update]; 00972 [pool drain]; 00973 return GHOST_kSuccess; 00974 } 00975 } 00976 return GHOST_kFailure; 00977 } 00978 00979 GHOST_TSuccess GHOST_WindowCocoa::activateDrawingContext() 00980 { 00981 if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { 00982 if (m_openGLContext != nil) { 00983 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00984 [m_openGLContext makeCurrentContext]; 00985 00986 // Disable AA by default 00987 if (m_numOfAASamples > 0) glDisable(GL_MULTISAMPLE_ARB); 00988 [pool drain]; 00989 return GHOST_kSuccess; 00990 } 00991 } 00992 return GHOST_kFailure; 00993 } 00994 00995 00996 GHOST_TSuccess GHOST_WindowCocoa::installDrawingContext(GHOST_TDrawingContextType type) 00997 { 00998 GHOST_TSuccess success = GHOST_kFailure; 00999 01000 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01001 01002 NSOpenGLPixelFormat *pixelFormat; 01003 NSOpenGLContext *tmpOpenGLContext; 01004 01005 /***** Multithreaded opengl code : uncomment for enabling 01006 CGLContextObj cglCtx; 01007 */ 01008 01009 switch (type) { 01010 case GHOST_kDrawingContextTypeOpenGL: 01011 if (!getValid()) break; 01012 01013 pixelFormat = [m_openGLView pixelFormat]; 01014 tmpOpenGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat 01015 shareContext:s_firstOpenGLcontext]; 01016 if (tmpOpenGLContext == nil) { 01017 success = GHOST_kFailure; 01018 break; 01019 } 01020 01021 //Switch openGL to multhreaded mode 01022 /******* Multithreaded opengl code : uncomment for enabling 01023 cglCtx = (CGLContextObj)[tmpOpenGLContext CGLContextObj]; 01024 if (CGLEnable(cglCtx, kCGLCEMPEngine) == kCGLNoError) 01025 printf("\nSwitched openGL to multithreaded mode"); 01026 */ 01027 01028 if (!s_firstOpenGLcontext) s_firstOpenGLcontext = tmpOpenGLContext; 01029 #ifdef WAIT_FOR_VSYNC 01030 { 01031 GLint swapInt = 1; 01032 /* wait for vsync, to avoid tearing artifacts */ 01033 [tmpOpenGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; 01034 } 01035 #endif 01036 [m_openGLView setOpenGLContext:tmpOpenGLContext]; 01037 [tmpOpenGLContext setView:m_openGLView]; 01038 01039 m_openGLContext = tmpOpenGLContext; 01040 break; 01041 01042 case GHOST_kDrawingContextTypeNone: 01043 success = GHOST_kSuccess; 01044 break; 01045 01046 default: 01047 break; 01048 } 01049 [pool drain]; 01050 return success; 01051 } 01052 01053 01054 GHOST_TSuccess GHOST_WindowCocoa::removeDrawingContext() 01055 { 01056 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01057 switch (m_drawingContextType) { 01058 case GHOST_kDrawingContextTypeOpenGL: 01059 if (m_openGLContext) 01060 { 01061 [m_openGLView clearGLContext]; 01062 if (s_firstOpenGLcontext == m_openGLContext) s_firstOpenGLcontext = nil; 01063 m_openGLContext = nil; 01064 } 01065 [pool drain]; 01066 return GHOST_kSuccess; 01067 case GHOST_kDrawingContextTypeNone: 01068 [pool drain]; 01069 return GHOST_kSuccess; 01070 break; 01071 default: 01072 [pool drain]; 01073 return GHOST_kFailure; 01074 } 01075 } 01076 01077 01078 GHOST_TSuccess GHOST_WindowCocoa::invalidate() 01079 { 01080 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::invalidate(): window invalid") 01081 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01082 [m_openGLView setNeedsDisplay:YES]; 01083 [pool drain]; 01084 return GHOST_kSuccess; 01085 } 01086 01087 #pragma mark Progress bar 01088 01089 GHOST_TSuccess GHOST_WindowCocoa::setProgressBar(float progress) 01090 { 01091 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01092 01093 if ((progress >=0.0) && (progress <=1.0)) { 01094 NSImage* dockIcon = [[NSImage alloc] initWithSize:NSMakeSize(128,128)]; 01095 01096 [dockIcon lockFocus]; 01097 NSRect progressBox = {{4, 4}, {120, 16}}; 01098 01099 [[NSImage imageNamed:@"NSApplicationIcon"] dissolveToPoint:NSZeroPoint fraction:1.0]; 01100 01101 // Track & Outline 01102 [[NSColor blackColor] setFill]; 01103 NSRectFill(progressBox); 01104 01105 [[NSColor whiteColor] set]; 01106 NSFrameRect(progressBox); 01107 01108 // Progress fill 01109 progressBox = NSInsetRect(progressBox, 1, 1); 01110 [[NSColor knobColor] setFill]; 01111 progressBox.size.width = progressBox.size.width * progress; 01112 NSRectFill(progressBox); 01113 01114 [dockIcon unlockFocus]; 01115 01116 [NSApp setApplicationIconImage:dockIcon]; 01117 [dockIcon release]; 01118 01119 m_progressBarVisible = true; 01120 } 01121 01122 [pool drain]; 01123 return GHOST_kSuccess; 01124 } 01125 01126 01127 GHOST_TSuccess GHOST_WindowCocoa::endProgressBar() 01128 { 01129 if (!m_progressBarVisible) return GHOST_kFailure; 01130 m_progressBarVisible = false; 01131 01132 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01133 01134 NSImage* dockIcon = [[NSImage alloc] initWithSize:NSMakeSize(128,128)]; 01135 [dockIcon lockFocus]; 01136 [[NSImage imageNamed:@"NSApplicationIcon"] dissolveToPoint:NSZeroPoint fraction:1.0]; 01137 [dockIcon unlockFocus]; 01138 [NSApp setApplicationIconImage:dockIcon]; 01139 [dockIcon release]; 01140 01141 [pool drain]; 01142 return GHOST_kSuccess; 01143 } 01144 01145 01146 01147 #pragma mark Cursor handling 01148 01149 void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) const 01150 { 01151 static bool systemCursorVisible = true; 01152 01153 NSCursor *tmpCursor =nil; 01154 01155 if (visible != systemCursorVisible) { 01156 if (visible) { 01157 [NSCursor unhide]; 01158 systemCursorVisible = true; 01159 } 01160 else { 01161 [NSCursor hide]; 01162 systemCursorVisible = false; 01163 } 01164 } 01165 01166 if (cursor == GHOST_kStandardCursorCustom && m_customCursor) { 01167 tmpCursor = m_customCursor; 01168 } else { 01169 switch (cursor) { 01170 case GHOST_kStandardCursorDestroy: 01171 tmpCursor = [NSCursor disappearingItemCursor]; 01172 break; 01173 case GHOST_kStandardCursorText: 01174 tmpCursor = [NSCursor IBeamCursor]; 01175 break; 01176 case GHOST_kStandardCursorCrosshair: 01177 tmpCursor = [NSCursor crosshairCursor]; 01178 break; 01179 case GHOST_kStandardCursorUpDown: 01180 tmpCursor = [NSCursor resizeUpDownCursor]; 01181 break; 01182 case GHOST_kStandardCursorLeftRight: 01183 tmpCursor = [NSCursor resizeLeftRightCursor]; 01184 break; 01185 case GHOST_kStandardCursorTopSide: 01186 tmpCursor = [NSCursor resizeUpCursor]; 01187 break; 01188 case GHOST_kStandardCursorBottomSide: 01189 tmpCursor = [NSCursor resizeDownCursor]; 01190 break; 01191 case GHOST_kStandardCursorLeftSide: 01192 tmpCursor = [NSCursor resizeLeftCursor]; 01193 break; 01194 case GHOST_kStandardCursorRightSide: 01195 tmpCursor = [NSCursor resizeRightCursor]; 01196 break; 01197 case GHOST_kStandardCursorRightArrow: 01198 case GHOST_kStandardCursorInfo: 01199 case GHOST_kStandardCursorLeftArrow: 01200 case GHOST_kStandardCursorHelp: 01201 case GHOST_kStandardCursorCycle: 01202 case GHOST_kStandardCursorSpray: 01203 case GHOST_kStandardCursorWait: 01204 case GHOST_kStandardCursorTopLeftCorner: 01205 case GHOST_kStandardCursorTopRightCorner: 01206 case GHOST_kStandardCursorBottomRightCorner: 01207 case GHOST_kStandardCursorBottomLeftCorner: 01208 case GHOST_kStandardCursorCopy: 01209 case GHOST_kStandardCursorDefault: 01210 default: 01211 tmpCursor = [NSCursor arrowCursor]; 01212 break; 01213 }; 01214 } 01215 [tmpCursor set]; 01216 } 01217 01218 01219 01220 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible) 01221 { 01222 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; 01223 01224 if ([m_window isVisible]) { 01225 loadCursor(visible, getCursorShape()); 01226 } 01227 01228 [pool drain]; 01229 return GHOST_kSuccess; 01230 } 01231 01232 01233 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode) 01234 { 01235 GHOST_TSuccess err = GHOST_kSuccess; 01236 01237 if (mode != GHOST_kGrabDisable) 01238 { 01239 //No need to perform grab without warp as it is always on in OS X 01240 if(mode != GHOST_kGrabNormal) { 01241 GHOST_TInt32 x_old,y_old; 01242 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01243 01244 m_systemCocoa->getCursorPosition(x_old,y_old); 01245 screenToClientIntern(x_old, y_old, m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]); 01246 //Warp position is stored in client (window base) coordinates 01247 setCursorGrabAccum(0, 0); 01248 01249 if(mode == GHOST_kGrabHide) { 01250 setWindowCursorVisibility(false); 01251 } 01252 01253 //Make window key if it wasn't to get the mouse move events 01254 [m_window makeKeyWindow]; 01255 01256 //Dissociate cursor position even for warp mode, to allow mouse acceleration to work even when warping the cursor 01257 err = CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; 01258 01259 [pool drain]; 01260 } 01261 } 01262 else { 01263 if(m_cursorGrab==GHOST_kGrabHide) 01264 { 01265 //No need to set again cursor position, as it has not changed for Cocoa 01266 setWindowCursorVisibility(true); 01267 } 01268 01269 err = CGAssociateMouseAndMouseCursorPosition(true) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; 01270 /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */ 01271 setCursorGrabAccum(0, 0); 01272 m_cursorGrabBounds.m_l= m_cursorGrabBounds.m_r= -1; /* disable */ 01273 } 01274 return err; 01275 } 01276 01277 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape) 01278 { 01279 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01280 01281 if (m_customCursor) { 01282 [m_customCursor release]; 01283 m_customCursor = nil; 01284 } 01285 01286 if ([m_window isVisible]) { 01287 loadCursor(getCursorVisibility(), shape); 01288 } 01289 01290 [pool drain]; 01291 return GHOST_kSuccess; 01292 } 01293 01306 static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt) 01307 { 01308 shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA); 01309 shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC); 01310 shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0); 01311 shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00); 01312 return shrt; 01313 } 01314 01315 GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, 01316 int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color) 01317 { 01318 int y,nbUns16; 01319 NSPoint hotSpotPoint; 01320 NSBitmapImageRep *cursorImageRep; 01321 NSImage *cursorImage; 01322 NSSize imSize; 01323 GHOST_TUns16 *cursorBitmap; 01324 01325 01326 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01327 01328 if (m_customCursor) { 01329 [m_customCursor release]; 01330 m_customCursor = nil; 01331 } 01332 01333 01334 cursorImageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil 01335 pixelsWide:sizex 01336 pixelsHigh:sizey 01337 bitsPerSample:1 01338 samplesPerPixel:2 01339 hasAlpha:YES 01340 isPlanar:YES 01341 colorSpaceName:NSDeviceWhiteColorSpace 01342 bytesPerRow:(sizex/8 + (sizex%8 >0 ?1:0)) 01343 bitsPerPixel:1]; 01344 01345 01346 cursorBitmap = (GHOST_TUns16*)[cursorImageRep bitmapData]; 01347 nbUns16 = [cursorImageRep bytesPerPlane]/2; 01348 01349 for (y=0; y<nbUns16; y++) { 01350 #if !defined(__LITTLE_ENDIAN__) 01351 cursorBitmap[y] = ~uns16ReverseBits((bitmap[2*y]<<0) | (bitmap[2*y+1]<<8)); 01352 cursorBitmap[nbUns16+y] = uns16ReverseBits((mask[2*y]<<0) | (mask[2*y+1]<<8)); 01353 #else 01354 cursorBitmap[y] = ~uns16ReverseBits((bitmap[2*y+1]<<0) | (bitmap[2*y]<<8)); 01355 cursorBitmap[nbUns16+y] = uns16ReverseBits((mask[2*y+1]<<0) | (mask[2*y]<<8)); 01356 #endif 01357 01358 } 01359 01360 01361 imSize.width = sizex; 01362 imSize.height= sizey; 01363 cursorImage = [[NSImage alloc] initWithSize:imSize]; 01364 [cursorImage addRepresentation:cursorImageRep]; 01365 01366 hotSpotPoint.x = hotX; 01367 hotSpotPoint.y = hotY; 01368 01369 //foreground and background color parameter is not handled for now (10.6) 01370 m_customCursor = [[NSCursor alloc] initWithImage:cursorImage 01371 hotSpot:hotSpotPoint]; 01372 01373 [cursorImageRep release]; 01374 [cursorImage release]; 01375 01376 if ([m_window isVisible]) { 01377 loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom); 01378 } 01379 [pool drain]; 01380 return GHOST_kSuccess; 01381 } 01382 01383 GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], 01384 GHOST_TUns8 mask[16][2], int hotX, int hotY) 01385 { 01386 return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*) mask, 16, 16, hotX, hotY, 0, 1); 01387 }