Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): Maarten Gribnau 05/2001 00024 Damien Plisson 10/2009 00025 * 00026 * ***** END GPL LICENSE BLOCK ***** 00027 */ 00028 00029 #include <Cocoa/Cocoa.h> 00030 00031 #ifndef MAC_OS_X_VERSION_10_6 00032 //Use of the SetSystemUIMode function (64bit compatible) 00033 #include <Carbon/Carbon.h> 00034 #endif 00035 00036 #include <OpenGL/gl.h> 00037 #include <OpenGL/CGLRenderers.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 <NSTextInput> 00243 { 00244 GHOST_SystemCocoa *systemCocoa; 00245 GHOST_WindowCocoa *associatedWindow; 00246 00247 bool composing; 00248 NSString *composing_text; 00249 } 00250 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa; 00251 @end 00252 @implementation CocoaOpenGLView 00253 00254 - (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa 00255 { 00256 systemCocoa = sysCocoa; 00257 associatedWindow = winCocoa; 00258 00259 composing = false; 00260 composing_text = nil; 00261 } 00262 00263 - (BOOL)acceptsFirstResponder 00264 { 00265 return YES; 00266 } 00267 00268 // The trick to prevent Cocoa from complaining (beeping) 00269 - (void)keyDown:(NSEvent *)event 00270 { 00271 // Start or continue composing? 00272 if([[event characters] length] == 0 || 00273 [[event charactersIgnoringModifiers] length] == 0 || 00274 composing) { 00275 composing = YES; 00276 00277 // interpret event to call insertText 00278 NSMutableArray *events; 00279 events = [[NSMutableArray alloc] initWithCapacity:1]; 00280 [events addObject:event]; 00281 [self interpretKeyEvents:events]; // calls insertText 00282 [events removeObject:event]; 00283 [events release]; 00284 00285 return; 00286 } 00287 } 00288 00289 #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 00290 //Cmd+key are handled differently before 10.5 00291 - (BOOL)performKeyEquivalent:(NSEvent *)theEvent 00292 { 00293 NSString *chars = [theEvent charactersIgnoringModifiers]; 00294 00295 if ([chars length] <1) 00296 return NO; 00297 00298 //Let cocoa handle menu shortcuts 00299 switch ([chars characterAtIndex:0]) { 00300 case 'q': 00301 case 'w': 00302 case 'h': 00303 case 'm': 00304 case '<': 00305 case '>': 00306 case '~': 00307 case '`': 00308 return NO; 00309 default: 00310 return YES; 00311 } 00312 } 00313 #endif 00314 00315 - (BOOL)isOpaque 00316 { 00317 return YES; 00318 } 00319 00320 - (void) drawRect:(NSRect)rect 00321 { 00322 if ([self inLiveResize]) 00323 { 00324 //Don't redraw while in live resize 00325 } 00326 else 00327 { 00328 [super drawRect:rect]; 00329 systemCocoa->handleWindowEvent(GHOST_kEventWindowUpdate, associatedWindow); 00330 } 00331 } 00332 00333 // Text input 00334 00335 - (void)composing_free 00336 { 00337 composing = NO; 00338 00339 if(composing_text) { 00340 [composing_text release]; 00341 composing_text = nil; 00342 } 00343 } 00344 00345 - (void)insertText:(id)chars 00346 { 00347 [self composing_free]; 00348 } 00349 00350 - (void)setMarkedText:(id)chars selectedRange:(NSRange)range 00351 { 00352 [self composing_free]; 00353 if([chars length] == 0) 00354 return; 00355 00356 // start composing 00357 composing = YES; 00358 composing_text = [chars copy]; 00359 00360 // if empty, cancel 00361 if([composing_text length] == 0) 00362 [self composing_free]; 00363 } 00364 00365 - (void)unmarkText 00366 { 00367 [self composing_free]; 00368 } 00369 00370 - (BOOL)hasMarkedText 00371 { 00372 return (composing)? YES: NO; 00373 } 00374 00375 - (void)doCommandBySelector:(SEL)selector 00376 { 00377 } 00378 00379 - (BOOL)isComposing 00380 { 00381 return composing; 00382 } 00383 00384 - (NSInteger)conversationIdentifier 00385 { 00386 return (NSInteger)self; 00387 } 00388 00389 - (NSAttributedString *)attributedSubstringFromRange:(NSRange)range 00390 { 00391 return [NSAttributedString new]; // XXX does this leak? 00392 } 00393 00394 - (NSRange)markedRange 00395 { 00396 unsigned int length = (composing_text)? [composing_text length]: 0; 00397 00398 if(composing) 00399 return NSMakeRange(0, length); 00400 00401 return NSMakeRange(NSNotFound, 0); 00402 } 00403 00404 - (NSRange)selectedRange 00405 { 00406 unsigned int length = (composing_text)? [composing_text length]: 0; 00407 return NSMakeRange(0, length); 00408 } 00409 00410 - (NSRect)firstRectForCharacterRange:(NSRange)range 00411 { 00412 return NSZeroRect; 00413 } 00414 00415 - (NSUInteger)characterIndexForPoint:(NSPoint)point 00416 { 00417 return NSNotFound; 00418 } 00419 00420 - (NSArray*)validAttributesForMarkedText 00421 { 00422 return [NSArray array]; // XXX does this leak? 00423 } 00424 00425 @end 00426 00427 #pragma mark initialization / finalization 00428 00429 NSOpenGLContext* GHOST_WindowCocoa::s_firstOpenGLcontext = nil; 00430 00431 GHOST_WindowCocoa::GHOST_WindowCocoa( 00432 GHOST_SystemCocoa *systemCocoa, 00433 const STR_String& title, 00434 GHOST_TInt32 left, 00435 GHOST_TInt32 bottom, 00436 GHOST_TUns32 width, 00437 GHOST_TUns32 height, 00438 GHOST_TWindowState state, 00439 GHOST_TDrawingContextType type, 00440 const bool stereoVisual, const GHOST_TUns16 numOfAASamples 00441 ) : 00442 GHOST_Window(width, height, state, GHOST_kDrawingContextTypeNone, stereoVisual, numOfAASamples), 00443 m_customCursor(0) 00444 { 00445 NSOpenGLPixelFormatAttribute pixelFormatAttrsWindow[40]; 00446 NSOpenGLPixelFormat *pixelFormat = nil; 00447 int i; 00448 00449 m_systemCocoa = systemCocoa; 00450 m_fullScreen = false; 00451 00452 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00453 00454 //Creates the window 00455 NSRect rect; 00456 NSSize minSize; 00457 00458 rect.origin.x = left; 00459 rect.origin.y = bottom; 00460 rect.size.width = width; 00461 rect.size.height = height; 00462 00463 m_window = [[CocoaWindow alloc] initWithContentRect:rect 00464 styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask 00465 backing:NSBackingStoreBuffered defer:NO]; 00466 if (m_window == nil) { 00467 [pool drain]; 00468 return; 00469 } 00470 00471 [m_window setSystemAndWindowCocoa:systemCocoa windowCocoa:this]; 00472 00473 //Forbid to resize the window below the blender defined minimum one 00474 minSize.width = 320; 00475 minSize.height = 240; 00476 [m_window setContentMinSize:minSize]; 00477 00478 setTitle(title); 00479 00480 00481 // Pixel Format Attributes for the windowed NSOpenGLContext 00482 i=0; 00483 pixelFormatAttrsWindow[i++] = NSOpenGLPFADoubleBuffer; 00484 00485 // Guarantees the back buffer contents to be valid after a call to NSOpenGLContext object’s flushBuffer 00486 // needed for 'Draw Overlap' drawing method 00487 pixelFormatAttrsWindow[i++] = NSOpenGLPFABackingStore; 00488 00489 // Force software OpenGL, for debugging 00490 if(getenv("BLENDER_SOFTWAREGL")) { 00491 pixelFormatAttrsWindow[i++] = NSOpenGLPFARendererID; 00492 pixelFormatAttrsWindow[i++] = kCGLRendererGenericID; 00493 } 00494 else 00495 pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccelerated; 00496 00497 //pixelFormatAttrsWindow[i++] = NSOpenGLPFAAllowOfflineRenderers,; // Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway 00498 00499 pixelFormatAttrsWindow[i++] = NSOpenGLPFADepthSize; 00500 pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32; 00501 00502 00503 if (stereoVisual) pixelFormatAttrsWindow[i++] = NSOpenGLPFAStereo; 00504 00505 if (numOfAASamples>0) { 00506 // Multisample anti-aliasing 00507 pixelFormatAttrsWindow[i++] = NSOpenGLPFAMultisample; 00508 00509 pixelFormatAttrsWindow[i++] = NSOpenGLPFASampleBuffers; 00510 pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 1; 00511 00512 pixelFormatAttrsWindow[i++] = NSOpenGLPFASamples; 00513 pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) numOfAASamples; 00514 00515 pixelFormatAttrsWindow[i++] = NSOpenGLPFANoRecovery; 00516 } 00517 00518 pixelFormatAttrsWindow[i] = (NSOpenGLPixelFormatAttribute) 0; 00519 00520 pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttrsWindow]; 00521 00522 00523 //Fall back to no multisampling if Antialiasing init failed 00524 if (pixelFormat == nil) { 00525 i=0; 00526 pixelFormatAttrsWindow[i++] = NSOpenGLPFADoubleBuffer; 00527 00528 // Guarantees the back buffer contents to be valid after a call to NSOpenGLContext object’s flushBuffer 00529 // needed for 'Draw Overlap' drawing method 00530 pixelFormatAttrsWindow[i++] = NSOpenGLPFABackingStore; 00531 00532 // Force software OpenGL, for debugging 00533 if(getenv("BLENDER_SOFTWAREGL")) { 00534 pixelFormatAttrsWindow[i++] = NSOpenGLPFARendererID; 00535 pixelFormatAttrsWindow[i++] = kCGLRendererGenericID; 00536 } 00537 else 00538 pixelFormatAttrsWindow[i++] = NSOpenGLPFAAccelerated; 00539 00540 //pixelFormatAttrsWindow[i++] = NSOpenGLPFAAllowOfflineRenderers,; // Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway 00541 00542 pixelFormatAttrsWindow[i++] = NSOpenGLPFADepthSize; 00543 pixelFormatAttrsWindow[i++] = (NSOpenGLPixelFormatAttribute) 32; 00544 00545 if (stereoVisual) pixelFormatAttrsWindow[i++] = NSOpenGLPFAStereo; 00546 00547 pixelFormatAttrsWindow[i] = (NSOpenGLPixelFormatAttribute) 0; 00548 00549 pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttrsWindow]; 00550 00551 } 00552 00553 if (numOfAASamples>0) { //Set m_numOfAASamples to the actual value 00554 GLint gli; 00555 [pixelFormat getValues:&gli forAttribute:NSOpenGLPFASamples forVirtualScreen:0]; 00556 if (m_numOfAASamples != (GHOST_TUns16)gli) { 00557 m_numOfAASamples = (GHOST_TUns16)gli; 00558 printf("GHOST_Window could be created with anti-aliasing of only %i samples\n",m_numOfAASamples); 00559 } 00560 } 00561 00562 //Creates the OpenGL View inside the window 00563 m_openGLView = [[CocoaOpenGLView alloc] initWithFrame:rect 00564 pixelFormat:pixelFormat]; 00565 00566 [m_openGLView setSystemAndWindowCocoa:systemCocoa windowCocoa:this]; 00567 00568 [pixelFormat release]; 00569 00570 m_openGLContext = [m_openGLView openGLContext]; //This context will be replaced by the proper one just after 00571 00572 [m_window setContentView:m_openGLView]; 00573 [m_window setInitialFirstResponder:m_openGLView]; 00574 00575 [m_window setReleasedWhenClosed:NO]; //To avoid bad pointer exception in case of user closing the window 00576 00577 [m_window makeKeyAndOrderFront:nil]; 00578 00579 setDrawingContextType(type); 00580 updateDrawingContext(); 00581 activateDrawingContext(); 00582 00583 m_tablet.Active = GHOST_kTabletModeNone; 00584 00585 CocoaWindowDelegate *windowDelegate = [[CocoaWindowDelegate alloc] init]; 00586 [windowDelegate setSystemAndWindowCocoa:systemCocoa windowCocoa:this]; 00587 [m_window setDelegate:windowDelegate]; 00588 00589 [m_window setAcceptsMouseMovedEvents:YES]; 00590 00591 [m_window registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, 00592 NSStringPboardType, NSTIFFPboardType, nil]]; 00593 00594 if (state == GHOST_kWindowStateFullScreen) 00595 setState(GHOST_kWindowStateFullScreen); 00596 00597 [pool drain]; 00598 } 00599 00600 00601 GHOST_WindowCocoa::~GHOST_WindowCocoa() 00602 { 00603 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00604 00605 if (m_customCursor) { 00606 [m_customCursor release]; 00607 m_customCursor = nil; 00608 } 00609 00610 [m_openGLView release]; 00611 00612 if (m_window) { 00613 [m_window close]; 00614 [[m_window delegate] release]; 00615 [m_window release]; 00616 m_window = nil; 00617 } 00618 00619 //Check for other blender opened windows and make the frontmost key 00620 NSArray *windowsList = [NSApp orderedWindows]; 00621 if ([windowsList count]) { 00622 [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil]; 00623 } 00624 [pool drain]; 00625 } 00626 00627 #pragma mark accessors 00628 00629 bool GHOST_WindowCocoa::getValid() const 00630 { 00631 return (m_window != 0); 00632 } 00633 00634 void* GHOST_WindowCocoa::getOSWindow() const 00635 { 00636 return (void*)m_window; 00637 } 00638 00639 void GHOST_WindowCocoa::setTitle(const STR_String& title) 00640 { 00641 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setTitle(): window invalid") 00642 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00643 00644 NSString *windowTitle = [[NSString alloc] initWithCString:title encoding:NSUTF8StringEncoding]; 00645 00646 //Set associated file if applicable 00647 if (windowTitle && [windowTitle hasPrefix:@"Blender"]) 00648 { 00649 NSRange fileStrRange; 00650 NSString *associatedFileName; 00651 int len; 00652 00653 fileStrRange.location = [windowTitle rangeOfString:@"["].location+1; 00654 len = [windowTitle rangeOfString:@"]"].location - fileStrRange.location; 00655 00656 if (len >0) 00657 { 00658 fileStrRange.length = len; 00659 associatedFileName = [windowTitle substringWithRange:fileStrRange]; 00660 [m_window setTitle:[associatedFileName lastPathComponent]]; 00661 00662 //Blender used file open/save functions converte file names into legal URL ones 00663 associatedFileName = [associatedFileName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 00664 @try { 00665 [m_window setRepresentedFilename:associatedFileName]; 00666 } 00667 @catch (NSException * e) { 00668 printf("\nInvalid file path given in window title"); 00669 } 00670 } 00671 else { 00672 [m_window setTitle:windowTitle]; 00673 [m_window setRepresentedFilename:@""]; 00674 } 00675 00676 } else { 00677 [m_window setTitle:windowTitle]; 00678 [m_window setRepresentedFilename:@""]; 00679 } 00680 00681 00682 [windowTitle release]; 00683 [pool drain]; 00684 } 00685 00686 00687 void GHOST_WindowCocoa::getTitle(STR_String& title) const 00688 { 00689 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getTitle(): window invalid") 00690 00691 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00692 00693 NSString *windowTitle = [m_window title]; 00694 00695 if (windowTitle != nil) { 00696 title = [windowTitle UTF8String]; 00697 } 00698 00699 [pool drain]; 00700 } 00701 00702 00703 void GHOST_WindowCocoa::getWindowBounds(GHOST_Rect& bounds) const 00704 { 00705 NSRect rect; 00706 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getWindowBounds(): window invalid") 00707 00708 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00709 00710 NSRect screenSize = [[m_window screen] visibleFrame]; 00711 00712 rect = [m_window frame]; 00713 00714 bounds.m_b = screenSize.size.height - (rect.origin.y -screenSize.origin.y); 00715 bounds.m_l = rect.origin.x -screenSize.origin.x; 00716 bounds.m_r = rect.origin.x-screenSize.origin.x + rect.size.width; 00717 bounds.m_t = screenSize.size.height - (rect.origin.y + rect.size.height -screenSize.origin.y); 00718 00719 [pool drain]; 00720 } 00721 00722 00723 void GHOST_WindowCocoa::getClientBounds(GHOST_Rect& bounds) const 00724 { 00725 NSRect rect; 00726 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getClientBounds(): window invalid") 00727 00728 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00729 00730 if (!m_fullScreen) 00731 { 00732 NSRect screenSize = [[m_window screen] visibleFrame]; 00733 00734 //Max window contents as screen size (excluding title bar...) 00735 NSRect contentRect = [CocoaWindow contentRectForFrameRect:screenSize 00736 styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)]; 00737 00738 rect = [m_window contentRectForFrameRect:[m_window frame]]; 00739 00740 bounds.m_b = contentRect.size.height - (rect.origin.y -contentRect.origin.y); 00741 bounds.m_l = rect.origin.x -contentRect.origin.x; 00742 bounds.m_r = rect.origin.x-contentRect.origin.x + rect.size.width; 00743 bounds.m_t = contentRect.size.height - (rect.origin.y + rect.size.height -contentRect.origin.y); 00744 } 00745 else { 00746 NSRect screenSize = [[m_window screen] frame]; 00747 00748 bounds.m_b = screenSize.origin.y + screenSize.size.height; 00749 bounds.m_l = screenSize.origin.x; 00750 bounds.m_r = screenSize.origin.x + screenSize.size.width; 00751 bounds.m_t = screenSize.origin.y; 00752 } 00753 [pool drain]; 00754 } 00755 00756 00757 GHOST_TSuccess GHOST_WindowCocoa::setClientWidth(GHOST_TUns32 width) 00758 { 00759 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientWidth(): window invalid") 00760 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00761 GHOST_Rect cBnds, wBnds; 00762 getClientBounds(cBnds); 00763 if (((GHOST_TUns32)cBnds.getWidth()) != width) { 00764 NSSize size; 00765 size.width=width; 00766 size.height=cBnds.getHeight(); 00767 [m_window setContentSize:size]; 00768 } 00769 [pool drain]; 00770 return GHOST_kSuccess; 00771 } 00772 00773 00774 GHOST_TSuccess GHOST_WindowCocoa::setClientHeight(GHOST_TUns32 height) 00775 { 00776 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientHeight(): window invalid") 00777 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00778 GHOST_Rect cBnds, wBnds; 00779 getClientBounds(cBnds); 00780 if (((GHOST_TUns32)cBnds.getHeight()) != height) { 00781 NSSize size; 00782 size.width=cBnds.getWidth(); 00783 size.height=height; 00784 [m_window setContentSize:size]; 00785 } 00786 [pool drain]; 00787 return GHOST_kSuccess; 00788 } 00789 00790 00791 GHOST_TSuccess GHOST_WindowCocoa::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) 00792 { 00793 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientSize(): window invalid") 00794 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00795 GHOST_Rect cBnds, wBnds; 00796 getClientBounds(cBnds); 00797 if ((((GHOST_TUns32)cBnds.getWidth()) != width) || 00798 (((GHOST_TUns32)cBnds.getHeight()) != height)) { 00799 NSSize size; 00800 size.width=width; 00801 size.height=height; 00802 [m_window setContentSize:size]; 00803 } 00804 [pool drain]; 00805 return GHOST_kSuccess; 00806 } 00807 00808 00809 GHOST_TWindowState GHOST_WindowCocoa::getState() const 00810 { 00811 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getState(): window invalid") 00812 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00813 GHOST_TWindowState state; 00814 if (m_fullScreen) { 00815 state = GHOST_kWindowStateFullScreen; 00816 } 00817 else if ([m_window isMiniaturized]) { 00818 state = GHOST_kWindowStateMinimized; 00819 } 00820 else if ([m_window isZoomed]) { 00821 state = GHOST_kWindowStateMaximized; 00822 } 00823 else { 00824 state = GHOST_kWindowStateNormal; 00825 } 00826 [pool drain]; 00827 return state; 00828 } 00829 00830 00831 void GHOST_WindowCocoa::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const 00832 { 00833 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::screenToClient(): window invalid") 00834 00835 screenToClientIntern(inX, inY, outX, outY); 00836 00837 /* switch y to match ghost convention */ 00838 GHOST_Rect cBnds; 00839 getClientBounds(cBnds); 00840 outY = (cBnds.getHeight() - 1) - outY; 00841 } 00842 00843 00844 void GHOST_WindowCocoa::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const 00845 { 00846 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::clientToScreen(): window invalid") 00847 00848 /* switch y to match ghost convention */ 00849 GHOST_Rect cBnds; 00850 getClientBounds(cBnds); 00851 inY = (cBnds.getHeight() - 1) - inY; 00852 00853 clientToScreenIntern(inX, inY, outX, outY); 00854 } 00855 00856 void GHOST_WindowCocoa::screenToClientIntern(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const 00857 { 00858 NSPoint screenCoord; 00859 NSPoint baseCoord; 00860 00861 screenCoord.x = inX; 00862 screenCoord.y = inY; 00863 00864 baseCoord = [m_window convertScreenToBase:screenCoord]; 00865 00866 outX = baseCoord.x; 00867 outY = baseCoord.y; 00868 } 00869 00870 void GHOST_WindowCocoa::clientToScreenIntern(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const 00871 { 00872 NSPoint screenCoord; 00873 NSPoint baseCoord; 00874 00875 baseCoord.x = inX; 00876 baseCoord.y = inY; 00877 00878 screenCoord = [m_window convertBaseToScreen:baseCoord]; 00879 00880 outX = screenCoord.x; 00881 outY = screenCoord.y; 00882 } 00883 00884 00885 NSScreen* GHOST_WindowCocoa::getScreen() 00886 { 00887 return [m_window screen]; 00888 } 00889 00890 00896 GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state) 00897 { 00898 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setState(): window invalid") 00899 switch (state) { 00900 case GHOST_kWindowStateMinimized: 00901 [m_window miniaturize:nil]; 00902 break; 00903 case GHOST_kWindowStateMaximized: 00904 [m_window zoom:nil]; 00905 break; 00906 00907 case GHOST_kWindowStateFullScreen: 00908 if (!m_fullScreen) 00909 { 00910 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00911 00912 //This status change needs to be done before Cocoa call to enter fullscreen mode 00913 //to give window delegate hint not to forward its deactivation to ghost wm that doesn't know view/window difference 00914 m_fullScreen = true; 00915 00916 #ifdef MAC_OS_X_VERSION_10_6 00917 //10.6 provides Cocoa functions to autoshow menu bar, and to change a window style 00918 //Hide menu & dock if needed 00919 if ([[m_window screen] isEqual:[[NSScreen screens] objectAtIndex:0]]) 00920 { 00921 [NSApp setPresentationOptions:(NSApplicationPresentationHideDock | NSApplicationPresentationAutoHideMenuBar)]; 00922 } 00923 //Make window borderless and enlarge it 00924 [m_window setStyleMask:NSBorderlessWindowMask]; 00925 [m_window setFrame:[[m_window screen] frame] display:YES]; 00926 [m_window makeFirstResponder:m_openGLView]; 00927 #else 00928 //With 10.5, we need to create a new window to change its style to borderless 00929 //Hide menu & dock if needed 00930 if ([[m_window screen] isEqual:[[NSScreen screens] objectAtIndex:0]]) 00931 { 00932 //Cocoa function in 10.5 does not allow to set the menu bar in auto-show mode [NSMenu setMenuBarVisible:NO]; 00933 //One of the very few 64bit compatible Carbon function 00934 SetSystemUIMode(kUIModeAllHidden,kUIOptionAutoShowMenuBar); 00935 } 00936 //Create a fullscreen borderless window 00937 CocoaWindow *tmpWindow = [[CocoaWindow alloc] 00938 initWithContentRect:[[m_window screen] frame] 00939 styleMask:NSBorderlessWindowMask 00940 backing:NSBackingStoreBuffered 00941 defer:YES]; 00942 //Copy current window parameters 00943 [tmpWindow setTitle:[m_window title]]; 00944 [tmpWindow setRepresentedFilename:[m_window representedFilename]]; 00945 [tmpWindow setReleasedWhenClosed:NO]; 00946 [tmpWindow setAcceptsMouseMovedEvents:YES]; 00947 [tmpWindow setDelegate:[m_window delegate]]; 00948 [tmpWindow setSystemAndWindowCocoa:[m_window systemCocoa] windowCocoa:this]; 00949 [tmpWindow registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, 00950 NSStringPboardType, NSTIFFPboardType, nil]]; 00951 00952 //Assign the openGL view to the new window 00953 [tmpWindow setContentView:m_openGLView]; 00954 00955 //Show the new window 00956 [tmpWindow makeKeyAndOrderFront:m_openGLView]; 00957 //Close and release old window 00958 [m_window setDelegate:nil]; // To avoid the notification of "window closed" event 00959 [m_window close]; 00960 [m_window release]; 00961 m_window = tmpWindow; 00962 #endif 00963 00964 //Tell WM of view new size 00965 m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this); 00966 00967 [pool drain]; 00968 } 00969 break; 00970 case GHOST_kWindowStateNormal: 00971 default: 00972 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 00973 if (m_fullScreen) 00974 { 00975 m_fullScreen = false; 00976 00977 //Exit fullscreen 00978 #ifdef MAC_OS_X_VERSION_10_6 00979 //Show again menu & dock if needed 00980 if ([[m_window screen] isEqual:[NSScreen mainScreen]]) 00981 { 00982 [NSApp setPresentationOptions:NSApplicationPresentationDefault]; 00983 } 00984 //Make window normal and resize it 00985 [m_window setStyleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)]; 00986 [m_window setFrame:[[m_window screen] visibleFrame] display:YES]; 00987 //TODO for 10.6 only : window title is forgotten after the style change 00988 [m_window makeFirstResponder:m_openGLView]; 00989 #else 00990 //With 10.5, we need to create a new window to change its style to borderless 00991 //Show menu & dock if needed 00992 if ([[m_window screen] isEqual:[NSScreen mainScreen]]) 00993 { 00994 //Cocoa function in 10.5 does not allow to set the menu bar in auto-show mode [NSMenu setMenuBarVisible:YES]; 00995 SetSystemUIMode(kUIModeNormal, 0); //One of the very few 64bit compatible Carbon function 00996 } 00997 //Create a fullscreen borderless window 00998 CocoaWindow *tmpWindow = [[CocoaWindow alloc] 00999 initWithContentRect:[[m_window screen] frame] 01000 styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask) 01001 backing:NSBackingStoreBuffered 01002 defer:YES]; 01003 //Copy current window parameters 01004 [tmpWindow setTitle:[m_window title]]; 01005 [tmpWindow setRepresentedFilename:[m_window representedFilename]]; 01006 [tmpWindow setReleasedWhenClosed:NO]; 01007 [tmpWindow setAcceptsMouseMovedEvents:YES]; 01008 [tmpWindow setDelegate:[m_window delegate]]; 01009 [tmpWindow setSystemAndWindowCocoa:[m_window systemCocoa] windowCocoa:this]; 01010 [tmpWindow registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, 01011 NSStringPboardType, NSTIFFPboardType, nil]]; 01012 //Forbid to resize the window below the blender defined minimum one 01013 [tmpWindow setContentMinSize:NSMakeSize(320, 240)]; 01014 01015 //Assign the openGL view to the new window 01016 [tmpWindow setContentView:m_openGLView]; 01017 01018 //Show the new window 01019 [tmpWindow makeKeyAndOrderFront:nil]; 01020 //Close and release old window 01021 [m_window setDelegate:nil]; // To avoid the notification of "window closed" event 01022 [m_window close]; 01023 [m_window release]; 01024 m_window = tmpWindow; 01025 #endif 01026 01027 //Tell WM of view new size 01028 m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this); 01029 } 01030 else if ([m_window isMiniaturized]) 01031 [m_window deminiaturize:nil]; 01032 else if ([m_window isZoomed]) 01033 [m_window zoom:nil]; 01034 [pool drain]; 01035 break; 01036 } 01037 01038 return GHOST_kSuccess; 01039 } 01040 01041 GHOST_TSuccess GHOST_WindowCocoa::setModifiedState(bool isUnsavedChanges) 01042 { 01043 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01044 01045 [m_window setDocumentEdited:isUnsavedChanges]; 01046 01047 [pool drain]; 01048 return GHOST_Window::setModifiedState(isUnsavedChanges); 01049 } 01050 01051 01052 01053 GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order) 01054 { 01055 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01056 01057 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setOrder(): window invalid") 01058 if (order == GHOST_kWindowOrderTop) { 01059 [m_window makeKeyAndOrderFront:nil]; 01060 } 01061 else { 01062 NSArray *windowsList; 01063 01064 [m_window orderBack:nil]; 01065 01066 //Check for other blender opened windows and make the frontmost key 01067 windowsList = [NSApp orderedWindows]; 01068 if ([windowsList count]) { 01069 [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil]; 01070 } 01071 } 01072 01073 [pool drain]; 01074 return GHOST_kSuccess; 01075 } 01076 01077 #pragma mark Drawing context 01078 01079 /*#define WAIT_FOR_VSYNC 1*/ 01080 01081 GHOST_TSuccess GHOST_WindowCocoa::swapBuffers() 01082 { 01083 if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { 01084 if (m_openGLContext != nil) { 01085 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01086 [m_openGLContext flushBuffer]; 01087 [pool drain]; 01088 return GHOST_kSuccess; 01089 } 01090 } 01091 return GHOST_kFailure; 01092 } 01093 01094 GHOST_TSuccess GHOST_WindowCocoa::updateDrawingContext() 01095 { 01096 if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { 01097 if (m_openGLContext != nil) { 01098 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01099 [m_openGLContext update]; 01100 [pool drain]; 01101 return GHOST_kSuccess; 01102 } 01103 } 01104 return GHOST_kFailure; 01105 } 01106 01107 GHOST_TSuccess GHOST_WindowCocoa::activateDrawingContext() 01108 { 01109 if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { 01110 if (m_openGLContext != nil) { 01111 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01112 [m_openGLContext makeCurrentContext]; 01113 01114 // Disable AA by default 01115 if (m_numOfAASamples > 0) glDisable(GL_MULTISAMPLE_ARB); 01116 [pool drain]; 01117 return GHOST_kSuccess; 01118 } 01119 } 01120 return GHOST_kFailure; 01121 } 01122 01123 01124 GHOST_TSuccess GHOST_WindowCocoa::installDrawingContext(GHOST_TDrawingContextType type) 01125 { 01126 GHOST_TSuccess success = GHOST_kFailure; 01127 01128 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01129 01130 NSOpenGLPixelFormat *pixelFormat; 01131 NSOpenGLContext *tmpOpenGLContext; 01132 01133 /***** Multithreaded opengl code : uncomment for enabling 01134 CGLContextObj cglCtx; 01135 */ 01136 01137 switch (type) { 01138 case GHOST_kDrawingContextTypeOpenGL: 01139 if (!getValid()) break; 01140 01141 pixelFormat = [m_openGLView pixelFormat]; 01142 tmpOpenGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat 01143 shareContext:s_firstOpenGLcontext]; 01144 if (tmpOpenGLContext == nil) { 01145 success = GHOST_kFailure; 01146 break; 01147 } 01148 01149 //Switch openGL to multhreaded mode 01150 /******* Multithreaded opengl code : uncomment for enabling 01151 cglCtx = (CGLContextObj)[tmpOpenGLContext CGLContextObj]; 01152 if (CGLEnable(cglCtx, kCGLCEMPEngine) == kCGLNoError) 01153 printf("\nSwitched openGL to multithreaded mode"); 01154 */ 01155 01156 if (!s_firstOpenGLcontext) s_firstOpenGLcontext = tmpOpenGLContext; 01157 #ifdef WAIT_FOR_VSYNC 01158 { 01159 GLint swapInt = 1; 01160 /* wait for vsync, to avoid tearing artifacts */ 01161 [tmpOpenGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; 01162 } 01163 #endif 01164 [m_openGLView setOpenGLContext:tmpOpenGLContext]; 01165 [tmpOpenGLContext setView:m_openGLView]; 01166 01167 m_openGLContext = tmpOpenGLContext; 01168 break; 01169 01170 case GHOST_kDrawingContextTypeNone: 01171 success = GHOST_kSuccess; 01172 break; 01173 01174 default: 01175 break; 01176 } 01177 [pool drain]; 01178 return success; 01179 } 01180 01181 01182 GHOST_TSuccess GHOST_WindowCocoa::removeDrawingContext() 01183 { 01184 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01185 switch (m_drawingContextType) { 01186 case GHOST_kDrawingContextTypeOpenGL: 01187 if (m_openGLContext) 01188 { 01189 [m_openGLView clearGLContext]; 01190 if (s_firstOpenGLcontext == m_openGLContext) s_firstOpenGLcontext = nil; 01191 m_openGLContext = nil; 01192 } 01193 [pool drain]; 01194 return GHOST_kSuccess; 01195 case GHOST_kDrawingContextTypeNone: 01196 [pool drain]; 01197 return GHOST_kSuccess; 01198 break; 01199 default: 01200 [pool drain]; 01201 return GHOST_kFailure; 01202 } 01203 } 01204 01205 01206 GHOST_TSuccess GHOST_WindowCocoa::invalidate() 01207 { 01208 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::invalidate(): window invalid") 01209 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01210 [m_openGLView setNeedsDisplay:YES]; 01211 [pool drain]; 01212 return GHOST_kSuccess; 01213 } 01214 01215 #pragma mark Progress bar 01216 01217 GHOST_TSuccess GHOST_WindowCocoa::setProgressBar(float progress) 01218 { 01219 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01220 01221 if ((progress >=0.0) && (progress <=1.0)) { 01222 NSImage* dockIcon = [[NSImage alloc] initWithSize:NSMakeSize(128,128)]; 01223 01224 [dockIcon lockFocus]; 01225 NSRect progressBox = {{4, 4}, {120, 16}}; 01226 01227 [[NSImage imageNamed:@"NSApplicationIcon"] dissolveToPoint:NSZeroPoint fraction:1.0]; 01228 01229 // Track & Outline 01230 [[NSColor blackColor] setFill]; 01231 NSRectFill(progressBox); 01232 01233 [[NSColor whiteColor] set]; 01234 NSFrameRect(progressBox); 01235 01236 // Progress fill 01237 progressBox = NSInsetRect(progressBox, 1, 1); 01238 [[NSColor knobColor] setFill]; 01239 progressBox.size.width = progressBox.size.width * progress; 01240 NSRectFill(progressBox); 01241 01242 [dockIcon unlockFocus]; 01243 01244 [NSApp setApplicationIconImage:dockIcon]; 01245 [dockIcon release]; 01246 01247 m_progressBarVisible = true; 01248 } 01249 01250 [pool drain]; 01251 return GHOST_kSuccess; 01252 } 01253 01254 01255 GHOST_TSuccess GHOST_WindowCocoa::endProgressBar() 01256 { 01257 if (!m_progressBarVisible) return GHOST_kFailure; 01258 m_progressBarVisible = false; 01259 01260 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01261 01262 NSImage* dockIcon = [[NSImage alloc] initWithSize:NSMakeSize(128,128)]; 01263 [dockIcon lockFocus]; 01264 [[NSImage imageNamed:@"NSApplicationIcon"] dissolveToPoint:NSZeroPoint fraction:1.0]; 01265 [dockIcon unlockFocus]; 01266 [NSApp setApplicationIconImage:dockIcon]; 01267 [dockIcon release]; 01268 01269 [pool drain]; 01270 return GHOST_kSuccess; 01271 } 01272 01273 01274 01275 #pragma mark Cursor handling 01276 01277 void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) const 01278 { 01279 static bool systemCursorVisible = true; 01280 01281 NSCursor *tmpCursor =nil; 01282 01283 if (visible != systemCursorVisible) { 01284 if (visible) { 01285 [NSCursor unhide]; 01286 systemCursorVisible = true; 01287 } 01288 else { 01289 [NSCursor hide]; 01290 systemCursorVisible = false; 01291 } 01292 } 01293 01294 if (cursor == GHOST_kStandardCursorCustom && m_customCursor) { 01295 tmpCursor = m_customCursor; 01296 } else { 01297 switch (cursor) { 01298 case GHOST_kStandardCursorDestroy: 01299 tmpCursor = [NSCursor disappearingItemCursor]; 01300 break; 01301 case GHOST_kStandardCursorText: 01302 tmpCursor = [NSCursor IBeamCursor]; 01303 break; 01304 case GHOST_kStandardCursorCrosshair: 01305 tmpCursor = [NSCursor crosshairCursor]; 01306 break; 01307 case GHOST_kStandardCursorUpDown: 01308 tmpCursor = [NSCursor resizeUpDownCursor]; 01309 break; 01310 case GHOST_kStandardCursorLeftRight: 01311 tmpCursor = [NSCursor resizeLeftRightCursor]; 01312 break; 01313 case GHOST_kStandardCursorTopSide: 01314 tmpCursor = [NSCursor resizeUpCursor]; 01315 break; 01316 case GHOST_kStandardCursorBottomSide: 01317 tmpCursor = [NSCursor resizeDownCursor]; 01318 break; 01319 case GHOST_kStandardCursorLeftSide: 01320 tmpCursor = [NSCursor resizeLeftCursor]; 01321 break; 01322 case GHOST_kStandardCursorRightSide: 01323 tmpCursor = [NSCursor resizeRightCursor]; 01324 break; 01325 case GHOST_kStandardCursorRightArrow: 01326 case GHOST_kStandardCursorInfo: 01327 case GHOST_kStandardCursorLeftArrow: 01328 case GHOST_kStandardCursorHelp: 01329 case GHOST_kStandardCursorCycle: 01330 case GHOST_kStandardCursorSpray: 01331 case GHOST_kStandardCursorWait: 01332 case GHOST_kStandardCursorTopLeftCorner: 01333 case GHOST_kStandardCursorTopRightCorner: 01334 case GHOST_kStandardCursorBottomRightCorner: 01335 case GHOST_kStandardCursorBottomLeftCorner: 01336 case GHOST_kStandardCursorCopy: 01337 case GHOST_kStandardCursorDefault: 01338 default: 01339 tmpCursor = [NSCursor arrowCursor]; 01340 break; 01341 }; 01342 } 01343 [tmpCursor set]; 01344 } 01345 01346 01347 01348 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible) 01349 { 01350 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; 01351 01352 if ([m_window isVisible]) { 01353 loadCursor(visible, getCursorShape()); 01354 } 01355 01356 [pool drain]; 01357 return GHOST_kSuccess; 01358 } 01359 01360 01361 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode) 01362 { 01363 GHOST_TSuccess err = GHOST_kSuccess; 01364 01365 if (mode != GHOST_kGrabDisable) 01366 { 01367 //No need to perform grab without warp as it is always on in OS X 01368 if(mode != GHOST_kGrabNormal) { 01369 GHOST_TInt32 x_old,y_old; 01370 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01371 01372 m_systemCocoa->getCursorPosition(x_old,y_old); 01373 screenToClientIntern(x_old, y_old, m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]); 01374 //Warp position is stored in client (window base) coordinates 01375 setCursorGrabAccum(0, 0); 01376 01377 if(mode == GHOST_kGrabHide) { 01378 setWindowCursorVisibility(false); 01379 } 01380 01381 //Make window key if it wasn't to get the mouse move events 01382 [m_window makeKeyWindow]; 01383 01384 //Dissociate cursor position even for warp mode, to allow mouse acceleration to work even when warping the cursor 01385 err = CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; 01386 01387 [pool drain]; 01388 } 01389 } 01390 else { 01391 if(m_cursorGrab==GHOST_kGrabHide) 01392 { 01393 //No need to set again cursor position, as it has not changed for Cocoa 01394 setWindowCursorVisibility(true); 01395 } 01396 01397 err = CGAssociateMouseAndMouseCursorPosition(true) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; 01398 /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */ 01399 setCursorGrabAccum(0, 0); 01400 m_cursorGrabBounds.m_l= m_cursorGrabBounds.m_r= -1; /* disable */ 01401 } 01402 return err; 01403 } 01404 01405 GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape) 01406 { 01407 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01408 01409 if (m_customCursor) { 01410 [m_customCursor release]; 01411 m_customCursor = nil; 01412 } 01413 01414 if ([m_window isVisible]) { 01415 loadCursor(getCursorVisibility(), shape); 01416 } 01417 01418 [pool drain]; 01419 return GHOST_kSuccess; 01420 } 01421 01434 static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt) 01435 { 01436 shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA); 01437 shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC); 01438 shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0); 01439 shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00); 01440 return shrt; 01441 } 01442 01443 GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, GHOST_TUns8 *mask, 01444 int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color) 01445 { 01446 int y,nbUns16; 01447 NSPoint hotSpotPoint; 01448 NSBitmapImageRep *cursorImageRep; 01449 NSImage *cursorImage; 01450 NSSize imSize; 01451 GHOST_TUns16 *cursorBitmap; 01452 01453 01454 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 01455 01456 if (m_customCursor) { 01457 [m_customCursor release]; 01458 m_customCursor = nil; 01459 } 01460 01461 01462 cursorImageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil 01463 pixelsWide:sizex 01464 pixelsHigh:sizey 01465 bitsPerSample:1 01466 samplesPerPixel:2 01467 hasAlpha:YES 01468 isPlanar:YES 01469 colorSpaceName:NSDeviceWhiteColorSpace 01470 bytesPerRow:(sizex/8 + (sizex%8 >0 ?1:0)) 01471 bitsPerPixel:1]; 01472 01473 01474 cursorBitmap = (GHOST_TUns16*)[cursorImageRep bitmapData]; 01475 nbUns16 = [cursorImageRep bytesPerPlane]/2; 01476 01477 for (y=0; y<nbUns16; y++) { 01478 #if !defined(__LITTLE_ENDIAN__) 01479 cursorBitmap[y] = ~uns16ReverseBits((bitmap[2*y]<<0) | (bitmap[2*y+1]<<8)); 01480 cursorBitmap[nbUns16+y] = uns16ReverseBits((mask[2*y]<<0) | (mask[2*y+1]<<8)); 01481 #else 01482 cursorBitmap[y] = ~uns16ReverseBits((bitmap[2*y+1]<<0) | (bitmap[2*y]<<8)); 01483 cursorBitmap[nbUns16+y] = uns16ReverseBits((mask[2*y+1]<<0) | (mask[2*y]<<8)); 01484 #endif 01485 01486 } 01487 01488 01489 imSize.width = sizex; 01490 imSize.height= sizey; 01491 cursorImage = [[NSImage alloc] initWithSize:imSize]; 01492 [cursorImage addRepresentation:cursorImageRep]; 01493 01494 hotSpotPoint.x = hotX; 01495 hotSpotPoint.y = hotY; 01496 01497 //foreground and background color parameter is not handled for now (10.6) 01498 m_customCursor = [[NSCursor alloc] initWithImage:cursorImage 01499 hotSpot:hotSpotPoint]; 01500 01501 [cursorImageRep release]; 01502 [cursorImage release]; 01503 01504 if ([m_window isVisible]) { 01505 loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom); 01506 } 01507 [pool drain]; 01508 return GHOST_kSuccess; 01509 } 01510 01511 GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], 01512 GHOST_TUns8 mask[16][2], int hotX, int hotY) 01513 { 01514 return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*) mask, 16, 16, hotX, hotY, 0, 1); 01515 }