Logo ROOT   6.12/07
Reference Guide
X11Events.mm
Go to the documentation of this file.
1 // @(#)root/graf2d:$Id$
2 // Author: Timur Pocheptsov 16/02/2012
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2012, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 //#define NDEBUG
13 
14 #include <algorithm>
15 #include <cassert>
16 
17 #include <Cocoa/Cocoa.h>
18 
19 #include "CocoaConstants.h"
20 #include "ROOTOpenGLView.h"
21 #include "QuartzWindow.h"
22 #include "CocoaUtils.h"
23 #include "KeySymbols.h"
24 #include "X11Events.h"
25 #include "TGClient.h"
26 #include "TGWindow.h"
27 #include "TList.h"
28 
29 @interface FakeCrossingEvent : NSEvent {
30  NSWindow *fQuartzWindow;
31  NSPoint fLocationInWindow;
32 }
33 
34 @end
35 
36 @implementation FakeCrossingEvent
37 
38 //______________________________________________________________________________
39 - (id) initWithWindow : (NSWindow *) window location : (NSPoint) location
40 {
41  //Window should be always non-nil: we either enter some window, or exit some window.
42  assert(window && "initWithWindow:location:, parameter 'window' is nil");
43 
44  if (self = [super init]) {
45  fQuartzWindow = window;
46  fLocationInWindow = location;
47  }
48 
49  return self;
50 }
51 
52 //______________________________________________________________________________
53 - (NSWindow *) window
54 {
55  assert(fQuartzWindow && "window, fQuartzWindow is nil");
56  return fQuartzWindow;
57 }
58 
59 //______________________________________________________________________________
60 - (NSPoint) locationInWindow
61 {
62  assert(fQuartzWindow != nil && "locationInWindow, fQuartzWindow is nil");
63  return fLocationInWindow;
64 }
65 
66 //______________________________________________________________________________
67 - (NSTimeInterval) timestamp
68 {
69  //Hehe.
70  return 0.;
71 }
72 
73 @end
74 
75 
76 namespace ROOT {
77 namespace MacOSX {
78 namespace X11 {
79 
80 namespace {
81 
82 //Convert unichar (from [NSEvent characters]) into
83 //ROOT's key symbol (from KeySymbols.h).
84 template<typename T1, typename T2>
85 struct KeySymPair {
88 
89  bool operator < (const KeySymPair &rhs)const
90  {
91  return fFirst < rhs.fFirst;
92  }
93 };
94 
95 }
96 
97 //______________________________________________________________________________
98 void MapUnicharToKeySym(unichar key, char *buf, Int_t /*len*/, UInt_t &rootKeySym)
99 {
100  assert(buf != 0 && "MapUnicharToKeySym, parameter 'buf' is null");
101 
102  static const KeySymPair<unichar, EKeySym> keyMap[] = {
103  {NSEnterCharacter, kKey_Enter},
104  {NSTabCharacter, kKey_Tab},
105  {NSCarriageReturnCharacter, kKey_Return},
106  {NSBackTabCharacter, kKey_Backtab},
107  //WHYWHYWHY apple does not have a constant for escape????
108  {27, kKey_Escape},
109  {NSDeleteCharacter, kKey_Backspace},
110  {NSUpArrowFunctionKey, kKey_Up},
111  {NSDownArrowFunctionKey, kKey_Down},
112  {NSLeftArrowFunctionKey, kKey_Left},
113  {NSRightArrowFunctionKey, kKey_Right},
114  {NSF1FunctionKey, kKey_F1},
115  {NSF2FunctionKey, kKey_F2},
116  {NSF3FunctionKey, kKey_F3},
117  {NSF4FunctionKey, kKey_F4},
118  {NSF5FunctionKey, kKey_F5},
119  {NSF6FunctionKey, kKey_F6},
120  {NSF7FunctionKey, kKey_F7},
121  {NSF8FunctionKey, kKey_F8},
122  {NSF9FunctionKey, kKey_F8},
123  {NSF10FunctionKey, kKey_F10},
124  {NSF11FunctionKey, kKey_F11},
125  {NSF12FunctionKey, kKey_F12},
126  {NSF13FunctionKey, kKey_F13},
127  {NSF14FunctionKey, kKey_F14},
128  {NSF15FunctionKey, kKey_F15},
129  {NSF16FunctionKey, kKey_F16},
130  {NSF17FunctionKey, kKey_F17},
131  {NSF18FunctionKey, kKey_F18},
132  {NSF19FunctionKey, kKey_F19},
133  {NSF20FunctionKey, kKey_F20},
134  {NSF21FunctionKey, kKey_F21},
135  {NSF22FunctionKey, kKey_F22},
136  {NSF23FunctionKey, kKey_F23},
137  {NSF24FunctionKey, kKey_F24},
138  {NSF25FunctionKey, kKey_F25},
139  {NSF26FunctionKey, kKey_F26},
140  {NSF27FunctionKey, kKey_F27},
141  {NSF28FunctionKey, kKey_F28},
142  {NSF29FunctionKey, kKey_F29},
143  {NSF30FunctionKey, kKey_F30},
144  {NSF31FunctionKey, kKey_F31},
145  {NSF32FunctionKey, kKey_F32},
146  {NSF33FunctionKey, kKey_F33},
147  {NSF34FunctionKey, kKey_F34},
148  {NSF35FunctionKey, kKey_F35},
149  {NSInsertFunctionKey, kKey_Insert},
150  {NSDeleteFunctionKey, kKey_Delete},
151  {NSHomeFunctionKey, kKey_Home},
152  {NSEndFunctionKey, kKey_End},
153  {NSPageUpFunctionKey, kKey_PageUp},
154  {NSPageDownFunctionKey, kKey_PageDown},
155  {NSPrintScreenFunctionKey, kKey_Print},
156  {NSScrollLockFunctionKey, kKey_ScrollLock},
157  {NSPauseFunctionKey, kKey_Pause},
158  {NSSysReqFunctionKey, kKey_SysReq}};
159 
160  const unsigned nEntries = sizeof keyMap / sizeof keyMap[0];
161 
162  buf[1] = 0;
163 
164  KeySymPair<unichar, EKeySym> valueToFind = {};
165  valueToFind.fFirst = key;
166  const KeySymPair<unichar, EKeySym> *iter = std::lower_bound(keyMap, keyMap + nEntries, valueToFind);
167 
168  if (iter != keyMap + nEntries && iter->fFirst == key) {
169  buf[0] = key <= 0x7e ? key : 0;
170  rootKeySym = iter->fSecond;
171  } else {
172  buf[0] = key;//????
173  rootKeySym = key;
174  }
175 }
176 
177 //______________________________________________________________________________
179 {
180  //Apart from special keys, ROOT has also ASCII symbols, they map directly to themselves.
181  if (keySym >= 0x20 && keySym <= 0x7e)
182  return keySym;
183 
184  static const KeySymPair<EKeySym, unichar> keyMap[] = {
185  {kKey_Escape, 27},
186  {kKey_Tab, NSTabCharacter},
187  {kKey_Backtab, NSBackTabCharacter},
188  {kKey_Backspace, NSDeleteCharacter},
189  {kKey_Return, NSCarriageReturnCharacter},
190  {kKey_Enter, NSEnterCharacter},
191  {kKey_Insert, NSInsertFunctionKey},
192  {kKey_Delete, NSDeleteFunctionKey},
193  {kKey_Pause, NSPauseFunctionKey},
194  {kKey_Print, NSPrintScreenFunctionKey},
195  {kKey_SysReq, NSSysReqFunctionKey},
196  {kKey_Home, NSHomeFunctionKey},
197  {kKey_End, NSEndFunctionKey},
198  {kKey_Left, NSLeftArrowFunctionKey},
199  {kKey_Up, NSUpArrowFunctionKey},
200  {kKey_Right, NSRightArrowFunctionKey},
201  {kKey_Down, NSDownArrowFunctionKey},
202  {kKey_PageUp, NSPageUpFunctionKey},
203  {kKey_PageDown, NSPageDownFunctionKey},
204  //This part is bad.
205  {kKey_Shift, 0},
206  {kKey_Control, 0},
207  {kKey_Alt, 0},
208  {kKey_CapsLock, 0},
209  {kKey_NumLock, 0},
210  //
211  {kKey_ScrollLock, NSScrollLockFunctionKey},
212  {kKey_F1, NSF1FunctionKey},
213  {kKey_F2, NSF2FunctionKey},
214  {kKey_F3, NSF3FunctionKey},
215  {kKey_F4, NSF4FunctionKey},
216  {kKey_F5, NSF5FunctionKey},
217  {kKey_F6, NSF6FunctionKey},
218  {kKey_F7, NSF7FunctionKey},
219  {kKey_F8, NSF8FunctionKey},
220  {kKey_F8, NSF9FunctionKey},
221  {kKey_F10, NSF10FunctionKey},
222  {kKey_F11, NSF11FunctionKey},
223  {kKey_F12, NSF12FunctionKey},
224  {kKey_F13, NSF13FunctionKey},
225  {kKey_F14, NSF14FunctionKey},
226  {kKey_F15, NSF15FunctionKey},
227  {kKey_F16, NSF16FunctionKey},
228  {kKey_F17, NSF17FunctionKey},
229  {kKey_F18, NSF18FunctionKey},
230  {kKey_F19, NSF19FunctionKey},
231  {kKey_F20, NSF20FunctionKey},
232  {kKey_F21, NSF21FunctionKey},
233  {kKey_F22, NSF22FunctionKey},
234  {kKey_F23, NSF23FunctionKey},
235  {kKey_F24, NSF24FunctionKey},
236  {kKey_F25, NSF25FunctionKey},
237  {kKey_F26, NSF26FunctionKey},
238  {kKey_F27, NSF27FunctionKey},
239  {kKey_F28, NSF28FunctionKey},
240  {kKey_F29, NSF29FunctionKey},
241  {kKey_F30, NSF30FunctionKey},
242  {kKey_F31, NSF31FunctionKey},
243  {kKey_F32, NSF32FunctionKey},
244  {kKey_F33, NSF33FunctionKey},
245  {kKey_F34, NSF34FunctionKey},
246  {kKey_F35, NSF35FunctionKey}
247  };
248 
249  const unsigned nEntries = sizeof keyMap / sizeof keyMap[0];
250 
251  KeySymPair<EKeySym, unichar> valueToFind = {};
252  valueToFind.fFirst = static_cast<EKeySym>(keySym);
253  const KeySymPair<EKeySym, unichar> *iter = std::lower_bound(keyMap, keyMap + nEntries, valueToFind);
254  if (iter != keyMap + nEntries && iter->fFirst == keySym)
255  return iter->fSecond;
256 
257  return 0;
258 }
259 
260 //______________________________________________________________________________
262 {
263  NSUInteger cocoaModifiers = 0;
264 
265  if (rootModifiers & kKeyLockMask)
266  cocoaModifiers |= Details::kAlphaShiftKeyMask;
267  if (rootModifiers & kKeyShiftMask)
268  cocoaModifiers |= Details::kShiftKeyMask;
269  if (rootModifiers & kKeyControlMask)
270  cocoaModifiers |= Details::kControlKeyMask;
271  if (rootModifiers & kKeyMod1Mask)
272  cocoaModifiers |= Details::kAlternateKeyMask;
273  if (rootModifiers & kKeyMod2Mask)
274  cocoaModifiers |= Details::kCommandKeyMask;
275 
276  return cocoaModifiers;
277 }
278 
279 //______________________________________________________________________________
281 {
282  const NSUInteger modifiers = [NSEvent modifierFlags];
283 
284  UInt_t rootModifiers = 0;
285  if (modifiers & Details::kAlphaShiftKeyMask)
286  rootModifiers |= kKeyLockMask;
287  if (modifiers & Details::kShiftKeyMask)
288  rootModifiers |= kKeyShiftMask;
289  if (modifiers & Details::kControlKeyMask)
290  rootModifiers |= kKeyControlMask;
291  if (modifiers & Details::kAlternateKeyMask)
292  rootModifiers |= kKeyMod1Mask;
293  if (modifiers & Details::kCommandKeyMask)
294  rootModifiers |= kKeyMod2Mask;
295 
296  return rootModifiers;
297 }
298 
299 //______________________________________________________________________________
301 {
302  UInt_t rootModifiers = GetKeyboardModifiers();
303  const NSUInteger buttons = [NSEvent pressedMouseButtons];
304  if (buttons & 1)
305  rootModifiers |= kButton1Mask;
306  if (buttons & 2)
307  rootModifiers |= kButton3Mask;
308  if (buttons & (1 << 2))
309  rootModifiers |= kButton2Mask;
310 
311  return rootModifiers;
312 }
313 
314 namespace Detail {
315 
316 #pragma mark - Several aux. functions to extract parameters from Cocoa events.
317 
318 //______________________________________________________________________________
319 Time_t TimeForCocoaEvent(NSEvent *theEvent)
320 {
321  //1. Event is not nil.
322  assert(theEvent != nil && "TimeForCocoaEvent, parameter 'theEvent' is nil");
323 
324  return [theEvent timestamp] * 1000;
325 }
326 
327 //______________________________________________________________________________
328 Event_t NewX11EventFromCocoaEvent(unsigned windowID, NSEvent *theEvent)
329 {
330  //1. Event is not nil.
331 
332  assert(theEvent != nil && "NewX11EventFromCocoaEvent, parameter 'theEvent' is nil");
333 
334  Event_t newEvent = {};
335  newEvent.fWindow = windowID;
336  newEvent.fTime = TimeForCocoaEvent(theEvent);
337  return newEvent;
338 }
339 
340 //______________________________________________________________________________
341 void ConvertEventLocationToROOTXY(NSEvent *cocoaEvent, NSView<X11Window> *eventView, Event_t *rootEvent)
342 {
343  //1. All parameters are valid.
344  //Both event and view must be in the same window, I do not check this here.
345 
346  assert(cocoaEvent != nil && "ConvertEventLocationToROOTXY, parameter 'cocoaEvent' is nil");
347  assert(eventView != nil && "ConvertEventLocationToROOTXY, parameter 'eventView' is nil");
348  assert(rootEvent != 0 && "ConvertEventLocationToROOTXY, parameter 'rootEvent' is null");
349 
350  if (![cocoaEvent window])
351  NSLog(@"Error in ConvertEventLocationToROOTXY, window property"
352  " of event is nil, can not convert coordinates correctly");
353 
354  //Due to some reason, Apple has deprectated point conversion and requires to convert ... a rect.
355  //Even more, on HiDPI point conversion produces wrong results and rect conversion works.
356 
357  const NSPoint screenPoint = ConvertPointFromBaseToScreen([cocoaEvent window], [cocoaEvent locationInWindow]);
358  const NSPoint winPoint = ConvertPointFromScreenToBase(screenPoint, [eventView window]);
359  const NSPoint viewPoint = [eventView convertPoint : winPoint fromView : nil];
360 
361  rootEvent->fX = viewPoint.x;
362  rootEvent->fY = viewPoint.y;
363 
364  rootEvent->fXRoot = GlobalXCocoaToROOT(screenPoint.x);
365  rootEvent->fYRoot = GlobalYCocoaToROOT(screenPoint.y);
366 }
367 
368 //______________________________________________________________________________
369 unsigned GetKeyboardModifiersFromCocoaEvent(NSEvent *theEvent)
370 {
371  assert(theEvent != nil && "GetKeyboardModifiersFromCocoaEvent, parameter 'event' is nil");
372 
373  const NSUInteger modifiers = [theEvent modifierFlags];
374  unsigned rootModifiers = 0;
375  if (modifiers & Details::kAlphaShiftKeyMask)
376  rootModifiers |= kKeyLockMask;
377  if (modifiers & Details::kShiftKeyMask)
378  rootModifiers |= kKeyShiftMask;
379  if (modifiers & Details::kControlKeyMask)
380  rootModifiers |= kKeyControlMask;
381  if (modifiers & Details::kAlternateKeyMask)
382  rootModifiers |= kKeyMod1Mask;
383  if (modifiers & Details::kCommandKeyMask)
384  rootModifiers |= kKeyMod2Mask;
385 
386  return rootModifiers;
387 }
388 
389 //______________________________________________________________________________
390 unsigned GetModifiersFromCocoaEvent(NSEvent *theEvent)
391 {
392  assert(theEvent != nil && "GetModifiersFromCocoaEvent, parameter 'event' is nil");
393 
394  unsigned rootModifiers = GetKeyboardModifiersFromCocoaEvent(theEvent);
395  const NSUInteger buttons = [NSEvent pressedMouseButtons];
396  if (buttons & 1)
397  rootModifiers |= kButton1Mask;
398  if (buttons & 2)
399  rootModifiers |= kButton3Mask;
400  if (buttons & (1 << 2))
401  rootModifiers |= kButton2Mask;
402 
403  return rootModifiers;
404 }
405 
406 #pragma mark - Misc. aux. functions.
407 
408 //______________________________________________________________________________
409 bool IsParent(NSView<X11Window> *testParent, NSView<X11Window> *testChild)
410 {
411  assert(testParent != nil && "IsParent, parameter 'testParent' is nil");
412  assert(testChild != nil && "IsParent, parameter 'testChild' is nil");
413 
414  if (testChild.fParentView) {
415  NSView<X11Window> *parent = testChild.fParentView;
416  while (parent) {
417  if(parent == testParent)
418  return true;
419  parent = parent.fParentView;
420  }
421  }
422 
423  return false;
424 }
425 
426 //______________________________________________________________________________
427 bool IsInBranch(NSView<X11Window> *parent, NSView<X11Window> *child, NSView<X11Window> *testView)
428 {
429  assert(child != nil && "IsInBranch, parameter 'child' is nil");
430  assert(testView != nil && "IsInBranch, parameter 'testView' is nil");
431 
432  if (testView == child || testView == parent)
433  return true;
434 
435  for (NSView<X11Window> *current = child.fParentView; current != parent; current = current.fParentView) {
436  if (current == testView)
437  return true;
438  }
439 
440  return false;
441 }
442 
443 //Relation between two views.
444 enum Ancestry {
449 };
450 
451 //______________________________________________________________________________
452 Ancestry FindLowestCommonAncestor(NSView<X11Window> *view1, NSView<X11Window> *view2,
453  NSView<X11Window> **lca)
454 {
455  //Search for the lowest common ancestor.
456  //View1 can not be parent of view2, view2 can not be parent of view1,
457  //I do not check this condition here.
458 
459  assert(view1 != nil && "FindLowestCommonAncestor, parameter 'view1' is nil");
460  assert(view2 != nil && "findLowestCommonAncestor, parameter 'view2' is nil");
461  assert(lca != 0 && "FindLowestCommonAncestor, parameter 'lca' is null");
462 
463  if (!view1.fParentView)
464  return kAAncestorIsRoot;
465 
466  if (!view2.fParentView)
467  return kAAncestorIsRoot;
468 
469  NSView<X11Window> * const ancestor = (NSView<X11Window> *)[view1 ancestorSharedWithView : view2];
470 
471  if (ancestor) {
472  *lca = ancestor;
473  return kAHaveNonRootAncestor;
474  }
475 
476  return kAAncestorIsRoot;
477 }
478 
479 //______________________________________________________________________________
480 Ancestry FindRelation(NSView<X11Window> *view1, NSView<X11Window> *view2, NSView<X11Window> **lca)
481 {
482  assert(view1 != nil && "FindRelation, view1 parameter is nil");
483  assert(view2 != nil && "FindRelation, view2 parameter is nil");
484  assert(lca != 0 && "FindRelation, lca parameter is nil");
485 
486  if (IsParent(view1, view2))
487  return kAView1IsParent;
488 
489  if (IsParent(view2, view1))
490  return kAView2IsParent;
491 
492  return FindLowestCommonAncestor(view1, view2, lca);
493 }
494 
495 //______________________________________________________________________________
496 NSView<X11Window> *FindViewToPropagateEvent(NSView<X11Window> *viewFrom, Mask_t checkMask)
497 {
498  //This function does not check passive grabs.
499  assert(viewFrom != nil && "FindViewToPropagateEvent, parameter 'view' is nil");
500 
501  if (viewFrom.fEventMask & checkMask)
502  return viewFrom;
503 
504  for (viewFrom = viewFrom.fParentView; viewFrom; viewFrom = viewFrom.fParentView) {
505  if (viewFrom.fEventMask & checkMask)
506  return viewFrom;
507  }
508 
509  return nil;
510 }
511 
512 //______________________________________________________________________________
513 NSView<X11Window> *FindViewToPropagateEvent(NSView<X11Window> *viewFrom, Mask_t checkMask,
514  NSView<X11Window> *grabView, Mask_t grabMask)
515 {
516  //This function is called when we have a grab and owner_events == true,
517  //in this case the grab view itself (and its grab mask) is checked
518  //at the end (if no view was found before). Grab view can be in a hierarchy
519  //for a 'viewFrom' view and can have matching fEventMask.
520 
521  assert(viewFrom != nil && "FindViewToPropagateEvent, parameter 'view' is nil");
522 
523  if (viewFrom.fEventMask & checkMask)
524  return viewFrom;
525 
526  for (viewFrom = viewFrom.fParentView; viewFrom; viewFrom = viewFrom.fParentView) {
527  if (viewFrom.fEventMask & checkMask)
528  return viewFrom;
529  }
530 
531  if (grabView && (grabMask & checkMask))
532  return grabView;
533 
534  return nil;
535 }
536 
537 #pragma mark - Aux. 'low-level' functions to generate events and call HandleEvent for a root window.
538 
539 //______________________________________________________________________________
540 void SendEnterEvent(EventQueue_t &queue, NSView<X11Window> *view, NSEvent *theEvent,
541  EXMagic detail)
542 {
543  //1. Parameters are valid.
544  //2. view.fID is valid.
545  //3. A window for view.fID exists.
546  //This view must receive enter notify, I do not check it here.
547 
548  assert(view != nil && "SendEnterEvent, parameter 'view' is nil");
549  assert(theEvent != nil && "SendEnterEvent, parameter 'event' is nil");
550  assert(view.fID != 0 && "SendEnterEvent, view.fID is 0");
551 
552  TGWindow * const window = gClient->GetWindowById(view.fID);
553  if (!window) {
554 #ifdef DEBUG_ROOT_COCOA
555  NSLog(@"SendEnterEvent, ROOT's widget %u was not found", view.fID);
556 #endif
557  return;
558  }
559 
560  Event_t enterEvent = NewX11EventFromCocoaEvent(view.fID, theEvent);
561  enterEvent.fType = kEnterNotify;
562  enterEvent.fCode = detail;
563  enterEvent.fState = GetModifiersFromCocoaEvent(theEvent);
564  //Coordinates. Event possible happend not in a view,
565  //but window should be the same. Also, coordinates are always
566  //inside a view.
567 
568  ConvertEventLocationToROOTXY(theEvent, view, &enterEvent);
569 
570  //Enqueue event again.
571  queue.push_back(enterEvent);
572 }
573 
574 //______________________________________________________________________________
575 void SendLeaveEvent(EventQueue_t &queue, NSView<X11Window> *view, NSEvent *theEvent,
576  EXMagic detail)
577 {
578  //1. Parameters are valid.
579  //2. view.fID is valid.
580  //3. A window for view.fID exists.
581  //This window should receive leave event, I do not check it here.
582 
583  assert(view != nil && "SendLeaveEvent, parameter 'view' is nil");
584  assert(theEvent != nil && "SendLeaveEvent, parameter 'event' is nil");
585  assert(view.fID != 0 && "SendLeaveEvent, view.fID is 0");
586 
587  TGWindow * const window = gClient->GetWindowById(view.fID);
588  if (!window) {
589 #ifdef DEBUG_ROOT_COCOA
590  NSLog(@"SendLeaveEvent, ROOT's widget %u was not found", view.fID);
591 #endif
592  return;
593  }
594 
595  Event_t leaveEvent = NewX11EventFromCocoaEvent(view.fID, theEvent);
596  leaveEvent.fType = kLeaveNotify;
597  leaveEvent.fCode = detail;
598  leaveEvent.fState = GetModifiersFromCocoaEvent(theEvent);
599  //Coordinates. Event possibly happend not in a view, also, coordinates are out of
600  //the view.
601  ConvertEventLocationToROOTXY(theEvent, view, &leaveEvent);
602  //Enqueue event for ROOT.
603  queue.push_back(leaveEvent);
604 }
605 
606 //______________________________________________________________________________
607 void SendPointerMotionEvent(EventQueue_t &queue, NSView<X11Window> *view, NSEvent *theEvent)
608 {
609  //1. Parameters are valid.
610  //2. view.fID is valid.
611  //3. A window for view.fID exists.
612  //View receives pointer motion events, I do not check this condition here.
613 
614  assert(view != nil && "SendPointerMotionEvent, parameter 'view' is nil");
615  assert(theEvent != nil && "SendPointerMotionEvent, parameter 'event' is nil");
616  assert(view.fID != 0 && "SendPointerMotionEvent, view.fID is 0");
617 
618  TGWindow * const window = gClient->GetWindowById(view.fID);
619  if (!window) {
620 #ifdef DEBUG_ROOT_COCOA
621  NSLog(@"SendPointerMotionEvent, ROOT's widget %u was not found", view.fID);
622 #endif
623  return;
624  }
625 
626  Event_t motionEvent = NewX11EventFromCocoaEvent(view.fID, theEvent);
627  motionEvent.fType = kMotionNotify;
628  motionEvent.fState = GetModifiersFromCocoaEvent(theEvent);
629 
630  ConvertEventLocationToROOTXY(theEvent, view, &motionEvent);
631  //Enqueue event for ROOT.
632  queue.push_back(motionEvent);
633 }
634 
635 //______________________________________________________________________________
636 void SendButtonPressEvent(EventQueue_t &queue, NSView<X11Window> *view, NSEvent *theEvent,
637  EMouseButton btn)
638 {
639  //1. Parameters are valid.
640  //2. view.fID is valid.
641  //3. A window for view.fID exists.
642  //View receives this event (either grab or select input)
643  // - I do not check this condition here.
644 
645  assert(view != nil && "SendButtonPressEvent, parameter 'view' is nil");
646  assert(theEvent != nil && "SendButtonPressEvent, parameter 'event' is nil");
647  assert(view.fID != 0 && "SendButtonPressEvent, view.fID is 0");
648 
649  TGWindow * const window = gClient->GetWindowById(view.fID);
650  if (!window) {
651 #ifdef DEBUG_ROOT_COCOA
652  NSLog(@"SendButtonpressEvent, ROOT's widget %u was not found", view.fID);
653 #endif
654  return;
655  }
656 
657  Event_t pressEvent = NewX11EventFromCocoaEvent(view.fID, theEvent);
658  pressEvent.fType = kButtonPress;
659  pressEvent.fCode = btn;
660  pressEvent.fState = GetKeyboardModifiersFromCocoaEvent(theEvent);
661  //
662  ConvertEventLocationToROOTXY(theEvent, view, &pressEvent);
663  //
664  //
665  //ROOT uses "subwindow" parameter for button press event also, for example,
666  //scroll bar has several children windows - "buttons", they are not selecting
667  //button press events (and not grabbing pointer).
668  //This will work wrong, if we have overlapping views - we'll find a wrong subwindow.
669  //
670 
671  NSPoint viewPoint = {};
672  viewPoint.x = pressEvent.fX;
673  viewPoint.y = pressEvent.fY;
674  for (NSView<X11Window> *child in [view subviews]) {
675  if (!child.fIsOverlapped && [child hitTest : viewPoint]) {//Hit test goes down along the tree.
676  pressEvent.fUser[0] = child.fID;
677  break;
678  }
679  }
680 
681  //Enqueue event for ROOT.
682  queue.push_back(pressEvent);
683 }
684 
685 //______________________________________________________________________________
686 void SendButtonReleaseEvent(EventQueue_t &queue, NSView<X11Window> *view, NSEvent *theEvent,
687  EMouseButton btn)
688 {
689  //1. Parameters are valid.
690  //2. view.fID is valid.
691  //3. A window for view.fID exists.
692  //View must button release events, I do not check this here.
693 
694  assert(view != nil && "SendButtonReleaseEvent, parameter 'view' is nil");
695  assert(theEvent != nil && "SendButtonReleaseEvent, parameter 'event' is nil");
696  assert(view.fID != 0 && "SendButtonReleaseEvent, view.fID is 0");
697 
698  TGWindow * const window = gClient->GetWindowById(view.fID);
699  if (!window) {
700 #ifdef DEBUG_ROOT_COCOA
701  NSLog(@"SendButtonReleaseEvent, ROOT's widget %u was not found", view.fID);
702 #endif
703  return;
704  }
705 
706  Event_t releaseEvent = NewX11EventFromCocoaEvent(view.fID, theEvent);
707  releaseEvent.fType = kButtonRelease;
708  releaseEvent.fCode = btn;
709  releaseEvent.fState = GetKeyboardModifiersFromCocoaEvent(theEvent);
710  //
711  ConvertEventLocationToROOTXY(theEvent, view, &releaseEvent);
712  //Enqueue for ROOT.
713  queue.push_back(releaseEvent);
714 }
715 
716 //______________________________________________________________________________
717 void SendKeyPressEvent(EventQueue_t &queue, NSView<X11Window> *view, NSView<X11Window> *childView,
718  NSEvent *theEvent, NSPoint windowPoint)
719 {
720  assert(view != nil && "SendKeyPressEvent, parameter 'view' is nil");
721  assert(theEvent != nil && "SendKeyPressEvent, parameter 'event' is nil");
722  assert(view.fID != 0 && "SendKeyPressEvent, view.fID is 0");
723 
724  TGWindow * const window = gClient->GetWindowById(view.fID);
725  if (!window) {
726 #ifdef DEBUG_ROOT_COCOA
727  NSLog(@"SendKeyPressEvent, ROOT's widget %u was not found", view.fID);
728 #endif
729  return;
730  }
731 
732  Event_t keyPressEvent = NewX11EventFromCocoaEvent(view.fID, theEvent);
733  keyPressEvent.fType = kGKeyPress;
734  keyPressEvent.fState = GetKeyboardModifiersFromCocoaEvent(theEvent);
735 
736  NSString * const characters = [theEvent charactersIgnoringModifiers];
737  assert(characters != nil && "SendKeyPressEvent, [theEvent characters] returned nil");
738  assert([characters length] > 0 && "SendKeyPressEvent, characters is an empty string");
739 
740  keyPressEvent.fCode = [characters characterAtIndex : 0];
741 
742  //convertPointFromBase is deprecated.
743  //const NSPoint viewPoint = [view convertPointFromBase : windowPoint];
744  const NSPoint viewPoint = [view convertPoint : windowPoint fromView : nil];
745 
746  //Coords.
747  keyPressEvent.fX = viewPoint.x;
748  keyPressEvent.fY = viewPoint.y;
749  const NSPoint screenPoint = TranslateToScreen(view, viewPoint);
750  keyPressEvent.fXRoot = screenPoint.x;
751  keyPressEvent.fYRoot = screenPoint.y;
752  //Subwindow.
753  if (childView)
754  keyPressEvent.fUser[0] = childView.fID;
755 
756  //Enqueue for ROOT.
757  queue.push_back(keyPressEvent);
758 }
759 
760 //______________________________________________________________________________
761 void SendKeyReleaseEvent(EventQueue_t &queue, NSView<X11Window> *view, NSView<X11Window> *childView,
762  NSEvent *theEvent, NSPoint windowPoint)
763 {
764  assert(view != nil && "SendKeyReleaseEvent, parameter 'view' is nil");
765  assert(theEvent != nil && "SendKeyReleaseEvent, parameter 'event' is nil");
766  assert(view.fID != 0 && "SendKeyReleaseEvent, view.fID is 0");
767 
768  TGWindow * const window = gClient->GetWindowById(view.fID);
769  if (!window) {
770 #ifdef DEBUG_ROOT_COCOA
771  NSLog(@"SendKeyPressEvent, ROOT's widget %u was not found", view.fID);
772 #endif
773  return;
774  }
775 
776  Event_t keyReleaseEvent = NewX11EventFromCocoaEvent(view.fID, theEvent);
777  keyReleaseEvent.fType = kKeyRelease;
778 
779  keyReleaseEvent.fState = GetKeyboardModifiersFromCocoaEvent(theEvent);
780 
781  NSString * const characters = [theEvent charactersIgnoringModifiers];
782  assert(characters != nil && "SendKeyReleaseEvent, [theEvent characters] returned nil");
783  assert([characters length] > 0 && "SendKeyReleaseEvent, characters is an empty string");
784  keyReleaseEvent.fCode = [characters characterAtIndex : 0];
785 
786  //Coords.
787  const NSPoint viewPoint = [view convertPoint : windowPoint fromView : nil];
788  keyReleaseEvent.fX = viewPoint.x;
789  keyReleaseEvent.fY = viewPoint.y;
790  const NSPoint screenPoint = TranslateToScreen(view, viewPoint);
791 
792  keyReleaseEvent.fXRoot = screenPoint.x;
793  keyReleaseEvent.fYRoot = screenPoint.y;
794 
795  //Subwindow.
796  if (childView)
797  keyReleaseEvent.fUser[0] = childView.fID;
798 
799  //Enqueue for ROOT.
800  queue.push_back(keyReleaseEvent);
801 }
802 
803 
804 //______________________________________________________________________________
805 void SendFocusInEvent(EventQueue_t &queue, NSView<X11Window> *view, EXMagic mode)
806 {
807  assert(view != nil && "SendFocusInEvent, parameter 'view' is nil");
808  //
809  TGWindow * const window = gClient->GetWindowById(view.fID);
810  if (!window) {
811 #ifdef DEBUG_ROOT_COCOA
812  NSLog(@"SendFocusInEvent, ROOT's widget %u was not found", view.fID);
813 #endif
814  return;
815  }
816 
817  Event_t focusInEvent = {};
818  focusInEvent.fWindow = view.fID;
819  focusInEvent.fType = kFocusIn;
820  focusInEvent.fCode = mode;
821 
822  queue.push_back(focusInEvent);
823 }
824 
825 //______________________________________________________________________________
826 void SendFocusOutEvent(EventQueue_t &queue, NSView<X11Window> *view, EXMagic mode)
827 {
828  assert(view != nil && "SendFocusOutEvent, parameter 'view' is nil");
829  //
830  TGWindow * const window = gClient->GetWindowById(view.fID);
831  if (!window) {
832 #ifdef DEBUG_ROOT_COCOA
833  NSLog(@"SendFocusOutEvent, ROOT's widget %u was not found", view.fID);
834 #endif
835  return;
836  }
837 
838  Event_t focusOutEvent = {};
839  focusOutEvent.fWindow = view.fID;
840  focusOutEvent.fType = kFocusOut;
841  focusOutEvent.fCode = mode;//code mode :)
842 
843  queue.push_back(focusOutEvent);
844 }
845 
846 #pragma mark - Aux. functions to send events to view's branch.
847 
848 //______________________________________________________________________________
849 void SendEnterEventRange(EventQueue_t &queue, NSView<X11Window> *from, NSView<X11Window> *to,
850  NSEvent *theEvent, EXMagic mode)
851 {
852  //[from, to) - legal range, 'to' must be ancestor for 'from'.
853  assert(from != nil && "SendEnterEventRange, 'from' parameter is nil");
854  assert(to != nil && "SendEnterEventRange, 'to' parameter is nil");
855  assert(theEvent != nil && "SendEnterEventRange, event parameter is nil");
856 
857  while (from != to) {
858  if ([from acceptsCrossingEvents : kEnterWindowMask])
859  SendEnterEvent(queue, from, theEvent, mode);
860  from = from.fParentView;
861  }
862 }
863 
864 //______________________________________________________________________________
865 void SendEnterEventClosedRange(EventQueue_t &queue, NSView<X11Window> *from, NSView<X11Window> *to,
866  NSEvent *theEvent, EXMagic mode)
867 {
868  //[from, to] - inclusive, legal range, 'to' must be ancestor for 'from'.
869  assert(from != nil && "SendEnterEventClosedRange, 'from' parameter is nil");
870  assert(to != nil && "SendEnterEventClosedRange, 'to' parameter is nil");
871  assert(theEvent != nil && "SendEnterEventClosedRange, event parameter is nil");
872 
873  SendEnterEventRange(queue, from, to, theEvent, mode);
874  if ([to acceptsCrossingEvents : kEnterWindowMask])
875  SendEnterEvent(queue, to, theEvent, mode);
876 }
877 
878 //______________________________________________________________________________
879 void SendLeaveEventRange(EventQueue_t &queue, NSView<X11Window> *from, NSView<X11Window> *to,
880  NSEvent *theEvent, EXMagic mode)
881 {
882  //[from, to) - legal range, 'to' must be ancestor for 'from'.
883  assert(from != nil && "SendLeaveEventRange, 'from' parameter is nil");
884  assert(to != nil && "SendLeaveEventRange, 'to' parameter is nil");
885  assert(theEvent != nil && "SendLeaveEventRange, event parameter is nil");
886 
887  while (from != to) {
888  if ([from acceptsCrossingEvents : kLeaveWindowMask])
889  SendLeaveEvent(queue, from, theEvent, mode);
890  from = from.fParentView;
891  }
892 }
893 
894 //______________________________________________________________________________
895 void SendLeaveEventClosedRange(EventQueue_t &queue, NSView<X11Window> *from, NSView<X11Window> *to,
896  NSEvent *theEvent, EXMagic mode)
897 {
898  //[from, to] - inclusive, legal range, 'to' must be ancestor for 'from'.
899  assert(from != nil && "SendLeaveEventClosedRange, 'from' parameter is nil");
900  assert(to != nil && "SendLeaveEventClosedRange, 'to' parameter is nil");
901  assert(theEvent != nil && "SendLeaveEventClosedRange, event parameter is nil");
902 
903  SendLeaveEventRange(queue, from, to, theEvent, mode);
904  if ([to acceptsCrossingEvents : kLeaveWindowMask])
905  SendLeaveEvent(queue, to, theEvent, mode);
906 }
907 
908 #pragma mark - Top-level crossing event generators.
909 
910 //When passing parent and child view, parent view always
911 //precedes the child, even if function's name is GenerateCrossingEventChildToParent.
912 
913 //______________________________________________________________________________
914 void GenerateCrossingEventChildToParent(EventQueue_t &queue, NSView<X11Window> *parent, NSView<X11Window> *child,
915  NSEvent *theEvent, EXMagic detail)
916 {
917  //Pointer moves from window A to window B and A is an inferior of B.
918  //Generate LeaveNotify on A (with detail NotifyAncestor).
919  //Generate LeaveNotify for every window between A and B, exclusive (with detail NotifyVirtual)
920  //Generate EnterNotify for B with detail NotifyInferior.
921 
922  //ROOT does not have NotifyAncestor/NotifyInferior.
923 
924  assert(parent != nil && "GenerateCrossingEventChildToParent, parameter 'parent' is nil");
925  assert(child != nil && "GenerateCrossingEventChildToParent, parameter 'child' is nil");
926  assert(theEvent != nil && "GenerateCrossingEventChildToParent, parameter 'event' is nil");
927  assert(child.fParentView != nil &&
928  "GenerateCrossingEventChildToParent, parameter 'child' must have QuartzView* parent");
929 
930  //acceptsCrossingEvents will check grab event mask also, if view is a grab and if
931  //owner_events == true.
932  if ([child acceptsCrossingEvents : kLeaveWindowMask])
933  SendLeaveEvent(queue, child, theEvent, detail);
934 
935  //Leave event to a branch [child.fParentView, parent)
936  SendLeaveEventRange(queue, child.fParentView, parent, theEvent, detail);
937 
938  //Enter event for the parent view.
939  if ([parent acceptsCrossingEvents : kEnterWindowMask])
940  SendEnterEvent(queue, parent, theEvent, detail);
941 }
942 
943 //______________________________________________________________________________
944 void GenerateCrossingEventParentToChild(EventQueue_t &queue, NSView<X11Window> *parent, NSView<X11Window> *child,
945  NSEvent *theEvent, EXMagic detail)
946 {
947  //Pointer moves from window A to window B and B is an inferior of A.
948  //Generate LeaveNotify event for A, detail == NotifyInferior.
949  //Generate EnterNotify for each window between window A and window B, exclusive,
950  // detail == NotifyVirtual (no such entity in ROOT).
951  //Generate EnterNotify on window B, detail == NotifyAncestor.
952 
953  //ROOT does not have NotifyInferior/NotifyAncestor.
954 
955  assert(parent != nil && "GenerateCrossingEventParentToChild, parameter 'parent' is nil");
956  assert(child != nil && "GenerateCrossingEventParentToChild, parameter 'child' is nil");
957  assert(theEvent != nil && "GenerateCrossingEventParentToChild, parameter 'event' is nil");
958  assert(child.fParentView != nil &&
959  "GenerateCrossingEventParentToChild, parameter 'child' must have QuartzView* parent");
960 
961  //If view is a grab and owner_events == true,
962  //acceptsCrossingEvents will check the grab event mask also.
963  if ([parent acceptsCrossingEvents : kLeaveWindowMask])
964  SendLeaveEvent(queue, parent, theEvent, detail);
965 
966  //Enter event for [child.fParentView, parent) - order is reversed, but it does not really matter.
967  SendEnterEventRange(queue, child.fParentView, parent, theEvent, detail);
968 
969  //Enter event for the child view.
970  if ([child acceptsCrossingEvents : kEnterWindowMask])
971  SendEnterEvent(queue, child, theEvent, detail);
972 }
973 
974 //______________________________________________________________________________
975 void GenerateCrossingEventFromChild1ToChild2(EventQueue_t &queue, NSView<X11Window> *child1, NSView<X11Window> *child2,
976  NSView<X11Window> *ancestor, NSEvent *theEvent, EXMagic detail)
977 {
978  //Pointer moves from window A to window B and window C is their lowest common ancestor.
979  //Generate LeaveNotify for window A with detail == NotifyNonlinear.
980  //Generate LeaveNotify for each window between A and C, exclusive, with detail == NotifyNonlinearVirtual
981  //Generate EnterNotify (detail == NotifyNonlinearVirtual) for each window between C and B, exclusive
982  //Generate EnterNotify for window B, with detail == NotifyNonlinear.
983 
984  assert(child1 != nil && "GenerateCrossingEventFromChild1ToChild2, parameter 'child1' is nil");
985  assert(child2 != nil && "GenerateCrossingEventFromChild1ToChild2, child2 parameter is nil");
986  assert(theEvent != nil && "GenerateCrossingEventFromChild1ToChild2, theEvent parameter is nil");
987 
988  //ROOT does not have NotifyNonlinear/NotifyNonlinearVirtual.
989 
990  //acceptsCrossingEvents also checks grab event mask, if this view has a grab
991  //and owner_events == true.
992  if ([child1 acceptsCrossingEvents : kLeaveWindowMask])
993  SendLeaveEvent(queue, child1, theEvent, detail);
994 
995  if (!ancestor) {
996  if (child1.fParentView)//Leave [child1.fParentView contentView]
997  SendLeaveEventClosedRange(queue, child1.fParentView,
998  (NSView<X11Window> *)[[child1 window] contentView], theEvent, detail);
999  if (child2.fParentView)//Enter [child2.fParentView contentView] - order is reversed.
1000  SendEnterEventClosedRange(queue, child2.fParentView,
1001  (NSView<X11Window> *)[[child2 window] contentView], theEvent, detail);
1002  } else {
1003  if (child1.fParentView)//Leave [child1.fParentView ancestor)
1004  SendLeaveEventRange(queue, child1.fParentView, ancestor, theEvent, detail);
1005  if (child2.fParentView)//Enter [child2.fParentView, ancestor) - order reversed.
1006  SendEnterEventRange(queue, child2.fParentView, ancestor, theEvent, detail);
1007  }
1008 
1009  if ([child2 acceptsCrossingEvents : kEnterWindowMask])
1010  SendEnterEvent(queue, child2, theEvent, detail);
1011 }
1012 
1013 
1014 //______________________________________________________________________________
1015 void GenerateCrossingEvents(EventQueue_t &queue, NSView<X11Window> *fromView, NSView<X11Window> *toView,
1016  NSEvent *theEvent, EXMagic detail)
1017 {
1018  //Pointer moved from 'fromView' to 'toView'.
1019  //Check their relationship and generate leave/enter notify events.
1020 
1021  assert(theEvent != nil && "GenerateCrossingEvent, event parameter is nil");
1022 
1023  if (fromView == toView) {
1024  //This can happen: tracking areas for stacked windows call
1025  //mouseExited even for overlapped views (so you have a bunch of mouseExited/mouseEntered
1026  //for one cursor move). In mouseEntered/mouseExited
1027  //I'm looking for the top level view under cursor and try to generate cross event
1028  //for this view only.
1029  return;
1030  }
1031 
1032  if (!fromView) {
1033  //We enter window "from the screen" - do not leave any window.
1034  //Send EnterNotify event.
1035  //Send enter notify event to a branch [toView contentView], order of
1036  //views is reversed, but no GUI actually depends on this.
1037  if (toView)
1038  SendEnterEventClosedRange(queue, toView, (NSView<X11Window> *)[[toView window] contentView],
1039  theEvent, detail);
1040  } else if (!toView) {
1041  //We exit all views. Order is correct here.
1042  SendLeaveEventClosedRange(queue, fromView, (NSView<X11Window> *)[[fromView window] contentView],
1043  theEvent, detail);
1044  } else {
1045  NSView<X11Window> *ancestor = 0;
1046  const Ancestry rel = FindRelation(fromView, toView, &ancestor);
1047  if (rel == kAView1IsParent) {
1048  //Case 1.
1049  //From A to B.
1050  //_________________
1051  //| A |
1052  //| |---------| |
1053  //| | B | |
1054  //| | | |
1055  //| |---------| |
1056  //| |
1057  //|________________|
1058  GenerateCrossingEventParentToChild(queue, fromView, toView, theEvent, detail);
1059  } else if (rel == kAView2IsParent) {
1060  //Case 2.
1061  //From A to B.
1062  //_________________
1063  //| B |
1064  //| |---------| |
1065  //| | A | |
1066  //| | | |
1067  //| |---------| |
1068  //| |
1069  //|________________|
1070  GenerateCrossingEventChildToParent(queue, toView, fromView, theEvent, detail);
1071  } else {
1072  //Case 3.
1073  //|--------------------------------|
1074  //| C |------| |-------| |
1075  //| | A | | B | |
1076  //| |______| |_______| |
1077  //|________________________________|
1078  //Ancestor is either some view, or 'root' window.
1079  //The fourth case (different screens) is not implemented (and I do not know, if I want to implement it).
1080  GenerateCrossingEventFromChild1ToChild2(queue, fromView, toView, ancestor, theEvent, detail);
1081  }
1082  }
1083 }
1084 
1085 //______________________________________________________________________________
1086 void GenerateCrossingEventForGrabView(EventQueue_t &queue, NSView<X11Window> *fromView, NSView<X11Window> *toView,
1087  NSView<X11Window> *grabView, Mask_t grabEventMask, NSEvent *theEvent)
1088 {
1089  //When owner events == false, only grab view receives enter/leave notify events.
1090 
1091  //Send enter/leave event to a grab view.
1092  assert(theEvent != nil && "GenerateCrossingEventForGrabView, parameter 'event' is nil");
1093  assert(grabView != nil && "GenerateCrossingEventForGrabView, parameter 'grabView' is nil");
1094  assert((fromView != nil || toView != nil) &&
1095  "GenerateCrossingEventForGrabView, both 'toView' and 'fromView' parameters are nil");
1096 
1097  if (fromView == toView)//No crossing at all?
1098  return;
1099 
1100  const bool wantsEnter = grabEventMask & kEnterWindowMask;
1101  const bool wantsLeave = grabEventMask & kLeaveWindowMask;
1102 
1103  if (fromView == grabView && wantsLeave)
1104  return SendLeaveEvent(queue, grabView, theEvent, kNotifyNormal);
1105 
1106  if (toView == grabView && wantsEnter)
1107  return SendEnterEvent(queue, grabView, theEvent, kNotifyNormal);
1108 
1109  if (!fromView) {
1110  //We enter window "from the screen" - do not leave any window.
1111  //Send EnterNotify event to the grab view, if it's "in the branch".
1112  if (wantsEnter && IsParent(grabView, toView))
1113  SendEnterEvent(queue, grabView, theEvent, kNotifyNormal);
1114  } else if (!toView) {
1115  //We exit all views..
1116  if (wantsLeave && IsParent(grabView, fromView))
1117  SendLeaveEvent(queue, grabView, theEvent, kNotifyNormal);
1118  } else {
1119  NSView<X11Window> *ancestor = 0;
1120  FindRelation(fromView, toView, &ancestor);
1121 
1122  if (IsInBranch(nil, fromView, grabView)) {
1123  if (wantsLeave)
1124  SendLeaveEvent(queue, grabView, theEvent, kNotifyNormal);
1125  } else if (IsInBranch(nil, toView, grabView)) {
1126  if (wantsEnter)
1127  SendEnterEvent(queue, grabView, theEvent, kNotifyNormal);
1128  }
1129  }
1130 }
1131 
1132 }//Detail
1133 
1134 //______________________________________________________________________________
1135 EventTranslator::EventTranslator()
1136  : fViewUnderPointer(nil),
1137  fPointerGrabType(kPGNoGrab),
1138  fGrabEventMask(0),
1139  fOwnerEvents(true),
1140  fButtonGrabView(nil),
1141  fKeyGrabView(nil),
1142  fFocusView(nil),
1143  fImplicitGrabButton(kAnyButton)
1144 
1145 {
1146 }
1147 
1148 //______________________________________________________________________________
1149 void EventTranslator::GenerateConfigureNotifyEvent(NSView<X11Window> *view, const NSRect &newFrame)
1150 {
1151  assert(view != nil && "GenerateConfigureNotifyEvent, parameter 'view' is nil");
1152 
1153  Event_t newEvent = {};
1154  newEvent.fWindow = view.fID;
1155  newEvent.fType = kConfigureNotify;
1156 
1157  newEvent.fX = newFrame.origin.x;
1158  newEvent.fY = newFrame.origin.y;
1159 
1160  newEvent.fWidth = newFrame.size.width;
1161  newEvent.fHeight = newFrame.size.height;
1162 
1163  TGWindow * const window = gClient->GetWindowById(view.fID);
1164  if (window) window->HandleEvent(&newEvent);
1165 }
1166 
1167 //______________________________________________________________________________
1168 void EventTranslator::GenerateDestroyNotify(unsigned /*winID*/)
1169 {
1170  //Noop.
1171 }
1172 
1173 //______________________________________________________________________________
1174 void EventTranslator::GenerateExposeEvent(NSView<X11Window> *view, const NSRect &exposedRect)
1175 {
1176  assert(view != nil && "GenerateExposeEvent, parameter 'view' is nil");
1177 
1178  Event_t exposeEvent = {};
1179  exposeEvent.fWindow = view.fID;
1180  exposeEvent.fType = kExpose;
1181  exposeEvent.fX = exposedRect.origin.x;
1182  exposeEvent.fY = exposedRect.origin.y;
1183  exposeEvent.fWidth = exposedRect.size.width;
1184  exposeEvent.fHeight = exposedRect.size.height;
1185 
1186  TGWindow * const window = gClient->GetWindowById(view.fID);
1187  assert(window != 0 && "GenerateExposeEvent, window was not found");
1188  window->HandleEvent(&exposeEvent);
1189 }
1190 
1191 //______________________________________________________________________________
1193 {
1194  //View parameter can be nil.
1195  assert(theEvent != nil && "GenerateCrossingEvent, parameter 'event' is nil");
1196 
1199 }
1200 
1201 //______________________________________________________________________________
1203 {
1204  assert(theEvent && "GenerateCrossingEventNoGrab, parameter 'theEvent' is nil");
1205 
1206  NSView<X11Window> * const candidateView = FindViewForPointerEvent(theEvent);
1207  //We moved from fViewUnderPointer (leave event) to candidateView (enter event).
1209  fViewUnderPointer = candidateView;
1210 }
1211 
1212 //______________________________________________________________________________
1214 {
1215  assert(theEvent != nil && "GenerateCrossingEventActiveGrab, parameter 'theEvent' is nil");
1216 
1217  NSView<X11Window> * const candidateView = FindViewForPointerEvent(theEvent);
1218 
1219  if (fOwnerEvents) {
1220  //Either passive grab (which was activated) or active grab set by TGCocoa::GrabPointer with
1221  //owner_events == true. This works the same way as nograb case, except not only fEventMask
1222  //is checked, but for grab view (if it's boundary was crossed) either it's passive grab mask
1223  //or active is also checked.
1225  theEvent, kNotifyNormal);
1226  } else if (fButtonGrabView && (fViewUnderPointer || candidateView)) {
1227  //Either implicit grab or GrabPointer with owner_events == false,
1228  //only grab view can receive enter/leave notify events. Only
1229  //grab event mask is checked, not view's own event mask.
1231  fButtonGrabView, fGrabEventMask, theEvent);
1232  }
1233 
1234  fViewUnderPointer = candidateView;
1235 }
1236 
1237 //______________________________________________________________________________
1239 {
1240  return fPointerGrabType != kPGNoGrab;
1241 }
1242 
1243 //______________________________________________________________________________
1245 {
1246  assert(theEvent != nil && "GeneratePointerMotionEvent, parameter 'theEvent' is nil");
1247 
1248 
1249 
1250  if (fPointerGrabType == kPGNoGrab)
1251  return GeneratePointerMotionEventNoGrab(theEvent);
1252  else
1253  return GeneratePointerMotionEventActiveGrab(theEvent);
1254 }
1255 
1256 //______________________________________________________________________________
1257 void EventTranslator::GenerateButtonPressEvent(NSView<X11Window> *eventView, NSEvent *theEvent,
1258  EMouseButton btn)
1259 {
1260  assert(eventView != nil && "GenerateButtonPressEvent, parameter 'eventView' is nil");
1261  assert(theEvent != nil && "GenerateButtonpressEvent, parameter 'theEvent' is nil");
1262 
1263  if (fPointerGrabType == kPGNoGrab)
1264  return GenerateButtonPressEventNoGrab(eventView, theEvent, btn);
1265  else
1266  return GenerateButtonPressEventActiveGrab(eventView, theEvent, btn);
1267 }
1268 
1269 //______________________________________________________________________________
1270 void EventTranslator::GenerateButtonReleaseEvent(NSView<X11Window> *eventView, NSEvent *theEvent,
1271  EMouseButton btn)
1272 {
1273  assert(eventView != nil && "GenerateButtonReleaseEvent, parameter 'eventView' is nil");
1274  assert(theEvent != nil && "GenerateButtonReleaseEvent, parameter 'theEvent' is nil");
1275 
1276  if (fPointerGrabType == kPGNoGrab)
1277  return GenerateButtonReleaseEventNoGrab(eventView, theEvent, btn);
1278  else
1279  return GenerateButtonReleaseEventActiveGrab(eventView, theEvent, btn);
1280 
1281 
1282 }
1283 
1284 //______________________________________________________________________________
1285 void EventTranslator::GenerateKeyPressEvent(NSView<X11Window> *eventView, NSEvent *theEvent)
1286 {
1287  assert(eventView != nil && "GenerateKeyPressEvent, parameter 'eventView' is nil");
1288  assert(theEvent != nil && "GenerateKeyPressEvent, parameter 'theEvent' is nil");
1289 
1290  if (![[theEvent charactersIgnoringModifiers] length])
1291  return;
1292 
1293  if (!fFocusView)
1294  return;
1295 
1296  !fKeyGrabView ? GenerateKeyPressEventNoGrab(eventView, theEvent) :
1297  GenerateKeyEventActiveGrab(eventView, theEvent);
1298 }
1299 
1300 //______________________________________________________________________________
1301 void EventTranslator::GenerateKeyReleaseEvent(NSView<X11Window> *eventView, NSEvent *theEvent)
1302 {
1303  assert(eventView != nil && "GenerateKeyReleaseEvent, parameter 'eventView' is nil");
1304  assert(theEvent != nil && "GenerateKeyReleaseEvent, parameter 'theEvent' is nil");
1305 
1306  if (![[theEvent charactersIgnoringModifiers] length])
1307  return;
1308 
1309  if (!fFocusView)
1310  return;
1311 
1312  !fKeyGrabView ? GenerateKeyReleaseEventNoGrab(eventView, theEvent) :
1313  //GenerateKeyEventActiveGrab(eventView, theEvent);
1315 
1316  //Oh, only God forgives.
1317  fKeyGrabView = nil;
1318 }
1319 
1320 //______________________________________________________________________________
1321 void EventTranslator::GenerateFocusChangeEvent(NSView<X11Window> *eventView)
1322 {
1323  if (eventView == fFocusView)
1324  return;
1325 
1326  if (fFocusView && (fFocusView.fEventMask & kFocusChangeMask))
1328 
1329  if (eventView) {
1330  if (eventView.fEventMask & kFocusChangeMask)
1332 
1333  fFocusView = eventView;
1334  } else
1335  fFocusView = nil;
1336 }
1337 
1338 //______________________________________________________________________________
1339 void EventTranslator::SetPointerGrab(NSView<X11Window> *grabView, unsigned eventMask, bool ownerEvents)
1340 {
1341  assert(grabView != nil && "SetPointerGrab, parameter 'grabView' is nil");
1342 
1343  if (fButtonGrabView) {
1344  //This can happen with X11, does this happen with ROOT's GUI?
1345  //Hm, should I send leave notify to the previous grab???
1346  [fButtonGrabView cancelGrab];
1347  }
1348 
1349  //There is no kNoButton, unfortunately (but there is additional check on
1350  //grab type).
1352 
1353  //
1354  fButtonGrabView = grabView;
1356  fGrabEventMask = eventMask;
1357  fOwnerEvents = ownerEvents;
1358 
1359  //Generate sequence of crossing events - as if pointer
1360  //"jumps" to the grab view.
1361 
1362  if (grabView != fViewUnderPointer) {
1363  const NSPoint location = [[grabView window] mouseLocationOutsideOfEventStream];
1364  const Util::NSScopeGuard<FakeCrossingEvent> event([[FakeCrossingEvent alloc] initWithWindow : [grabView window]
1365  location : location]);
1366  if (!event.Get()) {
1367  //Hehe, if this happend, is it still possible to log????
1368  NSLog(@"EventTranslator::SetPointerGrab, crossing event initialization failed");
1369  return;
1370  }
1371 
1372  Detail::GenerateCrossingEvents(fEventQueue, fViewUnderPointer, grabView, event.Get(), kNotifyGrab);//Uffffff, done!
1373  }
1374 
1375  //Activate the current grab now.
1376  [fButtonGrabView activateGrab : eventMask ownerEvents : fOwnerEvents];
1377 }
1378 
1379 //______________________________________________________________________________
1381 {
1382  if (fButtonGrabView)
1383  //Cancel grab (active, passive, implicit).
1384  [fButtonGrabView cancelGrab];
1385 
1386  //We generate sequence of leave/enter notify events (if any) as if we jumped from the grab view to the pointer view.
1387 
1388  if (NSView<X11Window> * const candidateView = FindViewUnderPointer()) {
1389  const NSPoint location = [[candidateView window] mouseLocationOutsideOfEventStream];
1390  const Util::NSScopeGuard<FakeCrossingEvent> event([[FakeCrossingEvent alloc] initWithWindow : [candidateView window]
1391  location : location ]);
1392 
1393  if (!event.Get()) {
1394  //Hehe, if this happend, is it still possible to log????
1395  NSLog(@"EventTranslator::CancelPointerGrab, crossing event initialization failed");
1396  return;
1397  }
1398 
1400  //
1401  fViewUnderPointer = candidateView;
1402  } else if (fButtonGrabView) {
1403  //convertScreenToBase is deprecated.
1404  //const NSPoint location = [[fButtonGrabView window] convertScreenToBase : [NSEvent mouseLocation]];
1405  const NSPoint location = ConvertPointFromScreenToBase([NSEvent mouseLocation], [fButtonGrabView window]);
1406 
1407  const Util::NSScopeGuard<FakeCrossingEvent> event([[FakeCrossingEvent alloc] initWithWindow : [fButtonGrabView window]
1408  location : location ]);
1409 
1410  if (!event.Get()) {
1411  //Hehe, if this happend, is it still possible to log????
1412  NSLog(@"EventTranslator::CancelPointerGrab, crossing event initialization failed");
1413  fViewUnderPointer = nil;
1414  return;
1415  }
1416 
1418  //
1419  fViewUnderPointer = nil;
1420  }
1421 
1422 
1424  fButtonGrabView = nil;
1426  fGrabEventMask = 0;
1427  fOwnerEvents = true;
1428 }
1429 
1430 //______________________________________________________________________________
1431 void EventTranslator::SetInputFocus(NSView<X11Window> *newFocusView)
1432 {
1433  if (fFocusView && (fFocusView.fEventMask & kFocusChangeMask))
1435 
1436  if (newFocusView) {
1437  if (newFocusView.fEventMask & kFocusChangeMask)
1439 
1440  fFocusView = newFocusView;
1441  } else
1442  fFocusView = nil;
1443 
1444 }
1445 
1446 //______________________________________________________________________________
1448 {
1449  if (fFocusView)
1450  return fFocusView.fID;
1451 
1452  return 0;
1453 }
1454 
1455 namespace {
1456 
1457 //______________________________________________________________________________
1458 void ClearPointerIfViewIsRelated(NSView<X11Window> *&view, Window_t winID)
1459 {
1460  NSView<X11Window> *v = view;
1461  if (v) {
1462  for (; v; v = v.fParentView) {
1463  if (v.fID == winID) {
1464  view = nil;
1465  break;
1466  }
1467  }
1468  }
1469 }
1470 
1471 }//unnamed namespace.
1472 
1473 //______________________________________________________________________________
1475 {
1476  //Window was unmapped, check, if it's the same window as the current grab,
1477  //or focus window, or key grabbing window and if so - do cleanup.
1478 
1479  if (fButtonGrabView) {
1480  for (NSView<X11Window> *view = fButtonGrabView; view; view = view.fParentView) {
1481  if (view.fID == winID) {
1483  break;
1484  }
1485  }
1486  }
1487 
1488  if (fViewUnderPointer) {
1489  for (NSView<X11Window> *view = fViewUnderPointer; view; view = view.fParentView) {
1490  if (view.fID == winID) {
1491  NSPoint location = {};
1492  location.x = fViewUnderPointer.fWidth / 2;
1493  location.y = fViewUnderPointer.fHeight / 2;
1494  location = [fViewUnderPointer convertPoint : location toView : nil];
1495 
1496  const Util::NSScopeGuard<FakeCrossingEvent> event([[FakeCrossingEvent alloc]
1497  initWithWindow : [fViewUnderPointer window]
1498  location : location]);
1499  if (!event.Get()) {
1500  //Hehe, if this happend, is it still possible to log????
1501  NSLog(@"EventTranslator::CheckUnmappedView, crossing event initialization failed");
1502  return;
1503  }
1504 
1506  fViewUnderPointer = nil;
1507 
1508  break;
1509  }
1510  }
1511  }
1512 
1513  ClearPointerIfViewIsRelated(fFocusView, winID);
1514  ClearPointerIfViewIsRelated(fKeyGrabView, winID);
1515 }
1516 
1517 //______________________________________________________________________________
1519 {
1520  //Without grab, things are simple: find a view which accepts pointer motion event.
1521  assert(theEvent != nil && "GeneratePointerMotionEventNoGrab, parameter 'theEvent' is nil");
1522 
1523  const Mask_t maskToTest = [NSEvent pressedMouseButtons] ?
1526 
1527  //Event without any emulated grab, receiver view can be "wrong" (result of Cocoa's "dragging").
1528  if (NSView<X11Window> *candidateView = FindViewForPointerEvent(theEvent)) {
1529  //Do propagation.
1530  candidateView = Detail::FindViewToPropagateEvent(candidateView, maskToTest);
1531  if (candidateView)//We have such a view, send event to a corresponding ROOT's window.
1532  Detail::SendPointerMotionEvent(fEventQueue, candidateView, theEvent);
1533  }
1534 }
1535 
1536 //______________________________________________________________________________
1538 {
1539  //More complex case. Grab can be result of button press and set by SetPointerGrab.
1540  //In case of button press (this is either passive->active or implicit grab),
1541  //Cocoa has it's own grab, so view (and window) can be not under cursor (but still
1542  //it receives events). So I can not simple use eventView here.
1543 
1544  if (!fButtonGrabView)//Implicit grab when nobody has PressButtonMask
1545  return;
1546 
1547  //assert(eventView != nil && "GeneratePointerMotionEventActiveGrab, view parameter is nil");
1548  assert(theEvent != nil && "GeneratePointerMotionEventActiveGrab, parameter 'theEvent' is nil");
1549 
1550  const Mask_t maskToTest = [NSEvent pressedMouseButtons] ?
1553 
1554  if (fOwnerEvents) {
1555  //Complex case, we have to correctly report event.
1556  if (NSView<X11Window> *candidateView = FindViewForPointerEvent(theEvent)) {
1557  candidateView = Detail::FindViewToPropagateEvent(candidateView, maskToTest,
1559  if (candidateView)//We have such a view, send event to a corresponding ROOT's window.
1560  Detail::SendPointerMotionEvent(fEventQueue, candidateView, theEvent);
1561  } else {
1562  //No such window - dispatch to the grab view.
1563  //Else: either implicit grab, or user requested grab with owner_grab == False.
1564  if (fGrabEventMask & maskToTest)
1566  }
1567  } else {
1568  //Else: either implicit grab, or user requested grab with owner_grab == False.
1569  if (fGrabEventMask & maskToTest)
1571  }
1572 }
1573 
1574 //______________________________________________________________________________
1575 void EventTranslator::GenerateButtonPressEventNoGrab(NSView<X11Window> *view, NSEvent *theEvent,
1576  EMouseButton btn)
1577 {
1578  //Generate button press event when no pointer grab is active:
1579  //either find a window with a passive grab, or create an implicit
1580  //grab (to emulate X11's behavior).
1581 
1582  assert(view != nil && "GenerateButtonPressEventNoGrab, parameter 'view' is nil");
1583  assert(theEvent != nil && "GenerateButtonPressEventNoGrab, parameter 'theEvent' is nil");
1584 
1585  FindButtonGrab(view, theEvent, btn);
1586 
1587  fImplicitGrabButton = btn;//This info is useless for any grab type except the implicit one.
1588 
1589  //Now we have to generate a sequence of enter/leave notify events,
1590  //like we "jump" from the previous view under the pointer to a grab view.
1591 
1593 
1594  //"Activate" a grab now, depending on type.
1595  if (fButtonGrabView) {
1597  [fButtonGrabView activatePassiveGrab];
1598  else if (fPointerGrabType == kPGImplicitGrab)
1599  [fButtonGrabView activateImplicitGrab];
1600  }
1601 
1602  //Send press event to a grab view (either passive grab or implicit,
1603  //but it has the required event bitmask).
1604  if (fButtonGrabView)
1606 }
1607 
1608 //______________________________________________________________________________
1609 void EventTranslator::GenerateButtonPressEventActiveGrab(NSView<X11Window> * /*view*/, NSEvent *theEvent,
1610  EMouseButton btn)
1611 {
1612  //Generate button press event in the presence of activated pointer grab.
1613 
1614  //assert(view != nil && "GenerateButtonPressEventActiveGrab, view parameter is nil");
1615  assert(theEvent != nil && "GenerateButtonPressEventActiveGrab, parameter 'theEvent' is nil");
1616 
1617  //I did not find in X11 spec. the case when I have two passive grabs on window A and window B,
1618  //say left button on A and right button on B. What should happen if I press left button in A, move to
1619  //B and press the right button? In my test programm on X11 (Ubuntu) I can see, that now they BOTH
1620  //are active grabs. I'm not going to implement this mess, unless I have a correct formal description.
1621  if (!fButtonGrabView)
1622  return;
1623 
1624  if (fOwnerEvents) {
1625  if (NSView<X11Window> *candidateView = FindViewForPointerEvent(theEvent)) {
1626  //Do propagation.
1627  candidateView = Detail::FindViewToPropagateEvent(candidateView, kButtonPressMask,
1629  //We have such a view, send an event to a corresponding ROOT's window.
1630  if (candidateView)
1631  Detail::SendButtonPressEvent(fEventQueue, candidateView, theEvent, btn);
1632  } else {
1635  }
1636  } else {
1639  }
1640 }
1641 
1642 //______________________________________________________________________________
1643 void EventTranslator::GenerateButtonReleaseEventNoGrab(NSView<X11Window> *eventView, NSEvent *theEvent,
1644  EMouseButton btn)
1645 {
1646  //Generate button release event when there is no active pointer grab. Can this even happen??
1647  assert(eventView != nil && "GenerateButtonReleaseEventNoGrab, parameter 'eventView' is nil");
1648  assert(theEvent != nil && "GenerateButtonReleaseEventNoGrabm parameter 'theEvent' is nil");
1649 
1650  if (NSView<X11Window> *candidateView = Detail::FindViewToPropagateEvent(eventView, kButtonReleaseMask))
1651  Detail::SendButtonReleaseEvent(fEventQueue, candidateView, theEvent, btn);
1652 }
1653 
1654 //______________________________________________________________________________
1655 void EventTranslator::GenerateButtonReleaseEventActiveGrab(NSView<X11Window> *eventView, NSEvent *theEvent,
1656  EMouseButton btn)
1657 {
1658  //Generate button release event in the presence of active grab (explicit pointer grab, activated passive grab or implicit grab).
1659 
1660  assert(eventView != nil && "GenerateButtonReleaseEventActiveGrab, parameter 'eventView' is nil");
1661  assert(theEvent != nil && "GenerateButtonReleaseEventActiveGrab, parameter 'theEvent' is nil");
1662 
1663  if (!fButtonGrabView) {
1664  //Still we have to cancel this grab (it's implicit grab on a root window).
1666  return;
1667  }
1668 
1669  //What if view is deleted in the middle of this function?
1670  const Util::NSStrongReference<NSView<X11Window> *> eventViewGuard(eventView);
1671 
1672  if (fButtonGrabView) {
1673  if (fOwnerEvents) {//X11: Either XGrabPointer with owner_events == True or passive grab (owner_events is always true)
1674  if (NSView<X11Window> *candidateView = FindViewForPointerEvent(theEvent)) {
1675  candidateView = Detail::FindViewToPropagateEvent(candidateView, kButtonReleaseMask,
1677  //candidateView is either some view, or grab view, if its mask is ok.
1678  if (candidateView)
1679  Detail::SendButtonReleaseEvent(fEventQueue, candidateView, theEvent, btn);
1680  } else if (fGrabEventMask & kButtonReleaseMask)
1682  } else {//Either implicit grab or GrabPointer with owner_events == False.
1685  }
1686  } else {
1687  CancelPointerGrab();//root window had a grab, cancel it now.
1688  }
1689 
1691  (btn == fButtonGrabView.fPassiveGrabButton || fButtonGrabView.fPassiveGrabButton == kAnyButton))
1693 
1696 }
1697 
1698 //______________________________________________________________________________
1699 void EventTranslator::GenerateKeyPressEventNoGrab(NSView<X11Window> *eventView, NSEvent *theEvent)
1700 {
1701  assert(eventView != nil && "GenerateKeyPressEventNoGrab, parameter 'eventView' is nil");
1702  assert(theEvent != nil && "GenerateKeyPressEventNoGrab, parameter 'theEvent' is nil");
1703  assert(fFocusView != nil && "GenerateKeyPressEventNoGrab, fFocusView is nil");
1704 
1705  FindKeyGrabView(eventView, theEvent);
1706 
1707  if (!fKeyGrabView) {
1708  NSView<X11Window> *candidateView = fFocusView;
1709  if (Detail::IsParent(fFocusView, eventView)) {
1710  NSView<X11Window> * const testView = Detail::FindViewToPropagateEvent(eventView, kKeyPressMask);
1711 
1712  if (testView && (testView == fFocusView || Detail::IsParent(fFocusView, testView)))
1713  candidateView = testView;
1714  }
1715 
1716  GenerateKeyEventForView(candidateView, theEvent);
1717  } else
1719 }
1720 
1721 //______________________________________________________________________________
1722 void EventTranslator::GenerateKeyEventActiveGrab(NSView<X11Window> *eventView, NSEvent *theEvent)
1723 {
1724  assert(eventView != nil && "GenerateKeyEventActiveGrab, parameter 'eventView' is nil");
1725  assert(theEvent != nil && "GenerateKeyEventActiveGrab, parameter 'theEvent' is nil");
1726  assert(fFocusView != nil && "GenerateKeyEventActiveGrab, fFocusView is nil");
1727 
1728  const Mask_t eventMask = theEvent.type == Details::kKeyDown ? kKeyPressMask : kKeyReleaseMask;
1729 
1730  if (Detail::IsParent(fFocusView, eventView) || fFocusView == eventView) {
1731  NSView<X11Window> * const testView = Detail::FindViewToPropagateEvent(eventView, eventMask);
1732  if (testView && (testView == fFocusView || Detail::IsParent(fFocusView, testView)))
1733  GenerateKeyEventForView(testView, theEvent);
1734  } else
1735  GenerateKeyEventForView(fFocusView, theEvent);//Should I check the mask???
1736 
1737  if (theEvent.type == Details::kKeyUp && fKeyGrabView) {
1738  //Cancel grab?
1739 
1740  //NSString *characters = [theEvent charactersIgnoringModifiers];
1741  //assert(characters != nil && "GenerateKeyEventActiveGrab, [theEvent characters] returned nil");
1742  //assert([characters length] > 0 && "GenerateKeyEventActiveGrab, characters is an empty string");
1743 
1744  //Here I have a real trouble: on a key press GUI removes ... passive key grabs ...
1745  //this "does not affect any active grab", but later on a key release ... I'm not
1746  //able to find a grab to remove and can not ... cancel the grab.
1747  //I do it the same way it's done on Windows after all.
1748  //So, the condition was commented :(
1749  //if ([fKeyGrabView findPassiveKeyGrab : [characters characterAtIndex : 0]])
1750  fKeyGrabView = nil;//Cancel grab.
1751  }
1752 }
1753 
1754 //______________________________________________________________________________
1755 void EventTranslator::GenerateKeyReleaseEventNoGrab(NSView<X11Window> *eventView, NSEvent *theEvent)
1756 {
1757  assert(eventView != nil && "GenerateKeyReleaseEventNoGrab, parameter 'eventView' is nil");
1758  assert(theEvent != nil && "GenerateKeyReleaseEventNoGrab, parameter 'theEvent' is nil");
1759 
1760  NSView<X11Window> *candidateView = fFocusView;
1761 
1762  if (eventView == fFocusView || Detail::IsParent(fFocusView, eventView)) {
1763  NSView<X11Window> * const testView = Detail::FindViewToPropagateEvent(eventView, kKeyReleaseMask);
1764  if (testView && (testView == fFocusView || Detail::IsParent(fFocusView, testView)))
1765  candidateView = testView;
1766  }
1767 
1768  GenerateKeyEventForView(candidateView, theEvent);
1769 }
1770 
1771 //______________________________________________________________________________
1772 void EventTranslator::GenerateKeyEventForView(NSView<X11Window> *view, NSEvent *theEvent)
1773 {
1774  //Generate key press event for a view without grab.
1775  assert(view != nil && "GenerateKeyEventForView, parameter 'view' is nil");
1776  assert(theEvent != nil && "GenerateKeyEventForView, parameter 'theEvent' is nil");
1777  assert((theEvent.type == Details::kKeyDown || theEvent.type == Details::kKeyUp) &&
1778  "GenerateKeyEvenForView, event's type must be keydown or keyup");
1779 
1780  const Mask_t eventType = theEvent.type == Details::kKeyDown ? kKeyPressMask : kKeyReleaseMask;
1781 
1782  NSView<X11Window> *childView = nil;
1783 
1784  NSPoint mousePosition = {};
1785  if (QuartzWindow * const topLevel = FindWindowUnderPointer())
1786  mousePosition = [topLevel mouseLocationOutsideOfEventStream];
1787 
1788  if (eventType == kKeyPressMask)
1789  Detail::SendKeyPressEvent(fEventQueue, view, childView, theEvent, mousePosition);
1790  else
1791  Detail::SendKeyReleaseEvent(fEventQueue, view, childView, theEvent, mousePosition);
1792 }
1793 
1794 //______________________________________________________________________________
1795 void EventTranslator::FindButtonGrab(NSView<X11Window> *fromView, NSEvent *theEvent, EMouseButton btn)
1796 {
1797  //Find a view to become a grab view - either passive or implicit.
1798 
1799  assert(fromView != nil && "FindButtonGrabView, parameter 'fromView' is nil");
1800  assert(theEvent != nil && "FindButtonGrabView, parameter 'theEvent' is nil");
1801 
1802  assert(fPointerGrabType == kPGNoGrab && "FindButtonGrabView, grab is already activated");
1803 
1804  const unsigned keyModifiers = Detail::GetKeyboardModifiersFromCocoaEvent(theEvent);
1805 
1806  NSView<X11Window> *grabView = 0;
1807  NSView<X11Window> *buttonPressView = 0;
1808 
1809  for (NSView<X11Window> *view = fromView; view != nil; view = view.fParentView) {
1810  //Top-first view to receive button press event.
1811  if (!buttonPressView && (view.fEventMask & kButtonPressMask))
1812  buttonPressView = view;
1813 
1814  //Bottom-first view with passive grab.
1815  if (view.fPassiveGrabButton == kAnyButton || view.fPassiveGrabButton == btn) {
1816  //Check modifiers.
1817  if (view.fPassiveGrabKeyModifiers == kAnyModifier || (view.fPassiveGrabKeyModifiers & keyModifiers))
1818  grabView = view;
1819  }
1820  }
1821 
1822  if (grabView) {
1823  fButtonGrabView = grabView;
1825  fGrabEventMask = grabView.fPassiveGrabEventMask;
1826  fOwnerEvents = grabView.fPassiveGrabOwnerEvents;
1827  } else if (buttonPressView) {
1828  //This is an implicit grab.
1829  fButtonGrabView = buttonPressView;
1831  fGrabEventMask = buttonPressView.fEventMask;
1832  fOwnerEvents = false;
1833  } else {
1834  //Implicit grab with 'root' window?
1835  fButtonGrabView = nil;
1837  fGrabEventMask = 0;
1838  fOwnerEvents = false;
1839  }
1840 }
1841 
1842 //______________________________________________________________________________
1843 void EventTranslator::FindKeyGrabView(NSView<X11Window> *eventView, NSEvent *theEvent)
1844 {
1845  assert(eventView != nil && "FindKeyGrabView, parameter 'eventView' is nil");
1846  assert(theEvent != nil && "FindKeyGrabView, parameter 'theEvent' is nil");
1847 
1848  NSString * const characters = [theEvent charactersIgnoringModifiers];
1849  assert(characters != nil && "FindKeyGrabView, [theEvent characters] returned nil");
1850  assert([characters length] > 0 && "FindKeyGrabView, characters is an empty string");
1851 
1852  const unichar keyCode = [characters characterAtIndex : 0];
1853  const NSUInteger modifiers = [theEvent modifierFlags] & Details::kDeviceIndependentModifierFlagsMask;
1854 
1855  NSView<X11Window> *currentView = fFocusView;
1856  if (eventView != fFocusView && Detail::IsParent(fFocusView, eventView))
1857  currentView = eventView;
1858 
1859  for (; currentView; currentView = currentView.fParentView) {
1860  if ([currentView findPassiveKeyGrab : keyCode modifiers : modifiers])
1861  fKeyGrabView = currentView;
1862  }
1863 }
1864 
1865 }//X11
1866 }//MacOSX
1867 }//ROOT
NSUInteger GetCocoaKeyModifiersFromROOTKeyModifiers(UInt_t rootKeyModifiers)
Definition: X11Events.mm:261
void GenerateCrossingEventForGrabView(EventQueue_t &queue, NSView< X11Window > *fromView, NSView< X11Window > *toView, NSView< X11Window > *grabView, Mask_t grabEventMask, NSEvent *theEvent)
Definition: X11Events.mm:1086
const Mask_t kKeyReleaseMask
Definition: GuiTypes.h:159
int GlobalXCocoaToROOT(CGFloat xCocoa)
EXMagic
Definition: GuiTypes.h:218
void SendLeaveEvent(EventQueue_t &queue, NSView< X11Window > *view, NSEvent *theEvent, EXMagic detail)
Definition: X11Events.mm:575
void GenerateCrossingEventParentToChild(EventQueue_t &queue, NSView< X11Window > *parent, NSView< X11Window > *child, NSEvent *theEvent, EXMagic detail)
Definition: X11Events.mm:944
void GenerateConfigureNotifyEvent(NSView< X11Window > *view, const NSRect &newFrame)
Definition: X11Events.mm:1149
void GeneratePointerMotionEventActiveGrab(NSEvent *theEvent)
Definition: X11Events.mm:1537
Bool_t operator<(const TDatime &d1, const TDatime &d2)
Definition: TDatime.h:106
NSView< X11Window > * FindViewForPointerEvent(NSEvent *pointerEvent)
void SendFocusOutEvent(EventQueue_t &queue, NSView< X11Window > *view, EXMagic mode)
Definition: X11Events.mm:826
UInt_t GetModifiers()
Definition: X11Events.mm:300
void GeneratePointerMotionEvent(NSEvent *theEvent)
Definition: X11Events.mm:1244
const Mask_t kButton2Mask
Definition: GuiTypes.h:203
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
Int_t MapKeySymToKeyCode(Int_t keySym)
Definition: X11Events.mm:178
const Mask_t kKeyMod2Mask
Definition: GuiTypes.h:198
UInt_t Mask_t
Definition: GuiTypes.h:40
const Mask_t kKeyShiftMask
Definition: GuiTypes.h:194
Ancestry FindRelation(NSView< X11Window > *view1, NSView< X11Window > *view2, NSView< X11Window > **lca)
Definition: X11Events.mm:480
const NSUInteger kDeviceIndependentModifierFlagsMask
const Mask_t kKeyMod1Mask
Definition: GuiTypes.h:197
void GenerateKeyReleaseEvent(NSView< X11Window > *eventView, NSEvent *theEvent)
Definition: X11Events.mm:1301
const Mask_t kButtonMotionMask
Definition: GuiTypes.h:163
ULong_t Time_t
Definition: GuiTypes.h:41
const Mask_t kLeaveWindowMask
Definition: GuiTypes.h:167
void SendLeaveEventClosedRange(EventQueue_t &queue, NSView< X11Window > *from, NSView< X11Window > *to, NSEvent *theEvent, EXMagic mode)
Definition: X11Events.mm:895
void MapUnicharToKeySym(unichar key, char *buf, Int_t len, UInt_t &rootKeySym)
Definition: X11Events.mm:98
NSView< X11Window > * FindViewToPropagateEvent(NSView< X11Window > *viewFrom, Mask_t checkMask)
Definition: X11Events.mm:496
Int_t fY
Definition: GuiTypes.h:177
unsigned GetKeyboardModifiersFromCocoaEvent(NSEvent *theEvent)
Definition: X11Events.mm:369
#define gClient
Definition: TGClient.h:166
void GenerateButtonReleaseEventActiveGrab(NSView< X11Window > *eventView, NSEvent *theEvent, EMouseButton btn)
Definition: X11Events.mm:1655
std::deque< Event_t > EventQueue_t
Definition: X11Events.h:49
const NSUInteger kAlternateKeyMask
int Int_t
Definition: RtypesCore.h:41
void GenerateKeyPressEventNoGrab(NSView< X11Window > *eventView, NSEvent *theEvent)
Definition: X11Events.mm:1699
void FindKeyGrabView(NSView< X11Window > *eventView, NSEvent *theEvent)
Definition: X11Events.mm:1843
DerivedType * Get() const
Definition: CocoaUtils.h:136
Window_t fWindow
Definition: GuiTypes.h:175
NSView< X11Window > * fButtonGrabView
Definition: X11Events.h:116
void GenerateButtonPressEvent(NSView< X11Window > *eventView, NSEvent *theEvent, EMouseButton btn)
Definition: X11Events.mm:1257
void SendButtonPressEvent(EventQueue_t &queue, NSView< X11Window > *view, NSEvent *theEvent, EMouseButton btn)
Definition: X11Events.mm:636
void GenerateCrossingEventFromChild1ToChild2(EventQueue_t &queue, NSView< X11Window > *child1, NSView< X11Window > *child2, NSView< X11Window > *ancestor, NSEvent *theEvent, EXMagic detail)
Definition: X11Events.mm:975
const NSEventType kKeyDown
const Mask_t kPointerMotionMask
Definition: GuiTypes.h:162
NSView< X11Window > * fFocusView
Definition: X11Events.h:118
NSView< X11Window > * FindViewToPropagateEvent(NSView< X11Window > *viewFrom, Mask_t checkMask, NSView< X11Window > *grabView, Mask_t grabMask)
Definition: X11Events.mm:513
void GenerateButtonReleaseEventNoGrab(NSView< X11Window > *eventView, NSEvent *theEvent, EMouseButton btn)
Definition: X11Events.mm:1643
void GenerateCrossingEventChildToParent(EventQueue_t &queue, NSView< X11Window > *parent, NSView< X11Window > *child, NSEvent *theEvent, EXMagic detail)
Definition: X11Events.mm:914
void SendPointerMotionEvent(EventQueue_t &queue, NSView< X11Window > *view, NSEvent *theEvent)
Definition: X11Events.mm:607
NSPoint ConvertPointFromBaseToScreen(NSWindow *window, NSPoint windowPoint)
Int_t fXRoot
Definition: GuiTypes.h:178
void SendKeyPressEvent(EventQueue_t &queue, NSView< X11Window > *view, NSView< X11Window > *childView, NSEvent *theEvent, NSPoint windowPoint)
Definition: X11Events.mm:717
const Mask_t kKeyLockMask
Definition: GuiTypes.h:195
void SetInputFocus(NSView< X11Window > *focusView)
Definition: X11Events.mm:1431
XFontStruct * id
Definition: TGX11.cxx:108
NSPoint ConvertPointFromScreenToBase(NSPoint screenPoint, NSWindow *window)
Time_t TimeForCocoaEvent(NSEvent *theEvent)
Definition: X11Events.mm:319
void GenerateCrossingEvents(EventQueue_t &queue, NSView< X11Window > *fromView, NSView< X11Window > *toView, NSEvent *theEvent, EXMagic detail)
Definition: X11Events.mm:1015
const NSEventType kKeyUp
void FindButtonGrab(NSView< X11Window > *fromView, NSEvent *theEvent, EMouseButton btn)
Definition: X11Events.mm:1795
const Mask_t kButtonPressMask
Definition: GuiTypes.h:160
NSView< X11Window > * FindViewUnderPointer()
NSPoint TranslateToScreen(NSView< X11Window > *from, NSPoint point)
const Mask_t kKeyPressMask
Definition: GuiTypes.h:158
const Mask_t kButton3Mask
Definition: GuiTypes.h:204
int GlobalYCocoaToROOT(CGFloat yCocoa)
EMouseButton
Definition: GuiTypes.h:213
void GenerateExposeEvent(NSView< X11Window > *view, const NSRect &exposedRect)
Definition: X11Events.mm:1174
Time_t fTime
Definition: GuiTypes.h:176
unsigned GetModifiersFromCocoaEvent(NSEvent *theEvent)
Definition: X11Events.mm:390
SVector< double, 2 > v
Definition: Dict.h:5
EGEventType fType
Definition: GuiTypes.h:174
UInt_t fHeight
Definition: GuiTypes.h:181
QuartzWindow * FindWindowUnderPointer()
void GenerateButtonPressEventActiveGrab(NSView< X11Window > *view, NSEvent *theEvent, EMouseButton btn)
Definition: X11Events.mm:1609
const NSUInteger kCommandKeyMask
void SendEnterEvent(EventQueue_t &queue, NSView< X11Window > *view, NSEvent *theEvent, EXMagic detail)
Definition: X11Events.mm:540
unsigned int UInt_t
Definition: RtypesCore.h:42
void GenerateDestroyNotify(unsigned winID)
Int_t fYRoot
Definition: GuiTypes.h:178
Ancestry FindLowestCommonAncestor(NSView< X11Window > *view1, NSView< X11Window > *view2, NSView< X11Window > **lca)
Definition: X11Events.mm:452
const NSUInteger kShiftKeyMask
void SendLeaveEventRange(EventQueue_t &queue, NSView< X11Window > *from, NSView< X11Window > *to, NSEvent *theEvent, EXMagic mode)
Definition: X11Events.mm:879
void SendEnterEventRange(EventQueue_t &queue, NSView< X11Window > *from, NSView< X11Window > *to, NSEvent *theEvent, EXMagic mode)
Definition: X11Events.mm:849
void GenerateKeyEventActiveGrab(NSView< X11Window > *eventView, NSEvent *theEvent)
Definition: X11Events.mm:1722
NSView< X11Window > * fKeyGrabView
Definition: X11Events.h:117
EKeySym
Definition: KeySymbols.h:25
bool IsInBranch(NSView< X11Window > *parent, NSView< X11Window > *child, NSView< X11Window > *testView)
Definition: X11Events.mm:427
const Mask_t kEnterWindowMask
Definition: GuiTypes.h:166
void GenerateButtonPressEventNoGrab(NSView< X11Window > *view, NSEvent *theEvent, EMouseButton btn)
Definition: X11Events.mm:1575
T2 fSecond
Definition: X11Events.mm:87
void ConvertEventLocationToROOTXY(NSEvent *cocoaEvent, NSView< X11Window > *eventView, Event_t *rootEvent)
Definition: X11Events.mm:341
void SendFocusInEvent(EventQueue_t &queue, NSView< X11Window > *view, EXMagic mode)
Definition: X11Events.mm:805
static Int_t init()
void GenerateCrossingEventActiveGrab(NSEvent *theEvent)
Definition: X11Events.mm:1213
virtual Bool_t HandleEvent(Event_t *)
Definition: TGWindow.h:107
const Mask_t kButtonReleaseMask
Definition: GuiTypes.h:161
UInt_t fCode
Definition: GuiTypes.h:179
NSView< X11Window > * fViewUnderPointer
Definition: X11Events.h:109
#define T2
Definition: md5.inl:146
void GenerateCrossingEvent(NSEvent *theEvent)
Definition: X11Events.mm:1192
const NSUInteger kControlKeyMask
Long_t fUser[5]
Definition: GuiTypes.h:186
UInt_t GetKeyboardModifiers()
Definition: X11Events.mm:280
void SendEnterEventClosedRange(EventQueue_t &queue, NSView< X11Window > *from, NSView< X11Window > *to, NSEvent *theEvent, EXMagic mode)
Definition: X11Events.mm:865
UInt_t fWidth
Definition: GuiTypes.h:181
#define T1
Definition: md5.inl:145
Handle_t Window_t
Definition: GuiTypes.h:28
void GenerateKeyReleaseEventNoGrab(NSView< X11Window > *eventView, NSEvent *theEvent)
Definition: X11Events.mm:1755
void GeneratePointerMotionEventNoGrab(NSEvent *theEvent)
Definition: X11Events.mm:1518
const Mask_t kFocusChangeMask
Definition: GuiTypes.h:168
void CheckUnmappedView(Window_t winID)
Definition: X11Events.mm:1474
void GenerateCrossingEventNoGrab(NSEvent *theEvent)
Definition: X11Events.mm:1202
void GenerateKeyPressEvent(NSView< X11Window > *eventView, NSEvent *theEvent)
Definition: X11Events.mm:1285
Event_t NewX11EventFromCocoaEvent(unsigned windowID, NSEvent *theEvent)
Definition: X11Events.mm:328
void SendButtonReleaseEvent(EventQueue_t &queue, NSView< X11Window > *view, NSEvent *theEvent, EMouseButton btn)
Definition: X11Events.mm:686
UInt_t fState
Definition: GuiTypes.h:180
const Mask_t kKeyControlMask
Definition: GuiTypes.h:196
void GenerateKeyEventForView(NSView< X11Window > *view, NSEvent *theEvent)
Definition: X11Events.mm:1772
bool IsParent(NSView< X11Window > *testParent, NSView< X11Window > *testChild)
Definition: X11Events.mm:409
const Mask_t kAnyModifier
Definition: GuiTypes.h:209
const NSUInteger kAlphaShiftKeyMask
const Mask_t kButton1Mask
Definition: GuiTypes.h:202
void SetPointerGrab(NSView< X11Window > *grabView, unsigned eventMask, bool ownerEvents)
Definition: X11Events.mm:1339
Int_t fX
Definition: GuiTypes.h:177
void GenerateFocusChangeEvent(NSView< X11Window > *eventView)
Definition: X11Events.mm:1321
void SendKeyReleaseEvent(EventQueue_t &queue, NSView< X11Window > *view, NSView< X11Window > *childView, NSEvent *theEvent, NSPoint windowPoint)
Definition: X11Events.mm:761
T1 fFirst
Definition: X11Events.mm:86
void GenerateButtonReleaseEvent(NSView< X11Window > *eventView, NSEvent *theEvent, EMouseButton btn)
Definition: X11Events.mm:1270