252ac9e6318d38c61889a00aca0d6a9f445b8024
[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 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
414 @end
415
416 @implementation CocoaAppDelegate : NSObject
417 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
418 {
419         //Note that Cmd+Q is already handled by keyhandler
420     //FIXME: Cocoa_SendQuit();
421         //sys->pushEvent( new GHOST_Event(sys->getMilliSeconds(), GHOST_kEventQuit, NULL) );
422     return NSTerminateCancel;
423 }
424 @end
425
426
427
428 #pragma mark initialization/finalization
429
430 /***/
431
432 GHOST_SystemCocoa::GHOST_SystemCocoa()
433 {
434         m_modifierMask =0;
435         m_pressedMouseButtons =0;
436         m_displayManager = new GHOST_DisplayManagerCocoa ();
437         GHOST_ASSERT(m_displayManager, "GHOST_SystemCocoa::GHOST_SystemCocoa(): m_displayManager==0\n");
438         m_displayManager->initialize();
439
440         //NSEvent timeStamp is given in system uptime, state start date is boot time
441         //FIXME : replace by Cocoa equivalent
442         int mib[2];
443         struct timeval boottime;
444         size_t len;
445         
446         mib[0] = CTL_KERN;
447         mib[1] = KERN_BOOTTIME;
448         len = sizeof(struct timeval);
449         
450         sysctl(mib, 2, &boottime, &len, NULL, 0);
451         m_start_time = ((boottime.tv_sec*1000)+(boottime.tv_usec/1000));
452         
453         m_ignoreWindowSizedMessages = false;
454 }
455
456 GHOST_SystemCocoa::~GHOST_SystemCocoa()
457 {
458 }
459
460
461 GHOST_TSuccess GHOST_SystemCocoa::init()
462 {
463         
464     GHOST_TSuccess success = GHOST_System::init();
465     if (success) {
466                 //ProcessSerialNumber psn;
467                 
468                 //FIXME: Carbon stuff to move window & menu to foreground
469                 /*if (!GetCurrentProcess(&psn)) {
470                         TransformProcessType(&psn, kProcessTransformToForegroundApplication);
471                         SetFrontProcess(&psn);
472                 }*/
473                 
474                 m_autoReleasePool = [[NSAutoreleasePool alloc] init];
475                 if (NSApp == nil) {
476                         [NSApplication sharedApplication];
477                         
478                         if ([NSApp mainMenu] == nil) {
479                                 //FIXME: CreateApplicationMenus();
480                         }
481                         [NSApp finishLaunching];
482                 }
483                 if ([NSApp delegate] == nil) {
484                         [NSApp setDelegate:[[CocoaAppDelegate alloc] init]];
485                 }
486                 
487                 
488                 /*
489          * Initialize the cursor to the standard arrow shape (so that we can change it later on).
490          * This initializes the cursor's visibility counter to 0.
491          */
492         /*::InitCursor();
493                 
494                 MenuRef windMenu;
495                 ::CreateStandardWindowMenu(0, &windMenu);
496                 ::InsertMenu(windMenu, 0);
497                 ::DrawMenuBar();
498                 
499         ::InstallApplicationEventHandler(sEventHandlerProc, GetEventTypeCount(kEvents), kEvents, this, &m_handler);
500                 
501                 ::AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, sAEHandlerLaunch, (SInt32) this, false);
502                 ::AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, sAEHandlerOpenDocs, (SInt32) this, false);
503                 ::AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, sAEHandlerPrintDocs, (SInt32) this, false);
504                 ::AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, sAEHandlerQuit, (SInt32) this, false);
505                 */
506     }
507     return success;
508 }
509
510
511 GHOST_TSuccess GHOST_SystemCocoa::exit()
512 {
513         NSAutoreleasePool* pool = (NSAutoreleasePool *)m_autoReleasePool;
514         [pool drain];
515     return GHOST_System::exit();
516 }
517
518 #pragma mark window management
519
520 GHOST_TUns64 GHOST_SystemCocoa::getMilliSeconds() const
521 {
522         //Cocoa equivalent exists in 10.6 ([[NSProcessInfo processInfo] systemUptime])
523         int mib[2];
524         struct timeval boottime;
525         size_t len;
526         
527         mib[0] = CTL_KERN;
528         mib[1] = KERN_BOOTTIME;
529         len = sizeof(struct timeval);
530         
531         sysctl(mib, 2, &boottime, &len, NULL, 0);
532
533         return ((boottime.tv_sec*1000)+(boottime.tv_usec/1000));
534 }
535
536
537 GHOST_TUns8 GHOST_SystemCocoa::getNumDisplays() const
538 {
539         //Note that OS X supports monitor hot plug
540         // We do not support multiple monitors at the moment
541         return [[NSScreen screens] count];
542 }
543
544
545 void GHOST_SystemCocoa::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const
546 {
547         //TODO: Provide visible frame or total frame, check for consistency with rest of code
548         NSRect frame = [[NSScreen mainScreen] visibleFrame];
549         
550         width = frame.size.width;
551         height = frame.size.height;
552 }
553
554
555 GHOST_IWindow* GHOST_SystemCocoa::createWindow(
556         const STR_String& title, 
557         GHOST_TInt32 left,
558         GHOST_TInt32 top,
559         GHOST_TUns32 width,
560         GHOST_TUns32 height,
561         GHOST_TWindowState state,
562         GHOST_TDrawingContextType type,
563         bool stereoVisual,
564         const GHOST_TEmbedderWindowID parentWindow
565 )
566 {
567     GHOST_IWindow* window = 0;
568
569         window = new GHOST_WindowCocoa (title, left, top, width, height, state, type);
570
571     if (window) {
572         if (window->getValid()) {
573             // Store the pointer to the window 
574             GHOST_ASSERT(m_windowManager, "m_windowManager not initialized");
575             m_windowManager->addWindow(window);
576             m_windowManager->setActiveWindow(window);
577             pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window));
578         }
579         else {
580                         GHOST_PRINT("GHOST_SystemCocoa::createWindow(): window invalid\n");
581             delete window;
582             window = 0;
583         }
584     }
585         else {
586                 GHOST_PRINT("GHOST_SystemCocoa::createWindow(): could not create window\n");
587         }
588     return window;
589 }
590
591 GHOST_TSuccess GHOST_SystemCocoa::beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, const bool stereoVisual)
592 {       
593         GHOST_TSuccess success = GHOST_kFailure;
594
595         //TODO: update this method
596         // need yo make this Carbon all on 10.5 for fullscreen to work correctly
597         CGCaptureAllDisplays();
598         
599         success = GHOST_System::beginFullScreen( setting, window, stereoVisual);
600         
601         if( success != GHOST_kSuccess ) {
602                         // fullscreen failed for other reasons, release
603                         CGReleaseAllDisplays(); 
604         }
605
606         return success;
607 }
608
609 GHOST_TSuccess GHOST_SystemCocoa::endFullScreen(void)
610 {       
611         //TODO: update this method
612         CGReleaseAllDisplays();
613         return GHOST_System::endFullScreen();
614 }
615
616
617         
618
619 GHOST_TSuccess GHOST_SystemCocoa::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const
620 {
621     NSPoint mouseLoc = [NSEvent mouseLocation];
622         
623     // Convert the coordinates to screen coordinates
624     x = (GHOST_TInt32)mouseLoc.x;
625     y = (GHOST_TInt32)mouseLoc.y;
626     return GHOST_kSuccess;
627 }
628
629
630 GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const
631 {
632         float xf=(float)x, yf=(float)y;
633
634         CGAssociateMouseAndMouseCursorPosition(false);
635         CGWarpMouseCursorPosition(CGPointMake(xf, yf));
636         CGAssociateMouseAndMouseCursorPosition(true);
637
638     return GHOST_kSuccess;
639 }
640
641
642 GHOST_TSuccess GHOST_SystemCocoa::getModifierKeys(GHOST_ModifierKeys& keys) const
643 {
644     NSUInteger modifiers = [[NSApp currentEvent] modifierFlags];
645         //Direct query to modifierFlags can be used in 10.6
646
647     keys.set(GHOST_kModifierKeyCommand, (modifiers & NSCommandKeyMask) ? true : false);
648     keys.set(GHOST_kModifierKeyLeftAlt, (modifiers & NSAlternateKeyMask) ? true : false);
649     keys.set(GHOST_kModifierKeyLeftShift, (modifiers & NSShiftKeyMask) ? true : false);
650     keys.set(GHOST_kModifierKeyLeftControl, (modifiers & NSControlKeyMask) ? true : false);
651         
652     return GHOST_kSuccess;
653 }
654
655 GHOST_TSuccess GHOST_SystemCocoa::getButtons(GHOST_Buttons& buttons) const
656 {
657         buttons.clear();
658     buttons.set(GHOST_kButtonMaskLeft, m_pressedMouseButtons & GHOST_kButtonMaskLeft);
659         buttons.set(GHOST_kButtonMaskRight, m_pressedMouseButtons & GHOST_kButtonMaskRight);
660         buttons.set(GHOST_kButtonMaskMiddle, m_pressedMouseButtons & GHOST_kButtonMaskMiddle);
661         buttons.set(GHOST_kButtonMaskButton4, m_pressedMouseButtons & GHOST_kButtonMaskButton4);
662         buttons.set(GHOST_kButtonMaskButton5, m_pressedMouseButtons & GHOST_kButtonMaskButton5);
663     return GHOST_kSuccess;
664 }
665
666
667
668 #pragma mark Event handlers
669
670 /**
671  * The event queue polling function
672  */
673 bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
674 {
675         NSAutoreleasePool* pool = (NSAutoreleasePool*)m_autoReleasePool;
676         //bool anyProcessed = false;
677         NSEvent *event;
678         
679         //Reinit the AutoReleasePool
680         //This is not done the typical Cocoa way (init at beginning of loop, and drain at the end)
681         //to allow pool to work with other function calls outside this loop (but in same thread)
682         [pool drain];
683         m_autoReleasePool = [[NSAutoreleasePool alloc] init];
684         
685         //      SetMouseCoalescingEnabled(false, NULL);
686         //TODO : implement timer ??
687         
688         /*do {
689                 GHOST_TimerManager* timerMgr = getTimerManager();
690                 
691                  if (waitForEvent) {
692                  GHOST_TUns64 next = timerMgr->nextFireTime();
693                  double timeOut;
694                  
695                  if (next == GHOST_kFireTimeNever) {
696                  timeOut = kEventDurationForever;
697                  } else {
698                  timeOut = (double)(next - getMilliSeconds())/1000.0;
699                  if (timeOut < 0.0)
700                  timeOut = 0.0;
701                  }
702                  
703                  ::ReceiveNextEvent(0, NULL, timeOut, false, &event);
704                  }
705                  
706                  if (timerMgr->fireTimers(getMilliSeconds())) {
707                  anyProcessed = true;
708                  }
709                  
710                  //TODO: check fullscreen redrawing issues
711                  if (getFullScreen()) {
712                  // Check if the full-screen window is dirty
713                  GHOST_IWindow* window = m_windowManager->getFullScreenWindow();
714                  if (((GHOST_WindowCarbon*)window)->getFullScreenDirty()) {
715                  pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) );
716                  anyProcessed = true;
717                  }
718                  }*/
719                 
720                 do {
721                         event = [NSApp nextEventMatchingMask:NSAnyEventMask
722                                                                            untilDate:[NSDate distantPast]
723                                                                                   inMode:NSDefaultRunLoopMode
724                                                                                  dequeue:YES];
725                         if (event==nil)
726                                 break;
727                         
728                         //anyProcessed = true;
729                         
730                         switch ([event type]) {
731                                 case NSKeyDown:
732                                 case NSKeyUp:
733                                 case NSFlagsChanged:
734                                         handleKeyEvent(event);
735                                         
736                                         /* Support system-wide keyboard shortcuts, like Exposé, ...) =>included in always NSApp sendEvent */
737                                         /*              if (([event modifierFlags] & NSCommandKeyMask) || [event type] == NSFlagsChanged) {
738                                          [NSApp sendEvent:event];
739                                          }*/
740                                         break;
741                                         
742                                 case NSLeftMouseDown:
743                                 case NSLeftMouseUp:
744                                 case NSRightMouseDown:
745                                 case NSRightMouseUp:
746                                 case NSMouseMoved:
747                                 case NSLeftMouseDragged:
748                                 case NSRightMouseDragged:
749                                 case NSScrollWheel:
750                                 case NSOtherMouseDown:
751                                 case NSOtherMouseUp:
752                                 case NSOtherMouseDragged:                               
753                                         handleMouseEvent(event);
754                                         break;
755                                         
756                                 case NSTabletPoint:
757                                 case NSTabletProximity:
758                                         handleTabletEvent(event);
759                                         break;
760                                         
761                                         /* Trackpad features, will need OS X 10.6 for implementation
762                                          case NSEventTypeGesture:
763                                          case NSEventTypeMagnify:
764                                          case NSEventTypeSwipe:
765                                          case NSEventTypeRotate:
766                                          case NSEventTypeBeginGesture:
767                                          case NSEventTypeEndGesture:
768                                          break; */
769                                         
770                                         /*Unused events
771                                          NSMouseEntered       = 8,
772                                          NSMouseExited        = 9,
773                                          NSAppKitDefined      = 13,
774                                          NSSystemDefined      = 14,
775                                          NSApplicationDefined = 15,
776                                          NSPeriodic           = 16,
777                                          NSCursorUpdate       = 17,*/
778                                         
779                                 default:
780                                         break;
781                         }
782                         //Resend event to NSApp to ensure Mac wide events are handled
783                         [NSApp sendEvent:event];
784                 } while (event!= nil);          
785         //} while (waitForEvent && !anyProcessed); Needed only for timer implementation
786         
787         
788     return true; //anyProcessed;
789 }
790
791 //TODO: To be called from NSWindow delegate
792 int GHOST_SystemCocoa::handleWindowEvent(void *eventPtr)
793 {
794         /*WindowRef windowRef;
795         GHOST_WindowCocoa *window;
796         
797         // Check if the event was send to a GHOST window
798         ::GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &windowRef);
799         window = (GHOST_WindowCarbon*) ::GetWRefCon(windowRef);
800         if (!validWindow(window)) {
801                 return err;
802         }
803
804         //if (!getFullScreen()) {
805                 err = noErr;
806                 switch([event ]) 
807                 {
808                         case kEventWindowClose:
809                                 pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, window) );
810                                 break;
811                         case kEventWindowActivated:
812                                 m_windowManager->setActiveWindow(window);
813                                 window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
814                                 pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window) );
815                                 break;
816                         case kEventWindowDeactivated:
817                                 m_windowManager->setWindowInactive(window);
818                                 pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowDeactivate, window) );
819                                 break;
820                         case kEventWindowUpdate:
821                                 //if (getFullScreen()) GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen update event\n");
822                                 pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) );
823                                 break;
824                         case kEventWindowBoundsChanged:
825                                 if (!m_ignoreWindowSizedMessages)
826                                 {
827                                         window->updateDrawingContext();
828                                         pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) );
829                                 }
830                                 break;
831                         default:
832                                 err = eventNotHandledErr;
833                                 break;
834                 }
835 //      }
836         //else {
837                 //window = (GHOST_WindowCarbon*) m_windowManager->getFullScreenWindow();
838                 //GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen window event, " << window << "\n");
839                 //::RemoveEventFromQueue(::GetMainEventQueue(), event);
840         //}
841         */
842         return GHOST_kSuccess;
843 }
844
845 int GHOST_SystemCocoa::handleTabletEvent(void *eventPtr)
846 {
847         NSEvent *event = (NSEvent *)eventPtr;
848         GHOST_IWindow* window = m_windowManager->getActiveWindow();
849         GHOST_TabletData& ct=((GHOST_WindowCocoa*)window)->GetCocoaTabletData();
850         NSUInteger tabletEvent;
851         
852         ct.Pressure = 0;
853         ct.Xtilt = 0;
854         ct.Ytilt = 0;
855         
856         //Handle tablet events combined with mouse events
857         switch ([event subtype]) {
858                 case NX_SUBTYPE_TABLET_POINT:
859                         tabletEvent = NSTabletPoint;
860                         break;
861                 case NX_SUBTYPE_TABLET_PROXIMITY:
862                         tabletEvent = NSTabletProximity;
863                         break;
864
865                 default:
866                         tabletEvent = [event type];
867                         break;
868         }
869         
870         switch (tabletEvent) {
871                 case NSTabletPoint:
872                         ct.Pressure = [event tangentialPressure];
873                         ct.Xtilt = [event tilt].x;
874                         ct.Ytilt = [event tilt].y;
875                         break;
876                 
877                 case NSTabletProximity:
878                         if ([event isEnteringProximity])
879                         {
880                                 //pointer is entering tablet area proximity
881                                 switch ([event pointingDeviceType]) {
882                                         case NSPenPointingDevice:
883                                                 ct.Active = GHOST_kTabletModeStylus;
884                                                 break;
885                                         case NSEraserPointingDevice:
886                                                 ct.Active = GHOST_kTabletModeEraser;
887                                                 break;
888                                         case NSCursorPointingDevice:
889                                         case NSUnknownPointingDevice:
890                                         default:
891                                                 ct.Active = GHOST_kTabletModeNone;
892                                                 break;
893                                 }
894                         } else {
895                                 // pointer is leaving - return to mouse
896                                 ct.Active = GHOST_kTabletModeNone;
897                         }
898                         break;
899                 
900                 default:
901                         GHOST_ASSERT(FALSE,"GHOST_SystemCocoa::handleTabletEvent : unknown event received");
902                         return GHOST_kFailure;
903                         break;
904         }
905         return GHOST_kSuccess;
906 }
907
908
909 int GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
910 {
911         NSEvent *event = (NSEvent *)eventPtr;
912     GHOST_IWindow* window = m_windowManager->getActiveWindow();
913         
914         switch ([event type])
915     {
916                 case NSLeftMouseDown:
917                 case NSRightMouseDown:
918                 case NSOtherMouseDown:
919                         if (m_windowManager->getActiveWindow()) {
920                                 pushEvent(new GHOST_EventButton([event timestamp], GHOST_kEventButtonDown, window, convertButton([event buttonNumber])));
921                         }
922                         handleTabletEvent(eventPtr);
923                         break;
924                                                 
925                 case NSLeftMouseUp:
926                 case NSRightMouseUp:
927                 case NSOtherMouseUp:
928                         if (m_windowManager->getActiveWindow()) {
929                                 pushEvent(new GHOST_EventButton([event timestamp], GHOST_kEventButtonUp, window, convertButton([event buttonNumber])));
930                         }
931                         handleTabletEvent(eventPtr);
932                         break;
933                         
934                 case NSLeftMouseDragged:
935                 case NSRightMouseDragged:
936                 case NSOtherMouseDragged:                               
937                         handleTabletEvent(eventPtr);
938                 case NSMouseMoved:
939                         {
940                                 NSPoint mousePos = [event locationInWindow];
941                                 pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, mousePos.x, mousePos.y));
942                                 break;
943                         }
944                         
945                 case NSScrollWheel:
946                         {
947                                 GHOST_TInt32 delta;
948                                 delta = [event deltaY] > 0 ? 1 : -1;
949                                 pushEvent(new GHOST_EventWheel(getMilliSeconds(), window, delta));
950
951                         }
952                         break;
953                         
954                 default:
955                         return GHOST_kFailure;
956                         break;
957                 }
958         
959         return GHOST_kSuccess;
960 }
961
962
963 int GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
964 {
965         NSEvent *event = (NSEvent *)eventPtr;
966         GHOST_IWindow* window = m_windowManager->getActiveWindow();
967         NSUInteger modifiers;
968         GHOST_TKey keyCode;
969         unsigned char ascii;
970
971         /* Can happen, very rarely - seems to only be when command-H makes
972          * the window go away and we still get an HKey up. 
973          */
974         if (!window) {
975                 return GHOST_kFailure;
976         }
977         
978         switch ([event type]) {
979                 case NSKeyDown:
980                 case NSKeyUp:
981                         keyCode = convertKey([event keyCode],
982                                                          [[event charactersIgnoringModifiers] characterAtIndex:0]);
983                         ascii= convertRomanToLatin((char)[[event characters] characterAtIndex:0]);
984                         
985                         if ([event type] == NSKeyDown) {
986                                 pushEvent( new GHOST_EventKey([event timestamp], GHOST_kEventKeyDown, window, keyCode, ascii) );
987                                 //printf("\nKey pressed keyCode=%u ascii=%i %c",keyCode,ascii,ascii);
988                         } else {
989                                 pushEvent( new GHOST_EventKey([event timestamp], GHOST_kEventKeyUp, window, keyCode, ascii) );
990                         }
991                         break;
992         
993                 case NSFlagsChanged: 
994                         modifiers = [event modifierFlags];
995                         if ((modifiers & NSShiftKeyMask) != (m_modifierMask & NSShiftKeyMask)) {
996                                 pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSShiftKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftShift) );
997                         }
998                         if ((modifiers & NSControlKeyMask) != (m_modifierMask & NSControlKeyMask)) {
999                                 pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSControlKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftControl) );
1000                         }
1001                         if ((modifiers & NSAlternateKeyMask) != (m_modifierMask & NSAlternateKeyMask)) {
1002                                 pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSAlternateKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftAlt) );
1003                         }
1004                         if ((modifiers & NSCommandKeyMask) != (m_modifierMask & NSCommandKeyMask)) {
1005                                 pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSCommandKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyCommand) );
1006                         }
1007                         
1008                         m_modifierMask = modifiers;
1009                         break;
1010                         
1011                 default:
1012                         return GHOST_kFailure;
1013                         break;
1014         }
1015         
1016         return GHOST_kSuccess;
1017 }
1018
1019
1020 /* System wide mouse clicks are handled directly through systematic event forwarding to Cocoa
1021 bool GHOST_SystemCarbon::handleMouseDown(void *eventPtr)
1022 {
1023         NSEvent *event = (NSEvent *)eventPtr;
1024         WindowPtr                       window;
1025         short                           part;
1026         BitMap                          screenBits;
1027     bool                                handled = true;
1028     GHOST_WindowCarbon* ghostWindow;
1029     Point                               mousePos = {0 , 0};
1030         
1031         ::GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &mousePos);
1032         
1033         part = ::FindWindow(mousePos, &window);
1034         ghostWindow = (GHOST_WindowCarbon*) ::GetWRefCon(window);
1035         
1036         switch (part) {
1037                 case inMenuBar:
1038                         handleMenuCommand(::MenuSelect(mousePos));
1039                         break;
1040                         
1041                 case inDrag:
1042                         // *
1043                         // * The DragWindow() routine creates a lot of kEventWindowBoundsChanged
1044                         // * events. By setting m_ignoreWindowSizedMessages these are suppressed.
1045                         // * @see GHOST_SystemCarbon::handleWindowEvent(EventRef event)
1046                         // *
1047                         // even worse: scale window also generates a load of events, and nothing 
1048                          //  is handled (read: client's event proc called) until you release mouse (ton) 
1049                         
1050                         GHOST_ASSERT(validWindow(ghostWindow), "GHOST_SystemCarbon::handleMouseDown: invalid window");
1051                         m_ignoreWindowSizedMessages = true;
1052                         ::DragWindow(window, mousePos, &GetQDGlobalsScreenBits(&screenBits)->bounds);
1053                         m_ignoreWindowSizedMessages = false;
1054                         
1055                         pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowMove, ghostWindow) );
1056
1057                         break;
1058                 
1059                 case inContent:
1060                         if (window != ::FrontWindow()) {
1061                                 ::SelectWindow(window);
1062                                 //
1063                                 // * We add a mouse down event on the newly actived window
1064                                 // *            
1065                                 //GHOST_PRINT("GHOST_SystemCarbon::handleMouseDown(): adding mouse down event, " << ghostWindow << "\n");
1066                                 EventMouseButton button;
1067                                 ::GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button);
1068                                 pushEvent(new GHOST_EventButton(getMilliSeconds(), GHOST_kEventButtonDown, ghostWindow, convertButton(button)));
1069                         } else {
1070                                 handled = false;
1071                         }
1072                         break;
1073                         
1074                 case inGoAway:
1075                         GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0");
1076                         if (::TrackGoAway(window, mousePos))
1077                         {
1078                                 // todo: add option-close, because itÿs in the HIG
1079                                 // if (event.modifiers & optionKey) {
1080                                         // Close the clean documents, others will be confirmed one by one.
1081                                 //}
1082                                 // else {
1083                                 pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, ghostWindow));
1084                                 //}
1085                         }
1086                         break;
1087                         
1088                 case inGrow:
1089                         GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0");
1090                         ::ResizeWindow(window, mousePos, NULL, NULL);
1091                         break;
1092                         
1093                 case inZoomIn:
1094                 case inZoomOut:
1095                         GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0");
1096                         if (::TrackBox(window, mousePos, part)) {
1097                                 int macState;
1098                                 
1099                                 macState = ghostWindow->getMac_windowState();
1100                                 if ( macState== 0)
1101                                         ::ZoomWindow(window, part, true);
1102                                 else 
1103                                         if (macState == 2) { // always ok
1104                                                         ::ZoomWindow(window, part, true);
1105                                                         ghostWindow->setMac_windowState(1);
1106                                         } else { // need to force size again
1107                                         //      GHOST_TUns32 scr_x,scr_y; //unused
1108                                                 Rect outAvailableRect;
1109                                                 
1110                                                 ghostWindow->setMac_windowState(2);
1111                                                 ::GetAvailableWindowPositioningBounds ( GetMainDevice(), &outAvailableRect);
1112                                                 
1113                                                 //this->getMainDisplayDimensions(scr_x,scr_y);
1114                                                 ::SizeWindow (window, outAvailableRect.right-outAvailableRect.left,outAvailableRect.bottom-outAvailableRect.top-1,false);
1115                                                 ::MoveWindow (window, outAvailableRect.left, outAvailableRect.top,true);
1116                                         }
1117                                 
1118                         }
1119                         break;
1120
1121                 default:
1122                         handled = false;
1123                         break;
1124         }
1125         
1126         return handled;
1127 }
1128
1129
1130 bool GHOST_SystemCarbon::handleMenuCommand(GHOST_TInt32 menuResult)
1131 {
1132         short           menuID;
1133         short           menuItem;
1134         UInt32          command;
1135         bool            handled;
1136         OSErr           err;
1137         
1138         menuID = HiWord(menuResult);
1139         menuItem = LoWord(menuResult);
1140
1141         err = ::GetMenuItemCommandID(::GetMenuHandle(menuID), menuItem, &command);
1142
1143         handled = false;
1144         
1145         if (err || command == 0) {
1146         }
1147         else {
1148                 switch(command) {
1149                 }
1150         }
1151
1152         ::HiliteMenu(0);
1153     return handled;
1154 }*/
1155
1156
1157
1158 #pragma mark Clipboard get/set
1159
1160 GHOST_TUns8* GHOST_SystemCocoa::getClipboard(bool selection) const
1161 {
1162         GHOST_TUns8 * temp_buff;
1163         size_t pastedTextSize;  
1164         
1165         NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
1166         
1167         if (pasteBoard = nil) {
1168                 return NULL;
1169         }
1170         
1171         NSArray *supportedTypes =
1172                 [NSArray arrayWithObjects: @"public.utf8-plain-text", nil];
1173         
1174         NSString *bestType = [[NSPasteboard generalPasteboard]
1175                                                   availableTypeFromArray:supportedTypes];
1176         
1177         if (bestType == nil) { return NULL; }
1178         
1179         NSString * textPasted = [pasteBoard stringForType:@"public.utf8-plain-text"];
1180
1181         pastedTextSize = [textPasted lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
1182         
1183         temp_buff = (GHOST_TUns8*) malloc(pastedTextSize+1); 
1184
1185         if (temp_buff == NULL) return NULL;
1186         
1187         strncpy((char*)temp_buff, [textPasted UTF8String], pastedTextSize);
1188         
1189         temp_buff[pastedTextSize] = '\0';
1190         
1191         if(temp_buff) {
1192                 return temp_buff;
1193         } else {
1194                 return NULL;
1195         }
1196 }
1197
1198 void GHOST_SystemCocoa::putClipboard(GHOST_TInt8 *buffer, bool selection) const
1199 {
1200         NSString *textToCopy;
1201         
1202         if(selection) {return;} // for copying the selection, used on X11
1203
1204         
1205         NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
1206         
1207         if (pasteBoard = nil) {
1208                 return;
1209         }
1210         
1211         NSArray *supportedTypes = [NSArray arrayWithObjects: @"public.utf8-plain-text",nil];
1212         
1213         [pasteBoard declareTypes:supportedTypes owner:nil];
1214         
1215         textToCopy = [NSString stringWithUTF8String:buffer];
1216         
1217         [pasteBoard setString:textToCopy forType:@"public.utf8-plain-text"];
1218         
1219         printf("\nCopy");
1220         
1221 }
1222
1223 #pragma mark Carbon stuff to remove
1224
1225 #ifdef WITH_CARBON
1226
1227
1228 OSErr GHOST_SystemCarbon::sAEHandlerLaunch(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
1229 {
1230         //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
1231         
1232         return noErr;
1233 }
1234
1235 OSErr GHOST_SystemCarbon::sAEHandlerOpenDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
1236 {
1237         //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
1238         AEDescList docs;
1239         SInt32 ndocs;
1240         OSErr err;
1241         
1242         err = AEGetParamDesc(event, keyDirectObject, typeAEList, &docs);
1243         if (err != noErr)  return err;
1244         
1245         err = AECountItems(&docs, &ndocs);
1246         if (err==noErr) {
1247                 int i;
1248                 
1249                 for (i=0; i<ndocs; i++) {
1250                         FSSpec fss;
1251                         AEKeyword kwd;
1252                         DescType actType;
1253                         Size actSize;
1254                         
1255                         err = AEGetNthPtr(&docs, i+1, typeFSS, &kwd, &actType, &fss, sizeof(fss), &actSize);
1256                         if (err!=noErr)
1257                                 break;
1258                         
1259                         if (i==0) {
1260                                 FSRef fsref;
1261                                 
1262                                 if (FSpMakeFSRef(&fss, &fsref)!=noErr)
1263                                         break;
1264                                 if (FSRefMakePath(&fsref, (UInt8*) g_firstFileBuf, sizeof(g_firstFileBuf))!=noErr)
1265                                         break;
1266                                 
1267                                 g_hasFirstFile = true;
1268                         }
1269                 }
1270         }
1271         
1272         AEDisposeDesc(&docs);
1273         
1274         return err;
1275 }
1276
1277 OSErr GHOST_SystemCarbon::sAEHandlerPrintDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
1278 {
1279         //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
1280         
1281         return noErr;
1282 }
1283
1284 OSErr GHOST_SystemCarbon::sAEHandlerQuit(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
1285 {
1286         GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
1287         
1288         sys->pushEvent( new GHOST_Event(sys->getMilliSeconds(), GHOST_kEventQuit, NULL) );
1289         
1290         return noErr;
1291 }
1292 #endif