Blender  V3.3
GHOST_SystemCocoa.mm
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
4 #include "GHOST_SystemCocoa.h"
5 
7 #include "GHOST_EventButton.h"
8 #include "GHOST_EventCursor.h"
9 #include "GHOST_EventDragnDrop.h"
10 #include "GHOST_EventKey.h"
11 #include "GHOST_EventString.h"
12 #include "GHOST_EventTrackpad.h"
13 #include "GHOST_EventWheel.h"
14 #include "GHOST_TimerManager.h"
15 #include "GHOST_TimerTask.h"
16 #include "GHOST_WindowCocoa.h"
17 #include "GHOST_WindowManager.h"
18 
19 #include "GHOST_ContextCGL.h"
20 
21 #ifdef WITH_INPUT_NDOF
22 # include "GHOST_NDOFManagerCocoa.h"
23 #endif
24 
25 #include "AssertMacros.h"
26 
27 #import <Cocoa/Cocoa.h>
28 
29 /* For the currently not ported to Cocoa keyboard layout functions (64bit & 10.6 compatible) */
30 #include <Carbon/Carbon.h>
31 
32 #include <sys/sysctl.h>
33 #include <sys/time.h>
34 #include <sys/types.h>
35 
36 #include <mach/mach_time.h>
37 
38 #pragma mark KeyMap, mouse converters
39 
40 static GHOST_TButton convertButton(int button)
41 {
42  switch (button) {
43  case 0:
44  return GHOST_kButtonMaskLeft;
45  case 1:
47  case 2:
49  case 3:
51  case 4:
53  case 5:
55  case 6:
57  default:
58  return GHOST_kButtonMaskLeft;
59  }
60 }
61 
69 static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction)
70 {
71  // printf("\nrecvchar %c 0x%x",recvChar,recvChar);
72  switch (rawCode) {
73  /* Physical key-codes: (not used due to map changes in int'l keyboards). */
74 #if 0
75  case kVK_ANSI_A: return GHOST_kKeyA;
76  case kVK_ANSI_B: return GHOST_kKeyB;
77  case kVK_ANSI_C: return GHOST_kKeyC;
78  case kVK_ANSI_D: return GHOST_kKeyD;
79  case kVK_ANSI_E: return GHOST_kKeyE;
80  case kVK_ANSI_F: return GHOST_kKeyF;
81  case kVK_ANSI_G: return GHOST_kKeyG;
82  case kVK_ANSI_H: return GHOST_kKeyH;
83  case kVK_ANSI_I: return GHOST_kKeyI;
84  case kVK_ANSI_J: return GHOST_kKeyJ;
85  case kVK_ANSI_K: return GHOST_kKeyK;
86  case kVK_ANSI_L: return GHOST_kKeyL;
87  case kVK_ANSI_M: return GHOST_kKeyM;
88  case kVK_ANSI_N: return GHOST_kKeyN;
89  case kVK_ANSI_O: return GHOST_kKeyO;
90  case kVK_ANSI_P: return GHOST_kKeyP;
91  case kVK_ANSI_Q: return GHOST_kKeyQ;
92  case kVK_ANSI_R: return GHOST_kKeyR;
93  case kVK_ANSI_S: return GHOST_kKeyS;
94  case kVK_ANSI_T: return GHOST_kKeyT;
95  case kVK_ANSI_U: return GHOST_kKeyU;
96  case kVK_ANSI_V: return GHOST_kKeyV;
97  case kVK_ANSI_W: return GHOST_kKeyW;
98  case kVK_ANSI_X: return GHOST_kKeyX;
99  case kVK_ANSI_Y: return GHOST_kKeyY;
100  case kVK_ANSI_Z: return GHOST_kKeyZ;
101 #endif
102  /* Numbers keys: mapped to handle some int'l keyboard (e.g. French). */
103  case kVK_ANSI_1:
104  return GHOST_kKey1;
105  case kVK_ANSI_2:
106  return GHOST_kKey2;
107  case kVK_ANSI_3:
108  return GHOST_kKey3;
109  case kVK_ANSI_4:
110  return GHOST_kKey4;
111  case kVK_ANSI_5:
112  return GHOST_kKey5;
113  case kVK_ANSI_6:
114  return GHOST_kKey6;
115  case kVK_ANSI_7:
116  return GHOST_kKey7;
117  case kVK_ANSI_8:
118  return GHOST_kKey8;
119  case kVK_ANSI_9:
120  return GHOST_kKey9;
121  case kVK_ANSI_0:
122  return GHOST_kKey0;
123 
124  case kVK_ANSI_Keypad0:
125  return GHOST_kKeyNumpad0;
126  case kVK_ANSI_Keypad1:
127  return GHOST_kKeyNumpad1;
128  case kVK_ANSI_Keypad2:
129  return GHOST_kKeyNumpad2;
130  case kVK_ANSI_Keypad3:
131  return GHOST_kKeyNumpad3;
132  case kVK_ANSI_Keypad4:
133  return GHOST_kKeyNumpad4;
134  case kVK_ANSI_Keypad5:
135  return GHOST_kKeyNumpad5;
136  case kVK_ANSI_Keypad6:
137  return GHOST_kKeyNumpad6;
138  case kVK_ANSI_Keypad7:
139  return GHOST_kKeyNumpad7;
140  case kVK_ANSI_Keypad8:
141  return GHOST_kKeyNumpad8;
142  case kVK_ANSI_Keypad9:
143  return GHOST_kKeyNumpad9;
144  case kVK_ANSI_KeypadDecimal:
145  return GHOST_kKeyNumpadPeriod;
146  case kVK_ANSI_KeypadEnter:
147  return GHOST_kKeyNumpadEnter;
148  case kVK_ANSI_KeypadPlus:
149  return GHOST_kKeyNumpadPlus;
150  case kVK_ANSI_KeypadMinus:
151  return GHOST_kKeyNumpadMinus;
152  case kVK_ANSI_KeypadMultiply:
154  case kVK_ANSI_KeypadDivide:
155  return GHOST_kKeyNumpadSlash;
156  case kVK_ANSI_KeypadClear:
157  return GHOST_kKeyUnknown;
158 
159  case kVK_F1:
160  return GHOST_kKeyF1;
161  case kVK_F2:
162  return GHOST_kKeyF2;
163  case kVK_F3:
164  return GHOST_kKeyF3;
165  case kVK_F4:
166  return GHOST_kKeyF4;
167  case kVK_F5:
168  return GHOST_kKeyF5;
169  case kVK_F6:
170  return GHOST_kKeyF6;
171  case kVK_F7:
172  return GHOST_kKeyF7;
173  case kVK_F8:
174  return GHOST_kKeyF8;
175  case kVK_F9:
176  return GHOST_kKeyF9;
177  case kVK_F10:
178  return GHOST_kKeyF10;
179  case kVK_F11:
180  return GHOST_kKeyF11;
181  case kVK_F12:
182  return GHOST_kKeyF12;
183  case kVK_F13:
184  return GHOST_kKeyF13;
185  case kVK_F14:
186  return GHOST_kKeyF14;
187  case kVK_F15:
188  return GHOST_kKeyF15;
189  case kVK_F16:
190  return GHOST_kKeyF16;
191  case kVK_F17:
192  return GHOST_kKeyF17;
193  case kVK_F18:
194  return GHOST_kKeyF18;
195  case kVK_F19:
196  return GHOST_kKeyF19;
197  case kVK_F20:
198  return GHOST_kKeyF20;
199 
200  case kVK_UpArrow:
201  return GHOST_kKeyUpArrow;
202  case kVK_DownArrow:
203  return GHOST_kKeyDownArrow;
204  case kVK_LeftArrow:
205  return GHOST_kKeyLeftArrow;
206  case kVK_RightArrow:
207  return GHOST_kKeyRightArrow;
208 
209  case kVK_Return:
210  return GHOST_kKeyEnter;
211  case kVK_Delete:
212  return GHOST_kKeyBackSpace;
213  case kVK_ForwardDelete:
214  return GHOST_kKeyDelete;
215  case kVK_Escape:
216  return GHOST_kKeyEsc;
217  case kVK_Tab:
218  return GHOST_kKeyTab;
219  case kVK_Space:
220  return GHOST_kKeySpace;
221 
222  case kVK_Home:
223  return GHOST_kKeyHome;
224  case kVK_End:
225  return GHOST_kKeyEnd;
226  case kVK_PageUp:
227  return GHOST_kKeyUpPage;
228  case kVK_PageDown:
229  return GHOST_kKeyDownPage;
230 #if 0 /* TODO: why are these commented? */
231  case kVK_ANSI_Minus: return GHOST_kKeyMinus;
232  case kVK_ANSI_Equal: return GHOST_kKeyEqual;
233  case kVK_ANSI_Comma: return GHOST_kKeyComma;
234  case kVK_ANSI_Period: return GHOST_kKeyPeriod;
235  case kVK_ANSI_Slash: return GHOST_kKeySlash;
236  case kVK_ANSI_Semicolon: return GHOST_kKeySemicolon;
237  case kVK_ANSI_Quote: return GHOST_kKeyQuote;
238  case kVK_ANSI_Backslash: return GHOST_kKeyBackslash;
239  case kVK_ANSI_LeftBracket: return GHOST_kKeyLeftBracket;
240  case kVK_ANSI_RightBracket: return GHOST_kKeyRightBracket;
241  case kVK_ANSI_Grave: return GHOST_kKeyAccentGrave;
242  case kVK_ISO_Section: return GHOST_kKeyUnknown;
243 #endif
244  case kVK_VolumeUp:
245  case kVK_VolumeDown:
246  case kVK_Mute:
247  return GHOST_kKeyUnknown;
248 
249  default: {
250  /* Alphanumerical or punctuation key that is remappable in int'l keyboards. */
251  if ((recvChar >= 'A') && (recvChar <= 'Z')) {
252  return (GHOST_TKey)(recvChar - 'A' + GHOST_kKeyA);
253  }
254  else if ((recvChar >= 'a') && (recvChar <= 'z')) {
255  return (GHOST_TKey)(recvChar - 'a' + GHOST_kKeyA);
256  }
257  else {
258  /* Leopard and Snow Leopard 64bit compatible API. */
259  CFDataRef uchrHandle; /* The keyboard layout. */
260  TISInputSourceRef kbdTISHandle;
261 
262  kbdTISHandle = TISCopyCurrentKeyboardLayoutInputSource();
263  uchrHandle = (CFDataRef)TISGetInputSourceProperty(kbdTISHandle,
264  kTISPropertyUnicodeKeyLayoutData);
265  CFRelease(kbdTISHandle);
266 
267  /* Get actual character value of the "remappable" keys in int'l keyboards,
268  * if keyboard layout is not correctly reported (e.g. some non Apple keyboards in Tiger),
269  * then fallback on using the received #charactersIgnoringModifiers. */
270  if (uchrHandle) {
271  UInt32 deadKeyState = 0;
272  UniCharCount actualStrLength = 0;
273 
274  UCKeyTranslate((UCKeyboardLayout *)CFDataGetBytePtr(uchrHandle),
275  rawCode,
276  keyAction,
277  0,
278  LMGetKbdType(),
279  kUCKeyTranslateNoDeadKeysBit,
280  &deadKeyState,
281  1,
282  &actualStrLength,
283  &recvChar);
284  }
285 
286  switch (recvChar) {
287  case '-':
288  return GHOST_kKeyMinus;
289  case '+':
290  return GHOST_kKeyPlus;
291  case '=':
292  return GHOST_kKeyEqual;
293  case ',':
294  return GHOST_kKeyComma;
295  case '.':
296  return GHOST_kKeyPeriod;
297  case '/':
298  return GHOST_kKeySlash;
299  case ';':
300  return GHOST_kKeySemicolon;
301  case '\'':
302  return GHOST_kKeyQuote;
303  case '\\':
304  return GHOST_kKeyBackslash;
305  case '[':
306  return GHOST_kKeyLeftBracket;
307  case ']':
308  return GHOST_kKeyRightBracket;
309  case '`':
310  case '<': /* The position of '`' is equivalent to this symbol in the French layout. */
311  return GHOST_kKeyAccentGrave;
312  default:
313  return GHOST_kKeyUnknown;
314  }
315  }
316  }
317  }
318  return GHOST_kKeyUnknown;
319 }
320 
321 #pragma mark Utility functions
322 
323 #define FIRSTFILEBUFLG 512
324 static bool g_hasFirstFile = false;
325 static char g_firstFileBuf[512];
326 
327 // TODO: Need to investigate this.
328 // Function called too early in creator.c to have g_hasFirstFile == true
329 extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG])
330 {
331  if (g_hasFirstFile) {
332  strncpy(buf, g_firstFileBuf, FIRSTFILEBUFLG - 1);
333  buf[FIRSTFILEBUFLG - 1] = '\0';
334  return 1;
335  }
336  else {
337  return 0;
338  }
339 }
340 
341 #pragma mark Cocoa objects
342 
347 @interface CocoaAppDelegate : NSObject <NSApplicationDelegate>
348 {
349 
351 }
352 
353 - (id)init;
354 - (void)dealloc;
355 - (void)setSystemCocoa:(GHOST_SystemCocoa *)sysCocoa;
356 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
357 - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename;
358 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
359 - (void)applicationWillTerminate:(NSNotification *)aNotification;
360 - (void)applicationWillBecomeActive:(NSNotification *)aNotification;
361 - (void)toggleFullScreen:(NSNotification *)notification;
362 - (void)windowWillClose:(NSNotification *)notification;
363 @end
364 
365 @implementation CocoaAppDelegate : NSObject
366 - (id)init
367 {
368  self = [super init];
369  NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
370  [center addObserver:self
371  selector:@selector(windowWillClose:)
372  name:NSWindowWillCloseNotification
373  object:nil];
374  return self;
375 }
376 
377 - (void)dealloc
378 {
379  NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
380  [center removeObserver:self name:NSWindowWillCloseNotification object:nil];
381  [super dealloc];
382 }
383 
384 - (void)setSystemCocoa:(GHOST_SystemCocoa *)sysCocoa
385 {
386  systemCocoa = sysCocoa;
387 }
388 
389 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
390 {
391  if (systemCocoa->m_windowFocus) {
392  // Raise application to front, convenient when starting from the terminal
393  // and important for launching the animation player. we call this after the
394  // application finishes launching, as doing it earlier can make us end up
395  // with a frontmost window but an inactive application.
396  [NSApp activateIgnoringOtherApps:YES];
397  }
398 
399  [NSEvent setMouseCoalescingEnabled:NO];
400 }
401 
402 - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
403 {
404  return systemCocoa->handleOpenDocumentRequest(filename);
405 }
406 
407 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
408 {
409  /* TODO: implement graceful termination through Cocoa mechanism
410  * to avoid session log off to be canceled. */
411  /* Note that Cmd+Q is already handled by key-handler. */
413  return NSTerminateCancel;
414 }
415 
416 // To avoid canceling a log off process, we must use Cocoa termination process
417 // And this function is the only chance to perform clean up
418 // So WM_exit needs to be called directly, as the event loop will never run before termination
419 - (void)applicationWillTerminate:(NSNotification *)aNotification
420 {
421 #if 0
422  G.is_break = false; /* Let Cocoa perform the termination at the end. */
423  WM_exit(C);
424 #endif
425 }
426 
427 - (void)applicationWillBecomeActive:(NSNotification *)aNotification
428 {
430 }
431 
432 - (void)toggleFullScreen:(NSNotification *)notification
433 {
434 }
435 
436 // The purpose of this function is to make sure closing "About" window does not
437 // leave Blender with no key windows. This is needed due to a custom event loop
438 // nature of the application: for some reason only using [NSApp run] will ensure
439 // correct behavior in this case.
440 //
441 // This is similar to an issue solved in SDL:
442 // https://bugzilla.libsdl.org/show_bug.cgi?id=1825
443 //
444 // Our solution is different, since we want Blender to keep track of what is
445 // the key window during normal operation. In order to do so we exploit the
446 // fact that "About" window is never in the orderedWindows array: we only force
447 // key window from here if the closing one is not in the orderedWindows. This
448 // saves lack of key windows when closing "About", but does not interfere with
449 // Blender's window manager when closing Blender's windows.
450 //
451 // NOTE: It also receives notifiers when menus are closed on macOS 14.
452 // Presumably it considers menus to be windows.
453 - (void)windowWillClose:(NSNotification *)notification
454 {
455  NSWindow *closing_window = (NSWindow *)[notification object];
456 
457  if (![closing_window isKeyWindow]) {
458  /* If the window wasn't key then its either none of the windows are key or another window
459  * is a key. The former situation is a bit strange, but probably forcin a key window is not
460  * something desirable. The latter situation is when we definitely do not want to change the
461  * key window.
462  *
463  * Ignoring non-key windows also avoids the code which ensures ordering below from running
464  * when the notifier is received for menus on macOS 14. */
465  return;
466  }
467 
468  NSInteger index = [[NSApp orderedWindows] indexOfObject:closing_window];
469  if (index != NSNotFound) {
470  return;
471  }
472  // Find first suitable window from the current space.
473  for (NSWindow *current_window in [NSApp orderedWindows]) {
474  if (current_window == closing_window) {
475  continue;
476  }
477  if ([current_window isOnActiveSpace] && [current_window canBecomeKeyWindow]) {
478  [current_window makeKeyAndOrderFront:nil];
479  return;
480  }
481  }
482  // If that didn't find any windows, we try to find any suitable window of
483  // the application.
484  for (NSNumber *window_number in [NSWindow windowNumbersWithOptions:0]) {
485  NSWindow *current_window = [NSApp windowWithWindowNumber:[window_number integerValue]];
486  if (current_window == closing_window) {
487  continue;
488  }
489  if ([current_window canBecomeKeyWindow]) {
490  [current_window makeKeyAndOrderFront:nil];
491  return;
492  }
493  }
494 }
495 
496 @end
497 
498 #pragma mark initialization/finalization
499 
501 {
502  int mib[2];
503  struct timeval boottime;
504  size_t len;
505  char *rstring = NULL;
506 
507  m_modifierMask = 0;
511  GHOST_ASSERT(m_displayManager, "GHOST_SystemCocoa::GHOST_SystemCocoa(): m_displayManager==0\n");
513 
514  // NSEvent timeStamp is given in system uptime, state start date is boot time
515  mib[0] = CTL_KERN;
516  mib[1] = KERN_BOOTTIME;
517  len = sizeof(struct timeval);
518 
519  sysctl(mib, 2, &boottime, &len, NULL, 0);
520  m_start_time = ((boottime.tv_sec * 1000) + (boottime.tv_usec / 1000));
521 
522  /* Detect multi-touch track-pad. */
523  mib[0] = CTL_HW;
524  mib[1] = HW_MODEL;
525  sysctl(mib, 2, NULL, &len, NULL, 0);
526  rstring = (char *)malloc(len);
527  sysctl(mib, 2, rstring, &len, NULL, 0);
528 
529  free(rstring);
530  rstring = NULL;
531 
533  m_ignoreMomentumScroll = false;
534  m_multiTouchScroll = false;
536 }
537 
539 {
540 }
541 
543 {
545  if (success) {
546 
547 #ifdef WITH_INPUT_NDOF
548  m_ndofManager = new GHOST_NDOFManagerCocoa(*this);
549 #endif
550 
551  // ProcessSerialNumber psn;
552 
553  // Carbon stuff to move window & menu to foreground
554 #if 0
555  if (!GetCurrentProcess(&psn)) {
556  TransformProcessType(&psn, kProcessTransformToForegroundApplication);
557  SetFrontProcess(&psn);
558  }
559 #endif
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 
703  int32_t top,
704  uint32_t width,
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  int32_t 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 
791 {
792  NSPoint scr_co = NSMakePoint(x, y);
793 
794  int windowNumberAtPoint = [NSWindow windowNumberAtPoint:scr_co belowWindowWithWindowNumber:0];
795  NSWindow *nswindow = [NSApp windowWithWindowNumber:windowNumberAtPoint];
796 
797  if (nswindow == nil) {
798  return nil;
799  }
800 
801  return m_windowManager->getWindowAssociatedWithOSWindow((void *)nswindow);
802 }
803 
808 {
809  NSPoint mouseLoc = [NSEvent mouseLocation];
810 
811  // Returns the mouse location in screen coordinates
812  x = (int32_t)mouseLoc.x;
813  y = (int32_t)mouseLoc.y;
814  return GHOST_kSuccess;
815 }
816 
821 {
823  if (!window)
824  return GHOST_kFailure;
825 
826  // Cursor and mouse dissociation placed here not to interfere with continuous grab
827  // (in cont. grab setMouseCursorPosition is directly called)
828  CGAssociateMouseAndMouseCursorPosition(false);
830  CGAssociateMouseAndMouseCursorPosition(true);
831 
832  // Force mouse move event (not pushed by Cocoa)
834  getMilliSeconds(), GHOST_kEventCursorMove, window, x, y, window->GetCocoaTabletData()));
836 
837  return GHOST_kSuccess;
838 }
839 
841 {
842  float xf = (float)x, yf = (float)y;
844  if (!window)
845  return GHOST_kFailure;
846 
847  @autoreleasepool {
848  NSScreen *windowScreen = window->getScreen();
849  NSRect screenRect = [windowScreen frame];
850 
851  // Set position relative to current screen
852  xf -= screenRect.origin.x;
853  yf -= screenRect.origin.y;
854 
855  // Quartz Display Services uses the old coordinates (top left origin)
856  yf = screenRect.size.height - yf;
857 
858  CGDisplayMoveCursorToPoint((CGDirectDisplayID)[[[windowScreen deviceDescription]
859  objectForKey:@"NSScreenNumber"] unsignedIntValue],
860  CGPointMake(xf, yf));
861 
862  // See https://stackoverflow.com/a/17559012. By default, hardware events
863  // will be suppressed for 500ms after a synthetic mouse event. For unknown
864  // reasons CGEventSourceSetLocalEventsSuppressionInterval does not work,
865  // however calling CGAssociateMouseAndMouseCursorPosition also removes the
866  // delay, even if this is undocumented.
867  CGAssociateMouseAndMouseCursorPosition(true);
868  }
869  return GHOST_kSuccess;
870 }
871 
873 {
874  keys.set(GHOST_kModifierKeyOS, (m_modifierMask & NSEventModifierFlagCommand) ? true : false);
875  keys.set(GHOST_kModifierKeyLeftAlt, (m_modifierMask & NSEventModifierFlagOption) ? true : false);
877  (m_modifierMask & NSEventModifierFlagShift) ? true : false);
879  (m_modifierMask & NSEventModifierFlagControl) ? true : false);
880 
881  return GHOST_kSuccess;
882 }
883 
885 {
886  UInt32 button_state = GetCurrentEventButtonState();
887 
888  buttons.clear();
889  buttons.set(GHOST_kButtonMaskLeft, button_state & (1 << 0));
890  buttons.set(GHOST_kButtonMaskRight, button_state & (1 << 1));
891  buttons.set(GHOST_kButtonMaskMiddle, button_state & (1 << 2));
892  buttons.set(GHOST_kButtonMaskButton4, button_state & (1 << 3));
893  buttons.set(GHOST_kButtonMaskButton5, button_state & (1 << 4));
894  return GHOST_kSuccess;
895 }
896 
897 #pragma mark Event handlers
898 
902 bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
903 {
904  bool anyProcessed = false;
905  NSEvent *event;
906 
907  /* TODO: implement timer? */
908 #if 0
909  do {
910  GHOST_TimerManager* timerMgr = getTimerManager();
911 
912  if (waitForEvent) {
913  uint64_t next = timerMgr->nextFireTime();
914  double timeOut;
915 
916  if (next == GHOST_kFireTimeNever) {
917  timeOut = kEventDurationForever;
918  }
919  else {
920  timeOut = (double)(next - getMilliSeconds())/1000.0;
921  if (timeOut < 0.0)
922  timeOut = 0.0;
923  }
924 
925  ::ReceiveNextEvent(0, NULL, timeOut, false, &event);
926  }
927 
928  if (timerMgr->fireTimers(getMilliSeconds())) {
929  anyProcessed = true;
930  }
931 #endif
932  do {
933  @autoreleasepool {
934  event = [NSApp nextEventMatchingMask:NSEventMaskAny
935  untilDate:[NSDate distantPast]
936  inMode:NSDefaultRunLoopMode
937  dequeue:YES];
938  if (event == nil) {
939  break;
940  }
941 
942  anyProcessed = true;
943 
944  // Send event to NSApp to ensure Mac wide events are handled,
945  // this will send events to CocoaWindow which will call back
946  // to handleKeyEvent, handleMouseEvent and handleTabletEvent
947 
948  // There is on special exception for ctrl+(shift)+tab. We do not
949  // get keyDown events delivered to the view because they are
950  // special hotkeys to switch between views, so override directly
951 
952  if ([event type] == NSEventTypeKeyDown && [event keyCode] == kVK_Tab &&
953  ([event modifierFlags] & NSEventModifierFlagControl)) {
954  handleKeyEvent(event);
955  }
956  else {
957  // For some reason NSApp is swallowing the key up events when modifier
958  // key is pressed, even if there seems to be no apparent reason to do
959  // so, as a workaround we always handle these up events.
960  if ([event type] == NSEventTypeKeyUp &&
961  ([event modifierFlags] & (NSEventModifierFlagCommand | NSEventModifierFlagOption)))
962  handleKeyEvent(event);
963 
964  [NSApp sendEvent:event];
965  }
966  }
967  } while (event != nil);
968 #if 0
969  } while (waitForEvent && !anyProcessed); // Needed only for timer implementation
970 #endif
971 
974 
977  return true;
978  }
979 
981 
982  return anyProcessed;
983 }
984 
985 /* NOTE: called from #NSApplication delegate. */
987 {
988  for (GHOST_IWindow *iwindow : m_windowManager->getWindows()) {
989  GHOST_WindowCocoa *window = (GHOST_WindowCocoa *)iwindow;
990  if (window->isDialog()) {
991  [window->getCocoaWindow() makeKeyAndOrderFront:nil];
992  }
993  }
994 
995  // Update the modifiers key mask, as its status may have changed when the application
996  // was not active (that is when update events are sent to another application).
997  unsigned int modifiers;
999 
1000  if (!window) {
1002  return GHOST_kFailure;
1003  }
1004  else
1006 
1007  modifiers = [[[NSApplication sharedApplication] currentEvent] modifierFlags];
1008 
1009  if ((modifiers & NSEventModifierFlagShift) != (m_modifierMask & NSEventModifierFlagShift)) {
1011  (modifiers & NSEventModifierFlagShift) ? GHOST_kEventKeyDown :
1013  window,
1015  false));
1016  }
1017  if ((modifiers & NSEventModifierFlagControl) != (m_modifierMask & NSEventModifierFlagControl)) {
1019  (modifiers & NSEventModifierFlagControl) ? GHOST_kEventKeyDown :
1021  window,
1023  false));
1024  }
1025  if ((modifiers & NSEventModifierFlagOption) != (m_modifierMask & NSEventModifierFlagOption)) {
1027  (modifiers & NSEventModifierFlagOption) ? GHOST_kEventKeyDown :
1029  window,
1031  false));
1032  }
1033  if ((modifiers & NSEventModifierFlagCommand) != (m_modifierMask & NSEventModifierFlagCommand)) {
1035  (modifiers & NSEventModifierFlagCommand) ? GHOST_kEventKeyDown :
1037  window,
1038  GHOST_kKeyOS,
1039  false));
1040  }
1041 
1042  m_modifierMask = modifiers;
1043 
1045  return GHOST_kSuccess;
1046 }
1047 
1050  for (GHOST_IWindow *iwindow : m_windowManager->getWindows()) {
1051  GHOST_WindowCocoa *window = (GHOST_WindowCocoa *)iwindow;
1052  if (window->isDialog()) {
1053  return true;
1054  }
1055  }
1056  return false;
1057 }
1058 
1062 }
1063 
1064 /* NOTE: called from #NSWindow delegate. */
1067 {
1068  if (!validWindow(window)) {
1069  return GHOST_kFailure;
1070  }
1071  switch (eventType) {
1074  break;
1077  window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
1079  break;
1083  break;
1085  if (m_nativePixel) {
1086  window->setNativePixelSize();
1088  }
1090  break;
1093  break;
1096  // Enforce only one resize message per event loop
1097  // (coalescing all the live resize messages)
1098  window->updateDrawingContext();
1100  // Mouse up event is trapped by the resizing event loop,
1101  // so send it anyway to the window manager.
1104  window,
1107  // m_ignoreWindowSizedMessages = true;
1108  }
1109  break;
1111 
1112  if (m_nativePixel) {
1113  window->setNativePixelSize();
1115  }
1116 
1117  default:
1118  return GHOST_kFailure;
1119  break;
1120  }
1121 
1123  return GHOST_kSuccess;
1124 }
1125 
1126 /* NOTE: called from #NSWindow subclass. */
1128  GHOST_TDragnDropTypes draggedObjectType,
1129  GHOST_WindowCocoa *window,
1130  int mouseX,
1131  int mouseY,
1132  void *data)
1133 {
1134  if (!validWindow(window)) {
1135  return GHOST_kFailure;
1136  }
1137  switch (eventType) {
1141  window->clientToScreenIntern(mouseX, mouseY, mouseX, mouseY);
1143  getMilliSeconds(), eventType, draggedObjectType, window, mouseX, mouseY, NULL));
1144  break;
1145 
1147  uint8_t *temp_buff;
1148  GHOST_TStringArray *strArray;
1149  NSArray *droppedArray;
1150  size_t pastedTextSize;
1151  NSString *droppedStr;
1152  GHOST_TEventDataPtr eventData;
1153  int i;
1154 
1155  if (!data)
1156  return GHOST_kFailure;
1157 
1158  switch (draggedObjectType) {
1160  droppedArray = (NSArray *)data;
1161 
1162  strArray = (GHOST_TStringArray *)malloc(sizeof(GHOST_TStringArray));
1163  if (!strArray)
1164  return GHOST_kFailure;
1165 
1166  strArray->count = [droppedArray count];
1167  if (strArray->count == 0) {
1168  free(strArray);
1169  return GHOST_kFailure;
1170  }
1171 
1172  strArray->strings = (uint8_t **)malloc(strArray->count * sizeof(uint8_t *));
1173 
1174  for (i = 0; i < strArray->count; i++) {
1175  droppedStr = [droppedArray objectAtIndex:i];
1176 
1177  pastedTextSize = [droppedStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
1178  temp_buff = (uint8_t *)malloc(pastedTextSize + 1);
1179 
1180  if (!temp_buff) {
1181  strArray->count = i;
1182  break;
1183  }
1184 
1185  strncpy((char *)temp_buff,
1186  [droppedStr cStringUsingEncoding:NSUTF8StringEncoding],
1187  pastedTextSize);
1188  temp_buff[pastedTextSize] = '\0';
1189 
1190  strArray->strings[i] = temp_buff;
1191  }
1192 
1193  eventData = (GHOST_TEventDataPtr)strArray;
1194  break;
1195 
1197  droppedStr = (NSString *)data;
1198  pastedTextSize = [droppedStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
1199 
1200  temp_buff = (uint8_t *)malloc(pastedTextSize + 1);
1201 
1202  if (temp_buff == NULL) {
1203  return GHOST_kFailure;
1204  }
1205 
1206  strncpy((char *)temp_buff,
1207  [droppedStr cStringUsingEncoding:NSUTF8StringEncoding],
1208  pastedTextSize);
1209 
1210  temp_buff[pastedTextSize] = '\0';
1211 
1212  eventData = (GHOST_TEventDataPtr)temp_buff;
1213  break;
1214 
1216  NSImage *droppedImg = (NSImage *)data;
1217  NSSize imgSize = [droppedImg size];
1218  ImBuf *ibuf = NULL;
1219  uint8_t *rasterRGB = NULL;
1220  uint8_t *rasterRGBA = NULL;
1221  uint8_t *toIBuf = NULL;
1222  int x, y, to_i, from_i;
1223  NSBitmapImageRep *blBitmapFormatImageRGB, *blBitmapFormatImageRGBA, *bitmapImage = nil;
1224  NSEnumerator *enumerator;
1225  NSImageRep *representation;
1226 
1227  ibuf = IMB_allocImBuf(imgSize.width, imgSize.height, 32, IB_rect);
1228  if (!ibuf) {
1229  [droppedImg release];
1230  return GHOST_kFailure;
1231  }
1232 
1233  /* Get the bitmap of the image. */
1234  enumerator = [[droppedImg representations] objectEnumerator];
1235  while ((representation = [enumerator nextObject])) {
1236  if ([representation isKindOfClass:[NSBitmapImageRep class]]) {
1237  bitmapImage = (NSBitmapImageRep *)representation;
1238  break;
1239  }
1240  }
1241  if (bitmapImage == nil)
1242  return GHOST_kFailure;
1243 
1244  if (([bitmapImage bitsPerPixel] == 32) && (([bitmapImage bitmapFormat] & 0x5) == 0) &&
1245  ![bitmapImage isPlanar]) {
1246  /* Try a fast copy if the image is a meshed RGBA 32bit bitmap. */
1247  toIBuf = (uint8_t *)ibuf->rect;
1248  rasterRGB = (uint8_t *)[bitmapImage bitmapData];
1249  for (y = 0; y < imgSize.height; y++) {
1250  to_i = (imgSize.height - y - 1) * imgSize.width;
1251  from_i = y * imgSize.width;
1252  memcpy(toIBuf + 4 * to_i, rasterRGB + 4 * from_i, 4 * imgSize.width);
1253  }
1254  }
1255  else {
1256  /* Tell cocoa image resolution is same as current system one */
1257  [bitmapImage setSize:imgSize];
1258 
1259  /* Convert the image in a RGBA 32bit format */
1260  /* As Core Graphics does not support contexts with non premutliplied alpha,
1261  * we need to get alpha key values in a separate batch */
1262 
1263  /* First get RGB values w/o Alpha to avoid pre-multiplication,
1264  * 32bit but last byte is unused */
1265  blBitmapFormatImageRGB = [[NSBitmapImageRep alloc]
1266  initWithBitmapDataPlanes:NULL
1267  pixelsWide:imgSize.width
1268  pixelsHigh:imgSize.height
1269  bitsPerSample:8
1270  samplesPerPixel:3
1271  hasAlpha:NO
1272  isPlanar:NO
1273  colorSpaceName:NSDeviceRGBColorSpace
1274  bitmapFormat:(NSBitmapFormat)0
1275  bytesPerRow:4 * imgSize.width
1276  bitsPerPixel:32 /* RGB format padded to 32bits. */];
1277 
1278  [NSGraphicsContext saveGraphicsState];
1279  [NSGraphicsContext
1280  setCurrentContext:[NSGraphicsContext
1281  graphicsContextWithBitmapImageRep:blBitmapFormatImageRGB]];
1282  [bitmapImage draw];
1283  [NSGraphicsContext restoreGraphicsState];
1284 
1285  rasterRGB = (uint8_t *)[blBitmapFormatImageRGB bitmapData];
1286  if (rasterRGB == NULL) {
1287  [bitmapImage release];
1288  [blBitmapFormatImageRGB release];
1289  [droppedImg release];
1290  return GHOST_kFailure;
1291  }
1292 
1293  /* Then get Alpha values by getting the RGBA image (that is pre-multiplied BTW) */
1294  blBitmapFormatImageRGBA = [[NSBitmapImageRep alloc]
1295  initWithBitmapDataPlanes:NULL
1296  pixelsWide:imgSize.width
1297  pixelsHigh:imgSize.height
1298  bitsPerSample:8
1299  samplesPerPixel:4
1300  hasAlpha:YES
1301  isPlanar:NO
1302  colorSpaceName:NSDeviceRGBColorSpace
1303  bitmapFormat:(NSBitmapFormat)0
1304  bytesPerRow:4 * imgSize.width
1305  bitsPerPixel:32 /* RGBA */];
1306 
1307  [NSGraphicsContext saveGraphicsState];
1308  [NSGraphicsContext
1309  setCurrentContext:[NSGraphicsContext
1310  graphicsContextWithBitmapImageRep:blBitmapFormatImageRGBA]];
1311  [bitmapImage draw];
1312  [NSGraphicsContext restoreGraphicsState];
1313 
1314  rasterRGBA = (uint8_t *)[blBitmapFormatImageRGBA bitmapData];
1315  if (rasterRGBA == NULL) {
1316  [bitmapImage release];
1317  [blBitmapFormatImageRGB release];
1318  [blBitmapFormatImageRGBA release];
1319  [droppedImg release];
1320  return GHOST_kFailure;
1321  }
1322 
1323  /* Copy the image to ibuf, flipping it vertically. */
1324  toIBuf = (uint8_t *)ibuf->rect;
1325  for (y = 0; y < imgSize.height; y++) {
1326  for (x = 0; x < imgSize.width; x++) {
1327  to_i = (imgSize.height - y - 1) * imgSize.width + x;
1328  from_i = y * imgSize.width + x;
1329 
1330  toIBuf[4 * to_i] = rasterRGB[4 * from_i]; /* R */
1331  toIBuf[4 * to_i + 1] = rasterRGB[4 * from_i + 1]; /* G */
1332  toIBuf[4 * to_i + 2] = rasterRGB[4 * from_i + 2]; /* B */
1333  toIBuf[4 * to_i + 3] = rasterRGBA[4 * from_i + 3]; /* A */
1334  }
1335  }
1336 
1337  [blBitmapFormatImageRGB release];
1338  [blBitmapFormatImageRGBA release];
1339  [droppedImg release];
1340  }
1341 
1342  eventData = (GHOST_TEventDataPtr)ibuf;
1343 
1344  break;
1345  }
1346  default:
1347  return GHOST_kFailure;
1348  break;
1349  }
1350 
1351  window->clientToScreenIntern(mouseX, mouseY, mouseX, mouseY);
1353  getMilliSeconds(), eventType, draggedObjectType, window, mouseX, mouseY, eventData));
1354 
1355  break;
1356  }
1357  default:
1358  return GHOST_kFailure;
1359  }
1361  return GHOST_kSuccess;
1362 }
1363 
1367 
1368  // Discard quit event if we are in cursor grab sequence
1369  if (window && window->getCursorGrabModeIsWarp())
1370  return;
1371 
1372  // Push the event to Blender so it can open a dialog if needed
1375 }
1376 
1377 bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr)
1379  NSString *filepath = (NSString *)filepathStr;
1380  NSArray *windowsList;
1381  char *temp_buff;
1382  size_t filenameTextSize;
1383 
1384  /* Check for blender opened windows and make the frontmost key. In case blender
1385  * is minimized, opened on another desktop space, or in full-screen mode. */
1386  windowsList = [NSApp orderedWindows];
1387  if ([windowsList count]) {
1388  [[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil];
1389  }
1390 
1392 
1393  if (!window) {
1394  return NO;
1395  }
1396 
1397  /* Discard event if we are in cursor grab sequence,
1398  * it'll lead to "stuck cursor" situation if the alert panel is raised. */
1399  if (window && window->getCursorGrabModeIsWarp()) {
1400  return NO;
1401  }
1402 
1403  filenameTextSize = [filepath lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
1404  temp_buff = (char *)malloc(filenameTextSize + 1);
1405 
1406  if (temp_buff == NULL) {
1407  return GHOST_kFailure;
1408  }
1409 
1410  strncpy(temp_buff, [filepath cStringUsingEncoding:NSUTF8StringEncoding], filenameTextSize);
1411  temp_buff[filenameTextSize] = '\0';
1412 
1415 
1416  return YES;
1417 }
1418 
1419 GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventType)
1421  NSEvent *event = (NSEvent *)eventPtr;
1422  GHOST_IWindow *window;
1423 
1424  window = m_windowManager->getWindowAssociatedWithOSWindow((void *)[event window]);
1425  if (!window) {
1426  // printf("\nW failure for event 0x%x",[event type]);
1427  return GHOST_kFailure;
1428  }
1429 
1430  GHOST_TabletData &ct = ((GHOST_WindowCocoa *)window)->GetCocoaTabletData();
1431 
1432  switch (eventType) {
1433  case NSEventTypeTabletPoint:
1434  // workaround 2 cornercases:
1435  // 1. if [event isEnteringProximity] was not triggered since program-start
1436  // 2. device is not sending [event pointingDeviceType], due no eraser
1437  if (ct.Active == GHOST_kTabletModeNone)
1439 
1440  ct.Pressure = [event pressure];
1441  ct.Xtilt = [event tilt].x;
1442  ct.Ytilt = [event tilt].y;
1443  break;
1444 
1445  case NSEventTypeTabletProximity:
1446  /* Reset tablet data when device enters proximity or leaves. */
1448  if ([event isEnteringProximity]) {
1449  /* Pointer is entering tablet area proximity. */
1450  switch ([event pointingDeviceType]) {
1451  case NSPointingDeviceTypePen:
1453  break;
1454  case NSPointingDeviceTypeEraser:
1456  break;
1457  case NSPointingDeviceTypeCursor:
1458  case NSPointingDeviceTypeUnknown:
1459  default:
1460  break;
1461  }
1462  }
1463  break;
1464 
1465  default:
1466  GHOST_ASSERT(FALSE, "GHOST_SystemCocoa::handleTabletEvent : unknown event received");
1467  return GHOST_kFailure;
1468  break;
1469  }
1470  return GHOST_kSuccess;
1471 }
1472 
1473 bool GHOST_SystemCocoa::handleTabletEvent(void *eventPtr)
1475  NSEvent *event = (NSEvent *)eventPtr;
1476 
1477  switch ([event subtype]) {
1478  case NSEventSubtypeTabletPoint:
1479  handleTabletEvent(eventPtr, NSEventTypeTabletPoint);
1480  return true;
1481  case NSEventSubtypeTabletProximity:
1482  handleTabletEvent(eventPtr, NSEventTypeTabletProximity);
1483  return true;
1484  default:
1485  // No tablet event included : do nothing
1486  return false;
1487  }
1488 }
1489 
1492  NSEvent *event = (NSEvent *)eventPtr;
1493  GHOST_WindowCocoa *window;
1494  CocoaWindow *cocoawindow;
1495 
1496  /* [event window] returns other windows if mouse-over, that's OSX input standard
1497  * however, if mouse exits window(s), the windows become inactive, until you click.
1498  * We then fall back to the active window from ghost. */
1500  (void *)[event window]);
1501  if (!window) {
1503  if (!window) {
1504  // printf("\nW failure for event 0x%x",[event type]);
1505  return GHOST_kFailure;
1506  }
1507  }
1508 
1509  cocoawindow = (CocoaWindow *)window->getOSWindow();
1510 
1511  switch ([event type]) {
1512  case NSEventTypeLeftMouseDown:
1513  handleTabletEvent(event); // Update window tablet state to be included in event.
1514  pushEvent(new GHOST_EventButton([event timestamp] * 1000,
1516  window,
1518  window -> GetCocoaTabletData()));
1519  break;
1520  case NSEventTypeRightMouseDown:
1521  handleTabletEvent(event); // Update window tablet state to be included in event.
1522  pushEvent(new GHOST_EventButton([event timestamp] * 1000,
1524  window,
1526  window -> GetCocoaTabletData()));
1527  break;
1528  case NSEventTypeOtherMouseDown:
1529  handleTabletEvent(event); // Handle tablet events combined with mouse events
1530  pushEvent(new GHOST_EventButton([event timestamp] * 1000,
1532  window,
1533  convertButton([event buttonNumber]),
1534  window -> GetCocoaTabletData()));
1535  break;
1536 
1537  case NSEventTypeLeftMouseUp:
1538  handleTabletEvent(event); // Update window tablet state to be included in event.
1539  pushEvent(new GHOST_EventButton([event timestamp] * 1000,
1541  window,
1543  window -> GetCocoaTabletData()));
1544  break;
1545  case NSEventTypeRightMouseUp:
1546  handleTabletEvent(event); // Update window tablet state to be included in event.
1547  pushEvent(new GHOST_EventButton([event timestamp] * 1000,
1549  window,
1551  window -> GetCocoaTabletData()));
1552  break;
1553  case NSEventTypeOtherMouseUp:
1554  handleTabletEvent(event); // Update window tablet state to be included in event.
1555  pushEvent(new GHOST_EventButton([event timestamp] * 1000,
1557  window,
1558  convertButton([event buttonNumber]),
1559  window -> GetCocoaTabletData()));
1560  break;
1561 
1562  case NSEventTypeLeftMouseDragged:
1563  case NSEventTypeRightMouseDragged:
1564  case NSEventTypeOtherMouseDragged:
1565  handleTabletEvent(event); // Update window tablet state to be included in event.
1566 
1567  case NSEventTypeMouseMoved: {
1568  GHOST_TGrabCursorMode grab_mode = window->getCursorGrabMode();
1569 
1570  /* TODO: CHECK IF THIS IS A TABLET EVENT */
1571  bool is_tablet = false;
1572 
1573  if (is_tablet && window->getCursorGrabModeIsWarp()) {
1574  grab_mode = GHOST_kGrabDisable;
1575  }
1576 
1577  switch (grab_mode) {
1578  case GHOST_kGrabHide: // Cursor hidden grab operation : no cursor move
1579  {
1580  int32_t x_warp, y_warp, x_accum, y_accum, x, y;
1581 
1582  window->getCursorGrabInitPos(x_warp, y_warp);
1583  window->screenToClientIntern(x_warp, y_warp, x_warp, y_warp);
1584 
1585  window->getCursorGrabAccum(x_accum, y_accum);
1586  x_accum += [event deltaX];
1587  y_accum += -[event
1588  deltaY]; // Strange Apple implementation (inverted coordinates for the deltaY) ...
1589  window->setCursorGrabAccum(x_accum, y_accum);
1590 
1591  window->clientToScreenIntern(x_warp + x_accum, y_warp + y_accum, x, y);
1592  pushEvent(new GHOST_EventCursor([event timestamp] * 1000,
1594  window,
1595  x,
1596  y,
1597  window -> GetCocoaTabletData()));
1598  break;
1599  }
1600  case GHOST_kGrabWrap: // Wrap cursor at area/window boundaries
1601  {
1602  NSTimeInterval timestamp = [event timestamp];
1603  if (timestamp < m_last_warp_timestamp) {
1604  /* After warping we can still receive older unwrapped mouse events,
1605  * ignore those. */
1606  break;
1607  }
1608 
1609  NSPoint mousePos = [event locationInWindow];
1610  int32_t x_mouse = mousePos.x;
1611  int32_t y_mouse = mousePos.y;
1612  GHOST_Rect bounds, windowBounds, correctedBounds;
1613 
1614  /* fallback to window bounds */
1615  if (window->getCursorGrabBounds(bounds) == GHOST_kFailure)
1616  window->getClientBounds(bounds);
1617 
1618  /* Switch back to Cocoa coordinates orientation
1619  * (y=0 at bottom, the same as blender internal BTW!), and to client coordinates. */
1620  window->getClientBounds(windowBounds);
1621  window->screenToClient(bounds.m_l, bounds.m_b, correctedBounds.m_l, correctedBounds.m_t);
1622  window->screenToClient(bounds.m_r, bounds.m_t, correctedBounds.m_r, correctedBounds.m_b);
1623  correctedBounds.m_b = (windowBounds.m_b - windowBounds.m_t) - correctedBounds.m_b;
1624  correctedBounds.m_t = (windowBounds.m_b - windowBounds.m_t) - correctedBounds.m_t;
1625 
1626  // Get accumulation from previous mouse warps
1627  int32_t x_accum, y_accum;
1628  window->getCursorGrabAccum(x_accum, y_accum);
1629 
1630  // Warp mouse cursor if needed
1631  int32_t warped_x_mouse = x_mouse;
1632  int32_t warped_y_mouse = y_mouse;
1633 
1634  correctedBounds.wrapPoint(
1635  warped_x_mouse, warped_y_mouse, 4, window->getCursorGrabAxis());
1636 
1637  // Set new cursor position
1638  if (x_mouse != warped_x_mouse || y_mouse != warped_y_mouse) {
1639  int32_t warped_x, warped_y;
1640  window->clientToScreenIntern(warped_x_mouse, warped_y_mouse, warped_x, warped_y);
1641  setMouseCursorPosition(warped_x, warped_y); /* wrap */
1642  window->setCursorGrabAccum(x_accum + (x_mouse - warped_x_mouse),
1643  y_accum + (y_mouse - warped_y_mouse));
1644 
1645  /* This is the current time that matches NSEvent timestamp. */
1646  m_last_warp_timestamp = [[NSProcessInfo processInfo] systemUptime];
1647  }
1648 
1649  // Generate event
1650  int32_t x, y;
1651  window->clientToScreenIntern(x_mouse + x_accum, y_mouse + y_accum, x, y);
1652  pushEvent(new GHOST_EventCursor([event timestamp] * 1000,
1654  window,
1655  x,
1656  y,
1657  window -> GetCocoaTabletData()));
1658  break;
1659  }
1660  default: {
1661  // Normal cursor operation: send mouse position in window
1662  NSPoint mousePos = [event locationInWindow];
1663  int32_t x, y;
1664 
1665  window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
1666  pushEvent(new GHOST_EventCursor([event timestamp] * 1000,
1668  window,
1669  x,
1670  y,
1671  window -> GetCocoaTabletData()));
1672  break;
1673  }
1674  }
1675  } break;
1676 
1677  case NSEventTypeScrollWheel: {
1678  NSEventPhase momentumPhase = NSEventPhaseNone;
1679  NSEventPhase phase = NSEventPhaseNone;
1680 
1681  momentumPhase = [event momentumPhase];
1682  phase = [event phase];
1683 
1684  /* when pressing a key while momentum scrolling continues after
1685  * lifting fingers off the trackpad, the action can unexpectedly
1686  * change from e.g. scrolling to zooming. this works around the
1687  * issue by ignoring momentum scroll after a key press */
1688  if (momentumPhase) {
1690  break;
1691  }
1692  else {
1693  m_ignoreMomentumScroll = false;
1694  }
1695 
1696  /* we assume phases are only set for gestures from trackpad or magic
1697  * mouse events. note that using tablet at the same time may not work
1698  * since this is a static variable */
1699  if (phase == NSEventPhaseBegan && m_multitouchGestures)
1700  m_multiTouchScroll = true;
1701  else if (phase == NSEventPhaseEnded)
1702  m_multiTouchScroll = false;
1703 
1704  /* Standard scroll-wheel case, if no swiping happened,
1705  * and no momentum (kinetic scroll) works. */
1706  if (!m_multiTouchScroll && momentumPhase == NSEventPhaseNone) {
1707  int32_t delta;
1708 
1709  double deltaF = [event deltaY];
1710 
1711  if (deltaF == 0.0)
1712  deltaF = [event deltaX]; // make blender decide if it's horizontal scroll
1713  if (deltaF == 0.0)
1714  break; // discard trackpad delta=0 events
1715 
1716  delta = deltaF > 0.0 ? 1 : -1;
1717  pushEvent(new GHOST_EventWheel([event timestamp] * 1000, window, delta));
1718  }
1719  else {
1720  NSPoint mousePos = [event locationInWindow];
1721  int32_t x, y;
1722  double dx;
1723  double dy;
1724 
1725  /* with 10.7 nice scrolling deltas are supported */
1726  dx = [event scrollingDeltaX];
1727  dy = [event scrollingDeltaY];
1728 
1729  /* However, Wacom tablet (intuos5) needs old deltas,
1730  * it then has momentum and phase at zero. */
1731  if (phase == NSEventPhaseNone && momentumPhase == NSEventPhaseNone) {
1732  dx = [event deltaX];
1733  dy = [event deltaY];
1734  }
1735  window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
1736 
1737  NSPoint delta = [[cocoawindow contentView] convertPointToBacking:NSMakePoint(dx, dy)];
1738  pushEvent(new GHOST_EventTrackpad([event timestamp] * 1000,
1739  window,
1741  x,
1742  y,
1743  delta.x,
1744  delta.y,
1745  [event isDirectionInvertedFromDevice]));
1746  }
1747  } break;
1748 
1749  case NSEventTypeMagnify: {
1750  NSPoint mousePos = [event locationInWindow];
1751  int32_t x, y;
1752  window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
1753  pushEvent(new GHOST_EventTrackpad([event timestamp] * 1000,
1754  window,
1756  x,
1757  y,
1758  [event magnification] * 125.0 + 0.1,
1759  0,
1760  false));
1761  } break;
1762 
1763  case NSEventTypeSmartMagnify: {
1764  NSPoint mousePos = [event locationInWindow];
1765  int32_t x, y;
1766  window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
1768  [event timestamp] * 1000, window, GHOST_kTrackpadEventSmartMagnify, x, y, 0, 0, false));
1769  } break;
1770 
1771  case NSEventTypeRotate: {
1772  NSPoint mousePos = [event locationInWindow];
1773  int32_t x, y;
1774  window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
1775  pushEvent(new GHOST_EventTrackpad([event timestamp] * 1000,
1776  window,
1778  x,
1779  y,
1780  [event rotation] * -5.0,
1781  0,
1782  false));
1783  }
1784  default:
1785  return GHOST_kFailure;
1786  break;
1787  }
1788 
1789  return GHOST_kSuccess;
1790 }
1791 
1794  NSEvent *event = (NSEvent *)eventPtr;
1795  GHOST_IWindow *window;
1796  unsigned int modifiers;
1797  NSString *characters;
1798  NSData *convertedCharacters;
1799  GHOST_TKey keyCode;
1800  NSString *charsIgnoringModifiers;
1801 
1802  window = m_windowManager->getWindowAssociatedWithOSWindow((void *)[event window]);
1803  if (!window) {
1804  // printf("\nW failure for event 0x%x",[event type]);
1805  return GHOST_kFailure;
1806  }
1807 
1808  char utf8_buf[6] = {'\0'};
1809 
1810  switch ([event type]) {
1811 
1812  case NSEventTypeKeyDown:
1813  case NSEventTypeKeyUp:
1814  charsIgnoringModifiers = [event charactersIgnoringModifiers];
1815  if ([charsIgnoringModifiers length] > 0) {
1816  keyCode = convertKey([event keyCode],
1817  [charsIgnoringModifiers characterAtIndex:0],
1818  [event type] == NSEventTypeKeyDown ? kUCKeyActionDown :
1819  kUCKeyActionUp);
1820  }
1821  else {
1822  keyCode = convertKey([event keyCode],
1823  0,
1824  [event type] == NSEventTypeKeyDown ? kUCKeyActionDown :
1825  kUCKeyActionUp);
1826  }
1827 
1828  characters = [event characters];
1829  if ([characters length] > 0) {
1830  convertedCharacters = [characters dataUsingEncoding:NSUTF8StringEncoding];
1831 
1832  for (int x = 0; x < [convertedCharacters length]; x++) {
1833  utf8_buf[x] = ((char *)[convertedCharacters bytes])[x];
1834  }
1835  }
1836 
1837  /* arrow keys should not have utf8 */
1838  if ((keyCode >= GHOST_kKeyLeftArrow) && (keyCode <= GHOST_kKeyDownArrow)) {
1839  utf8_buf[0] = '\0';
1840  }
1841 
1842  /* F keys should not have utf8 */
1843  if ((keyCode >= GHOST_kKeyF1) && (keyCode <= GHOST_kKeyF20))
1844  utf8_buf[0] = '\0';
1845 
1846  /* no text with command key pressed */
1847  if (m_modifierMask & NSEventModifierFlagCommand)
1848  utf8_buf[0] = '\0';
1849 
1850  if ((keyCode == GHOST_kKeyQ) && (m_modifierMask & NSEventModifierFlagCommand))
1851  break; // Cmd-Q is directly handled by Cocoa
1852 
1853  if ([event type] == NSEventTypeKeyDown) {
1854  pushEvent(new GHOST_EventKey([event timestamp] * 1000,
1856  window,
1857  keyCode,
1858  [event isARepeat],
1859  utf8_buf));
1860 #if 0
1861  printf("Key down rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u utf8=%s\n",
1862  [event keyCode],
1863  [charsIgnoringModifiers length] > 0 ? [charsIgnoringModifiers characterAtIndex:0] :
1864  ' ',
1865  keyCode,
1866  utf8_buf);
1867 #endif
1868  }
1869  else {
1871  [event timestamp] * 1000, GHOST_kEventKeyUp, window, keyCode, false, NULL));
1872 #if 0
1873  printf("Key up rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u utf8=%s\n",
1874  [event keyCode],
1875  [charsIgnoringModifiers length] > 0 ? [charsIgnoringModifiers characterAtIndex:0] :
1876  ' ',
1877  keyCode,
1878  utf8_buf);
1879 #endif
1880  }
1881  m_ignoreMomentumScroll = true;
1882  break;
1883 
1884  case NSEventTypeFlagsChanged:
1885  modifiers = [event modifierFlags];
1886 
1887  if ((modifiers & NSEventModifierFlagShift) != (m_modifierMask & NSEventModifierFlagShift)) {
1888  pushEvent(new GHOST_EventKey([event timestamp] * 1000,
1889  (modifiers & NSEventModifierFlagShift) ? GHOST_kEventKeyDown :
1891  window,
1893  false));
1894  }
1895  if ((modifiers & NSEventModifierFlagControl) !=
1896  (m_modifierMask & NSEventModifierFlagControl)) {
1898  [event timestamp] * 1000,
1899  (modifiers & NSEventModifierFlagControl) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
1900  window,
1902  false));
1903  }
1904  if ((modifiers & NSEventModifierFlagOption) !=
1905  (m_modifierMask & NSEventModifierFlagOption)) {
1907  [event timestamp] * 1000,
1908  (modifiers & NSEventModifierFlagOption) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
1909  window,
1911  false));
1912  }
1913  if ((modifiers & NSEventModifierFlagCommand) !=
1914  (m_modifierMask & NSEventModifierFlagCommand)) {
1916  [event timestamp] * 1000,
1917  (modifiers & NSEventModifierFlagCommand) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
1918  window,
1919  GHOST_kKeyOS,
1920  false));
1921  }
1922 
1923  m_modifierMask = modifiers;
1924  m_ignoreMomentumScroll = true;
1925  break;
1926 
1927  default:
1928  return GHOST_kFailure;
1929  break;
1930  }
1931 
1932  return GHOST_kSuccess;
1933 }
1934 
1935 #pragma mark Clipboard get/set
1936 
1937 char *GHOST_SystemCocoa::getClipboard(bool selection) const
1939  char *temp_buff;
1940  size_t pastedTextSize;
1941 
1942  @autoreleasepool {
1943 
1944  NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
1945 
1946  NSString *textPasted = [pasteBoard stringForType:NSStringPboardType];
1947 
1948  if (textPasted == nil) {
1949  return NULL;
1950  }
1951 
1952  pastedTextSize = [textPasted lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
1953 
1954  temp_buff = (char *)malloc(pastedTextSize + 1);
1955 
1956  if (temp_buff == NULL) {
1957  return NULL;
1958  }
1959 
1960  strncpy(temp_buff, [textPasted cStringUsingEncoding:NSUTF8StringEncoding], pastedTextSize);
1961 
1962  temp_buff[pastedTextSize] = '\0';
1963 
1964  if (temp_buff) {
1965  return temp_buff;
1966  }
1967  else {
1968  return NULL;
1969  }
1970  }
1971 }
1972 
1973 void GHOST_SystemCocoa::putClipboard(const char *buffer, bool selection) const
1975  if (selection)
1976  return; // for copying the selection, used on X11
1977 
1978  @autoreleasepool {
1979 
1980  NSPasteboard *pasteBoard = NSPasteboard.generalPasteboard;
1981  [pasteBoard declareTypes:@[ NSStringPboardType ] owner:nil];
1982  NSString *textToCopy = [NSString stringWithCString:buffer encoding:NSUTF8StringEncoding];
1983  [pasteBoard setString:textToCopy forType:NSStringPboardType];
1984  }
1985 }
typedef float(TangentPoint)[2]
void BLI_kdtree_nd_() free(KDTree *tree)
Definition: kdtree_impl.h:102
typedef double(DMatrix)[4][4]
#define FALSE
Definition: GHOST_C-Test.c:17
#define GHOST_ASSERT(x, info)
Definition: GHOST_Debug.h:54
#define GHOST_PRINT(x)
Definition: GHOST_Debug.h:35
NSNotificationCenter * center
#define FIRSTFILEBUFLG
int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG])
static GHOST_TKey convertKey(int rawCode, unichar recvChar, UInt16 keyAction)
static bool g_hasFirstFile
static GHOST_TButton convertButton(int button)
static char g_firstFileBuf[512]
@ GHOST_kTrackpadEventMagnify
Definition: GHOST_Types.h:455
@ GHOST_kTrackpadEventSmartMagnify
Definition: GHOST_Types.h:456
@ GHOST_kTrackpadEventRotate
Definition: GHOST_Types.h:453
@ GHOST_kTrackpadEventScroll
Definition: GHOST_Types.h:452
GHOST_TWindowState
Definition: GHOST_Types.h:129
GHOST_TEventType
Definition: GHOST_Types.h:169
@ GHOST_kEventWindowClose
Definition: GHOST_Types.h:189
@ GHOST_kEventWindowMove
Definition: GHOST_Types.h:194
@ GHOST_kEventWindowSize
Definition: GHOST_Types.h:193
@ GHOST_kEventDraggingDropDone
Definition: GHOST_Types.h:200
@ GHOST_kEventDraggingExited
Definition: GHOST_Types.h:199
@ GHOST_kEventNativeResolutionChange
Definition: GHOST_Types.h:203
@ GHOST_kEventCursorMove
Definition: GHOST_Types.h:172
@ GHOST_kEventDraggingUpdated
Definition: GHOST_Types.h:198
@ GHOST_kEventOpenMainFile
Definition: GHOST_Types.h:202
@ GHOST_kEventDraggingEntered
Definition: GHOST_Types.h:197
@ GHOST_kEventButtonUp
Definition: GHOST_Types.h:174
@ GHOST_kEventWindowActivate
Definition: GHOST_Types.h:190
@ GHOST_kEventWindowUpdate
Definition: GHOST_Types.h:192
@ GHOST_kEventWindowDeactivate
Definition: GHOST_Types.h:191
@ GHOST_kEventButtonDown
Definition: GHOST_Types.h:173
@ GHOST_kEventKeyDown
Definition: GHOST_Types.h:183
@ GHOST_kEventKeyUp
Definition: GHOST_Types.h:184
@ GHOST_kEventQuitRequest
Definition: GHOST_Types.h:187
static const GHOST_TabletData GHOST_TABLET_DATA_NONE
Definition: GHOST_Types.h:104
@ GHOST_kTabletModeEraser
Definition: GHOST_Types.h:86
@ GHOST_kTabletModeStylus
Definition: GHOST_Types.h:85
@ GHOST_kTabletModeNone
Definition: GHOST_Types.h:84
@ GHOST_glStereoVisual
Definition: GHOST_Types.h:62
@ GHOST_glDebugContext
Definition: GHOST_Types.h:63
void * GHOST_TEventDataPtr
Definition: GHOST_Types.h:427
GHOST_TKey
Definition: GHOST_Types.h:259
@ GHOST_kKeySemicolon
Definition: GHOST_Types.h:288
@ GHOST_kKey5
Definition: GHOST_Types.h:282
@ GHOST_kKeyZ
Definition: GHOST_Types.h:317
@ GHOST_kKeyQuote
Definition: GHOST_Types.h:269
@ GHOST_kKey4
Definition: GHOST_Types.h:281
@ GHOST_kKeyT
Definition: GHOST_Types.h:311
@ GHOST_kKeyNumpad3
Definition: GHOST_Types.h:357
@ GHOST_kKeyAccentGrave
Definition: GHOST_Types.h:322
@ GHOST_kKeyNumpad1
Definition: GHOST_Types.h:355
@ GHOST_kKeyW
Definition: GHOST_Types.h:314
@ GHOST_kKeyLeftAlt
Definition: GHOST_Types.h:328
@ GHOST_kKey3
Definition: GHOST_Types.h:280
@ GHOST_kKeyG
Definition: GHOST_Types.h:298
@ GHOST_kKeyF9
Definition: GHOST_Types.h:380
@ GHOST_kKeyC
Definition: GHOST_Types.h:294
@ GHOST_kKeyI
Definition: GHOST_Types.h:300
@ GHOST_kKeyEnter
Definition: GHOST_Types.h:265
@ GHOST_kKeyF20
Definition: GHOST_Types.h:391
@ GHOST_kKeyP
Definition: GHOST_Types.h:307
@ GHOST_kKeyJ
Definition: GHOST_Types.h:301
@ GHOST_kKeyNumpadSlash
Definition: GHOST_Types.h:369
@ GHOST_kKeyRightArrow
Definition: GHOST_Types.h:339
@ GHOST_kKeyF13
Definition: GHOST_Types.h:384
@ GHOST_kKeyF6
Definition: GHOST_Types.h:377
@ GHOST_kKeyNumpad4
Definition: GHOST_Types.h:358
@ GHOST_kKeyF11
Definition: GHOST_Types.h:382
@ GHOST_kKeyR
Definition: GHOST_Types.h:309
@ GHOST_kKeyN
Definition: GHOST_Types.h:305
@ GHOST_kKeyMinus
Definition: GHOST_Types.h:271
@ GHOST_kKeyO
Definition: GHOST_Types.h:306
@ GHOST_kKey6
Definition: GHOST_Types.h:283
@ GHOST_kKeyBackSpace
Definition: GHOST_Types.h:261
@ GHOST_kKey0
Definition: GHOST_Types.h:277
@ GHOST_kKeyF5
Definition: GHOST_Types.h:376
@ GHOST_kKeyF19
Definition: GHOST_Types.h:390
@ GHOST_kKeyDownPage
Definition: GHOST_Types.h:351
@ GHOST_kKeyDownArrow
Definition: GHOST_Types.h:341
@ GHOST_kKeyQ
Definition: GHOST_Types.h:308
@ GHOST_kKeyNumpadPeriod
Definition: GHOST_Types.h:364
@ GHOST_kKeyF12
Definition: GHOST_Types.h:383
@ GHOST_kKeyF1
Definition: GHOST_Types.h:372
@ GHOST_kKeyF
Definition: GHOST_Types.h:297
@ GHOST_kKeyU
Definition: GHOST_Types.h:312
@ GHOST_kKeyNumpadAsterisk
Definition: GHOST_Types.h:368
@ GHOST_kKeyB
Definition: GHOST_Types.h:293
@ GHOST_kKeyLeftControl
Definition: GHOST_Types.h:326
@ GHOST_kKeyLeftBracket
Definition: GHOST_Types.h:319
@ GHOST_kKey1
Definition: GHOST_Types.h:278
@ GHOST_kKeyM
Definition: GHOST_Types.h:304
@ GHOST_kKeyTab
Definition: GHOST_Types.h:262
@ GHOST_kKey8
Definition: GHOST_Types.h:285
@ GHOST_kKeyComma
Definition: GHOST_Types.h:270
@ GHOST_kKeyRightBracket
Definition: GHOST_Types.h:320
@ GHOST_kKeyBackslash
Definition: GHOST_Types.h:321
@ GHOST_kKeyOS
Definition: GHOST_Types.h:330
@ GHOST_kKeyNumpad2
Definition: GHOST_Types.h:356
@ GHOST_kKeyX
Definition: GHOST_Types.h:315
@ GHOST_kKeyL
Definition: GHOST_Types.h:303
@ GHOST_kKeyY
Definition: GHOST_Types.h:316
@ GHOST_kKeyPeriod
Definition: GHOST_Types.h:273
@ GHOST_kKeyNumpadPlus
Definition: GHOST_Types.h:366
@ GHOST_kKeyUpPage
Definition: GHOST_Types.h:350
@ GHOST_kKey9
Definition: GHOST_Types.h:286
@ GHOST_kKeyNumpad5
Definition: GHOST_Types.h:359
@ GHOST_kKeyLeftArrow
Definition: GHOST_Types.h:338
@ GHOST_kKeyF17
Definition: GHOST_Types.h:388
@ GHOST_kKeyD
Definition: GHOST_Types.h:295
@ GHOST_kKeyEqual
Definition: GHOST_Types.h:289
@ GHOST_kKey7
Definition: GHOST_Types.h:284
@ GHOST_kKeyS
Definition: GHOST_Types.h:310
@ GHOST_kKeyF8
Definition: GHOST_Types.h:379
@ GHOST_kKeyF18
Definition: GHOST_Types.h:389
@ GHOST_kKeyHome
Definition: GHOST_Types.h:348
@ GHOST_kKeyNumpad6
Definition: GHOST_Types.h:360
@ GHOST_kKeyF14
Definition: GHOST_Types.h:385
@ GHOST_kKeyNumpad8
Definition: GHOST_Types.h:362
@ GHOST_kKeyNumpad9
Definition: GHOST_Types.h:363
@ GHOST_kKeyF15
Definition: GHOST_Types.h:386
@ GHOST_kKeyEnd
Definition: GHOST_Types.h:349
@ GHOST_kKeyUpArrow
Definition: GHOST_Types.h:340
@ GHOST_kKeyH
Definition: GHOST_Types.h:299
@ GHOST_kKeyDelete
Definition: GHOST_Types.h:347
@ GHOST_kKeyF16
Definition: GHOST_Types.h:387
@ GHOST_kKeyNumpad0
Definition: GHOST_Types.h:354
@ GHOST_kKeyA
Definition: GHOST_Types.h:292
@ GHOST_kKey2
Definition: GHOST_Types.h:279
@ GHOST_kKeyK
Definition: GHOST_Types.h:302
@ GHOST_kKeyNumpad7
Definition: GHOST_Types.h:361
@ GHOST_kKeyEsc
Definition: GHOST_Types.h:267
@ GHOST_kKeyPlus
Definition: GHOST_Types.h:272
@ GHOST_kKeyUnknown
Definition: GHOST_Types.h:260
@ GHOST_kKeySlash
Definition: GHOST_Types.h:274
@ GHOST_kKeyV
Definition: GHOST_Types.h:313
@ GHOST_kKeyF7
Definition: GHOST_Types.h:378
@ GHOST_kKeyNumpadEnter
Definition: GHOST_Types.h:365
@ GHOST_kKeyNumpadMinus
Definition: GHOST_Types.h:367
@ GHOST_kKeyF10
Definition: GHOST_Types.h:381
@ GHOST_kKeyLeftShift
Definition: GHOST_Types.h:324
@ GHOST_kKeyF3
Definition: GHOST_Types.h:374
@ GHOST_kKeyF2
Definition: GHOST_Types.h:373
@ GHOST_kKeyF4
Definition: GHOST_Types.h:375
@ GHOST_kKeyE
Definition: GHOST_Types.h:296
@ GHOST_kKeySpace
Definition: GHOST_Types.h:268
GHOST_TDrawingContextType
Definition: GHOST_Types.h:148
@ GHOST_kModifierKeyLeftControl
Definition: GHOST_Types.h:123
@ GHOST_kModifierKeyOS
Definition: GHOST_Types.h:125
@ GHOST_kModifierKeyLeftAlt
Definition: GHOST_Types.h:121
@ GHOST_kModifierKeyLeftShift
Definition: GHOST_Types.h:119
GHOST_TSuccess
Definition: GHOST_Types.h:74
@ GHOST_kFailure
Definition: GHOST_Types.h:74
@ GHOST_kSuccess
Definition: GHOST_Types.h:74
@ GHOST_kFireTimeNever
Definition: GHOST_Types.h:116
GHOST_TGrabCursorMode
Definition: GHOST_Types.h:404
@ GHOST_kGrabWrap
Definition: GHOST_Types.h:410
@ GHOST_kGrabDisable
Definition: GHOST_Types.h:406
@ GHOST_kGrabHide
Definition: GHOST_Types.h:415
GHOST_TDragnDropTypes
Definition: GHOST_Types.h:474
@ GHOST_kDragnDropTypeFilenames
Definition: GHOST_Types.h:476
@ GHOST_kDragnDropTypeBitmap
Definition: GHOST_Types.h:478
@ GHOST_kDragnDropTypeString
Definition: GHOST_Types.h:477
GHOST_TButton
Definition: GHOST_Types.h:156
@ GHOST_kButtonMaskRight
Definition: GHOST_Types.h:160
@ GHOST_kButtonMaskButton4
Definition: GHOST_Types.h:161
@ GHOST_kButtonMaskLeft
Definition: GHOST_Types.h:158
@ GHOST_kButtonMaskButton7
Definition: GHOST_Types.h:165
@ GHOST_kButtonMaskButton6
Definition: GHOST_Types.h:164
@ GHOST_kButtonMaskButton5
Definition: GHOST_Types.h:162
@ GHOST_kButtonMaskMiddle
Definition: GHOST_Types.h:159
_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 type
_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 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:500
@ IB_rect
#define C
Definition: RandGen.cpp:25
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition: btDbvt.cpp:299
virtual GHOST_TSuccess initialize(void)
virtual bool getValid() const =0
int32_t m_l
Definition: GHOST_Rect.h:156
int32_t m_r
Definition: GHOST_Rect.h:160
int32_t m_b
Definition: GHOST_Rect.h:162
virtual void wrapPoint(int32_t &x, int32_t &y, int32_t ofs, GHOST_TAxisFlag axis)
Definition: GHOST_Rect.h:229
int32_t m_t
Definition: GHOST_Rect.h:158
bool processEvents(bool waitForEvent)
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)
GHOST_IWindow * getWindowUnderCursor(int32_t x, int32_t y)
bool m_needDelayedApplicationBecomeActiveEventProcessing
GHOST_TSuccess handleApplicationBecomeActiveEvent()
GHOST_TSuccess setCursorPosition(int32_t x, int32_t y)
GHOST_TSuccess handleMouseEvent(void *eventPtr)
GHOST_TSuccess handleKeyEvent(void *eventPtr)
uint8_t getNumDisplays() const
void getAllDisplayDimensions(uint32_t &width, uint32_t &height) const
GHOST_TSuccess getButtons(GHOST_Buttons &buttons) const
void putClipboard(const char *buffer, bool selection) const
void getMainDisplayDimensions(uint32_t &width, uint32_t &height) const
GHOST_TSuccess handleTabletEvent(void *eventPtr, short eventType)
bool handleOpenDocumentRequest(void *filepathStr)
GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const
uint64_t getMilliSeconds() const
char * getClipboard(bool selection) const
GHOST_TSuccess setMouseCursorPosition(int32_t x, int32_t y)
GHOST_IContext * createOffscreenContext(GHOST_GLSettings glSettings)
GHOST_TSuccess getCursorPosition(int32_t &x, int32_t &y) const
GHOST_IWindow * createWindow(const char *title, int32_t left, int32_t top, uint32_t width, uint32_t 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 init()
bool m_multitouchGestures
Definition: GHOST_System.h:414
virtual GHOST_TSuccess init()
GHOST_TimerManager * getTimerManager() const
Definition: GHOST_System.h:422
bool m_windowFocus
Definition: GHOST_System.h:162
GHOST_WindowManager * m_windowManager
Definition: GHOST_System.h:395
bool validWindow(GHOST_IWindow *window)
GHOST_TSuccess pushEvent(GHOST_IEvent *event)
GHOST_DisplayManager * m_displayManager
Definition: GHOST_System.h:389
bool m_nativePixel
Definition: GHOST_System.h:152
bool fireTimers(uint64_t time)
void clientToScreenIntern(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const
void getClientBounds(GHOST_Rect &bounds) const
void * getOSWindow() const
void setNativePixelSize(void)
void screenToClientIntern(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const
GHOST_TabletData & GetCocoaTabletData()
void loadCursor(bool visible, GHOST_TStandardCursor cursor) const
void screenToClient(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) 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:408
void setCursorGrabAccum(int32_t x, int32_t y)
Definition: GHOST_Window.h:440
void getCursorGrabInitPos(int32_t &x, int32_t &y) const
Definition: GHOST_Window.h:428
GHOST_TAxisFlag getCursorGrabAxis() const
Definition: GHOST_Window.h:423
GHOST_TGrabCursorMode getCursorGrabMode() const
Definition: GHOST_Window.h:413
GHOST_TSuccess updateDrawingContext()
GHOST_TStandardCursor getCursorShape() const
Definition: GHOST_Window.h:446
bool getCursorGrabModeIsWarp() const
Definition: GHOST_Window.h:418
void getCursorGrabAccum(int32_t &x, int32_t &y) const
Definition: GHOST_Window.h:434
SyclQueue void void size_t num_bytes void
int len
Definition: draw_manager.c:108
GHOST_SystemCocoa * systemCocoa
void setSystemCocoa:(GHOST_SystemCocoa *sysCocoa)
int count
ccl_global float * buffer
const int state
static ulong * next
static int left
#define G(x, y, z)
T length(const vec_base< T, Size > &a)
unsigned int uint32_t
Definition: stdint.h:80
signed int int32_t
Definition: stdint.h:77
unsigned char uint8_t
Definition: stdint.h:78
unsigned __int64 uint64_t
Definition: stdint.h:90
void set(GHOST_TButton mask, bool down)
void set(GHOST_TModifierKey mask, bool down)
uint8_t ** strings
Definition: GHOST_Types.h:508
GHOST_TTabletMode Active
Definition: GHOST_Types.h:98
unsigned int * rect
void WM_exit(bContext *C)
Main exit function to close Blender ordinarily.
Definition: wm_init_exit.c:646