d0c382e1469756c23a0cce00633a15f84219bb38
[blender.git] / intern / ghost / intern / GHOST_SystemCocoa.mm
1 /**
2  * $Id$
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s):      Maarten Gribnau 05/2001
25  *                                      Damien Plisson 09/2009
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #import <Cocoa/Cocoa.h>
31
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <sys/sysctl.h>
35
36 #include "GHOST_SystemCocoa.h"
37
38 #include "GHOST_DisplayManagerCocoa.h"
39 #include "GHOST_EventKey.h"
40 #include "GHOST_EventButton.h"
41 #include "GHOST_EventCursor.h"
42 #include "GHOST_EventWheel.h"
43 #include "GHOST_EventNDOF.h"
44
45 #include "GHOST_TimerManager.h"
46 #include "GHOST_TimerTask.h"
47 #include "GHOST_WindowManager.h"
48 #include "GHOST_WindowCocoa.h"
49 #include "GHOST_NDOFManager.h"
50 #include "AssertMacros.h"
51
52 #pragma mark KeyMap, mouse converters
53
54 //TODO: remove (kept as reminder to implement window events)
55 /*
56 const EventTypeSpec     kEvents[] =
57 {
58         { kEventClassAppleEvent, kEventAppleEvent },
59
60 //      { kEventClassApplication, kEventAppActivated },
61 //      { kEventClassApplication, kEventAppDeactivated },
62         
63         { kEventClassKeyboard, kEventRawKeyDown },
64         { kEventClassKeyboard, kEventRawKeyRepeat },
65         { kEventClassKeyboard, kEventRawKeyUp },
66         { kEventClassKeyboard, kEventRawKeyModifiersChanged },
67         
68         { kEventClassMouse, kEventMouseDown },
69         { kEventClassMouse, kEventMouseUp },
70         { kEventClassMouse, kEventMouseMoved },
71         { kEventClassMouse, kEventMouseDragged },
72         { kEventClassMouse, kEventMouseWheelMoved },
73         
74         { kEventClassWindow, kEventWindowClickZoomRgn } ,  // for new zoom behaviour  
75         { kEventClassWindow, kEventWindowZoom },  // for new zoom behaviour  
76         { kEventClassWindow, kEventWindowExpand } ,  // for new zoom behaviour 
77         { kEventClassWindow, kEventWindowExpandAll },  // for new zoom behaviour 
78
79         { kEventClassWindow, kEventWindowClose },
80         { kEventClassWindow, kEventWindowActivated },
81         { kEventClassWindow, kEventWindowDeactivated },
82         { kEventClassWindow, kEventWindowUpdate },
83         { kEventClassWindow, kEventWindowBoundsChanged },
84         
85         { kEventClassBlender, kEventBlenderNdofAxis },
86         { kEventClassBlender, kEventBlenderNdofButtons }
87         
88         
89         
90 };*/
91
92 static GHOST_TButtonMask convertButton(EventMouseButton button)
93 {
94         switch (button) {
95                 case 0:
96                         return GHOST_kButtonMaskLeft;
97                 case 1:
98                         return GHOST_kButtonMaskRight;
99                 case 2:
100                         return GHOST_kButtonMaskMiddle;
101                 case 3:
102                         return GHOST_kButtonMaskButton4;
103                 case 4:
104                         return GHOST_kButtonMaskButton5;
105                 default:
106                         return GHOST_kButtonMaskLeft;
107         }
108 }
109
110 /**
111  * Converts Mac rawkey codes (same for Cocoa & Carbon)
112  * into GHOST key codes
113  * @param rawCode The raw physical key code
114  * @param recvChar the character ignoring modifiers (except for shift)
115  * @return Ghost key code
116  */
117 static GHOST_TKey convertKey(int rawCode, unichar recvChar) 
118 {       
119         
120         //printf("\nrecvchar %c 0x%x",recvChar,recvChar);
121         switch (rawCode) {
122                 /*Physical keycodes not used due to map changes in int'l keyboards
123                 case kVK_ANSI_A:        return GHOST_kKeyA;
124                 case kVK_ANSI_B:        return GHOST_kKeyB;
125                 case kVK_ANSI_C:        return GHOST_kKeyC;
126                 case kVK_ANSI_D:        return GHOST_kKeyD;
127                 case kVK_ANSI_E:        return GHOST_kKeyE;
128                 case kVK_ANSI_F:        return GHOST_kKeyF;
129                 case kVK_ANSI_G:        return GHOST_kKeyG;
130                 case kVK_ANSI_H:        return GHOST_kKeyH;
131                 case kVK_ANSI_I:        return GHOST_kKeyI;
132                 case kVK_ANSI_J:        return GHOST_kKeyJ;
133                 case kVK_ANSI_K:        return GHOST_kKeyK;
134                 case kVK_ANSI_L:        return GHOST_kKeyL;
135                 case kVK_ANSI_M:        return GHOST_kKeyM;
136                 case kVK_ANSI_N:        return GHOST_kKeyN;
137                 case kVK_ANSI_O:        return GHOST_kKeyO;
138                 case kVK_ANSI_P:        return GHOST_kKeyP;
139                 case kVK_ANSI_Q:        return GHOST_kKeyQ;
140                 case kVK_ANSI_R:        return GHOST_kKeyR;
141                 case kVK_ANSI_S:        return GHOST_kKeyS;
142                 case kVK_ANSI_T:        return GHOST_kKeyT;
143                 case kVK_ANSI_U:        return GHOST_kKeyU;
144                 case kVK_ANSI_V:        return GHOST_kKeyV;
145                 case kVK_ANSI_W:        return GHOST_kKeyW;
146                 case kVK_ANSI_X:        return GHOST_kKeyX;
147                 case kVK_ANSI_Y:        return GHOST_kKeyY;
148                 case kVK_ANSI_Z:        return GHOST_kKeyZ;*/
149                 
150                 /* Numbers keys mapped to handle some int'l keyboard (e.g. French)*/
151                 case kVK_ISO_Section: return    GHOST_kKeyUnknown;
152                 case kVK_ANSI_1:        return GHOST_kKey1;
153                 case kVK_ANSI_2:        return GHOST_kKey2;
154                 case kVK_ANSI_3:        return GHOST_kKey3;
155                 case kVK_ANSI_4:        return GHOST_kKey4;
156                 case kVK_ANSI_5:        return GHOST_kKey5;
157                 case kVK_ANSI_6:        return GHOST_kKey6;
158                 case kVK_ANSI_7:        return GHOST_kKey7;
159                 case kVK_ANSI_8:        return GHOST_kKey8;
160                 case kVK_ANSI_9:        return GHOST_kKey9;
161                 case kVK_ANSI_0:        return GHOST_kKey0;
162         
163                 case kVK_ANSI_Keypad0:                  return GHOST_kKeyNumpad0;
164                 case kVK_ANSI_Keypad1:                  return GHOST_kKeyNumpad1;
165                 case kVK_ANSI_Keypad2:                  return GHOST_kKeyNumpad2;
166                 case kVK_ANSI_Keypad3:                  return GHOST_kKeyNumpad3;
167                 case kVK_ANSI_Keypad4:                  return GHOST_kKeyNumpad4;
168                 case kVK_ANSI_Keypad5:                  return GHOST_kKeyNumpad5;
169                 case kVK_ANSI_Keypad6:                  return GHOST_kKeyNumpad6;
170                 case kVK_ANSI_Keypad7:                  return GHOST_kKeyNumpad7;
171                 case kVK_ANSI_Keypad8:                  return GHOST_kKeyNumpad8;
172                 case kVK_ANSI_Keypad9:                  return GHOST_kKeyNumpad9;
173                 case kVK_ANSI_KeypadDecimal:    return GHOST_kKeyNumpadPeriod;
174                 case kVK_ANSI_KeypadEnter:              return GHOST_kKeyNumpadEnter;
175                 case kVK_ANSI_KeypadPlus:               return GHOST_kKeyNumpadPlus;
176                 case kVK_ANSI_KeypadMinus:              return GHOST_kKeyNumpadMinus;
177                 case kVK_ANSI_KeypadMultiply:   return GHOST_kKeyNumpadAsterisk;
178                 case kVK_ANSI_KeypadDivide:     return GHOST_kKeyNumpadSlash;
179                 case kVK_ANSI_KeypadClear:              return GHOST_kKeyUnknown;
180
181                 case kVK_F1:                            return GHOST_kKeyF1;
182                 case kVK_F2:                            return GHOST_kKeyF2;
183                 case kVK_F3:                            return GHOST_kKeyF3;
184                 case kVK_F4:                            return GHOST_kKeyF4;
185                 case kVK_F5:                            return GHOST_kKeyF5;
186                 case kVK_F6:                            return GHOST_kKeyF6;
187                 case kVK_F7:                            return GHOST_kKeyF7;
188                 case kVK_F8:                            return GHOST_kKeyF8;
189                 case kVK_F9:                            return GHOST_kKeyF9;
190                 case kVK_F10:                           return GHOST_kKeyF10;
191                 case kVK_F11:                           return GHOST_kKeyF11;
192                 case kVK_F12:                           return GHOST_kKeyF12;
193                 case kVK_F13:                           return GHOST_kKeyF13;
194                 case kVK_F14:                           return GHOST_kKeyF14;
195                 case kVK_F15:                           return GHOST_kKeyF15;
196                 case kVK_F16:                           return GHOST_kKeyF16;
197                 case kVK_F17:                           return GHOST_kKeyF17;
198                 case kVK_F18:                           return GHOST_kKeyF18;
199                 case kVK_F19:                           return GHOST_kKeyF19;
200                 case kVK_F20:                           return GHOST_kKeyF20;
201                         
202                 case kVK_UpArrow:                       return GHOST_kKeyUpArrow;
203                 case kVK_DownArrow:                     return GHOST_kKeyDownArrow;
204                 case kVK_LeftArrow:                     return GHOST_kKeyLeftArrow;
205                 case kVK_RightArrow:            return GHOST_kKeyRightArrow;
206                         
207                 case kVK_Return:                        return GHOST_kKeyEnter;
208                 case kVK_Delete:                        return GHOST_kKeyBackSpace;
209                 case kVK_ForwardDelete:         return GHOST_kKeyDelete;
210                 case kVK_Escape:                        return GHOST_kKeyEsc;
211                 case kVK_Tab:                           return GHOST_kKeyTab;
212                 case kVK_Space:                         return GHOST_kKeySpace;
213                         
214                 case kVK_Home:                          return GHOST_kKeyHome;
215                 case kVK_End:                           return GHOST_kKeyEnd;
216                 case kVK_PageUp:                        return GHOST_kKeyUpPage;
217                 case kVK_PageDown:                      return GHOST_kKeyDownPage;
218                         
219                 /*case kVK_ANSI_Minus:          return GHOST_kKeyMinus;
220                 case kVK_ANSI_Equal:            return GHOST_kKeyEqual;
221                 case kVK_ANSI_Comma:            return GHOST_kKeyComma;
222                 case kVK_ANSI_Period:           return GHOST_kKeyPeriod;
223                 case kVK_ANSI_Slash:            return GHOST_kKeySlash;
224                 case kVK_ANSI_Semicolon:        return GHOST_kKeySemicolon;
225                 case kVK_ANSI_Quote:            return GHOST_kKeyQuote;
226                 case kVK_ANSI_Backslash:        return GHOST_kKeyBackslash;
227                 case kVK_ANSI_LeftBracket:      return GHOST_kKeyLeftBracket;
228                 case kVK_ANSI_RightBracket:     return GHOST_kKeyRightBracket;
229                 case kVK_ANSI_Grave:            return GHOST_kKeyAccentGrave;*/
230                         
231                 case kVK_VolumeUp:
232                 case kVK_VolumeDown:
233                 case kVK_Mute:
234                         return GHOST_kKeyUnknown;
235                         
236                 default:
237                         /*Then detect on character value for "remappable" keys in int'l keyboards*/
238                         if ((recvChar >= 'A') && (recvChar <= 'Z')) {
239                                 return (GHOST_TKey) (recvChar - 'A' + GHOST_kKeyA);
240                         } else if ((recvChar >= 'a') && (recvChar <= 'z')) {
241                                 return (GHOST_TKey) (recvChar - 'a' + GHOST_kKeyA);
242                         } else
243                         switch (recvChar) {
244                                 case '-':       return GHOST_kKeyMinus;
245                                 case '=':       return GHOST_kKeyEqual;
246                                 case ',':       return GHOST_kKeyComma;
247                                 case '.':       return GHOST_kKeyPeriod;
248                                 case '/':       return GHOST_kKeySlash;
249                                 case ';':       return GHOST_kKeySemicolon;
250                                 case '\'':      return GHOST_kKeyQuote;
251                                 case '\\':      return GHOST_kKeyBackslash;
252                                 case '[':       return GHOST_kKeyLeftBracket;
253                                 case ']':       return GHOST_kKeyRightBracket;
254                                 case '`':       return GHOST_kKeyAccentGrave;
255                                 default:
256                                         return GHOST_kKeyUnknown;
257                         }
258         }
259         return GHOST_kKeyUnknown;
260 }
261
262 /* MacOSX returns a Roman charset with kEventParamKeyMacCharCodes
263  * as defined here: http://developer.apple.com/documentation/mac/Text/Text-516.html
264  * I am not sure how international this works...
265  * For cross-platform convention, we'll use the Latin ascii set instead.
266  * As defined at: http://www.ramsch.org/martin/uni/fmi-hp/iso8859-1.html
267  * 
268  */
269 static unsigned char convertRomanToLatin(unsigned char ascii)
270 {
271
272         if(ascii<128) return ascii;
273         
274         switch(ascii) {
275         case 128:       return 142;
276         case 129:       return 143;
277         case 130:       return 128;
278         case 131:       return 201;
279         case 132:       return 209;
280         case 133:       return 214;
281         case 134:       return 220;
282         case 135:       return 225;
283         case 136:       return 224;
284         case 137:       return 226;
285         case 138:       return 228;
286         case 139:       return 227;
287         case 140:       return 229;
288         case 141:       return 231;
289         case 142:       return 233;
290         case 143:       return 232;
291         case 144:       return 234;
292         case 145:       return 235;
293         case 146:       return 237;
294         case 147:       return 236;
295         case 148:       return 238;
296         case 149:       return 239;
297         case 150:       return 241;
298         case 151:       return 243;
299         case 152:       return 242;
300         case 153:       return 244;
301         case 154:       return 246;
302         case 155:       return 245;
303         case 156:       return 250;
304         case 157:       return 249;
305         case 158:       return 251;
306         case 159:       return 252;
307         case 160:       return 0;
308         case 161:       return 176;
309         case 162:       return 162;
310         case 163:       return 163;
311         case 164:       return 167;
312         case 165:       return 183;
313         case 166:       return 182;
314         case 167:       return 223;
315         case 168:       return 174;
316         case 169:       return 169;
317         case 170:       return 174;
318         case 171:       return 180;
319         case 172:       return 168;
320         case 173:       return 0;
321         case 174:       return 198;
322         case 175:       return 216;
323         case 176:       return 0;
324         case 177:       return 177;
325         case 178:       return 0;
326         case 179:       return 0;
327         case 180:       return 165;
328         case 181:       return 181;
329         case 182:       return 0;
330         case 183:       return 0;
331         case 184:       return 215;
332         case 185:       return 0;
333         case 186:       return 0;
334         case 187:       return 170;
335         case 188:       return 186;
336         case 189:       return 0;
337         case 190:       return 230;
338         case 191:       return 248;
339         case 192:       return 191;
340         case 193:       return 161;
341         case 194:       return 172;
342         case 195:       return 0;
343         case 196:       return 0;
344         case 197:       return 0;
345         case 198:       return 0;
346         case 199:       return 171;
347         case 200:       return 187;
348         case 201:       return 201;
349         case 202:       return 0;
350         case 203:       return 192;
351         case 204:       return 195;
352         case 205:       return 213;
353         case 206:       return 0;
354         case 207:       return 0;
355         case 208:       return 0;
356         case 209:       return 0;
357         case 210:       return 0;
358         
359         case 214:       return 247;
360
361         case 229:       return 194;
362         case 230:       return 202;
363         case 231:       return 193;
364         case 232:       return 203;
365         case 233:       return 200;
366         case 234:       return 205;
367         case 235:       return 206;
368         case 236:       return 207;
369         case 237:       return 204;
370         case 238:       return 211;
371         case 239:       return 212;
372         case 240:       return 0;
373         case 241:       return 210;
374         case 242:       return 218;
375         case 243:       return 219;
376         case 244:       return 217;
377         case 245:       return 0;
378         case 246:       return 0;
379         case 247:       return 0;
380         case 248:       return 0;
381         case 249:       return 0;
382         case 250:       return 0;
383
384         
385                 default: return 0;
386         }
387
388 }
389
390 #define FIRSTFILEBUFLG 512
391 static bool g_hasFirstFile = false;
392 static char g_firstFileBuf[512];
393
394 //TODO:Need to investigate this. Function called too early in creator.c to have g_hasFirstFile == true
395 extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG]) { 
396         if (g_hasFirstFile) {
397                 strncpy(buf, g_firstFileBuf, FIRSTFILEBUFLG - 1);
398                 buf[FIRSTFILEBUFLG - 1] = '\0';
399                 return 1;
400         } else {
401                 return 0; 
402         }
403 }
404
405
406 #pragma mark Cocoa objects
407
408 /**
409  * CocoaAppDelegate
410  * ObjC object to capture applicationShouldTerminate, and send quit event
411  **/
412 @interface CocoaAppDelegate : NSObject {
413         GHOST_SystemCocoa *systemCocoa;
414 }
415 -(void)setSystemCocoa:(GHOST_SystemCocoa *)sysCocoa;
416 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
417 @end
418
419 @implementation CocoaAppDelegate : NSObject
420 -(void)setSystemCocoa:(GHOST_SystemCocoa *)sysCocoa
421 {
422         systemCocoa = sysCocoa;
423 }
424
425 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
426 {
427         //Note that Cmd+Q is already handled by keyhandler
428     //FIXME: Need an event "QuitRequest"
429         int shouldQuit = NSRunAlertPanel(@"Exit Blender", @"Some changes may not have been saved. Do you really want to quit ?",
430                                                                          @"No", @"Yes", nil);
431         
432         if (shouldQuit == NSAlertAlternateReturn)
433                 systemCocoa->pushEvent( new GHOST_Event(systemCocoa->getMilliSeconds(), GHOST_kEventQuit, NULL) );
434     
435         return NSTerminateCancel;
436 }
437 @end
438
439
440
441 #pragma mark initialization/finalization
442
443 /***/
444
445 GHOST_SystemCocoa::GHOST_SystemCocoa()
446 {
447         m_modifierMask =0;
448         m_pressedMouseButtons =0;
449         m_displayManager = new GHOST_DisplayManagerCocoa ();
450         GHOST_ASSERT(m_displayManager, "GHOST_SystemCocoa::GHOST_SystemCocoa(): m_displayManager==0\n");
451         m_displayManager->initialize();
452
453         //NSEvent timeStamp is given in system uptime, state start date is boot time
454         //FIXME : replace by Cocoa equivalent
455         int mib[2];
456         struct timeval boottime;
457         size_t len;
458         
459         mib[0] = CTL_KERN;
460         mib[1] = KERN_BOOTTIME;
461         len = sizeof(struct timeval);
462         
463         sysctl(mib, 2, &boottime, &len, NULL, 0);
464         m_start_time = ((boottime.tv_sec*1000)+(boottime.tv_usec/1000));
465         
466         m_ignoreWindowSizedMessages = false;
467 }
468
469 GHOST_SystemCocoa::~GHOST_SystemCocoa()
470 {
471 }
472
473
474 GHOST_TSuccess GHOST_SystemCocoa::init()
475 {
476         
477     GHOST_TSuccess success = GHOST_System::init();
478     if (success) {
479                 //ProcessSerialNumber psn;
480                 
481                 //FIXME: Carbon stuff to move window & menu to foreground
482                 /*if (!GetCurrentProcess(&psn)) {
483                         TransformProcessType(&psn, kProcessTransformToForegroundApplication);
484                         SetFrontProcess(&psn);
485                 }*/
486                 
487                 m_autoReleasePool = [[NSAutoreleasePool alloc] init];
488                 if (NSApp == nil) {
489                         [NSApplication sharedApplication];
490                         
491                         if ([NSApp mainMenu] == nil) {
492                                 NSMenu *mainMenubar = [[NSMenu alloc] init];
493                                 NSMenuItem *menuItem;
494                                 
495                                 //Create the application menu
496                                 NSMenu *appMenu = [[NSMenu alloc] initWithTitle:@"Blender"];
497                                 
498                                 [appMenu addItemWithTitle:@"About Blender" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
499                                 [appMenu addItem:[NSMenuItem separatorItem]];
500                                 
501                                 menuItem = [appMenu addItemWithTitle:@"Hide Blender" action:@selector(hide:) keyEquivalent:@"h"];
502                                 [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
503                                  
504                                 menuItem = [appMenu addItemWithTitle:@"Hide others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
505                                 [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask | NSCommandKeyMask)];
506                                 
507                                 [appMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
508                                 
509                                 menuItem = [appMenu addItemWithTitle:@"Quit Blender" action:@selector(terminate:) keyEquivalent:@"q"];
510                                 [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
511                                 
512                                 menuItem = [[NSMenuItem alloc] init];
513                                 [menuItem setSubmenu:appMenu];
514                                 
515                                 [mainMenubar addItem:menuItem];
516                                 [menuItem release];
517                                 [appMenu release];
518                                 
519                                 //Create the window menu
520                                 NSMenu *windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
521                                 
522                                 menuItem = [windowMenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
523                                 [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask];
524                                 
525                                 [windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
526                                 
527                                 menuItem = [[NSMenuItem alloc] init];
528                                 [menuItem setSubmenu:windowMenu];
529                                 
530                                 [mainMenubar addItem:menuItem];
531                                 [menuItem release];
532                                 
533                                 [NSApp setMainMenu:mainMenubar];
534                                 [NSApp setWindowsMenu:windowMenu];
535                                 [windowMenu release];
536                         }
537                         [NSApp finishLaunching];
538                 }
539                 if ([NSApp delegate] == nil) {
540                         CocoaAppDelegate *appDelegate = [[CocoaAppDelegate alloc] init];
541                         [appDelegate setSystemCocoa:this];
542                         [NSApp setDelegate:appDelegate];
543                 }
544                 
545                 
546                 /*
547          * Initialize the cursor to the standard arrow shape (so that we can change it later on).
548          * This initializes the cursor's visibility counter to 0.
549          */
550         /*::InitCursor();
551                 
552                 MenuRef windMenu;
553                 ::CreateStandardWindowMenu(0, &windMenu);
554                 ::InsertMenu(windMenu, 0);
555                 ::DrawMenuBar();
556                 
557         ::InstallApplicationEventHandler(sEventHandlerProc, GetEventTypeCount(kEvents), kEvents, this, &m_handler);
558                 
559                 ::AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, sAEHandlerLaunch, (SInt32) this, false);
560                 ::AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, sAEHandlerOpenDocs, (SInt32) this, false);
561                 ::AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, sAEHandlerPrintDocs, (SInt32) this, false);
562                 ::AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, sAEHandlerQuit, (SInt32) this, false);
563                 */
564     }
565     return success;
566 }
567
568
569 GHOST_TSuccess GHOST_SystemCocoa::exit()
570 {
571         NSAutoreleasePool* pool = (NSAutoreleasePool *)m_autoReleasePool;
572         [pool drain];
573     return GHOST_System::exit();
574 }
575
576 #pragma mark window management
577
578 GHOST_TUns64 GHOST_SystemCocoa::getMilliSeconds() const
579 {
580         //Cocoa equivalent exists in 10.6 ([[NSProcessInfo processInfo] systemUptime])
581         int mib[2];
582         struct timeval boottime;
583         size_t len;
584         
585         mib[0] = CTL_KERN;
586         mib[1] = KERN_BOOTTIME;
587         len = sizeof(struct timeval);
588         
589         sysctl(mib, 2, &boottime, &len, NULL, 0);
590
591         return ((boottime.tv_sec*1000)+(boottime.tv_usec/1000));
592 }
593
594
595 GHOST_TUns8 GHOST_SystemCocoa::getNumDisplays() const
596 {
597         //Note that OS X supports monitor hot plug
598         // We do not support multiple monitors at the moment
599         return [[NSScreen screens] count];
600 }
601
602
603 void GHOST_SystemCocoa::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const
604 {
605         //TODO: Provide visible frame or total frame, check for consistency with rest of code
606         NSRect frame = [[NSScreen mainScreen] visibleFrame];
607         
608         width = frame.size.width;
609         height = frame.size.height;
610 }
611
612
613 GHOST_IWindow* GHOST_SystemCocoa::createWindow(
614         const STR_String& title, 
615         GHOST_TInt32 left,
616         GHOST_TInt32 top,
617         GHOST_TUns32 width,
618         GHOST_TUns32 height,
619         GHOST_TWindowState state,
620         GHOST_TDrawingContextType type,
621         bool stereoVisual,
622         const GHOST_TEmbedderWindowID parentWindow
623 )
624 {
625     GHOST_IWindow* window = 0;
626
627         window = new GHOST_WindowCocoa (title, left, top, width, height, state, type);
628
629     if (window) {
630         if (window->getValid()) {
631             // Store the pointer to the window 
632             GHOST_ASSERT(m_windowManager, "m_windowManager not initialized");
633             m_windowManager->addWindow(window);
634             m_windowManager->setActiveWindow(window);
635             pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window));
636         }
637         else {
638                         GHOST_PRINT("GHOST_SystemCocoa::createWindow(): window invalid\n");
639             delete window;
640             window = 0;
641         }
642     }
643         else {
644                 GHOST_PRINT("GHOST_SystemCocoa::createWindow(): could not create window\n");
645         }
646     return window;
647 }
648
649 GHOST_TSuccess GHOST_SystemCocoa::beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, const bool stereoVisual)
650 {       
651         GHOST_TSuccess success = GHOST_kFailure;
652
653         //TODO: update this method
654         // need yo make this Carbon all on 10.5 for fullscreen to work correctly
655         CGCaptureAllDisplays();
656         
657         success = GHOST_System::beginFullScreen( setting, window, stereoVisual);
658         
659         if( success != GHOST_kSuccess ) {
660                         // fullscreen failed for other reasons, release
661                         CGReleaseAllDisplays(); 
662         }
663
664         return success;
665 }
666
667 GHOST_TSuccess GHOST_SystemCocoa::endFullScreen(void)
668 {       
669         //TODO: update this method
670         CGReleaseAllDisplays();
671         return GHOST_System::endFullScreen();
672 }
673
674
675         
676
677 GHOST_TSuccess GHOST_SystemCocoa::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const
678 {
679     NSPoint mouseLoc = [NSEvent mouseLocation];
680         
681     // Convert the coordinates to screen coordinates
682     x = (GHOST_TInt32)mouseLoc.x;
683     y = (GHOST_TInt32)mouseLoc.y;
684     return GHOST_kSuccess;
685 }
686
687
688 GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const
689 {
690         float xf=(float)x, yf=(float)y;
691
692         CGAssociateMouseAndMouseCursorPosition(false);
693         CGWarpMouseCursorPosition(CGPointMake(xf, yf));
694         CGAssociateMouseAndMouseCursorPosition(true);
695
696     return GHOST_kSuccess;
697 }
698
699
700 GHOST_TSuccess GHOST_SystemCocoa::getModifierKeys(GHOST_ModifierKeys& keys) const
701 {
702     NSUInteger modifiers = [[NSApp currentEvent] modifierFlags];
703         //Direct query to modifierFlags can be used in 10.6
704
705     keys.set(GHOST_kModifierKeyCommand, (modifiers & NSCommandKeyMask) ? true : false);
706     keys.set(GHOST_kModifierKeyLeftAlt, (modifiers & NSAlternateKeyMask) ? true : false);
707     keys.set(GHOST_kModifierKeyLeftShift, (modifiers & NSShiftKeyMask) ? true : false);
708     keys.set(GHOST_kModifierKeyLeftControl, (modifiers & NSControlKeyMask) ? true : false);
709         
710     return GHOST_kSuccess;
711 }
712
713 GHOST_TSuccess GHOST_SystemCocoa::getButtons(GHOST_Buttons& buttons) const
714 {
715         buttons.clear();
716     buttons.set(GHOST_kButtonMaskLeft, m_pressedMouseButtons & GHOST_kButtonMaskLeft);
717         buttons.set(GHOST_kButtonMaskRight, m_pressedMouseButtons & GHOST_kButtonMaskRight);
718         buttons.set(GHOST_kButtonMaskMiddle, m_pressedMouseButtons & GHOST_kButtonMaskMiddle);
719         buttons.set(GHOST_kButtonMaskButton4, m_pressedMouseButtons & GHOST_kButtonMaskButton4);
720         buttons.set(GHOST_kButtonMaskButton5, m_pressedMouseButtons & GHOST_kButtonMaskButton5);
721     return GHOST_kSuccess;
722 }
723
724
725
726 #pragma mark Event handlers
727
728 /**
729  * The event queue polling function
730  */
731 bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
732 {
733         NSAutoreleasePool* pool = (NSAutoreleasePool*)m_autoReleasePool;
734         //bool anyProcessed = false;
735         NSEvent *event;
736         
737         //Reinit the AutoReleasePool
738         //This is not done the typical Cocoa way (init at beginning of loop, and drain at the end)
739         //to allow pool to work with other function calls outside this loop (but in same thread)
740         [pool drain];
741         m_autoReleasePool = [[NSAutoreleasePool alloc] init];
742         
743         //      SetMouseCoalescingEnabled(false, NULL);
744         //TODO : implement timer ??
745         
746         /*do {
747                 GHOST_TimerManager* timerMgr = getTimerManager();
748                 
749                  if (waitForEvent) {
750                  GHOST_TUns64 next = timerMgr->nextFireTime();
751                  double timeOut;
752                  
753                  if (next == GHOST_kFireTimeNever) {
754                  timeOut = kEventDurationForever;
755                  } else {
756                  timeOut = (double)(next - getMilliSeconds())/1000.0;
757                  if (timeOut < 0.0)
758                  timeOut = 0.0;
759                  }
760                  
761                  ::ReceiveNextEvent(0, NULL, timeOut, false, &event);
762                  }
763                  
764                  if (timerMgr->fireTimers(getMilliSeconds())) {
765                  anyProcessed = true;
766                  }
767                  
768                  //TODO: check fullscreen redrawing issues
769                  if (getFullScreen()) {
770                  // Check if the full-screen window is dirty
771                  GHOST_IWindow* window = m_windowManager->getFullScreenWindow();
772                  if (((GHOST_WindowCarbon*)window)->getFullScreenDirty()) {
773                  pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) );
774                  anyProcessed = true;
775                  }
776                  }*/
777                 
778                 do {
779                         event = [NSApp nextEventMatchingMask:NSAnyEventMask
780                                                                            untilDate:[NSDate distantPast]
781                                                                                   inMode:NSDefaultRunLoopMode
782                                                                                  dequeue:YES];
783                         if (event==nil)
784                                 break;
785                         
786                         //anyProcessed = true;
787                         
788                         switch ([event type]) {
789                                 case NSKeyDown:
790                                 case NSKeyUp:
791                                 case NSFlagsChanged:
792                                         handleKeyEvent(event);
793                                         
794                                         /* Support system-wide keyboard shortcuts, like Exposé, ...) =>included in always NSApp sendEvent */
795                                         /*              if (([event modifierFlags] & NSCommandKeyMask) || [event type] == NSFlagsChanged) {
796                                          [NSApp sendEvent:event];
797                                          }*/
798                                         break;
799                                         
800                                 case NSLeftMouseDown:
801                                 case NSLeftMouseUp:
802                                 case NSRightMouseDown:
803                                 case NSRightMouseUp:
804                                 case NSMouseMoved:
805                                 case NSLeftMouseDragged:
806                                 case NSRightMouseDragged:
807                                 case NSScrollWheel:
808                                 case NSOtherMouseDown:
809                                 case NSOtherMouseUp:
810                                 case NSOtherMouseDragged:                               
811                                         handleMouseEvent(event);
812                                         break;
813                                         
814                                 case NSTabletPoint:
815                                 case NSTabletProximity:
816                                         handleTabletEvent(event);
817                                         break;
818                                         
819                                         /* Trackpad features, will need OS X 10.6 for implementation
820                                          case NSEventTypeGesture:
821                                          case NSEventTypeMagnify:
822                                          case NSEventTypeSwipe:
823                                          case NSEventTypeRotate:
824                                          case NSEventTypeBeginGesture:
825                                          case NSEventTypeEndGesture:
826                                          break; */
827                                         
828                                         /*Unused events
829                                          NSMouseEntered       = 8,
830                                          NSMouseExited        = 9,
831                                          NSAppKitDefined      = 13,
832                                          NSSystemDefined      = 14,
833                                          NSApplicationDefined = 15,
834                                          NSPeriodic           = 16,
835                                          NSCursorUpdate       = 17,*/
836                                         
837                                 default:
838                                         break;
839                         }
840                         //Resend event to NSApp to ensure Mac wide events are handled
841                         [NSApp sendEvent:event];
842                 } while (event!= nil);          
843         //} while (waitForEvent && !anyProcessed); Needed only for timer implementation
844         
845         
846     return true; //anyProcessed;
847 }
848
849 //TODO: To be called from NSWindow delegate
850 int GHOST_SystemCocoa::handleWindowEvent(void *eventPtr)
851 {
852         /*WindowRef windowRef;
853         GHOST_WindowCocoa *window;
854         
855         // Check if the event was send to a GHOST window
856         ::GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &windowRef);
857         window = (GHOST_WindowCarbon*) ::GetWRefCon(windowRef);
858         if (!validWindow(window)) {
859                 return err;
860         }
861
862         //if (!getFullScreen()) {
863                 err = noErr;
864                 switch([event ]) 
865                 {
866                         case kEventWindowClose:
867                                 pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, window) );
868                                 break;
869                         case kEventWindowActivated:
870                                 m_windowManager->setActiveWindow(window);
871                                 window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
872                                 pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window) );
873                                 break;
874                         case kEventWindowDeactivated:
875                                 m_windowManager->setWindowInactive(window);
876                                 pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowDeactivate, window) );
877                                 break;
878                         case kEventWindowUpdate:
879                                 //if (getFullScreen()) GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen update event\n");
880                                 pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) );
881                                 break;
882                         case kEventWindowBoundsChanged:
883                                 if (!m_ignoreWindowSizedMessages)
884                                 {
885                                         window->updateDrawingContext();
886                                         pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) );
887                                 }
888                                 break;
889                         default:
890                                 err = eventNotHandledErr;
891                                 break;
892                 }
893 //      }
894         //else {
895                 //window = (GHOST_WindowCarbon*) m_windowManager->getFullScreenWindow();
896                 //GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen window event, " << window << "\n");
897                 //::RemoveEventFromQueue(::GetMainEventQueue(), event);
898         //}
899         */
900         return GHOST_kSuccess;
901 }
902
903 int GHOST_SystemCocoa::handleTabletEvent(void *eventPtr)
904 {
905         NSEvent *event = (NSEvent *)eventPtr;
906         GHOST_IWindow* window = m_windowManager->getActiveWindow();
907         GHOST_TabletData& ct=((GHOST_WindowCocoa*)window)->GetCocoaTabletData();
908         NSUInteger tabletEvent;
909         
910         ct.Pressure = 0;
911         ct.Xtilt = 0;
912         ct.Ytilt = 0;
913         
914         //Handle tablet events combined with mouse events
915         switch ([event subtype]) {
916                 case NX_SUBTYPE_TABLET_POINT:
917                         tabletEvent = NSTabletPoint;
918                         break;
919                 case NX_SUBTYPE_TABLET_PROXIMITY:
920                         tabletEvent = NSTabletProximity;
921                         break;
922
923                 default:
924                         tabletEvent = [event type];
925                         break;
926         }
927         
928         switch (tabletEvent) {
929                 case NSTabletPoint:
930                         ct.Pressure = [event tangentialPressure];
931                         ct.Xtilt = [event tilt].x;
932                         ct.Ytilt = [event tilt].y;
933                         break;
934                 
935                 case NSTabletProximity:
936                         if ([event isEnteringProximity])
937                         {
938                                 //pointer is entering tablet area proximity
939                                 switch ([event pointingDeviceType]) {
940                                         case NSPenPointingDevice:
941                                                 ct.Active = GHOST_kTabletModeStylus;
942                                                 break;
943                                         case NSEraserPointingDevice:
944                                                 ct.Active = GHOST_kTabletModeEraser;
945                                                 break;
946                                         case NSCursorPointingDevice:
947                                         case NSUnknownPointingDevice:
948                                         default:
949                                                 ct.Active = GHOST_kTabletModeNone;
950                                                 break;
951                                 }
952                         } else {
953                                 // pointer is leaving - return to mouse
954                                 ct.Active = GHOST_kTabletModeNone;
955                         }
956                         break;
957                 
958                 default:
959                         GHOST_ASSERT(FALSE,"GHOST_SystemCocoa::handleTabletEvent : unknown event received");
960                         return GHOST_kFailure;
961                         break;
962         }
963         return GHOST_kSuccess;
964 }
965
966
967 int GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
968 {
969         NSEvent *event = (NSEvent *)eventPtr;
970     GHOST_IWindow* window = m_windowManager->getActiveWindow();
971         
972         switch ([event type])
973     {
974                 case NSLeftMouseDown:
975                 case NSRightMouseDown:
976                 case NSOtherMouseDown:
977                         if (m_windowManager->getActiveWindow()) {
978                                 pushEvent(new GHOST_EventButton([event timestamp], GHOST_kEventButtonDown, window, convertButton([event buttonNumber])));
979                         }
980                         handleTabletEvent(eventPtr);
981                         break;
982                                                 
983                 case NSLeftMouseUp:
984                 case NSRightMouseUp:
985                 case NSOtherMouseUp:
986                         if (m_windowManager->getActiveWindow()) {
987                                 pushEvent(new GHOST_EventButton([event timestamp], GHOST_kEventButtonUp, window, convertButton([event buttonNumber])));
988                         }
989                         handleTabletEvent(eventPtr);
990                         break;
991                         
992                 case NSLeftMouseDragged:
993                 case NSRightMouseDragged:
994                 case NSOtherMouseDragged:                               
995                         handleTabletEvent(eventPtr);
996                 case NSMouseMoved:
997                         {
998                                 NSPoint mousePos = [event locationInWindow];
999                                 pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, mousePos.x, mousePos.y));
1000                                 break;
1001                         }
1002                         
1003                 case NSScrollWheel:
1004                         {
1005                                 GHOST_TInt32 delta;
1006                                 delta = [event deltaY] > 0 ? 1 : -1;
1007                                 pushEvent(new GHOST_EventWheel(getMilliSeconds(), window, delta));
1008
1009                         }
1010                         break;
1011                         
1012                 default:
1013                         return GHOST_kFailure;
1014                         break;
1015                 }
1016         
1017         return GHOST_kSuccess;
1018 }
1019
1020
1021 int GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
1022 {
1023         NSEvent *event = (NSEvent *)eventPtr;
1024         GHOST_IWindow* window = m_windowManager->getActiveWindow();
1025         NSUInteger modifiers;
1026         GHOST_TKey keyCode;
1027         unsigned char ascii;
1028
1029         /* Can happen, very rarely - seems to only be when command-H makes
1030          * the window go away and we still get an HKey up. 
1031          */
1032         if (!window) {
1033                 return GHOST_kFailure;
1034         }
1035         
1036         switch ([event type]) {
1037                 case NSKeyDown:
1038                 case NSKeyUp:
1039                         keyCode = convertKey([event keyCode],
1040                                                          [[event charactersIgnoringModifiers] characterAtIndex:0]);
1041                         ascii= convertRomanToLatin((char)[[event characters] characterAtIndex:0]);
1042                         
1043                         if ((keyCode == GHOST_kKeyQ) && (m_modifierMask & NSCommandKeyMask))
1044                                 break; //Cmd-Q is directly handled by Cocoa
1045                         
1046                         if ([event type] == NSKeyDown) {
1047                                 pushEvent( new GHOST_EventKey([event timestamp], GHOST_kEventKeyDown, window, keyCode, ascii) );
1048                                 //printf("\nKey pressed keyCode=%u ascii=%i %c",keyCode,ascii,ascii);
1049                         } else {
1050                                 pushEvent( new GHOST_EventKey([event timestamp], GHOST_kEventKeyUp, window, keyCode, ascii) );
1051                         }
1052                         break;
1053         
1054                 case NSFlagsChanged: 
1055                         modifiers = [event modifierFlags];
1056                         if ((modifiers & NSShiftKeyMask) != (m_modifierMask & NSShiftKeyMask)) {
1057                                 pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSShiftKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftShift) );
1058                         }
1059                         if ((modifiers & NSControlKeyMask) != (m_modifierMask & NSControlKeyMask)) {
1060                                 pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSControlKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftControl) );
1061                         }
1062                         if ((modifiers & NSAlternateKeyMask) != (m_modifierMask & NSAlternateKeyMask)) {
1063                                 pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSAlternateKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftAlt) );
1064                         }
1065                         if ((modifiers & NSCommandKeyMask) != (m_modifierMask & NSCommandKeyMask)) {
1066                                 pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSCommandKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyCommand) );
1067                         }
1068                         
1069                         m_modifierMask = modifiers;
1070                         break;
1071                         
1072                 default:
1073                         return GHOST_kFailure;
1074                         break;
1075         }
1076         
1077         return GHOST_kSuccess;
1078 }
1079
1080
1081 /* System wide mouse clicks are handled directly through systematic event forwarding to Cocoa
1082 bool GHOST_SystemCarbon::handleMouseDown(void *eventPtr)
1083 {
1084         NSEvent *event = (NSEvent *)eventPtr;
1085         WindowPtr                       window;
1086         short                           part;
1087         BitMap                          screenBits;
1088     bool                                handled = true;
1089     GHOST_WindowCarbon* ghostWindow;
1090     Point                               mousePos = {0 , 0};
1091         
1092         ::GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &mousePos);
1093         
1094         part = ::FindWindow(mousePos, &window);
1095         ghostWindow = (GHOST_WindowCarbon*) ::GetWRefCon(window);
1096         
1097         switch (part) {
1098                 case inMenuBar:
1099                         handleMenuCommand(::MenuSelect(mousePos));
1100                         break;
1101                         
1102                 case inDrag:
1103                         // *
1104                         // * The DragWindow() routine creates a lot of kEventWindowBoundsChanged
1105                         // * events. By setting m_ignoreWindowSizedMessages these are suppressed.
1106                         // * @see GHOST_SystemCarbon::handleWindowEvent(EventRef event)
1107                         // *
1108                         // even worse: scale window also generates a load of events, and nothing 
1109                          //  is handled (read: client's event proc called) until you release mouse (ton) 
1110                         
1111                         GHOST_ASSERT(validWindow(ghostWindow), "GHOST_SystemCarbon::handleMouseDown: invalid window");
1112                         m_ignoreWindowSizedMessages = true;
1113                         ::DragWindow(window, mousePos, &GetQDGlobalsScreenBits(&screenBits)->bounds);
1114                         m_ignoreWindowSizedMessages = false;
1115                         
1116                         pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowMove, ghostWindow) );
1117
1118                         break;
1119                 
1120                 case inContent:
1121                         if (window != ::FrontWindow()) {
1122                                 ::SelectWindow(window);
1123                                 //
1124                                 // * We add a mouse down event on the newly actived window
1125                                 // *            
1126                                 //GHOST_PRINT("GHOST_SystemCarbon::handleMouseDown(): adding mouse down event, " << ghostWindow << "\n");
1127                                 EventMouseButton button;
1128                                 ::GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button);
1129                                 pushEvent(new GHOST_EventButton(getMilliSeconds(), GHOST_kEventButtonDown, ghostWindow, convertButton(button)));
1130                         } else {
1131                                 handled = false;
1132                         }
1133                         break;
1134                         
1135                 case inGoAway:
1136                         GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0");
1137                         if (::TrackGoAway(window, mousePos))
1138                         {
1139                                 // todo: add option-close, because itÿs in the HIG
1140                                 // if (event.modifiers & optionKey) {
1141                                         // Close the clean documents, others will be confirmed one by one.
1142                                 //}
1143                                 // else {
1144                                 pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, ghostWindow));
1145                                 //}
1146                         }
1147                         break;
1148                         
1149                 case inGrow:
1150                         GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0");
1151                         ::ResizeWindow(window, mousePos, NULL, NULL);
1152                         break;
1153                         
1154                 case inZoomIn:
1155                 case inZoomOut:
1156                         GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0");
1157                         if (::TrackBox(window, mousePos, part)) {
1158                                 int macState;
1159                                 
1160                                 macState = ghostWindow->getMac_windowState();
1161                                 if ( macState== 0)
1162                                         ::ZoomWindow(window, part, true);
1163                                 else 
1164                                         if (macState == 2) { // always ok
1165                                                         ::ZoomWindow(window, part, true);
1166                                                         ghostWindow->setMac_windowState(1);
1167                                         } else { // need to force size again
1168                                         //      GHOST_TUns32 scr_x,scr_y; //unused
1169                                                 Rect outAvailableRect;
1170                                                 
1171                                                 ghostWindow->setMac_windowState(2);
1172                                                 ::GetAvailableWindowPositioningBounds ( GetMainDevice(), &outAvailableRect);
1173                                                 
1174                                                 //this->getMainDisplayDimensions(scr_x,scr_y);
1175                                                 ::SizeWindow (window, outAvailableRect.right-outAvailableRect.left,outAvailableRect.bottom-outAvailableRect.top-1,false);
1176                                                 ::MoveWindow (window, outAvailableRect.left, outAvailableRect.top,true);
1177                                         }
1178                                 
1179                         }
1180                         break;
1181
1182                 default:
1183                         handled = false;
1184                         break;
1185         }
1186         
1187         return handled;
1188 }
1189
1190
1191 bool GHOST_SystemCarbon::handleMenuCommand(GHOST_TInt32 menuResult)
1192 {
1193         short           menuID;
1194         short           menuItem;
1195         UInt32          command;
1196         bool            handled;
1197         OSErr           err;
1198         
1199         menuID = HiWord(menuResult);
1200         menuItem = LoWord(menuResult);
1201
1202         err = ::GetMenuItemCommandID(::GetMenuHandle(menuID), menuItem, &command);
1203
1204         handled = false;
1205         
1206         if (err || command == 0) {
1207         }
1208         else {
1209                 switch(command) {
1210                 }
1211         }
1212
1213         ::HiliteMenu(0);
1214     return handled;
1215 }*/
1216
1217
1218
1219 #pragma mark Clipboard get/set
1220
1221 GHOST_TUns8* GHOST_SystemCocoa::getClipboard(bool selection) const
1222 {
1223         GHOST_TUns8 * temp_buff;
1224         size_t pastedTextSize;  
1225         
1226         NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
1227         
1228         if (pasteBoard = nil) {
1229                 return NULL;
1230         }
1231         
1232         NSArray *supportedTypes =
1233                 [NSArray arrayWithObjects: @"public.utf8-plain-text", nil];
1234         
1235         NSString *bestType = [[NSPasteboard generalPasteboard]
1236                                                   availableTypeFromArray:supportedTypes];
1237         
1238         if (bestType == nil) { return NULL; }
1239         
1240         NSString * textPasted = [pasteBoard stringForType:@"public.utf8-plain-text"];
1241
1242         pastedTextSize = [textPasted lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
1243         
1244         temp_buff = (GHOST_TUns8*) malloc(pastedTextSize+1); 
1245
1246         if (temp_buff == NULL) return NULL;
1247         
1248         strncpy((char*)temp_buff, [textPasted UTF8String], pastedTextSize);
1249         
1250         temp_buff[pastedTextSize] = '\0';
1251         
1252         if(temp_buff) {
1253                 return temp_buff;
1254         } else {
1255                 return NULL;
1256         }
1257 }
1258
1259 void GHOST_SystemCocoa::putClipboard(GHOST_TInt8 *buffer, bool selection) const
1260 {
1261         NSString *textToCopy;
1262         
1263         if(selection) {return;} // for copying the selection, used on X11
1264
1265         
1266         NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
1267         
1268         if (pasteBoard = nil) {
1269                 return;
1270         }
1271         
1272         NSArray *supportedTypes = [NSArray arrayWithObjects: @"public.utf8-plain-text",nil];
1273         
1274         [pasteBoard declareTypes:supportedTypes owner:nil];
1275         
1276         textToCopy = [NSString stringWithUTF8String:buffer];
1277         
1278         [pasteBoard setString:textToCopy forType:@"public.utf8-plain-text"];
1279         
1280         printf("\nCopy");
1281         
1282 }
1283
1284 #pragma mark Carbon stuff to remove
1285
1286 #ifdef WITH_CARBON
1287
1288
1289 OSErr GHOST_SystemCarbon::sAEHandlerLaunch(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
1290 {
1291         //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
1292         
1293         return noErr;
1294 }
1295
1296 OSErr GHOST_SystemCarbon::sAEHandlerOpenDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
1297 {
1298         //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
1299         AEDescList docs;
1300         SInt32 ndocs;
1301         OSErr err;
1302         
1303         err = AEGetParamDesc(event, keyDirectObject, typeAEList, &docs);
1304         if (err != noErr)  return err;
1305         
1306         err = AECountItems(&docs, &ndocs);
1307         if (err==noErr) {
1308                 int i;
1309                 
1310                 for (i=0; i<ndocs; i++) {
1311                         FSSpec fss;
1312                         AEKeyword kwd;
1313                         DescType actType;
1314                         Size actSize;
1315                         
1316                         err = AEGetNthPtr(&docs, i+1, typeFSS, &kwd, &actType, &fss, sizeof(fss), &actSize);
1317                         if (err!=noErr)
1318                                 break;
1319                         
1320                         if (i==0) {
1321                                 FSRef fsref;
1322                                 
1323                                 if (FSpMakeFSRef(&fss, &fsref)!=noErr)
1324                                         break;
1325                                 if (FSRefMakePath(&fsref, (UInt8*) g_firstFileBuf, sizeof(g_firstFileBuf))!=noErr)
1326                                         break;
1327                                 
1328                                 g_hasFirstFile = true;
1329                         }
1330                 }
1331         }
1332         
1333         AEDisposeDesc(&docs);
1334         
1335         return err;
1336 }
1337
1338 OSErr GHOST_SystemCarbon::sAEHandlerPrintDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
1339 {
1340         //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
1341         
1342         return noErr;
1343 }
1344
1345 OSErr GHOST_SystemCarbon::sAEHandlerQuit(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
1346 {
1347         GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
1348         
1349         sys->pushEvent( new GHOST_Event(sys->getMilliSeconds(), GHOST_kEventQuit, NULL) );
1350         
1351         return noErr;
1352 }
1353 #endif