Blender  V2.93
GHOST_SystemCocoa.mm
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
20 #include "GHOST_SystemCocoa.h"
21 
23 #include "GHOST_EventButton.h"
24 #include "GHOST_EventCursor.h"
25 #include "GHOST_EventDragnDrop.h"
26 #include "GHOST_EventKey.h"
27 #include "GHOST_EventString.h"
28 #include "GHOST_EventTrackpad.h"
29 #include "GHOST_EventWheel.h"
30 #include "GHOST_TimerManager.h"
31 #include "GHOST_TimerTask.h"
32 #include "GHOST_WindowCocoa.h"
33 #include "GHOST_WindowManager.h"
34 
35 #if defined(WITH_GL_EGL)
36 # include "GHOST_ContextEGL.h"
37 #else
38 # include "GHOST_ContextCGL.h"
39 #endif
40 
41 #ifdef WITH_INPUT_NDOF
42 # include "GHOST_NDOFManagerCocoa.h"
43 #endif
44 
45 #include "AssertMacros.h"
46 
47 #import <Cocoa/Cocoa.h>
48 
49 /* For the currently not ported to Cocoa keyboard layout functions (64bit & 10.6 compatible) */
50 #include <Carbon/Carbon.h>
51 
52 #include <sys/sysctl.h>
53 #include <sys/time.h>
54 #include <sys/types.h>
55 
56 #include <mach/mach_time.h>
57 
58 #pragma mark KeyMap, mouse converters
59 
60 static GHOST_TButtonMask convertButton(int button)
61 {
62  switch (button) {
63  case 0:
64  return GHOST_kButtonMaskLeft;
65  case 1:
67  case 2:
69  case 3:
71  case 4:
73  case 5:
75  case 6:
77  default:
78  return GHOST_kButtonMaskLeft;
79  }
80 }
81 
89 static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction)
90 {
91  // printf("\nrecvchar %c 0x%x",recvChar,recvChar);
92  switch (rawCode) {
93  /*Physical keycodes not used due to map changes in int'l keyboards
94  case kVK_ANSI_A: return GHOST_kKeyA;
95  case kVK_ANSI_B: return GHOST_kKeyB;
96  case kVK_ANSI_C: return GHOST_kKeyC;
97  case kVK_ANSI_D: return GHOST_kKeyD;
98  case kVK_ANSI_E: return GHOST_kKeyE;
99  case kVK_ANSI_F: return GHOST_kKeyF;
100  case kVK_ANSI_G: return GHOST_kKeyG;
101  case kVK_ANSI_H: return GHOST_kKeyH;
102  case kVK_ANSI_I: return GHOST_kKeyI;
103  case kVK_ANSI_J: return GHOST_kKeyJ;
104  case kVK_ANSI_K: return GHOST_kKeyK;
105  case kVK_ANSI_L: return GHOST_kKeyL;
106  case kVK_ANSI_M: return GHOST_kKeyM;
107  case kVK_ANSI_N: return GHOST_kKeyN;
108  case kVK_ANSI_O: return GHOST_kKeyO;
109  case kVK_ANSI_P: return GHOST_kKeyP;
110  case kVK_ANSI_Q: return GHOST_kKeyQ;
111  case kVK_ANSI_R: return GHOST_kKeyR;
112  case kVK_ANSI_S: return GHOST_kKeyS;
113  case kVK_ANSI_T: return GHOST_kKeyT;
114  case kVK_ANSI_U: return GHOST_kKeyU;
115  case kVK_ANSI_V: return GHOST_kKeyV;
116  case kVK_ANSI_W: return GHOST_kKeyW;
117  case kVK_ANSI_X: return GHOST_kKeyX;
118  case kVK_ANSI_Y: return GHOST_kKeyY;
119  case kVK_ANSI_Z: return GHOST_kKeyZ;*/
120 
121  /* Numbers keys mapped to handle some int'l keyboard (e.g. French)*/
122  case kVK_ISO_Section:
123  return GHOST_kKeyUnknown;
124  case kVK_ANSI_1:
125  return GHOST_kKey1;
126  case kVK_ANSI_2:
127  return GHOST_kKey2;
128  case kVK_ANSI_3:
129  return GHOST_kKey3;
130  case kVK_ANSI_4:
131  return GHOST_kKey4;
132  case kVK_ANSI_5:
133  return GHOST_kKey5;
134  case kVK_ANSI_6:
135  return GHOST_kKey6;
136  case kVK_ANSI_7:
137  return GHOST_kKey7;
138  case kVK_ANSI_8:
139  return GHOST_kKey8;
140  case kVK_ANSI_9:
141  return GHOST_kKey9;
142  case kVK_ANSI_0:
143  return GHOST_kKey0;
144 
145  case kVK_ANSI_Keypad0:
146  return GHOST_kKeyNumpad0;
147  case kVK_ANSI_Keypad1:
148  return GHOST_kKeyNumpad1;
149  case kVK_ANSI_Keypad2:
150  return GHOST_kKeyNumpad2;
151  case kVK_ANSI_Keypad3:
152  return GHOST_kKeyNumpad3;
153  case kVK_ANSI_Keypad4:
154  return GHOST_kKeyNumpad4;
155  case kVK_ANSI_Keypad5:
156  return GHOST_kKeyNumpad5;
157  case kVK_ANSI_Keypad6:
158  return GHOST_kKeyNumpad6;
159  case kVK_ANSI_Keypad7:
160  return GHOST_kKeyNumpad7;
161  case kVK_ANSI_Keypad8:
162  return GHOST_kKeyNumpad8;
163  case kVK_ANSI_Keypad9:
164  return GHOST_kKeyNumpad9;
165  case kVK_ANSI_KeypadDecimal:
166  return GHOST_kKeyNumpadPeriod;
167  case kVK_ANSI_KeypadEnter:
168  return GHOST_kKeyNumpadEnter;
169  case kVK_ANSI_KeypadPlus:
170  return GHOST_kKeyNumpadPlus;
171  case kVK_ANSI_KeypadMinus:
172  return GHOST_kKeyNumpadMinus;
173  case kVK_ANSI_KeypadMultiply:
175  case kVK_ANSI_KeypadDivide:
176  return GHOST_kKeyNumpadSlash;
177  case kVK_ANSI_KeypadClear:
178  return GHOST_kKeyUnknown;
179 
180  case kVK_F1:
181  return GHOST_kKeyF1;
182  case kVK_F2:
183  return GHOST_kKeyF2;
184  case kVK_F3:
185  return GHOST_kKeyF3;
186  case kVK_F4:
187  return GHOST_kKeyF4;
188  case kVK_F5:
189  return GHOST_kKeyF5;
190  case kVK_F6:
191  return GHOST_kKeyF6;
192  case kVK_F7:
193  return GHOST_kKeyF7;
194  case kVK_F8:
195  return GHOST_kKeyF8;
196  case kVK_F9:
197  return GHOST_kKeyF9;
198  case kVK_F10:
199  return GHOST_kKeyF10;
200  case kVK_F11:
201  return GHOST_kKeyF11;
202  case kVK_F12:
203  return GHOST_kKeyF12;
204  case kVK_F13:
205  return GHOST_kKeyF13;
206  case kVK_F14:
207  return GHOST_kKeyF14;
208  case kVK_F15:
209  return GHOST_kKeyF15;
210  case kVK_F16:
211  return GHOST_kKeyF16;
212  case kVK_F17:
213  return GHOST_kKeyF17;
214  case kVK_F18:
215  return GHOST_kKeyF18;
216  case kVK_F19:
217  return GHOST_kKeyF19;
218  case kVK_F20:
219  return GHOST_kKeyF20;
220 
221  case kVK_UpArrow:
222  return GHOST_kKeyUpArrow;
223  case kVK_DownArrow:
224  return GHOST_kKeyDownArrow;
225  case kVK_LeftArrow:
226  return GHOST_kKeyLeftArrow;
227  case kVK_RightArrow:
228  return GHOST_kKeyRightArrow;
229 
230  case kVK_Return:
231  return GHOST_kKeyEnter;
232  case kVK_Delete:
233  return GHOST_kKeyBackSpace;
234  case kVK_ForwardDelete:
235  return GHOST_kKeyDelete;
236  case kVK_Escape:
237  return GHOST_kKeyEsc;
238  case kVK_Tab:
239  return GHOST_kKeyTab;
240  case kVK_Space:
241  return GHOST_kKeySpace;
242 
243  case kVK_Home:
244  return GHOST_kKeyHome;
245  case kVK_End:
246  return GHOST_kKeyEnd;
247  case kVK_PageUp:
248  return GHOST_kKeyUpPage;
249  case kVK_PageDown:
250  return GHOST_kKeyDownPage;
251 
252  /*case kVK_ANSI_Minus: return GHOST_kKeyMinus;
253  case kVK_ANSI_Equal: return GHOST_kKeyEqual;
254  case kVK_ANSI_Comma: return GHOST_kKeyComma;
255  case kVK_ANSI_Period: return GHOST_kKeyPeriod;
256  case kVK_ANSI_Slash: return GHOST_kKeySlash;
257  case kVK_ANSI_Semicolon: return GHOST_kKeySemicolon;
258  case kVK_ANSI_Quote: return GHOST_kKeyQuote;
259  case kVK_ANSI_Backslash: return GHOST_kKeyBackslash;
260  case kVK_ANSI_LeftBracket: return GHOST_kKeyLeftBracket;
261  case kVK_ANSI_RightBracket: return GHOST_kKeyRightBracket;
262  case kVK_ANSI_Grave: return GHOST_kKeyAccentGrave;*/
263 
264  case kVK_VolumeUp:
265  case kVK_VolumeDown:
266  case kVK_Mute:
267  return GHOST_kKeyUnknown;
268 
269  default: {
270  /* alphanumerical or punctuation key that is remappable in int'l keyboards */
271  if ((recvChar >= 'A') && (recvChar <= 'Z')) {
272  return (GHOST_TKey)(recvChar - 'A' + GHOST_kKeyA);
273  }
274  else if ((recvChar >= 'a') && (recvChar <= 'z')) {
275  return (GHOST_TKey)(recvChar - 'a' + GHOST_kKeyA);
276  }
277  else {
278  /* Leopard and Snow Leopard 64bit compatible API*/
279  CFDataRef uchrHandle; /*the keyboard layout*/
280  TISInputSourceRef kbdTISHandle;
281 
282  kbdTISHandle = TISCopyCurrentKeyboardLayoutInputSource();
283  uchrHandle = (CFDataRef)TISGetInputSourceProperty(kbdTISHandle,
284  kTISPropertyUnicodeKeyLayoutData);
285  CFRelease(kbdTISHandle);
286 
287  /*get actual character value of the "remappable" keys in int'l keyboards,
288  if keyboard layout is not correctly reported (e.g. some non Apple keyboards in Tiger),
289  then fallback on using the received charactersIgnoringModifiers */
290  if (uchrHandle) {
291  UInt32 deadKeyState = 0;
292  UniCharCount actualStrLength = 0;
293 
294  UCKeyTranslate((UCKeyboardLayout *)CFDataGetBytePtr(uchrHandle),
295  rawCode,
296  keyAction,
297  0,
298  LMGetKbdType(),
299  kUCKeyTranslateNoDeadKeysBit,
300  &deadKeyState,
301  1,
302  &actualStrLength,
303  &recvChar);
304  }
305 
306  switch (recvChar) {
307  case '-':
308  return GHOST_kKeyMinus;
309  case '+':
310  return GHOST_kKeyPlus;
311  case '=':
312  return GHOST_kKeyEqual;
313  case ',':
314  return GHOST_kKeyComma;
315  case '.':
316  return GHOST_kKeyPeriod;
317  case '/':
318  return GHOST_kKeySlash;
319  case ';':
320  return GHOST_kKeySemicolon;
321  case '\'':
322  return GHOST_kKeyQuote;
323  case '\\':
324  return GHOST_kKeyBackslash;
325  case '[':
326  return GHOST_kKeyLeftBracket;
327  case ']':
328  return GHOST_kKeyRightBracket;
329  case '`':
330  return GHOST_kKeyAccentGrave;
331  default:
332  return GHOST_kKeyUnknown;
333  }
334  }
335  }
336  }
337  return GHOST_kKeyUnknown;
338 }
339 
340 #pragma mark Utility functions
341 
342 #define FIRSTFILEBUFLG 512
343 static bool g_hasFirstFile = false;
344 static char g_firstFileBuf[512];
345 
346 // TODO: Need to investigate this.
347 // Function called too early in creator.c to have g_hasFirstFile == true
348 extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG])
349 {
350  if (g_hasFirstFile) {
351  strncpy(buf, g_firstFileBuf, FIRSTFILEBUFLG - 1);
352  buf[FIRSTFILEBUFLG - 1] = '\0';
353  return 1;
354  }
355  else {
356  return 0;
357  }
358 }
359 
360 #pragma mark Cocoa objects
361 
366 @interface CocoaAppDelegate : NSObject <NSApplicationDelegate>
367 {
368 
370 }
371 
372 - (id)init;
373 - (void)dealloc;
374 - (void)setSystemCocoa:(GHOST_SystemCocoa *)sysCocoa;
375 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
376 - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename;
377 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
378 - (void)applicationWillTerminate:(NSNotification *)aNotification;
379 - (void)applicationWillBecomeActive:(NSNotification *)aNotification;
380 - (void)toggleFullScreen:(NSNotification *)notification;
381 - (void)windowWillClose:(NSNotification *)notification;
382 @end
383 
384 @implementation CocoaAppDelegate : NSObject
385 - (id)init
386 {
387  self = [super init];
388  NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
389  [center addObserver:self
390  selector:@selector(windowWillClose:)
391  name:NSWindowWillCloseNotification
392  object:nil];
393  return self;
394 }
395 
396 - (void)dealloc
397 {
398  NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
399  [center removeObserver:self name:NSWindowWillCloseNotification object:nil];
400  [super dealloc];
401 }
402 
403 - (void)setSystemCocoa:(GHOST_SystemCocoa *)sysCocoa
404 {
405  systemCocoa = sysCocoa;
406 }
407 
408 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
409 {
410  if (systemCocoa->m_windowFocus) {
411  // Raise application to front, convenient when starting from the terminal
412  // and important for launching the animation player. we call this after the
413  // application finishes launching, as doing it earlier can make us end up
414  // with a frontmost window but an inactive application.
415  [NSApp activateIgnoringOtherApps:YES];
416  }
417 
418  [NSEvent setMouseCoalescingEnabled:NO];
419 }
420 
421 - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
422 {
423  return systemCocoa->handleOpenDocumentRequest(filename);
424 }
425 
426 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
427 {
428  /* TODO: implement graceful termination through Cocoa mechanism
429  * to avoid session log off to be canceled. */
430  /* Note that Cmd+Q is already handled by keyhandler. */
432  return NSTerminateCancel;
433 }
434 
435 // To avoid canceling a log off process, we must use Cocoa termination process
436 // And this function is the only chance to perform clean up
437 // So WM_exit needs to be called directly, as the event loop will never run before termination
438 - (void)applicationWillTerminate:(NSNotification *)aNotification
439 {
440  /*G.is_break = FALSE; //Let Cocoa perform the termination at the end
441  WM_exit(C);*/
442 }
443 
444 - (void)applicationWillBecomeActive:(NSNotification *)aNotification
445 {
447 }
448 
449 - (void)toggleFullScreen:(NSNotification *)notification
450 {
451 }
452 
453 // The purpose of this function is to make sure closing "About" window does not
454 // leave Blender with no key windows. This is needed due to a custom event loop
455 // nature of the application: for some reason only using [NSApp run] will ensure
456 // correct behavior in this case.
457 //
458 // This is similar to an issue solved in SDL:
459 // https://bugzilla.libsdl.org/show_bug.cgi?id=1825
460 //
461 // Our solution is different, since we want Blender to keep track of what is
462 // the key window during normal operation. In order to do so we exploit the
463 // fact that "About" window is never in the orderedWindows array: we only force
464 // key window from here if the closing one is not in the orderedWindows. This
465 // saves lack of key windows when closing "About", but does not interfere with
466 // Blender's window manager when closing Blender's windows.
467 - (void)windowWillClose:(NSNotification *)notification
468 {
469  NSWindow *closing_window = (NSWindow *)[notification object];
470  NSInteger index = [[NSApp orderedWindows] indexOfObject:closing_window];
471  if (index != NSNotFound) {
472  return;
473  }
474  // Find first suitable window from the current space.
475  for (NSWindow *current_window in [NSApp orderedWindows]) {
476  if (current_window == closing_window) {
477  continue;
478  }
479  if ([current_window isOnActiveSpace] && [current_window canBecomeKeyWindow]) {
480  [current_window makeKeyAndOrderFront:nil];
481  return;
482  }
483  }
484  // If that didn't find any windows, we try to find any suitable window of
485  // the application.
486  for (NSNumber *window_number in [NSWindow windowNumbersWithOptions:0]) {
487  NSWindow *current_window = [NSApp windowWithWindowNumber:[window_number integerValue]];
488  if (current_window == closing_window) {
489  continue;
490  }
491  if ([current_window canBecomeKeyWindow]) {
492  [current_window makeKeyAndOrderFront:nil];
493  return;
494  }
495  }
496 }
497 
498 @end
499 
500 #pragma mark initialization/finalization
501 
503 {
504  int mib[2];
505  struct timeval boottime;
506  size_t len;
507  char *rstring = NULL;
508 
509  m_modifierMask = 0;
513  GHOST_ASSERT(m_displayManager, "GHOST_SystemCocoa::GHOST_SystemCocoa(): m_displayManager==0\n");
515 
516  // NSEvent timeStamp is given in system uptime, state start date is boot time
517  mib[0] = CTL_KERN;
518  mib[1] = KERN_BOOTTIME;
519  len = sizeof(struct timeval);
520 
521  sysctl(mib, 2, &boottime, &len, NULL, 0);
522  m_start_time = ((boottime.tv_sec * 1000) + (boottime.tv_usec / 1000));
523 
524  // Detect multitouch trackpad
525  mib[0] = CTL_HW;
526  mib[1] = HW_MODEL;
527  sysctl(mib, 2, NULL, &len, NULL, 0);
528  rstring = (char *)malloc(len);
529  sysctl(mib, 2, rstring, &len, NULL, 0);
530 
531  free(rstring);
532  rstring = NULL;
533 
535  m_ignoreMomentumScroll = false;
536  m_multiTouchScroll = false;
538 }
539 
541 {
542 }
543 
545 {
547  if (success) {
548 
549 #ifdef WITH_INPUT_NDOF
550  m_ndofManager = new GHOST_NDOFManagerCocoa(*this);
551 #endif
552 
553  // ProcessSerialNumber psn;
554 
555  // Carbon stuff to move window & menu to foreground
556  /*if (!GetCurrentProcess(&psn)) {
557  TransformProcessType(&psn, kProcessTransformToForegroundApplication);
558  SetFrontProcess(&psn);
559  }*/
560 
561  @autoreleasepool {
562  [NSApplication sharedApplication]; // initializes NSApp
563 
564  if ([NSApp mainMenu] == nil) {
565  NSMenu *mainMenubar = [[NSMenu alloc] init];
566  NSMenuItem *menuItem;
567  NSMenu *windowMenu;
568  NSMenu *appMenu;
569 
570  // Create the application menu
571  appMenu = [[NSMenu alloc] initWithTitle:@"Blender"];
572 
573  [appMenu addItemWithTitle:@"About Blender"
574  action:@selector(orderFrontStandardAboutPanel:)
575  keyEquivalent:@""];
576  [appMenu addItem:[NSMenuItem separatorItem]];
577 
578  menuItem = [appMenu addItemWithTitle:@"Hide Blender"
579  action:@selector(hide:)
580  keyEquivalent:@"h"];
581  [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
582 
583  menuItem = [appMenu addItemWithTitle:@"Hide Others"
584  action:@selector(hideOtherApplications:)
585  keyEquivalent:@"h"];
586  [menuItem
587  setKeyEquivalentModifierMask:(NSEventModifierFlagOption | NSEventModifierFlagCommand)];
588 
589  [appMenu addItemWithTitle:@"Show All"
590  action:@selector(unhideAllApplications:)
591  keyEquivalent:@""];
592 
593  menuItem = [appMenu addItemWithTitle:@"Quit Blender"
594  action:@selector(terminate:)
595  keyEquivalent:@"q"];
596  [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
597 
598  menuItem = [[NSMenuItem alloc] init];
599  [menuItem setSubmenu:appMenu];
600 
601  [mainMenubar addItem:menuItem];
602  [menuItem release];
603  [NSApp performSelector:@selector(setAppleMenu:) withObject:appMenu]; // Needed for 10.5
604  [appMenu release];
605 
606  // Create the window menu
607  windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
608 
609  menuItem = [windowMenu addItemWithTitle:@"Minimize"
610  action:@selector(performMiniaturize:)
611  keyEquivalent:@"m"];
612  [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
613 
614  [windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
615 
616  menuItem = [windowMenu addItemWithTitle:@"Enter Full Screen"
617  action:@selector(toggleFullScreen:)
618  keyEquivalent:@"f"];
619  [menuItem
620  setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
621 
622  menuItem = [windowMenu addItemWithTitle:@"Close"
623  action:@selector(performClose:)
624  keyEquivalent:@"w"];
625  [menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
626 
627  menuItem = [[NSMenuItem alloc] init];
628  [menuItem setSubmenu:windowMenu];
629 
630  [mainMenubar addItem:menuItem];
631  [menuItem release];
632 
633  [NSApp setMainMenu:mainMenubar];
634  [NSApp setWindowsMenu:windowMenu];
635  [windowMenu release];
636  }
637 
638  if ([NSApp delegate] == nil) {
639  CocoaAppDelegate *appDelegate = [[CocoaAppDelegate alloc] init];
640  [appDelegate setSystemCocoa:this];
641  [NSApp setDelegate:appDelegate];
642  }
643 
644  // AppKit provides automatic window tabbing. Blender is a single-tabbed application
645  // without a macOS tab bar, and should explicitly opt-out of this. This is also
646  // controlled by the macOS user default #NSWindowTabbingEnabled.
647  NSWindow.allowsAutomaticWindowTabbing = NO;
648 
649  [NSApp finishLaunching];
650  }
651  }
652  return success;
653 }
654 
655 #pragma mark window management
656 
658 {
659  // Cocoa equivalent exists in 10.6 ([[NSProcessInfo processInfo] systemUptime])
660  struct timeval currentTime;
661 
662  gettimeofday(&currentTime, NULL);
663 
664  // Return timestamp of system uptime
665 
666  return ((currentTime.tv_sec * 1000) + (currentTime.tv_usec / 1000) - m_start_time);
667 }
668 
670 {
671  // Note that OS X supports monitor hot plug
672  // We do not support multiple monitors at the moment
673  @autoreleasepool {
674  return NSScreen.screens.count;
675  }
676 }
677 
679 {
680  @autoreleasepool {
681  // Get visible frame, that is frame excluding dock and top menu bar
682  NSRect frame = [[NSScreen mainScreen] visibleFrame];
683 
684  // Returns max window contents (excluding title bar...)
685  NSRect contentRect = [NSWindow
686  contentRectForFrameRect:frame
687  styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
688  NSWindowStyleMaskMiniaturizable)];
689 
690  width = contentRect.size.width;
691  height = contentRect.size.height;
692  }
693 }
694 
696 {
697  /* TODO! */
699 }
700 
708  GHOST_GLSettings glSettings,
709  const bool exclusive,
710  const bool is_dialog,
711  const GHOST_IWindow *parentWindow)
712 {
713  GHOST_IWindow *window = NULL;
714  @autoreleasepool {
715 
716  // Get the available rect for including window contents
717  NSRect frame = [[NSScreen mainScreen] visibleFrame];
718  NSRect contentRect = [NSWindow
719  contentRectForFrameRect:frame
720  styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
721  NSWindowStyleMaskMiniaturizable)];
722 
723  GHOST_TInt32 bottom = (contentRect.size.height - 1) - height - top;
724 
725  // Ensures window top left is inside this available rect
726  left = left > contentRect.origin.x ? left : contentRect.origin.x;
727  // Add contentRect.origin.y to respect docksize
728  bottom = bottom > contentRect.origin.y ? bottom + contentRect.origin.y : contentRect.origin.y;
729 
730  window = new GHOST_WindowCocoa(this,
731  title,
732  left,
733  bottom,
734  width,
735  height,
736  state,
737  type,
738  glSettings.flags & GHOST_glStereoVisual,
739  glSettings.flags & GHOST_glDebugContext,
740  is_dialog,
741  (GHOST_WindowCocoa *)parentWindow);
742 
743  if (window->getValid()) {
744  // Store the pointer to the window
745  GHOST_ASSERT(m_windowManager, "m_windowManager not initialized");
746  m_windowManager->addWindow(window);
748  /* Need to tell window manager the new window is the active one
749  * (Cocoa does not send the event activate upon window creation). */
752  }
753  else {
754  GHOST_PRINT("GHOST_SystemCocoa::createWindow(): window invalid\n");
755  delete window;
756  window = NULL;
757  }
758  }
759  return window;
760 }
761 
768 {
770  if (context->initializeDrawingContext())
771  return context;
772  else
773  delete context;
774 
775  return NULL;
776 }
777 
784 {
785  delete context;
786 
787  return GHOST_kSuccess;
788 }
789 
794 {
795  NSPoint mouseLoc = [NSEvent mouseLocation];
796 
797  // Returns the mouse location in screen coordinates
798  x = (GHOST_TInt32)mouseLoc.x;
799  y = (GHOST_TInt32)mouseLoc.y;
800  return GHOST_kSuccess;
801 }
802 
807 {
809  if (!window)
810  return GHOST_kFailure;
811 
812  // Cursor and mouse dissociation placed here not to interfere with continuous grab
813  // (in cont. grab setMouseCursorPosition is directly called)
814  CGAssociateMouseAndMouseCursorPosition(false);
816  CGAssociateMouseAndMouseCursorPosition(true);
817 
818  // Force mouse move event (not pushed by Cocoa)
820  getMilliSeconds(), GHOST_kEventCursorMove, window, x, y, window->GetCocoaTabletData()));
822 
823  return GHOST_kSuccess;
824 }
825 
827 {
828  float xf = (float)x, yf = (float)y;
830  if (!window)
831  return GHOST_kFailure;
832 
833  @autoreleasepool {
834  NSScreen *windowScreen = window->getScreen();
835  NSRect screenRect = [windowScreen frame];
836 
837  // Set position relative to current screen
838  xf -= screenRect.origin.x;
839  yf -= screenRect.origin.y;
840 
841  // Quartz Display Services uses the old coordinates (top left origin)
842  yf = screenRect.size.height - yf;
843 
844  CGDisplayMoveCursorToPoint((CGDirectDisplayID)[[[windowScreen deviceDescription]
845  objectForKey:@"NSScreenNumber"] unsignedIntValue],
846  CGPointMake(xf, yf));
847 
848  // See https://stackoverflow.com/a/17559012. By default, hardware events
849  // will be suppressed for 500ms after a synthetic mouse event. For unknown
850  // reasons CGEventSourceSetLocalEventsSuppressionInterval does not work,
851  // however calling CGAssociateMouseAndMouseCursorPosition also removes the
852  // delay, even if this is undocumented.
853  CGAssociateMouseAndMouseCursorPosition(true);
854  }
855  return GHOST_kSuccess;
856 }
857 
859 {
860  keys.set(GHOST_kModifierKeyOS, (m_modifierMask & NSEventModifierFlagCommand) ? true : false);
861  keys.set(GHOST_kModifierKeyLeftAlt, (m_modifierMask & NSEventModifierFlagOption) ? true : false);
863  (m_modifierMask & NSEventModifierFlagShift) ? true : false);
865  (m_modifierMask & NSEventModifierFlagControl) ? true : false);
866 
867  return GHOST_kSuccess;
868 }
869 
871 {
872  UInt32 button_state = GetCurrentEventButtonState();
873 
874  buttons.clear();
875  buttons.set(GHOST_kButtonMaskLeft, button_state & (1 << 0));
876  buttons.set(GHOST_kButtonMaskRight, button_state & (1 << 1));
877  buttons.set(GHOST_kButtonMaskMiddle, button_state & (1 << 2));
878  buttons.set(GHOST_kButtonMaskButton4, button_state & (1 << 3));
879  buttons.set(GHOST_kButtonMaskButton5, button_state & (1 << 4));
880  return GHOST_kSuccess;
881 }
882 
883 #pragma mark Event handlers
884 
888 bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
889 {
890  bool anyProcessed = false;
891  NSEvent *event;
892 
893  // TODO : implement timer ??
894 #if 0
895  do {
896  GHOST_TimerManager* timerMgr = getTimerManager();
897 
898  if (waitForEvent) {
899  GHOST_TUns64 next = timerMgr->nextFireTime();
900  double timeOut;
901 
902  if (next == GHOST_kFireTimeNever) {
903  timeOut = kEventDurationForever;
904  }
905  else {
906  timeOut = (double)(next - getMilliSeconds())/1000.0;
907  if (timeOut < 0.0)
908  timeOut = 0.0;
909  }
910 
911  ::ReceiveNextEvent(0, NULL, timeOut, false, &event);
912  }
913 
914  if (timerMgr->fireTimers(getMilliSeconds())) {
915  anyProcessed = true;
916  }
917 #endif
918  do {
919  @autoreleasepool {
920  event = [NSApp nextEventMatchingMask:NSEventMaskAny
921  untilDate:[NSDate distantPast]
922  inMode:NSDefaultRunLoopMode
923  dequeue:YES];
924  if (event == nil) {
925  break;
926  }
927 
928  anyProcessed = true;
929 
930  // Send event to NSApp to ensure Mac wide events are handled,
931  // this will send events to CocoaWindow which will call back
932  // to handleKeyEvent, handleMouseEvent and handleTabletEvent
933 
934  // There is on special exception for ctrl+(shift)+tab. We do not
935  // get keyDown events delivered to the view because they are
936  // special hotkeys to switch between views, so override directly
937 
938  if ([event type] == NSEventTypeKeyDown && [event keyCode] == kVK_Tab &&
939  ([event modifierFlags] & NSEventModifierFlagControl)) {
940  handleKeyEvent(event);
941  }
942  else {
943  // For some reason NSApp is swallowing the key up events when modifier
944  // key is pressed, even if there seems to be no apparent reason to do
945  // so, as a workaround we always handle these up events.
946  if ([event type] == NSEventTypeKeyUp &&
947  ([event modifierFlags] & (NSEventModifierFlagCommand | NSEventModifierFlagOption)))
948  handleKeyEvent(event);
949 
950  [NSApp sendEvent:event];
951  }
952  }
953  } while (event != nil);
954 #if 0
955  } while (waitForEvent && !anyProcessed); // Needed only for timer implementation
956 #endif
957 
960 
963  return true;
964  }
965 
967 
968  return anyProcessed;
969 }
970 
971 // Note: called from NSApplication delegate
973 {
974  for (GHOST_IWindow *iwindow : m_windowManager->getWindows()) {
975  GHOST_WindowCocoa *window = (GHOST_WindowCocoa *)iwindow;
976  if (window->isDialog()) {
977  [window->getCocoaWindow() makeKeyAndOrderFront:nil];
978  }
979  }
980 
981  // Update the modifiers key mask, as its status may have changed when the application
982  // was not active (that is when update events are sent to another application).
983  unsigned int modifiers;
985 
986  if (!window) {
988  return GHOST_kFailure;
989  }
990  else
992 
993  modifiers = [[[NSApplication sharedApplication] currentEvent] modifierFlags];
994 
995  if ((modifiers & NSEventModifierFlagShift) != (m_modifierMask & NSEventModifierFlagShift)) {
997  (modifiers & NSEventModifierFlagShift) ? GHOST_kEventKeyDown :
999  window,
1001  false));
1002  }
1003  if ((modifiers & NSEventModifierFlagControl) != (m_modifierMask & NSEventModifierFlagControl)) {
1005  (modifiers & NSEventModifierFlagControl) ? GHOST_kEventKeyDown :
1007  window,
1009  false));
1010  }
1011  if ((modifiers & NSEventModifierFlagOption) != (m_modifierMask & NSEventModifierFlagOption)) {
1013  (modifiers & NSEventModifierFlagOption) ? GHOST_kEventKeyDown :
1015  window,
1017  false));
1018  }
1019  if ((modifiers & NSEventModifierFlagCommand) != (m_modifierMask & NSEventModifierFlagCommand)) {
1021  (modifiers & NSEventModifierFlagCommand) ? GHOST_kEventKeyDown :
1023  window,
1024  GHOST_kKeyOS,
1025  false));
1026  }
1027 
1028  m_modifierMask = modifiers;
1029 
1031  return GHOST_kSuccess;
1032 }
1033 
1036  for (GHOST_IWindow *iwindow : m_windowManager->getWindows()) {
1037  GHOST_WindowCocoa *window = (GHOST_WindowCocoa *)iwindow;
1038  if (window->isDialog()) {
1039  return true;
1040  }
1041  }
1042  return false;
1043 }
1044 
1048 }
1049 
1050 // Note: called from NSWindow delegate
1053 {
1054  NSArray *windowsList;
1055  windowsList = [NSApp orderedWindows];
1056  if (!validWindow(window)) {
1057  return GHOST_kFailure;
1058  }
1059  switch (eventType) {
1062  break;
1065  window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
1067  break;
1071  break;
1073  if (m_nativePixel) {
1074  window->setNativePixelSize();
1076  }
1078  break;
1081  break;
1084  // Enforce only one resize message per event loop
1085  // (coalescing all the live resize messages)
1086  window->updateDrawingContext();
1088  // Mouse up event is trapped by the resizing event loop,
1089  // so send it anyway to the window manager.
1092  window,
1095  // m_ignoreWindowSizedMessages = true;
1096  }
1097  break;
1099 
1100  if (m_nativePixel) {
1101  window->setNativePixelSize();
1103  }
1104 
1105  default:
1106  return GHOST_kFailure;
1107  break;
1108  }
1109 
1111  return GHOST_kSuccess;
1112 }
1113 
1114 // Note: called from NSWindow subclass
1116  GHOST_TDragnDropTypes draggedObjectType,
1117  GHOST_WindowCocoa *window,
1118  int mouseX,
1119  int mouseY,
1120  void *data)
1121 {
1122  if (!validWindow(window)) {
1123  return GHOST_kFailure;
1124  }
1125  switch (eventType) {
1130  getMilliSeconds(), eventType, draggedObjectType, window, mouseX, mouseY, NULL));
1131  break;
1132 
1134  GHOST_TUns8 *temp_buff;
1135  GHOST_TStringArray *strArray;
1136  NSArray *droppedArray;
1137  size_t pastedTextSize;
1138  NSString *droppedStr;
1139  GHOST_TEventDataPtr eventData;
1140  int i;
1141 
1142  if (!data)
1143  return GHOST_kFailure;
1144 
1145  switch (draggedObjectType) {
1147  droppedArray = (NSArray *)data;
1148 
1149  strArray = (GHOST_TStringArray *)malloc(sizeof(GHOST_TStringArray));
1150  if (!strArray)
1151  return GHOST_kFailure;
1152 
1153  strArray->count = [droppedArray count];
1154  if (strArray->count == 0) {
1155  free(strArray);
1156  return GHOST_kFailure;
1157  }
1158 
1159  strArray->strings = (GHOST_TUns8 **)malloc(strArray->count * sizeof(GHOST_TUns8 *));
1160 
1161  for (i = 0; i < strArray->count; i++) {
1162  droppedStr = [droppedArray objectAtIndex:i];
1163 
1164  pastedTextSize = [droppedStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
1165  temp_buff = (GHOST_TUns8 *)malloc(pastedTextSize + 1);
1166 
1167  if (!temp_buff) {
1168  strArray->count = i;
1169  break;
1170  }
1171 
1172  strncpy((char *)temp_buff,
1173  [droppedStr cStringUsingEncoding:NSUTF8StringEncoding],
1174  pastedTextSize);
1175  temp_buff[pastedTextSize] = '\0';
1176 
1177  strArray->strings[i] = temp_buff;
1178  }
1179 
1180  eventData = (GHOST_TEventDataPtr)strArray;
1181  break;
1182 
1184  droppedStr = (NSString *)data;
1185  pastedTextSize = [droppedStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
1186 
1187  temp_buff = (GHOST_TUns8 *)malloc(pastedTextSize + 1);
1188 
1189  if (temp_buff == NULL) {
1190  return GHOST_kFailure;
1191  }
1192 
1193  strncpy((char *)temp_buff,
1194  [droppedStr cStringUsingEncoding:NSUTF8StringEncoding],
1195  pastedTextSize);
1196 
1197  temp_buff[pastedTextSize] = '\0';
1198 
1199  eventData = (GHOST_TEventDataPtr)temp_buff;
1200  break;
1201 
1203  NSImage *droppedImg = (NSImage *)data;
1204  NSSize imgSize = [droppedImg size];
1205  ImBuf *ibuf = NULL;
1206  GHOST_TUns8 *rasterRGB = NULL;
1207  GHOST_TUns8 *rasterRGBA = NULL;
1208  GHOST_TUns8 *toIBuf = NULL;
1209  int x, y, to_i, from_i;
1210  NSBitmapImageRep *blBitmapFormatImageRGB, *blBitmapFormatImageRGBA, *bitmapImage = nil;
1211  NSEnumerator *enumerator;
1212  NSImageRep *representation;
1213 
1214  ibuf = IMB_allocImBuf(imgSize.width, imgSize.height, 32, IB_rect);
1215  if (!ibuf) {
1216  [droppedImg release];
1217  return GHOST_kFailure;
1218  }
1219 
1220  /*Get the bitmap of the image*/
1221  enumerator = [[droppedImg representations] objectEnumerator];
1222  while ((representation = [enumerator nextObject])) {
1223  if ([representation isKindOfClass:[NSBitmapImageRep class]]) {
1224  bitmapImage = (NSBitmapImageRep *)representation;
1225  break;
1226  }
1227  }
1228  if (bitmapImage == nil)
1229  return GHOST_kFailure;
1230 
1231  if (([bitmapImage bitsPerPixel] == 32) && (([bitmapImage bitmapFormat] & 0x5) == 0) &&
1232  ![bitmapImage isPlanar]) {
1233  /* Try a fast copy if the image is a meshed RGBA 32bit bitmap*/
1234  toIBuf = (GHOST_TUns8 *)ibuf->rect;
1235  rasterRGB = (GHOST_TUns8 *)[bitmapImage bitmapData];
1236  for (y = 0; y < imgSize.height; y++) {
1237  to_i = (imgSize.height - y - 1) * imgSize.width;
1238  from_i = y * imgSize.width;
1239  memcpy(toIBuf + 4 * to_i, rasterRGB + 4 * from_i, 4 * imgSize.width);
1240  }
1241  }
1242  else {
1243  /* Tell cocoa image resolution is same as current system one */
1244  [bitmapImage setSize:imgSize];
1245 
1246  /* Convert the image in a RGBA 32bit format */
1247  /* As Core Graphics does not support contexts with non premutliplied alpha,
1248  we need to get alpha key values in a separate batch */
1249 
1250  /* First get RGB values w/o Alpha to avoid pre-multiplication,
1251  * 32bit but last byte is unused */
1252  blBitmapFormatImageRGB = [[NSBitmapImageRep alloc]
1253  initWithBitmapDataPlanes:NULL
1254  pixelsWide:imgSize.width
1255  pixelsHigh:imgSize.height
1256  bitsPerSample:8
1257  samplesPerPixel:3
1258  hasAlpha:NO
1259  isPlanar:NO
1260  colorSpaceName:NSDeviceRGBColorSpace
1261  bitmapFormat:(NSBitmapFormat)0
1262  bytesPerRow:4 * imgSize.width
1263  bitsPerPixel:32 /*RGB format padded to 32bits*/];
1264 
1265  [NSGraphicsContext saveGraphicsState];
1266  [NSGraphicsContext
1267  setCurrentContext:[NSGraphicsContext
1268  graphicsContextWithBitmapImageRep:blBitmapFormatImageRGB]];
1269  [bitmapImage draw];
1270  [NSGraphicsContext restoreGraphicsState];
1271 
1272  rasterRGB = (GHOST_TUns8 *)[blBitmapFormatImageRGB bitmapData];
1273  if (rasterRGB == NULL) {
1274  [bitmapImage release];
1275  [blBitmapFormatImageRGB release];
1276  [droppedImg release];
1277  return GHOST_kFailure;
1278  }
1279 
1280  /* Then get Alpha values by getting the RGBA image (that is pre-multiplied BTW) */
1281  blBitmapFormatImageRGBA = [[NSBitmapImageRep alloc]
1282  initWithBitmapDataPlanes:NULL
1283  pixelsWide:imgSize.width
1284  pixelsHigh:imgSize.height
1285  bitsPerSample:8
1286  samplesPerPixel:4
1287  hasAlpha:YES
1288  isPlanar:NO
1289  colorSpaceName:NSDeviceRGBColorSpace
1290  bitmapFormat:(NSBitmapFormat)0
1291  bytesPerRow:4 * imgSize.width
1292  bitsPerPixel:32 /* RGBA */];
1293 
1294  [NSGraphicsContext saveGraphicsState];
1295  [NSGraphicsContext
1296  setCurrentContext:[NSGraphicsContext
1297  graphicsContextWithBitmapImageRep:blBitmapFormatImageRGBA]];
1298  [bitmapImage draw];
1299  [NSGraphicsContext restoreGraphicsState];
1300 
1301  rasterRGBA = (GHOST_TUns8 *)[blBitmapFormatImageRGBA bitmapData];
1302  if (rasterRGBA == NULL) {
1303  [bitmapImage release];
1304  [blBitmapFormatImageRGB release];
1305  [blBitmapFormatImageRGBA release];
1306  [droppedImg release];
1307  return GHOST_kFailure;
1308  }
1309 
1310  /*Copy the image to ibuf, flipping it vertically*/
1311  toIBuf = (GHOST_TUns8 *)ibuf->rect;
1312  for (y = 0; y < imgSize.height; y++) {
1313  for (x = 0; x < imgSize.width; x++) {
1314  to_i = (imgSize.height - y - 1) * imgSize.width + x;
1315  from_i = y * imgSize.width + x;
1316 
1317  toIBuf[4 * to_i] = rasterRGB[4 * from_i]; /* R */
1318  toIBuf[4 * to_i + 1] = rasterRGB[4 * from_i + 1]; /* G */
1319  toIBuf[4 * to_i + 2] = rasterRGB[4 * from_i + 2]; /* B */
1320  toIBuf[4 * to_i + 3] = rasterRGBA[4 * from_i + 3]; /* A */
1321  }
1322  }
1323 
1324  [blBitmapFormatImageRGB release];
1325  [blBitmapFormatImageRGBA release];
1326  [droppedImg release];
1327  }
1328 
1329  eventData = (GHOST_TEventDataPtr)ibuf;
1330 
1331  break;
1332  }
1333  default:
1334  return GHOST_kFailure;
1335  break;
1336  }
1338  getMilliSeconds(), eventType, draggedObjectType, window, mouseX, mouseY, eventData));
1339 
1340  break;
1341  }
1342  default:
1343  return GHOST_kFailure;
1344  }
1346  return GHOST_kSuccess;
1347 }
1348 
1352 
1353  // Discard quit event if we are in cursor grab sequence
1354  if (window && window->getCursorGrabModeIsWarp())
1355  return;
1356 
1357  // Push the event to Blender so it can open a dialog if needed
1360 }
1361 
1362 bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr)
1364  NSString *filepath = (NSString *)filepathStr;
1365  NSArray *windowsList;
1366  char *temp_buff;
1367  size_t filenameTextSize;
1368 
1369  /* Check for blender opened windows and make the frontmost key. In case blender
1370  * is minimized, opened on another desktop space, or in full-screen mode. */
1371  windowsList = [NSApp orderedWindows];
1372  if ([windowsList count]) {
1373  [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil];
1374  }
1375 
1377 
1378  if (!window) {
1379  return NO;
1380  }
1381 
1382  /* Discard event if we are in cursor grab sequence,
1383  * it'll lead to "stuck cursor" situation if the alert panel is raised. */
1384  if (window && window->getCursorGrabModeIsWarp()) {
1385  return NO;
1386  }
1387 
1388  filenameTextSize = [filepath lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
1389  temp_buff = (char *)malloc(filenameTextSize + 1);
1390 
1391  if (temp_buff == NULL) {
1392  return GHOST_kFailure;
1393  }
1394 
1395  strncpy(temp_buff, [filepath cStringUsingEncoding:NSUTF8StringEncoding], filenameTextSize);
1396  temp_buff[filenameTextSize] = '\0';
1397 
1400 
1401  return YES;
1402 }
1403 
1404 GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventType)
1406  NSEvent *event = (NSEvent *)eventPtr;
1407  GHOST_IWindow *window;
1408 
1409  window = m_windowManager->getWindowAssociatedWithOSWindow((void *)[event window]);
1410  if (!window) {
1411  // printf("\nW failure for event 0x%x",[event type]);
1412  return GHOST_kFailure;
1413  }
1414 
1415  GHOST_TabletData &ct = ((GHOST_WindowCocoa *)window)->GetCocoaTabletData();
1416 
1417  switch (eventType) {
1418  case NSEventTypeTabletPoint:
1419  // workaround 2 cornercases:
1420  // 1. if [event isEnteringProximity] was not triggered since program-start
1421  // 2. device is not sending [event pointingDeviceType], due no eraser
1422  if (ct.Active == GHOST_kTabletModeNone)
1424 
1425  ct.Pressure = [event pressure];
1426  ct.Xtilt = [event tilt].x;
1427  ct.Ytilt = [event tilt].y;
1428  break;
1429 
1430  case NSEventTypeTabletProximity:
1431  /* Reset tablet data when device enters proximity or leaves. */
1433  if ([event isEnteringProximity]) {
1434  /* Pointer is entering tablet area proximity. */
1435  switch ([event pointingDeviceType]) {
1436  case NSPointingDeviceTypePen:
1438  break;
1439  case NSPointingDeviceTypeEraser:
1441  break;
1442  case NSPointingDeviceTypeCursor:
1443  case NSPointingDeviceTypeUnknown:
1444  default:
1445  break;
1446  }
1447  }
1448  break;
1449 
1450  default:
1451  GHOST_ASSERT(FALSE, "GHOST_SystemCocoa::handleTabletEvent : unknown event received");
1452  return GHOST_kFailure;
1453  break;
1454  }
1455  return GHOST_kSuccess;
1456 }
1457 
1458 bool GHOST_SystemCocoa::handleTabletEvent(void *eventPtr)
1460  NSEvent *event = (NSEvent *)eventPtr;
1461 
1462  switch ([event subtype]) {
1463  case NSEventSubtypeTabletPoint:
1464  handleTabletEvent(eventPtr, NSEventTypeTabletPoint);
1465  return true;
1466  case NSEventSubtypeTabletProximity:
1467  handleTabletEvent(eventPtr, NSEventTypeTabletProximity);
1468  return true;
1469  default:
1470  // No tablet event included : do nothing
1471  return false;
1472  }
1473 }
1474 
1477  NSEvent *event = (NSEvent *)eventPtr;
1478  GHOST_WindowCocoa *window;
1479  CocoaWindow *cocoawindow;
1480 
1481  /* [event window] returns other windows if mouse-over, that's OSX input standard
1482  however, if mouse exits window(s), the windows become inactive, until you click.
1483  We then fall back to the active window from ghost */
1485  (void *)[event window]);
1486  if (!window) {
1488  if (!window) {
1489  // printf("\nW failure for event 0x%x",[event type]);
1490  return GHOST_kFailure;
1491  }
1492  }
1493 
1494  cocoawindow = (CocoaWindow *)window->getOSWindow();
1495 
1496  switch ([event type]) {
1497  case NSEventTypeLeftMouseDown:
1498  handleTabletEvent(event); // Update window tablet state to be included in event.
1499  pushEvent(new GHOST_EventButton([event timestamp] * 1000,
1501  window,
1503  window -> GetCocoaTabletData()));
1504  break;
1505  case NSEventTypeRightMouseDown:
1506  handleTabletEvent(event); // Update window tablet state to be included in event.
1507  pushEvent(new GHOST_EventButton([event timestamp] * 1000,
1509  window,
1511  window -> GetCocoaTabletData()));
1512  break;
1513  case NSEventTypeOtherMouseDown:
1514  handleTabletEvent(event); // Handle tablet events combined with mouse events
1515  pushEvent(new GHOST_EventButton([event timestamp] * 1000,
1517  window,
1518  convertButton([event buttonNumber]),
1519  window -> GetCocoaTabletData()));
1520  break;
1521 
1522  case NSEventTypeLeftMouseUp:
1523  handleTabletEvent(event); // Update window tablet state to be included in event.
1524  pushEvent(new GHOST_EventButton([event timestamp] * 1000,
1526  window,
1528  window -> GetCocoaTabletData()));
1529  break;
1530  case NSEventTypeRightMouseUp:
1531  handleTabletEvent(event); // Update window tablet state to be included in event.
1532  pushEvent(new GHOST_EventButton([event timestamp] * 1000,
1534  window,
1536  window -> GetCocoaTabletData()));
1537  break;
1538  case NSEventTypeOtherMouseUp:
1539  handleTabletEvent(event); // Update window tablet state to be included in event.
1540  pushEvent(new GHOST_EventButton([event timestamp] * 1000,
1542  window,
1543  convertButton([event buttonNumber]),
1544  window -> GetCocoaTabletData()));
1545  break;
1546 
1547  case NSEventTypeLeftMouseDragged:
1548  case NSEventTypeRightMouseDragged:
1549  case NSEventTypeOtherMouseDragged:
1550  handleTabletEvent(event); // Update window tablet state to be included in event.
1551 
1552  case NSEventTypeMouseMoved: {
1553  GHOST_TGrabCursorMode grab_mode = window->getCursorGrabMode();
1554 
1555  /* TODO: CHECK IF THIS IS A TABLET EVENT */
1556  bool is_tablet = false;
1557 
1558  if (is_tablet && window->getCursorGrabModeIsWarp()) {
1559  grab_mode = GHOST_kGrabDisable;
1560  }
1561 
1562  switch (grab_mode) {
1563  case GHOST_kGrabHide: // Cursor hidden grab operation : no cursor move
1564  {
1565  GHOST_TInt32 x_warp, y_warp, x_accum, y_accum, x, y;
1566 
1567  window->getCursorGrabInitPos(x_warp, y_warp);
1568  window->screenToClientIntern(x_warp, y_warp, x_warp, y_warp);
1569 
1570  window->getCursorGrabAccum(x_accum, y_accum);
1571  x_accum += [event deltaX];
1572  y_accum += -[event
1573  deltaY]; // Strange Apple implementation (inverted coordinates for the deltaY) ...
1574  window->setCursorGrabAccum(x_accum, y_accum);
1575 
1576  window->clientToScreenIntern(x_warp + x_accum, y_warp + y_accum, x, y);
1577  pushEvent(new GHOST_EventCursor([event timestamp] * 1000,
1579  window,
1580  x,
1581  y,
1582  window -> GetCocoaTabletData()));
1583  break;
1584  }
1585  case GHOST_kGrabWrap: // Wrap cursor at area/window boundaries
1586  {
1587  NSTimeInterval timestamp = [event timestamp];
1588  if (timestamp < m_last_warp_timestamp) {
1589  /* After warping we can still receive older unwarped mouse events,
1590  * ignore those. */
1591  break;
1592  }
1593 
1594  NSPoint mousePos = [event locationInWindow];
1595  GHOST_TInt32 x_mouse = mousePos.x;
1596  GHOST_TInt32 y_mouse = mousePos.y;
1597  GHOST_Rect bounds, windowBounds, correctedBounds;
1598 
1599  /* fallback to window bounds */
1600  if (window->getCursorGrabBounds(bounds) == GHOST_kFailure)
1601  window->getClientBounds(bounds);
1602 
1603  /* Switch back to Cocoa coordinates orientation
1604  * (y=0 at bottom, the same as blender internal BTW!), and to client coordinates. */
1605  window->getClientBounds(windowBounds);
1606  window->screenToClient(bounds.m_l, bounds.m_b, correctedBounds.m_l, correctedBounds.m_t);
1607  window->screenToClient(bounds.m_r, bounds.m_t, correctedBounds.m_r, correctedBounds.m_b);
1608  correctedBounds.m_b = (windowBounds.m_b - windowBounds.m_t) - correctedBounds.m_b;
1609  correctedBounds.m_t = (windowBounds.m_b - windowBounds.m_t) - correctedBounds.m_t;
1610 
1611  // Get accumulation from previous mouse warps
1612  GHOST_TInt32 x_accum, y_accum;
1613  window->getCursorGrabAccum(x_accum, y_accum);
1614 
1615  // Warp mouse cursor if needed
1616  GHOST_TInt32 warped_x_mouse = x_mouse;
1617  GHOST_TInt32 warped_y_mouse = y_mouse;
1618 
1619  correctedBounds.wrapPoint(
1620  warped_x_mouse, warped_y_mouse, 4, window->getCursorGrabAxis());
1621 
1622  // Set new cursor position
1623  if (x_mouse != warped_x_mouse || y_mouse != warped_y_mouse) {
1624  GHOST_TInt32 warped_x, warped_y;
1625  window->clientToScreenIntern(warped_x_mouse, warped_y_mouse, warped_x, warped_y);
1626  setMouseCursorPosition(warped_x, warped_y); /* wrap */
1627  window->setCursorGrabAccum(x_accum + (x_mouse - warped_x_mouse),
1628  y_accum + (y_mouse - warped_y_mouse));
1629 
1630  /* This is the current time that matches NSEvent timestamp. */
1631  m_last_warp_timestamp = [[NSProcessInfo processInfo] systemUptime];
1632  }
1633 
1634  // Generate event
1635  GHOST_TInt32 x, y;
1636  window->clientToScreenIntern(x_mouse + x_accum, y_mouse + y_accum, x, y);
1637  pushEvent(new GHOST_EventCursor([event timestamp] * 1000,
1639  window,
1640  x,
1641  y,
1642  window -> GetCocoaTabletData()));
1643  break;
1644  }
1645  default: {
1646  // Normal cursor operation: send mouse position in window
1647  NSPoint mousePos = [event locationInWindow];
1648  GHOST_TInt32 x, y;
1649 
1650  window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
1651  pushEvent(new GHOST_EventCursor([event timestamp] * 1000,
1653  window,
1654  x,
1655  y,
1656  window -> GetCocoaTabletData()));
1657  break;
1658  }
1659  }
1660  } break;
1661 
1662  case NSEventTypeScrollWheel: {
1663  NSEventPhase momentumPhase = NSEventPhaseNone;
1664  NSEventPhase phase = NSEventPhaseNone;
1665 
1666  momentumPhase = [event momentumPhase];
1667  phase = [event phase];
1668 
1669  /* when pressing a key while momentum scrolling continues after
1670  * lifting fingers off the trackpad, the action can unexpectedly
1671  * change from e.g. scrolling to zooming. this works around the
1672  * issue by ignoring momentum scroll after a key press */
1673  if (momentumPhase) {
1675  break;
1676  }
1677  else {
1678  m_ignoreMomentumScroll = false;
1679  }
1680 
1681  /* we assume phases are only set for gestures from trackpad or magic
1682  * mouse events. note that using tablet at the same time may not work
1683  * since this is a static variable */
1684  if (phase == NSEventPhaseBegan)
1685  m_multiTouchScroll = true;
1686  else if (phase == NSEventPhaseEnded)
1687  m_multiTouchScroll = false;
1688 
1689  /* Standard scroll-wheel case, if no swiping happened,
1690  * and no momentum (kinetic scroll) works. */
1691  if (!m_multiTouchScroll && momentumPhase == NSEventPhaseNone) {
1692  GHOST_TInt32 delta;
1693 
1694  double deltaF = [event deltaY];
1695 
1696  if (deltaF == 0.0)
1697  deltaF = [event deltaX]; // make blender decide if it's horizontal scroll
1698  if (deltaF == 0.0)
1699  break; // discard trackpad delta=0 events
1700 
1701  delta = deltaF > 0.0 ? 1 : -1;
1702  pushEvent(new GHOST_EventWheel([event timestamp] * 1000, window, delta));
1703  }
1704  else {
1705  NSPoint mousePos = [event locationInWindow];
1706  GHOST_TInt32 x, y;
1707  double dx;
1708  double dy;
1709 
1710  /* with 10.7 nice scrolling deltas are supported */
1711  dx = [event scrollingDeltaX];
1712  dy = [event scrollingDeltaY];
1713 
1714  /* However, wacom tablet (intuos5) needs old deltas,
1715  * it then has momentum and phase at zero. */
1716  if (phase == NSEventPhaseNone && momentumPhase == NSEventPhaseNone) {
1717  dx = [event deltaX];
1718  dy = [event deltaY];
1719  }
1720  window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
1721 
1722  NSPoint delta = [[cocoawindow contentView] convertPointToBacking:NSMakePoint(dx, dy)];
1723  pushEvent(new GHOST_EventTrackpad([event timestamp] * 1000,
1724  window,
1726  x,
1727  y,
1728  delta.x,
1729  delta.y,
1730  [event isDirectionInvertedFromDevice]));
1731  }
1732  } break;
1733 
1734  case NSEventTypeMagnify: {
1735  NSPoint mousePos = [event locationInWindow];
1736  GHOST_TInt32 x, y;
1737  window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
1738  pushEvent(new GHOST_EventTrackpad([event timestamp] * 1000,
1739  window,
1741  x,
1742  y,
1743  [event magnification] * 125.0 + 0.1,
1744  0,
1745  false));
1746  } break;
1747 
1748  case NSEventTypeSmartMagnify: {
1749  NSPoint mousePos = [event locationInWindow];
1750  GHOST_TInt32 x, y;
1751  window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
1753  [event timestamp] * 1000, window, GHOST_kTrackpadEventSmartMagnify, x, y, 0, 0, false));
1754  } break;
1755 
1756  case NSEventTypeRotate: {
1757  NSPoint mousePos = [event locationInWindow];
1758  GHOST_TInt32 x, y;
1759  window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
1760  pushEvent(new GHOST_EventTrackpad([event timestamp] * 1000,
1761  window,
1763  x,
1764  y,
1765  [event rotation] * -5.0,
1766  0,
1767  false));
1768  }
1769  default:
1770  return GHOST_kFailure;
1771  break;
1772  }
1773 
1774  return GHOST_kSuccess;
1775 }
1776 
1779  NSEvent *event = (NSEvent *)eventPtr;
1780  GHOST_IWindow *window;
1781  unsigned int modifiers;
1782  NSString *characters;
1783  NSData *convertedCharacters;
1784  GHOST_TKey keyCode;
1785  unsigned char ascii;
1786  NSString *charsIgnoringModifiers;
1787 
1788  window = m_windowManager->getWindowAssociatedWithOSWindow((void *)[event window]);
1789  if (!window) {
1790  // printf("\nW failure for event 0x%x",[event type]);
1791  return GHOST_kFailure;
1792  }
1793 
1794  char utf8_buf[6] = {'\0'};
1795  ascii = 0;
1796 
1797  switch ([event type]) {
1798 
1799  case NSEventTypeKeyDown:
1800  case NSEventTypeKeyUp:
1801  charsIgnoringModifiers = [event charactersIgnoringModifiers];
1802  if ([charsIgnoringModifiers length] > 0) {
1803  keyCode = convertKey([event keyCode],
1804  [charsIgnoringModifiers characterAtIndex:0],
1805  [event type] == NSEventTypeKeyDown ? kUCKeyActionDown :
1806  kUCKeyActionUp);
1807  }
1808  else {
1809  keyCode = convertKey([event keyCode],
1810  0,
1811  [event type] == NSEventTypeKeyDown ? kUCKeyActionDown :
1812  kUCKeyActionUp);
1813  }
1814 
1815  /* handling both unicode or ascii */
1816  characters = [event characters];
1817  if ([characters length] > 0) {
1818  convertedCharacters = [characters dataUsingEncoding:NSUTF8StringEncoding];
1819 
1820  for (int x = 0; x < [convertedCharacters length]; x++) {
1821  utf8_buf[x] = ((char *)[convertedCharacters bytes])[x];
1822  }
1823  }
1824 
1825  /* arrow keys should not have utf8 */
1826  if ((keyCode >= GHOST_kKeyLeftArrow) && (keyCode <= GHOST_kKeyDownArrow)) {
1827  utf8_buf[0] = '\0';
1828  }
1829 
1830  /* F keys should not have utf8 */
1831  if ((keyCode >= GHOST_kKeyF1) && (keyCode <= GHOST_kKeyF20))
1832  utf8_buf[0] = '\0';
1833 
1834  /* no text with command key pressed */
1835  if (m_modifierMask & NSEventModifierFlagCommand)
1836  utf8_buf[0] = '\0';
1837 
1838  if ((keyCode == GHOST_kKeyQ) && (m_modifierMask & NSEventModifierFlagCommand))
1839  break; // Cmd-Q is directly handled by Cocoa
1840 
1841  /* ascii is a subset of unicode */
1842  if (utf8_buf[0] && !utf8_buf[1]) {
1843  ascii = utf8_buf[0];
1844  }
1845 
1846  if ([event type] == NSEventTypeKeyDown) {
1847  pushEvent(new GHOST_EventKey([event timestamp] * 1000,
1849  window,
1850  keyCode,
1851  ascii,
1852  utf8_buf,
1853  [event isARepeat]));
1854 #if 0
1855  printf("Key down rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u ascii=%i %c utf8=%s\n",
1856  [event keyCode],
1857  [charsIgnoringModifiers length] > 0 ? [charsIgnoringModifiers characterAtIndex:0] :
1858  ' ',
1859  keyCode,
1860  ascii,
1861  ascii,
1862  utf8_buf);
1863 #endif
1864  }
1865  else {
1867  [event timestamp] * 1000, GHOST_kEventKeyUp, window, keyCode, 0, NULL, false));
1868 #if 0
1869  printf("Key up rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u ascii=%i %c utf8=%s\n",
1870  [event keyCode],
1871  [charsIgnoringModifiers length] > 0 ? [charsIgnoringModifiers characterAtIndex:0] :
1872  ' ',
1873  keyCode,
1874  ascii,
1875  ascii,
1876  utf8_buf);
1877 #endif
1878  }
1879  m_ignoreMomentumScroll = true;
1880  break;
1881 
1882  case NSEventTypeFlagsChanged:
1883  modifiers = [event modifierFlags];
1884 
1885  if ((modifiers & NSEventModifierFlagShift) != (m_modifierMask & NSEventModifierFlagShift)) {
1886  pushEvent(new GHOST_EventKey([event timestamp] * 1000,
1887  (modifiers & NSEventModifierFlagShift) ? GHOST_kEventKeyDown :
1889  window,
1891  false));
1892  }
1893  if ((modifiers & NSEventModifierFlagControl) !=
1894  (m_modifierMask & NSEventModifierFlagControl)) {
1896  [event timestamp] * 1000,
1897  (modifiers & NSEventModifierFlagControl) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
1898  window,
1900  false));
1901  }
1902  if ((modifiers & NSEventModifierFlagOption) !=
1903  (m_modifierMask & NSEventModifierFlagOption)) {
1905  [event timestamp] * 1000,
1906  (modifiers & NSEventModifierFlagOption) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
1907  window,
1909  false));
1910  }
1911  if ((modifiers & NSEventModifierFlagCommand) !=
1912  (m_modifierMask & NSEventModifierFlagCommand)) {
1914  [event timestamp] * 1000,
1915  (modifiers & NSEventModifierFlagCommand) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
1916  window,
1917  GHOST_kKeyOS,
1918  false));
1919  }
1920 
1921  m_modifierMask = modifiers;
1922  m_ignoreMomentumScroll = true;
1923  break;
1924 
1925  default:
1926  return GHOST_kFailure;
1927  break;
1928  }
1929 
1930  return GHOST_kSuccess;
1931 }
1932 
1933 #pragma mark Clipboard get/set
1934 
1935 GHOST_TUns8 *GHOST_SystemCocoa::getClipboard(bool selection) const
1937  GHOST_TUns8 *temp_buff;
1938  size_t pastedTextSize;
1939 
1940  @autoreleasepool {
1941 
1942  NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
1943 
1944  NSString *textPasted = [pasteBoard stringForType:NSStringPboardType];
1945 
1946  if (textPasted == nil) {
1947  return NULL;
1948  }
1949 
1950  pastedTextSize = [textPasted lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
1951 
1952  temp_buff = (GHOST_TUns8 *)malloc(pastedTextSize + 1);
1953 
1954  if (temp_buff == NULL) {
1955  return NULL;
1956  }
1957 
1958  strncpy(
1959  (char *)temp_buff, [textPasted cStringUsingEncoding:NSUTF8StringEncoding], pastedTextSize);
1960 
1961  temp_buff[pastedTextSize] = '\0';
1962 
1963  if (temp_buff) {
1964  return temp_buff;
1965  }
1966  else {
1967  return NULL;
1968  }
1969  }
1970 }
1971 
1972 void GHOST_SystemCocoa::putClipboard(GHOST_TInt8 *buffer, bool selection) const
1974  if (selection)
1975  return; // for copying the selection, used on X11
1976 
1977  @autoreleasepool {
1978 
1979  NSPasteboard *pasteBoard = NSPasteboard.generalPasteboard;
1980  [pasteBoard declareTypes:@[ NSStringPboardType ] owner:nil];
1981  NSString *textToCopy = [NSString stringWithCString:buffer encoding:NSUTF8StringEncoding];
1982  [pasteBoard setString:textToCopy forType:NSStringPboardType];
1983  }
1984 }
typedef float(TangentPoint)[2]
void BLI_kdtree_nd_() free(KDTree *tree)
Definition: kdtree_impl.h:116
typedef double(DMatrix)[4][4]
#define FALSE
Definition: GHOST_C-Test.c:33
#define GHOST_ASSERT(x, info)
Definition: GHOST_Debug.h:79
#define GHOST_PRINT(x)
Definition: GHOST_Debug.h:51
NSNotificationCenter * center
static GHOST_TButtonMask convertButton(int button)
#define FIRSTFILEBUFLG
int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG])
static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction)
static bool g_hasFirstFile
static char g_firstFileBuf[512]
@ GHOST_kTrackpadEventMagnify
Definition: GHOST_Types.h:458
@ GHOST_kTrackpadEventSmartMagnify
Definition: GHOST_Types.h:459
@ GHOST_kTrackpadEventRotate
Definition: GHOST_Types.h:456
@ GHOST_kTrackpadEventScroll
Definition: GHOST_Types.h:455
GHOST_TWindowState
Definition: GHOST_Types.h:144
unsigned int GHOST_TUns32
Definition: GHOST_Types.h:64
unsigned long long GHOST_TUns64
Definition: GHOST_Types.h:86
GHOST_TEventType
Definition: GHOST_Types.h:177
@ GHOST_kEventWindowClose
Definition: GHOST_Types.h:197
@ GHOST_kEventWindowMove
Definition: GHOST_Types.h:202
@ GHOST_kEventWindowSize
Definition: GHOST_Types.h:201
@ GHOST_kEventDraggingDropDone
Definition: GHOST_Types.h:208
@ GHOST_kEventDraggingExited
Definition: GHOST_Types.h:207
@ GHOST_kEventNativeResolutionChange
Definition: GHOST_Types.h:211
@ GHOST_kEventCursorMove
Definition: GHOST_Types.h:180
@ GHOST_kEventDraggingUpdated
Definition: GHOST_Types.h:206
@ GHOST_kEventOpenMainFile
Definition: GHOST_Types.h:210
@ GHOST_kEventDraggingEntered
Definition: GHOST_Types.h:205
@ GHOST_kEventButtonUp
Mouse button event.
Definition: GHOST_Types.h:182
@ GHOST_kEventWindowActivate
Definition: GHOST_Types.h:198
@ GHOST_kEventWindowUpdate
Definition: GHOST_Types.h:200
@ GHOST_kEventWindowDeactivate
Definition: GHOST_Types.h:199
@ GHOST_kEventButtonDown
Mouse move event.
Definition: GHOST_Types.h:181
@ GHOST_kEventKeyDown
Trackpad event.
Definition: GHOST_Types.h:191
@ GHOST_kEventKeyUp
Definition: GHOST_Types.h:192
@ GHOST_kEventQuitRequest
Definition: GHOST_Types.h:195
static const GHOST_TabletData GHOST_TABLET_DATA_NONE
Definition: GHOST_Types.h:119
int GHOST_TInt32
Definition: GHOST_Types.h:63
@ GHOST_kTabletModeEraser
Definition: GHOST_Types.h:103
@ GHOST_kTabletModeStylus
Definition: GHOST_Types.h:102
@ GHOST_kTabletModeNone
Definition: GHOST_Types.h:101
@ GHOST_glStereoVisual
Definition: GHOST_Types.h:71
@ GHOST_glDebugContext
Definition: GHOST_Types.h:72
void * GHOST_TEventDataPtr
Definition: GHOST_Types.h:430
GHOST_TKey
Definition: GHOST_Types.h:267
@ GHOST_kKeySemicolon
Definition: GHOST_Types.h:296
@ GHOST_kKey5
Definition: GHOST_Types.h:290
@ GHOST_kKeyQuote
Definition: GHOST_Types.h:277
@ GHOST_kKey4
Definition: GHOST_Types.h:289
@ GHOST_kKeyNumpad3
Definition: GHOST_Types.h:365
@ GHOST_kKeyAccentGrave
Definition: GHOST_Types.h:330
@ GHOST_kKeyNumpad1
Definition: GHOST_Types.h:363
@ GHOST_kKeyLeftAlt
Definition: GHOST_Types.h:336
@ GHOST_kKey3
Definition: GHOST_Types.h:288
@ GHOST_kKeyF9
Definition: GHOST_Types.h:388
@ GHOST_kKeyEnter
Definition: GHOST_Types.h:273
@ GHOST_kKeyF20
Definition: GHOST_Types.h:399
@ GHOST_kKeyNumpadSlash
Definition: GHOST_Types.h:377
@ GHOST_kKeyRightArrow
Definition: GHOST_Types.h:347
@ GHOST_kKeyF13
Definition: GHOST_Types.h:392
@ GHOST_kKeyF6
Definition: GHOST_Types.h:385
@ GHOST_kKeyNumpad4
Definition: GHOST_Types.h:366
@ GHOST_kKeyF11
Definition: GHOST_Types.h:390
@ GHOST_kKeyMinus
Definition: GHOST_Types.h:279
@ GHOST_kKey6
Definition: GHOST_Types.h:291
@ GHOST_kKeyBackSpace
Definition: GHOST_Types.h:269
@ GHOST_kKey0
Definition: GHOST_Types.h:285
@ GHOST_kKeyF5
Definition: GHOST_Types.h:384
@ GHOST_kKeyF19
Definition: GHOST_Types.h:398
@ GHOST_kKeyDownPage
Definition: GHOST_Types.h:359
@ GHOST_kKeyDownArrow
Definition: GHOST_Types.h:349
@ GHOST_kKeyQ
Definition: GHOST_Types.h:316
@ GHOST_kKeyNumpadPeriod
Definition: GHOST_Types.h:372
@ GHOST_kKeyF12
Definition: GHOST_Types.h:391
@ GHOST_kKeyF1
Definition: GHOST_Types.h:380
@ GHOST_kKeyNumpadAsterisk
Definition: GHOST_Types.h:376
@ GHOST_kKeyLeftControl
Definition: GHOST_Types.h:334
@ GHOST_kKeyLeftBracket
Definition: GHOST_Types.h:327
@ GHOST_kKey1
Definition: GHOST_Types.h:286
@ GHOST_kKeyTab
Definition: GHOST_Types.h:270
@ GHOST_kKey8
Definition: GHOST_Types.h:293
@ GHOST_kKeyComma
Definition: GHOST_Types.h:278
@ GHOST_kKeyRightBracket
Definition: GHOST_Types.h:328
@ GHOST_kKeyBackslash
Definition: GHOST_Types.h:329
@ GHOST_kKeyOS
Definition: GHOST_Types.h:338
@ GHOST_kKeyNumpad2
Definition: GHOST_Types.h:364
@ GHOST_kKeyPeriod
Definition: GHOST_Types.h:281
@ GHOST_kKeyNumpadPlus
Definition: GHOST_Types.h:374
@ GHOST_kKeyUpPage
Definition: GHOST_Types.h:358
@ GHOST_kKey9
Definition: GHOST_Types.h:294
@ GHOST_kKeyNumpad5
Definition: GHOST_Types.h:367
@ GHOST_kKeyLeftArrow
Definition: GHOST_Types.h:346
@ GHOST_kKeyF17
Definition: GHOST_Types.h:396
@ GHOST_kKeyEqual
Definition: GHOST_Types.h:297
@ GHOST_kKey7
Definition: GHOST_Types.h:292
@ GHOST_kKeyF8
Definition: GHOST_Types.h:387
@ GHOST_kKeyF18
Definition: GHOST_Types.h:397
@ GHOST_kKeyHome
Definition: GHOST_Types.h:356
@ GHOST_kKeyNumpad6
Definition: GHOST_Types.h:368
@ GHOST_kKeyF14
Definition: GHOST_Types.h:393
@ GHOST_kKeyNumpad8
Definition: GHOST_Types.h:370
@ GHOST_kKeyNumpad9
Definition: GHOST_Types.h:371
@ GHOST_kKeyF15
Definition: GHOST_Types.h:394
@ GHOST_kKeyEnd
Definition: GHOST_Types.h:357
@ GHOST_kKeyUpArrow
Definition: GHOST_Types.h:348
@ GHOST_kKeyDelete
Definition: GHOST_Types.h:355
@ GHOST_kKeyF16
Definition: GHOST_Types.h:395
@ GHOST_kKeyNumpad0
Definition: GHOST_Types.h:362
@ GHOST_kKeyA
Definition: GHOST_Types.h:300
@ GHOST_kKey2
Definition: GHOST_Types.h:287
@ GHOST_kKeyNumpad7
Definition: GHOST_Types.h:369
@ GHOST_kKeyEsc
Definition: GHOST_Types.h:275
@ GHOST_kKeyPlus
Definition: GHOST_Types.h:280
@ GHOST_kKeyUnknown
Definition: GHOST_Types.h:268
@ GHOST_kKeySlash
Definition: GHOST_Types.h:282
@ GHOST_kKeyF7
Definition: GHOST_Types.h:386
@ GHOST_kKeyNumpadEnter
Definition: GHOST_Types.h:373
@ GHOST_kKeyNumpadMinus
Definition: GHOST_Types.h:375
@ GHOST_kKeyF10
Definition: GHOST_Types.h:389
@ GHOST_kKeyLeftShift
Definition: GHOST_Types.h:332
@ GHOST_kKeyF3
Definition: GHOST_Types.h:382
@ GHOST_kKeyF2
Definition: GHOST_Types.h:381
@ GHOST_kKeyF4
Definition: GHOST_Types.h:383
@ GHOST_kKeySpace
Definition: GHOST_Types.h:276
GHOST_TDrawingContextType
Definition: GHOST_Types.h:156
GHOST_TButtonMask
Definition: GHOST_Types.h:164
@ GHOST_kButtonMaskRight
Definition: GHOST_Types.h:168
@ GHOST_kButtonMaskButton4
Definition: GHOST_Types.h:169
@ GHOST_kButtonMaskLeft
Definition: GHOST_Types.h:166
@ GHOST_kButtonMaskButton7
Definition: GHOST_Types.h:173
@ GHOST_kButtonMaskButton6
Definition: GHOST_Types.h:172
@ GHOST_kButtonMaskButton5
Definition: GHOST_Types.h:170
@ GHOST_kButtonMaskMiddle
Definition: GHOST_Types.h:167
char GHOST_TInt8
Definition: GHOST_Types.h:59
GHOST_TSuccess
Definition: GHOST_Types.h:91
@ GHOST_kFailure
Definition: GHOST_Types.h:91
@ GHOST_kSuccess
Definition: GHOST_Types.h:91
@ GHOST_kFireTimeNever
Definition: GHOST_Types.h:131
@ GHOST_kModifierKeyLeftControl
Definition: GHOST_Types.h:138
@ GHOST_kModifierKeyOS
Definition: GHOST_Types.h:140
@ GHOST_kModifierKeyLeftAlt
Definition: GHOST_Types.h:136
@ GHOST_kModifierKeyLeftShift
Definition: GHOST_Types.h:134
GHOST_TGrabCursorMode
Definition: GHOST_Types.h:412
@ GHOST_kGrabWrap
Definition: GHOST_Types.h:418
@ GHOST_kGrabDisable
Definition: GHOST_Types.h:414
@ GHOST_kGrabHide
Definition: GHOST_Types.h:420
GHOST_TDragnDropTypes
Definition: GHOST_Types.h:477
@ GHOST_kDragnDropTypeFilenames
Definition: GHOST_Types.h:479
@ GHOST_kDragnDropTypeBitmap
Definition: GHOST_Types.h:481
@ GHOST_kDragnDropTypeString
Definition: GHOST_Types.h:480
unsigned char GHOST_TUns8
Definition: GHOST_Types.h:60
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble top
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble bottom
struct ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
Definition: allocimbuf.c:478
@ IB_rect
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition: btDbvt.cpp:299
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
virtual GHOST_TSuccess initialize(void)
virtual bool getValid() const =0
GHOST_TInt32 m_l
Definition: GHOST_Rect.h:169
GHOST_TInt32 m_t
Definition: GHOST_Rect.h:171
GHOST_TInt32 m_r
Definition: GHOST_Rect.h:173
virtual void wrapPoint(GHOST_TInt32 &x, GHOST_TInt32 &y, GHOST_TInt32 ofs, GHOST_TAxisFlag axis)
Definition: GHOST_Rect.h:234
GHOST_TInt32 m_b
Definition: GHOST_Rect.h:175
bool processEvents(bool waitForEvent)
GHOST_TSuccess setMouseCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y)
GHOST_TSuccess disposeContext(GHOST_IContext *context)
GHOST_TSuccess handleWindowEvent(GHOST_TEventType eventType, GHOST_WindowCocoa *window)
GHOST_TSuccess handleDraggingEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType, GHOST_WindowCocoa *window, int mouseX, int mouseY, void *data)
void putClipboard(GHOST_TInt8 *buffer, bool selection) const
bool m_needDelayedApplicationBecomeActiveEventProcessing
GHOST_TSuccess handleApplicationBecomeActiveEvent()
GHOST_TSuccess handleMouseEvent(void *eventPtr)
GHOST_TSuccess setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y)
GHOST_TSuccess handleKeyEvent(void *eventPtr)
GHOST_TUns64 getMilliSeconds() const
GHOST_TUns8 getNumDisplays() const
GHOST_TSuccess getButtons(GHOST_Buttons &buttons) const
GHOST_TUns32 m_modifierMask
void getMainDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const
GHOST_TSuccess handleTabletEvent(void *eventPtr, short eventType)
bool handleOpenDocumentRequest(void *filepathStr)
GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const
GHOST_IContext * createOffscreenContext(GHOST_GLSettings glSettings)
GHOST_IWindow * createWindow(const char *title, GHOST_TInt32 left, GHOST_TInt32 top, GHOST_TUns32 width, GHOST_TUns32 height, GHOST_TWindowState state, GHOST_TDrawingContextType type, GHOST_GLSettings glSettings, const bool exclusive=false, const bool is_dialog=false, const GHOST_IWindow *parentWindow=NULL)
GHOST_TSuccess getCursorPosition(GHOST_TInt32 &x, GHOST_TInt32 &y) const
GHOST_TUns64 m_start_time
GHOST_TUns8 * getClipboard(bool selection) const
void getAllDisplayDimensions(GHOST_TUns32 &width, GHOST_TUns32 &height) const
GHOST_TSuccess init()
virtual GHOST_TSuccess init()
GHOST_TimerManager * getTimerManager() const
Definition: GHOST_System.h:407
bool m_windowFocus
Definition: GHOST_System.h:174
GHOST_WindowManager * m_windowManager
Definition: GHOST_System.h:383
bool validWindow(GHOST_IWindow *window)
GHOST_TSuccess pushEvent(GHOST_IEvent *event)
GHOST_DisplayManager * m_displayManager
Definition: GHOST_System.h:377
bool m_nativePixel
Definition: GHOST_System.h:168
GHOST_TUns64 nextFireTime()
bool fireTimers(GHOST_TUns64 time)
void clientToScreenIntern(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32 &outX, GHOST_TInt32 &outY) const
void getClientBounds(GHOST_Rect &bounds) const
void * getOSWindow() const
void screenToClientIntern(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32 &outX, GHOST_TInt32 &outY) const
void setNativePixelSize(void)
void screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32 &outX, GHOST_TInt32 &outY) const
GHOST_TabletData & GetCocoaTabletData()
void loadCursor(bool visible, GHOST_TStandardCursor cursor) const
GHOST_TSuccess addWindow(GHOST_IWindow *window)
GHOST_IWindow * getActiveWindow(void) const
GHOST_IWindow * getWindowAssociatedWithOSWindow(void *osWindow)
const std::vector< GHOST_IWindow * > & getWindows() const
GHOST_TSuccess setActiveWindow(GHOST_IWindow *window)
void setWindowInactive(const GHOST_IWindow *window)
GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds)
bool getCursorVisibility() const
Definition: GHOST_Window.h:415
GHOST_TAxisFlag getCursorGrabAxis() const
Definition: GHOST_Window.h:430
void getCursorGrabInitPos(GHOST_TInt32 &x, GHOST_TInt32 &y) const
Definition: GHOST_Window.h:435
void setCursorGrabAccum(GHOST_TInt32 x, GHOST_TInt32 y)
Definition: GHOST_Window.h:447
GHOST_TGrabCursorMode getCursorGrabMode() const
Definition: GHOST_Window.h:420
void getCursorGrabAccum(GHOST_TInt32 &x, GHOST_TInt32 &y) const
Definition: GHOST_Window.h:441
GHOST_TSuccess updateDrawingContext()
GHOST_TStandardCursor getCursorShape() const
Definition: GHOST_Window.h:453
bool getCursorGrabModeIsWarp() const
Definition: GHOST_Window.h:425
GHOST_SystemCocoa * systemCocoa
void setSystemCocoa:(GHOST_SystemCocoa *sysCocoa)
int count
__kernel void ccl_constant KernelData ccl_global void ccl_global char ccl_global int ccl_global char ccl_global unsigned int ccl_global float * buffer
static ulong * next
static ulong state[N]
static int left
struct SELECTID_Context context
Definition: select_engine.c:47
void set(GHOST_TButtonMask mask, bool down)
void set(GHOST_TModifierKeyMask mask, bool down)
GHOST_TUns8 ** strings
Definition: GHOST_Types.h:513
GHOST_TTabletMode Active
Definition: GHOST_Types.h:113
unsigned int * rect
uint len