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