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