Logo ROOT   6.10/09
Reference Guide
QuartzWindow.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 DEBUG_ROOT_COCOA
13 
14 //#define NDEBUG
15 
16 #ifdef DEBUG_ROOT_COCOA
17 #include <iostream>
18 #include <fstream>
19 
20 #include "TClass.h"
21 #endif
22 
23 #include <algorithm>
24 #include <stdexcept>
25 #include <cassert>
26 #include <vector>
27 
28 #include <Availability.h>
29 
30 #include "ROOTOpenGLView.h"
31 #include "CocoaConstants.h"
32 #include "QuartzWindow.h"
33 #include "QuartzPixmap.h"
34 #include "QuartzUtils.h"
35 #include "CocoaUtils.h"
36 #include "RConfigure.h"
37 #include "X11Colors.h"
38 #include "X11Buffer.h"
39 #include "TGWindow.h"
40 #include "TGClient.h"
41 #include "TSystem.h"
42 #include "TGCocoa.h"
43 #include "TROOT.h"
44 
45 
46 namespace ROOT {
47 namespace MacOSX {
48 namespace X11 {
49 
50 #pragma mark - Create a window or a view.
51 
52 //______________________________________________________________________________
54  UInt_t clss, void */*visual*/, SetWindowAttributes_t *attr, UInt_t)
55 {
56  using namespace Details;
57 
58  NSRect winRect = {};
59  winRect.origin.x = GlobalXROOTToCocoa(x);
60  winRect.origin.y = GlobalYROOTToCocoa(y + h);
61  winRect.size.width = w;
62  winRect.size.height = h;
63 
64  const NSUInteger styleMask = kTitledWindowMask | kClosableWindowMask |
66 
67  QuartzWindow * const newWindow = [[QuartzWindow alloc] initWithContentRect : winRect
68  styleMask : styleMask
69  backing : NSBackingStoreBuffered
70  defer : YES
71  windowAttributes : attr];
72  if (!newWindow)
73  throw std::runtime_error("CreateTopLevelWindow failed");
74 
75  newWindow.fDepth = depth;
76  newWindow.fClass = clss;
77 
78  return newWindow;
79 }
80 
81 //______________________________________________________________________________
82 QuartzView *CreateChildView(QuartzView * /*parent*/, Int_t x, Int_t y, UInt_t w, UInt_t h, UInt_t /*border*/, Int_t /*depth*/,
83  UInt_t /*clss*/, void * /*visual*/, SetWindowAttributes_t *attr, UInt_t /*wtype*/)
84 {
85  NSRect viewRect = {};
86  viewRect.origin.x = x;
87  viewRect.origin.y = y;
88  viewRect.size.width = w;
89  viewRect.size.height = h;
90 
91  QuartzView * const view = [[QuartzView alloc] initWithFrame : viewRect windowAttributes : attr];
92  if (!view)
93  throw std::runtime_error("CreateChildView failed");
94 
95  return view;
96 }
97 
98 #pragma mark - root window (does not really exist, it's our desktop built of all screens).
99 
100 //______________________________________________________________________________
102 {
103  //'root' window does not exist, but we can request its attributes.
104  assert(attr != 0 && "GetRootWindowAttributes, parameter 'attr' is null");
105 
106 
107  NSArray * const screens = [NSScreen screens];
108  assert(screens != nil && "screens array is nil");
109  NSScreen * const mainScreen = [screens objectAtIndex : 0];
110  assert(mainScreen != nil && "screen with index 0 is nil");
111 
112  *attr = WindowAttributes_t();
113 
114  assert(dynamic_cast<TGCocoa *>(gVirtualX) &&
115  "GetRootWindowAttributes, gVirtualX is either null or has a wrong type");
116 
117  TGCocoa * const gCocoa = static_cast<TGCocoa *>(gVirtualX);
118 
119  const Rectangle &frame = gCocoa->GetDisplayGeometry();
120 
121  attr->fX = 0;
122  attr->fY = 0;
123  attr->fWidth = frame.fWidth;
124  attr->fHeight = frame.fHeight;
125  attr->fBorderWidth = 0;
126  attr->fYourEventMask = 0;
127  attr->fAllEventMasks = 0;//???
128 
129  attr->fDepth = NSBitsPerPixelFromDepth([mainScreen depth]);
130  attr->fVisual = 0;
131  attr->fRoot = 0;
132 }
133 
134 
135 #pragma mark - Coordinate conversions.
136 
137 //______________________________________________________________________________
138 NSPoint ConvertPointFromBaseToScreen(NSWindow *window, NSPoint windowPoint)
139 {
140  assert(window != nil && "ConvertPointFromBaseToScreen, parameter 'window' is nil");
141 
142  //I have no idea why apple deprecated function for a point conversion and requires rect conversion,
143  //point conversion seems to produce wrong results with HiDPI.
144 
145  NSRect tmpRect = {};
146  tmpRect.origin = windowPoint;
147  tmpRect.size = NSMakeSize(1., 1.);//This is strange size :) But if they require rect, 0,0 - will not work?
148  tmpRect = [window convertRectToScreen : tmpRect];
149 
150  return tmpRect.origin;
151 }
152 
153 //______________________________________________________________________________
154 NSPoint ConvertPointFromScreenToBase(NSPoint screenPoint, NSWindow *window)
155 {
156  assert(window != nil && "ConvertPointFromScreenToBase, parameter 'window' is nil");
157 
158  //I have no idea why apple deprecated function for a point conversion and requires rect conversion,
159  //point conversion seems to produce wrong results with HiDPI.
160 
161  NSRect tmpRect = {};
162  tmpRect.origin = screenPoint;
163  tmpRect.size = NSMakeSize(1., 1.);
164  tmpRect = [window convertRectFromScreen : tmpRect];
165 
166  return tmpRect.origin;
167 }
168 
169 //______________________________________________________________________________
170 int GlobalYCocoaToROOT(CGFloat yCocoa)
171 {
172  //We can have several physical displays and thus several NSScreens in some arbitrary order.
173  //With Cocoa, some screens can have negative coordinates - to the left ro down to the primary
174  //screen (whatever it means). With X11 (XQuartz) though it's always 0,0.
175 
176  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
177  "GlobalYCocoaToROOT, gVirtualX is either nul or has a wrong type");
178 
179  const Rectangle frame = ((TGCocoa *)gVirtualX)->GetDisplayGeometry();
180 
181  return int(frame.fHeight - (yCocoa - frame.fY));
182 }
183 
184 //______________________________________________________________________________
185 int GlobalXCocoaToROOT(CGFloat xCocoa)
186 {
187  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
188  "GlobalXCocoaToROOT, gVirtualX is either nul or has a wrong type");
189  const Rectangle frame = ((TGCocoa *)gVirtualX)->GetDisplayGeometry();
190  //With X11 coordinate space always starts from 0, 0
191  return int(xCocoa - frame.fX);
192 }
193 
194 //______________________________________________________________________________
195 int GlobalYROOTToCocoa(CGFloat yROOT)
196 {
197  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
198  "GlobalYROOTToCocoa, gVirtualX is either nul or has a wrong type");
199  const Rectangle frame = ((TGCocoa *)gVirtualX)->GetDisplayGeometry();
200 
201  return int(frame.fY + (frame.fHeight - yROOT));
202 }
203 
204 //______________________________________________________________________________
205 int GlobalXROOTToCocoa(CGFloat xROOT)
206 {
207  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
208  "GlobalXROOTToCocoa, gVirtualX is either nul or has a wrong type");
209  const Rectangle frame = ((TGCocoa *)gVirtualX)->GetDisplayGeometry();
210  //With X11 coordinate space always starts from 0, 0
211  return int(frame.fX + xROOT);
212 }
213 
214 //______________________________________________________________________________
215 int LocalYCocoaToROOT(NSView<X11Window> *parentView, CGFloat yCocoa)
216 {
217  assert(parentView != nil && "LocalYCocoaToROOT, parent view is nil");
218 
219  return int(parentView.frame.size.height - yCocoa);
220 }
221 
222 //______________________________________________________________________________
223 int LocalYROOTToCocoa(NSView<X11Window> *parentView, CGFloat yROOT)
224 {
225  //:)
226  assert(parentView != nil && "LocalYROOTToCocoa, parent view is nil");
227 
228  return int(parentView.frame.size.height - yROOT);
229 }
230 
231 
232 //______________________________________________________________________________
233 int LocalYROOTToCocoa(NSObject<X11Drawable> *drawable, CGFloat yROOT)
234 {
235  //:)
236  assert(drawable != nil && "LocalYROOTToCocoa, drawable is nil");
237 
238  return int(drawable.fHeight - yROOT);
239 }
240 
241 //______________________________________________________________________________
242 NSPoint TranslateToScreen(NSView<X11Window> *from, NSPoint point)
243 {
244  assert(from != nil && "TranslateToScreen, parameter 'from' is nil");
245 
246  const NSPoint winPoint = [from convertPoint : point toView : nil];
247 
248  NSPoint screenPoint = ConvertPointFromBaseToScreen([from window], winPoint);
249  screenPoint.x = GlobalXCocoaToROOT(screenPoint.x);
250  screenPoint.y = GlobalYCocoaToROOT(screenPoint.y);
251 
252  return screenPoint;
253 }
254 
255 //______________________________________________________________________________
256 NSPoint TranslateFromScreen(NSPoint point, NSView<X11Window> *to)
257 {
258  assert(to != nil && "TranslateFromScreen, parameter 'to' is nil");
259 
260  point.x = GlobalXROOTToCocoa(point.x);
261  point.y = GlobalYROOTToCocoa(point.y);
262  point = ConvertPointFromScreenToBase(point, [to window]);
263 
264  return [to convertPoint : point fromView : nil];
265 }
266 
267 //______________________________________________________________________________
268 NSPoint TranslateCoordinates(NSView<X11Window> *from, NSView<X11Window> *to, NSPoint sourcePoint)
269 {
270  //Both views are valid.
271  assert(from != nil && "TranslateCoordinates, parameter 'from' is nil");
272  assert(to != nil && "TranslateCoordinates, parameter 'to' is nil");
273 
274  if ([from window] == [to window]) {
275  //Both views are in the same window.
276  return [to convertPoint : sourcePoint fromView : from];
277  } else {
278  //May be, I can do it in one call, but it's not obvious for me
279  //what is 'pixel aligned backing store coordinates' and
280  //if they are the same as screen coordinates.
281 
282  //Many thanks to Apple for deprecated functions!!!
283 
284  const NSPoint win1Point = [from convertPoint : sourcePoint toView : nil];
285  const NSPoint screenPoint = ConvertPointFromBaseToScreen([from window], win1Point);
286  const NSPoint win2Point = ConvertPointFromScreenToBase(screenPoint, [to window]);
287 
288  return [to convertPoint : win2Point fromView : nil];
289  }
290 }
291 
292 //______________________________________________________________________________
293 bool ScreenPointIsInView(NSView<X11Window> *view, Int_t x, Int_t y)
294 {
295  assert(view != nil && "ScreenPointIsInView, parameter 'view' is nil");
296 
297  NSPoint point = {};
298  point.x = x, point.y = y;
299  point = TranslateFromScreen(point, view);
300  const NSRect viewFrame = view.frame;
301 
302  if (point.x < 0 || point.x > viewFrame.size.width)
303  return false;
304  if (point.y < 0 || point.y > viewFrame.size.height)
305  return false;
306 
307  return true;
308 }
309 
310 #pragma mark - Different FindView/Window functions iterating on the ROOT's windows/views.
311 
312 //______________________________________________________________________________
314 {
315  //array's counter is increased, all object in array are also retained.
316  const Util::AutoreleasePool pool;
317 
318  NSArray * const orderedWindows = [NSApp orderedWindows];
319  for (NSWindow *window in orderedWindows) {
320  if (![window isKindOfClass : [QuartzWindow class]])
321  continue;
322  QuartzWindow * const qw = (QuartzWindow *)window;
323  if (qw.fIsDeleted)//Because of reference counting this can happen.
324  continue;
325  //Check if point is inside.
326  if (ScreenPointIsInView(qw.fContentView, x, y))
327  return qw;
328  }
329 
330  return nil;
331 }
332 
333 //______________________________________________________________________________
334 NSView<X11Window> *FindDNDAwareViewInPoint(NSArray *children, Window_t dragWinID,
335  Window_t inputWinID, Int_t x, Int_t y, Int_t maxDepth)
336 {
337  assert(children != nil && "FindDNDAwareViewInPoint, parameter 'children' is nil");
338 
339  if (maxDepth <= 0)
340  return nil;
341 
342  NSEnumerator * const reverseEnumerator = [children reverseObjectEnumerator];
343  for (NSView<X11Window> *child in reverseEnumerator) {
344  if (!ScreenPointIsInView(child, x, y))
345  continue;
346  if (child.fIsDNDAware && child.fID != dragWinID && child.fID != inputWinID)
347  return child;//got it!
348 
349  NSView<X11Window> * const testView = FindDNDAwareViewInPoint([child subviews], dragWinID,
350  inputWinID, x, y, maxDepth - 1);
351  if (testView)
352  return testView;
353  }
354 
355  return nil;
356 }
357 
358 //______________________________________________________________________________
359 NSView<X11Window> *FindDNDAwareViewInPoint(NSView *parentView, Window_t dragWinID, Window_t inputWinID,
360  Int_t x, Int_t y, Int_t maxDepth)
361 {
362  //X and Y are ROOT's screen coordinates (Y is inverted).
363  if (maxDepth <= 0)
364  return nil;
365 
366  const Util::AutoreleasePool pool;
367 
368  if (!parentView) {//Start from the screen as a 'root' window.
369  NSArray * const orderedWindows = [NSApp orderedWindows];
370  for (NSWindow *window in orderedWindows) {
371  if (![window isKindOfClass : [QuartzWindow class]])
372  continue;
373  QuartzWindow * const qw = (QuartzWindow *)window;
374 
375  if (qw.fIsDeleted)//Because of reference counting this can happen.
376  continue;
377 
378  if (qw.fMapState != kIsViewable)
379  continue;
380 
381  //First, check this view itself, my be we found what we need already.
382  NSView<X11Window> *testView = qw.fContentView;
383  if (!ScreenPointIsInView(testView, x, y))
384  continue;
385 
386  if (testView.fIsDNDAware && testView.fID != dragWinID && testView.fID != inputWinID)
387  return testView;
388 
389  //Recursive part, check children.
390  NSArray * const children = [testView subviews];
391  testView = FindDNDAwareViewInPoint(children, dragWinID, inputWinID, x, y, maxDepth - 1);
392  if (testView)
393  return testView;
394  }
395 
396  //We did not find anything for 'root' window as parent.
397  return nil;
398  } else {
399  //Parent view is tested already (or should not be tested at all, check children.
400  return FindDNDAwareViewInPoint([parentView subviews], dragWinID, inputWinID, x, y, maxDepth);
401  }
402 }
403 
404 //______________________________________________________________________________
406 {
407  const Util::AutoreleasePool pool;
408 
409  NSArray * const orderedWindows = [NSApp orderedWindows];
410  for (NSWindow *nsWindow in orderedWindows) {
411  if (![nsWindow isKindOfClass : [QuartzWindow class]])
412  continue;
413 
414  QuartzWindow * const qWindow = (QuartzWindow *)nsWindow;
415 
416  if (qWindow.fIsDeleted)//Because of reference counting this can happen.
417  continue;
418 
419  if (qWindow.fMapState != kIsViewable)//Can it be false and still in this array???
420  continue;
421 
422  const NSPoint mousePosition = [qWindow mouseLocationOutsideOfEventStream];
423  const NSSize windowSize = qWindow.frame.size;
424  if (mousePosition.x >= 0 && mousePosition.x <= windowSize.width &&
425  mousePosition.y >= 0 && mousePosition.y <= windowSize.height)
426  return qWindow;
427  }
428 
429  return nil;
430 }
431 
432 //______________________________________________________________________________
433 NSView<X11Window> *FindViewUnderPointer()
434 {
435  const Util::AutoreleasePool pool;
436 
437  if (QuartzWindow *topLevel = FindWindowUnderPointer()) {
438  const NSPoint mousePosition = [topLevel mouseLocationOutsideOfEventStream];
439  return (NSView<X11Window> *)[[topLevel contentView] hitTest : mousePosition];
440  }
441 
442  return nil;
443 }
444 
445 //______________________________________________________________________________
447 {
448  //FindWindowForPointerEvent is required because due to grabs
449  //the receiver of the event can be different from the actual
450  //window under cursor.
451 
452  assert(pointerEvent != nil &&
453  "FindWindowForPointerEvent, parameter 'pointerEvent' is nil");
454 
455  const Util::AutoreleasePool pool;
456 
457  NSArray * const orderedWindows = [NSApp orderedWindows];
458  for (NSWindow *nsWindow in orderedWindows) {
459  if (![nsWindow isKindOfClass : [QuartzWindow class]])
460  continue;
461 
462  QuartzWindow * const qWindow = (QuartzWindow *)nsWindow;
463 
464  if (qWindow.fIsDeleted)//Because of reference counting this can happen.
465  continue;
466 
467  //Can it be false and still in this array???
468  if (qWindow.fMapState != kIsViewable)
469  continue;
470 
471  NSPoint mousePosition = [pointerEvent locationInWindow];
472  //The event has a window, so position is in this window's coordinate system,
473  //convert it into screen point first.
474  if ([pointerEvent window]) {
475  //convertBaseToScreen is deprecated.
476  //mousePosition = [[pointerEvent window] convertBaseToScreen : mousePosition];
477  mousePosition = ConvertPointFromBaseToScreen([pointerEvent window], mousePosition);
478  }
479 
480  //convertScreenToBase is deprecated.
481  //mousePosition = [qWindow convertScreenToBase : mousePosition];
482  mousePosition = ConvertPointFromScreenToBase(mousePosition, qWindow);
483 
484  const NSSize windowSize = qWindow.frame.size;
485  if (mousePosition.x >= 0 && mousePosition.x <= windowSize.width &&
486  mousePosition.y >= 0 && mousePosition.y <= windowSize.height)
487  return qWindow;
488  }
489 
490  return nil;
491 }
492 
493 //______________________________________________________________________________
494 NSView<X11Window> *FindViewForPointerEvent(NSEvent *pointerEvent)
495 {
496  //FindViewForPointerEvent is required because of grabs - the receiver of the
497  //event can be different from the actual window under cursor.
498 
499  assert(pointerEvent != nil &&
500  "FindViewForPointerEvent, parameter 'pointerEvent' is nil");
501 
502  const Util::AutoreleasePool pool;
503 
504  if (QuartzWindow *topLevel = FindWindowForPointerEvent(pointerEvent)) {
505  NSPoint mousePosition = [pointerEvent locationInWindow];
506  if ([pointerEvent window])
507  mousePosition = ConvertPointFromBaseToScreen([pointerEvent window], mousePosition);
508 
509  //convertScreenToBase is deprecated.
510  //mousePosition = [topLevel convertScreenToBase : mousePosition];
511  mousePosition = ConvertPointFromScreenToBase(mousePosition, topLevel);
512 
513  return (NSView<X11Window> *)[[topLevel contentView] hitTest : mousePosition];
514  }
515 
516  return nil;
517 }
518 
519 #pragma mark - Downscale image ("reading color bits" on retina macs).
520 
521 //Hoho, we support C++11?? Let's return by value then!!!
522 std::vector<unsigned char> DownscaledImageData(unsigned w, unsigned h, CGImageRef image)
523 {
524  assert(w != 0 && h != 0 && "DownscaledImageData, invalid geometry");
525  assert(image != nullptr && "DonwscaledImageData, invalid parameter 'image'");
526 
527  std::vector<unsigned char> result;
528  try {
529  result.resize(w * h * 4);
530  } catch (const std::bad_alloc &) {
531  NSLog(@"DownscaledImageData, memory allocation failed");
532  return result;
533  }
534 
535  const Util::CFScopeGuard<CGColorSpaceRef> colorSpace(CGColorSpaceCreateDeviceRGB());//[1]
536  if (!colorSpace.Get()) {
537  NSLog(@"DownscaledImageData, CGColorSpaceCreateDeviceRGB failed");
538  return result;
539  }
540 
541  Util::CFScopeGuard<CGContextRef> ctx(CGBitmapContextCreateWithData(&result[0], w, h, 8,
542  w * 4, colorSpace.Get(),
543  kCGImageAlphaPremultipliedLast, NULL, 0));
544  if (!ctx.Get()) {
545  NSLog(@"DownscaledImageData, CGBitmapContextCreateWithData failed");
546  return result;
547  }
548 
549  CGContextDrawImage(ctx.Get(), CGRectMake(0, 0, w, h), image);
550 
551  return result;
552 }
553 
554 #pragma mark - "Focus management" - just make another window key window.
555 
556 //______________________________________________________________________________
558 {
559  //XQuartz (and other X11
560  if (![NSApp isActive])
561  return;
562 
563  const Util::AutoreleasePool pool;
564 
565  NSArray * const orderedWindows = [NSApp orderedWindows];
566  for (NSWindow *nsWindow in orderedWindows) {
567  if (![nsWindow isKindOfClass : [QuartzWindow class]])
568  continue;
569 
570  QuartzWindow * const qWindow = (QuartzWindow *)nsWindow;
571 
572  if (qWindow.fIsDeleted || qWindow.fMapState != kIsViewable || qWindow.fID == winID)
573  continue;
574 
575  if (qWindow.fContentView.fOverrideRedirect)
576  continue;
577 
578  [qWindow makeKeyAndOrderFront : qWindow];
579  break;
580  }
581 }
582 
583 #pragma mark - 'shape mask' - to create a window with arbitrary (probably non-rectangle) shape.
584 
585 //______________________________________________________________________________
586 void ClipToShapeMask(NSView<X11Window> *view, CGContextRef ctx)
587 {
588  assert(view != nil && "ClipToShapeMask, parameter 'view' is nil");
589  assert(ctx != 0 && "ClipToShapeMask, parameter 'ctx' is null");
590 
591  QuartzWindow * const topLevelParent = view.fQuartzWindow;
592  assert(topLevelParent.fShapeCombineMask != nil &&
593  "ClipToShapeMask, fShapeCombineMask is nil on a top-level window");
594  assert(topLevelParent.fShapeCombineMask.fImage != 0 &&
595  "ClipToShapeMask, shape mask is null");
596 
597  //Important: shape mask should have the same width and height as
598  //a top-level window. In ROOT it does not :( Say hello to visual artifacts.
599 
600  //Attach clip mask to the context.
601  if (!view.fParentView) {
602  //'view' is a top-level view.
603  const CGRect clipRect = CGRectMake(0, 0, topLevelParent.fShapeCombineMask.fWidth,
604  topLevelParent.fShapeCombineMask.fHeight);
605  CGContextClipToMask(ctx, clipRect, topLevelParent.fShapeCombineMask.fImage);
606  } else {
607  NSRect clipRect = view.frame;
608  //More complex case: 'self' is a child view, we have to create a subimage from shape mask.
609  clipRect.origin = [view.fParentView convertPoint : clipRect.origin
610  toView : [view window].contentView];
611  clipRect.origin.y = X11::LocalYROOTToCocoa((NSView<X11Window> *)[view window].contentView,
612  clipRect.origin.y + clipRect.size.height);
613 
614  if (AdjustCropArea(topLevelParent.fShapeCombineMask, clipRect)) {
616  clipImageGuard(CGImageCreateWithImageInRect(topLevelParent.fShapeCombineMask.fImage,
617  NSRectToCGRect(clipRect)));
618  clipRect.origin = NSPoint();
619  CGContextClipToMask(ctx, NSRectToCGRect(clipRect), clipImageGuard.Get());
620  } else {
621  //View is invisible.
622  CGRect rect = {};
623  CGContextClipToRect(ctx, rect);
624  }
625  }
626 }
627 
628 #pragma mark - Window's geometry and attributes.
629 
630 //______________________________________________________________________________
631 void SetWindowAttributes(const SetWindowAttributes_t *attr, NSObject<X11Window> *window)
632 {
633  assert(attr != 0 && "SetWindowAttributes, parameter 'attr' is null");
634  assert(window != nil && "SetWindowAttributes, parameter 'window' is nil");
635 
636  const Mask_t mask = attr->fMask;
637 
638  if (mask & kWABackPixel)
639  window.fBackgroundPixel = attr->fBackgroundPixel;
640 
641  if (mask & kWAEventMask)
642  window.fEventMask = attr->fEventMask;
643 
644  if (mask & kWABitGravity)
645  window.fBitGravity = attr->fBitGravity;
646 
647  if (mask & kWAWinGravity)
648  window.fWinGravity = attr->fWinGravity;
649 
650  if (mask & kWAOverrideRedirect) {
651  if ([(NSObject *)window isKindOfClass : [QuartzWindow class]]) {
652  QuartzWindow * const qw = (QuartzWindow *)window;
653  [qw setStyleMask : Details::kBorderlessWindowMask];
654  [qw setAlphaValue : 0.95];
655  }
656 
657  window.fOverrideRedirect = YES;
658  }
659 }
660 
661 //______________________________________________________________________________
662 void GetWindowGeometry(NSObject<X11Window> *win, WindowAttributes_t *dst)
663 {
664  assert(win != nil && "GetWindowGeometry, parameter 'win' is nil");
665  assert(dst != 0 && "GetWindowGeometry, parameter 'dst' is null");
666 
667  dst->fX = win.fX;
668  dst->fY = win.fY;
669 
670  dst->fWidth = win.fWidth;
671  dst->fHeight = win.fHeight;
672 }
673 
674 //______________________________________________________________________________
675 void GetWindowAttributes(NSObject<X11Window> *window, WindowAttributes_t *dst)
676 {
677  assert(window != nil && "GetWindowAttributes, parameter 'window' is nil");
678  assert(dst != 0 && "GetWindowAttributes, parameter 'attr' is null");
679 
680  *dst = WindowAttributes_t();
681 
682  //fX, fY, fWidth, fHeight.
683  GetWindowGeometry(window, dst);
684 
685  //Actually, most of them are not used by GUI.
686  dst->fBorderWidth = 0;
687  dst->fDepth = window.fDepth;
688  //Dummy value.
689  dst->fVisual = 0;
690  //Dummy value.
691  dst->fRoot = 0;
692  dst->fClass = window.fClass;
693  dst->fBitGravity = window.fBitGravity;
694  dst->fWinGravity = window.fWinGravity;
695  //Dummy value.
696  dst->fBackingStore = kAlways;//??? CHECK
697  dst->fBackingPlanes = 0;
698 
699  //Dummy value.
700  dst->fBackingPixel = 0;
701 
702  dst->fSaveUnder = 0;
703 
704  //Dummy value.
705  dst->fColormap = 0;
706  //Dummy value.
707  dst->fMapInstalled = kTRUE;
708 
709  dst->fMapState = window.fMapState;
710 
711  dst->fAllEventMasks = window.fEventMask;
712  dst->fYourEventMask = window.fEventMask;
713 
714  //Not used by GUI.
715  //dst->fDoNotPropagateMask
716 
717  dst->fOverrideRedirect = window.fOverrideRedirect;
718  //Dummy value.
719  dst->fScreen = 0;
720 }
721 
722 //With Apple's poor man's objective C/C++ + "brilliant" Cocoa you never know, what should be
723 //the linkage of callback functions, API + language dialects == MESS. I declare/define this comparators here
724 //as having "C++" linkage. If one good day clang will start to complane, I'll have to change this.
725 
726 #pragma mark - Comparators (I need them when changing a window's z-order).
727 
728 //______________________________________________________________________________
729 // SDK 10.11 and above ...
730 #ifdef MAC_OS_X_VERSION_10_11
731 NSComparisonResult CompareViewsToLower(__kindof NSView *view1, __kindof NSView *view2, void *context)
732 #else
733 NSComparisonResult CompareViewsToLower(id view1, id view2, void *context)
734 #endif
735 {
736  id topView = (id)context;
737  if (view1 == topView)
738  return NSOrderedAscending;
739  if (view2 == topView)
740  return NSOrderedDescending;
741 
742  return NSOrderedSame;
743 }
744 
745 //______________________________________________________________________________
746 // SDK 10.11 and above ...
747 #ifdef MAC_OS_X_VERSION_10_11
748 NSComparisonResult CompareViewsToRaise(__kindof NSView *view1, __kindof NSView *view2, void *context)
749 #else
750 NSComparisonResult CompareViewsToRaise(id view1, id view2, void *context)
751 #endif
752 {
753  id topView = (id)context;
754  if (view1 == topView)
755  return NSOrderedDescending;
756  if (view2 == topView)
757  return NSOrderedAscending;
758 
759  return NSOrderedSame;
760 }
761 
762 #pragma mark - Cursor's area.
763 
764 //______________________________________________________________________________
765 NSPoint GetCursorHotStop(NSImage *image, ECursor cursor)
766 {
767  assert(image != nil && "CursroHotSpot, parameter 'image' is nil");
768 
769  const NSSize imageSize = image.size;
770 
771  if (cursor == kArrowRight)
772  return NSMakePoint(imageSize.width, imageSize.height / 2);
773 
774  return NSMakePoint(imageSize.width / 2, imageSize.height / 2);
775 }
776 
777 //______________________________________________________________________________
778 NSCursor *CreateCustomCursor(ECursor currentCursor)
779 {
780  // Returns auto-released cursor object.
781  const char *pngFileName = 0;
782 
783  switch (currentCursor) {
784  case kMove:
785  pngFileName = "move_cursor.png";
786  break;
787  case kArrowHor:
788  pngFileName = "hor_arrow_cursor.png";
789  break;
790  case kArrowVer:
791  pngFileName = "ver_arrow_cursor.png";
792  break;
793  case kArrowRight:
794  pngFileName = "right_arrow_cursor.png";
795  break;
796  case kRotate:
797  pngFileName = "rotate.png";
798  break;
799  case kBottomLeft:
800  case kTopRight:
801  pngFileName = "top_right_cursor.png";
802  break;
803  case kTopLeft:
804  case kBottomRight:
805  pngFileName = "top_left_cursor.png";
806  break;
807  default:;
808  }
809 
810  if (pngFileName) {
811  const char * const path = gSystem->Which(TROOT::GetIconPath(), pngFileName, kReadPermission);
812  const Util::ScopedArray<const char> arrayGuard(path);
813 
814  if (!path || path[0] == 0) {
815  //File was not found.
816  return nil;
817  }
818 
819  NSString *nsPath = [NSString stringWithFormat : @"%s", path];//in autorelease pool.
820  NSImage * const cursorImage = [[NSImage alloc] initWithContentsOfFile : nsPath];
821 
822  if (!cursorImage)
823  return nil;
824 
825  const NSPoint hotSpot(X11::GetCursorHotStop(cursorImage, currentCursor));
826  NSCursor * const customCursor = [[[NSCursor alloc] initWithImage : cursorImage
827  hotSpot : hotSpot] autorelease];
828 
829  [cursorImage release];
830 
831  return customCursor;
832  }
833 
834  return nil;
835 }
836 
837 //______________________________________________________________________________
838 NSCursor *CreateCursor(ECursor currentCursor)
839 {
840  // Returns auto-released cursor object.
841 
842  //Cursors from TVirtaulX:
843  // kBottomLeft, kBottomRight, kTopLeft, kTopRight,
844  // kBottomSide, kLeftSide, kTopSide, kRightSide,
845  // kMove, kCross, kArrowHor, kArrowVer,
846  // kHand, kRotate, kPointer, kArrowRight,
847  // kCaret, kWatch
848 
849  NSCursor *cursor = nil;
850  switch (currentCursor) {
851  case kCross:
852  cursor = [NSCursor crosshairCursor];
853  break;
854  case kPointer:
855  cursor = [NSCursor arrowCursor];
856  break;
857  case kHand:
858  cursor = [NSCursor openHandCursor];
859  break;
860  case kLeftSide:
861  cursor = [NSCursor resizeLeftCursor];
862  break;
863  case kRightSide:
864  cursor = [NSCursor resizeRightCursor];
865  break;
866  case kTopSide:
867  cursor = [NSCursor resizeUpCursor];
868  break;
869  case kBottomSide:
870  cursor = [NSCursor resizeDownCursor];
871  break;
872  case kCaret:
873  cursor = [NSCursor IBeamCursor];
874  break;
875  case kRotate:
876  case kWatch:
877  default:
878  cursor = CreateCustomCursor(currentCursor);
879  }
880 
881  return cursor;
882 }
883 
884 //TGTextView/TGHtml is a very special window: it's a TGCompositeFrame,
885 //which has TGCompositeFrame inside (TGViewFrame). This TGViewFrame
886 //delegates Expose events to its parent, and parent tries to draw
887 //inside a TGViewFrame. This does not work with default
888 //QuartzView -drawRect/TGCocoa. So I need a trick to identify
889 //this special window.
890 
891 #pragma mark - Workarounds for a text view and its descendants.
892 
893 //______________________________________________________________________________
894 bool ViewIsTextView(unsigned viewID)
895 {
896  const TGWindow * const window = gClient->GetWindowById(viewID);
897  if (!window)
898  return false;
899  return window->InheritsFrom("TGTextView");
900 }
901 
902 //______________________________________________________________________________
903 bool ViewIsTextView(NSView<X11Window> *view)
904 {
905  assert(view != nil && "ViewIsTextView, parameter 'view' is nil");
906 
907  return ViewIsTextView(view.fID);
908 }
909 
910 //______________________________________________________________________________
911 bool ViewIsTextViewFrame(NSView<X11Window> *view, bool checkParent)
912 {
913  assert(view != nil && "ViewIsTextViewFrame, parameter 'view' is nil");
914 
915  const TGWindow * const window = gClient->GetWindowById(view.fID);
916  if (!window)
917  return false;
918 
919  if (!window->InheritsFrom("TGViewFrame"))
920  return false;
921 
922  if (!checkParent)
923  return true;
924 
925  if (!view.fParentView)
926  return false;
927 
928  return ViewIsTextView(view.fParentView);
929 }
930 
931 //______________________________________________________________________________
932 bool ViewIsHtmlView(unsigned viewID)
933 {
934  const TGWindow * const window = gClient->GetWindowById(viewID);
935  if (!window)
936  return false;
937  return window->InheritsFrom("TGHtml");
938 }
939 
940 //______________________________________________________________________________
941 bool ViewIsHtmlView(NSView<X11Window> *view)
942 {
943  assert(view != nil && "ViewIsHtmlView, parameter 'view' is nil");
944 
945  return ViewIsHtmlView(view.fID);
946 }
947 
948 //______________________________________________________________________________
949 bool ViewIsHtmlViewFrame(NSView<X11Window> *view, bool checkParent)
950 {
951  //
952  assert(view != nil && "ViewIsHtmlViewFrame, parameter 'view' is nil");
953 
954  const TGWindow * const window = gClient->GetWindowById(view.fID);
955  if (!window)
956  return false;
957 
958  if (!window->InheritsFrom("TGViewFrame"))
959  return false;
960 
961  if (!checkParent)
962  return true;
963 
964  if (!view.fParentView)
965  return false;
966 
967  return ViewIsHtmlView(view.fParentView);
968 }
969 
970 //______________________________________________________________________________
971 NSView<X11Window> *FrameForTextView(NSView<X11Window> *textView)
972 {
973  assert(textView != nil && "FrameForTextView, parameter 'textView' is nil");
974 
975  for (NSView<X11Window> *child in [textView subviews]) {
976  if (ViewIsTextViewFrame(child, false))
977  return child;
978  }
979 
980  return nil;
981 }
982 
983 //______________________________________________________________________________
984 NSView<X11Window> *FrameForHtmlView(NSView<X11Window> *htmlView)
985 {
986  assert(htmlView != nil && "FrameForHtmlView, parameter 'htmlView' is nil");
987 
988  for (NSView<X11Window> *child in [htmlView subviews]) {
989  if (ViewIsHtmlViewFrame(child, false))
990  return child;
991  }
992 
993  return nil;
994 }
995 
996 #pragma mark - Workarounds for 'paint out of paint events'.
997 
998 //______________________________________________________________________________
999 bool LockFocus(NSView<X11Window> *view)
1000 {
1001  assert(view != nil && "LockFocus, parameter 'view' is nil");
1002  assert([view isKindOfClass : [QuartzView class]] &&
1003  "LockFocus, QuartzView is expected");
1004 
1005  if ([view lockFocusIfCanDraw]) {
1006  NSGraphicsContext *nsContext = [NSGraphicsContext currentContext];
1007  assert(nsContext != nil && "LockFocus, currentContext is nil");
1008  CGContextRef currContext = (CGContextRef)[nsContext graphicsPort];
1009  assert(currContext != 0 && "LockFocus, graphicsPort is null");//remove this assert?
1010 
1011  ((QuartzView *)view).fContext = currContext;
1012 
1013  return true;
1014  }
1015 
1016  return false;
1017 }
1018 
1019 //______________________________________________________________________________
1020 void UnlockFocus(NSView<X11Window> *view)
1021 {
1022  assert(view != nil && "UnlockFocus, parameter 'view' is nil");
1023  assert([view isKindOfClass : [QuartzView class]] &&
1024  "UnlockFocus, QuartzView is expected");
1025 
1026  [view unlockFocus];
1027  ((QuartzView *)view).fContext = 0;
1028 }
1029 
1030 }//X11
1031 }//MacOSX
1032 }//ROOT
1033 
1034 namespace Quartz = ROOT::Quartz;
1035 namespace Util = ROOT::MacOSX::Util;
1036 namespace X11 = ROOT::MacOSX::X11;
1037 namespace Details = ROOT::MacOSX::Details;
1038 
1039 #ifdef DEBUG_ROOT_COCOA
1040 
1041 #pragma mark - 'loggers'.
1042 
1043 namespace {
1044 
1045 //______________________________________________________________________________
1046 void log_attributes(const SetWindowAttributes_t *attr, unsigned winID)
1047 {
1048  //This function is loggin requests, at the moment I can not set all
1049  //of these attributes, so I first have to check, what is actually
1050  //requested by ROOT.
1051  static std::ofstream logfile("win_attr.txt");
1052 
1053  const Mask_t mask = attr->fMask;
1054  if (mask & kWABackPixmap)
1055  logfile<<"win "<<winID<<": BackPixmap\n";
1056  if (mask & kWABackPixel)
1057  logfile<<"win "<<winID<<": BackPixel\n";
1058  if (mask & kWABorderPixmap)
1059  logfile<<"win "<<winID<<": BorderPixmap\n";
1060  if (mask & kWABorderPixel)
1061  logfile<<"win "<<winID<<": BorderPixel\n";
1062  if (mask & kWABorderWidth)
1063  logfile<<"win "<<winID<<": BorderWidth\n";
1064  if (mask & kWABitGravity)
1065  logfile<<"win "<<winID<<": BitGravity\n";
1066  if (mask & kWAWinGravity)
1067  logfile<<"win "<<winID<<": WinGravity\n";
1068  if (mask & kWABackingStore)
1069  logfile<<"win "<<winID<<": BackingStore\n";
1070  if (mask & kWABackingPlanes)
1071  logfile<<"win "<<winID<<": BackingPlanes\n";
1072  if (mask & kWABackingPixel)
1073  logfile<<"win "<<winID<<": BackingPixel\n";
1074  if (mask & kWAOverrideRedirect)
1075  logfile<<"win "<<winID<<": OverrideRedirect\n";
1076  if (mask & kWASaveUnder)
1077  logfile<<"win "<<winID<<": SaveUnder\n";
1078  if (mask & kWAEventMask)
1079  logfile<<"win "<<winID<<": EventMask\n";
1080  if (mask & kWADontPropagate)
1081  logfile<<"win "<<winID<<": DontPropagate\n";
1082  if (mask & kWAColormap)
1083  logfile<<"win "<<winID<<": Colormap\n";
1084  if (mask & kWACursor)
1085  logfile<<"win "<<winID<<": Cursor\n";
1086 }
1087 
1088 //______________________________________________________________________________
1089 void print_mask_info(ULong_t mask)
1090 {
1091  if (mask & kButtonPressMask)
1092  NSLog(@"button press mask");
1093  if (mask & kButtonReleaseMask)
1094  NSLog(@"button release mask");
1095  if (mask & kExposureMask)
1096  NSLog(@"exposure mask");
1097  if (mask & kPointerMotionMask)
1098  NSLog(@"pointer motion mask");
1099  if (mask & kButtonMotionMask)
1100  NSLog(@"button motion mask");
1101  if (mask & kEnterWindowMask)
1102  NSLog(@"enter notify mask");
1103  if (mask & kLeaveWindowMask)
1104  NSLog(@"leave notify mask");
1105 }
1106 
1107 }
1108 #endif
1109 
1110 
1111 @implementation QuartzWindow
1112 
1113 @synthesize fMainWindow;
1114 @synthesize fHasFocus;
1115 
1116 #pragma mark - QuartzWindow's life cycle.
1117 
1118 //______________________________________________________________________________
1119 - (id) initWithContentRect : (NSRect) contentRect styleMask : (NSUInteger) windowStyle
1120  backing : (NSBackingStoreType) bufferingType defer : (BOOL) deferCreation
1121  windowAttributes : (const SetWindowAttributes_t *) attr
1122 {
1123  self = [super initWithContentRect : contentRect styleMask : windowStyle
1124  backing : bufferingType defer : deferCreation];
1125 
1126  if (self) {
1127  //ROOT's not able to draw GUI concurrently, thanks to global variables and gVirtualX itself.
1128  [self setAllowsConcurrentViewDrawing : NO];
1129 
1130  self.delegate = self;
1131  //create content view here.
1132  NSRect contentViewRect = contentRect;
1133  contentViewRect.origin.x = 0.f;
1134  contentViewRect.origin.y = 0.f;
1135 
1136  fContentView = [[QuartzView alloc] initWithFrame : contentViewRect windowAttributes : 0];
1137 
1138  [self setContentView : fContentView];
1139 
1140  [fContentView release];
1141  fDelayedTransient = NO;
1142 
1143  if (attr)
1144  X11::SetWindowAttributes(attr, self);
1145 
1146  fIsDeleted = NO;
1147  fHasFocus = NO;
1148  }
1149 
1150  return self;
1151 }
1152 
1153 //______________________________________________________________________________
1154 - (id) initWithGLView : (ROOTOpenGLView *) glView
1155 {
1156  using namespace Details;
1157 
1158  assert(glView != nil && "-initWithGLView, parameter 'glView' is nil");
1159 
1160  const NSUInteger styleMask = kTitledWindowMask | kClosableWindowMask |
1162 
1163  NSRect contentRect = glView.frame;
1164  contentRect.origin = NSPoint();
1165 
1166  self = [super initWithContentRect : contentRect styleMask : styleMask
1167  backing : NSBackingStoreBuffered defer : NO];
1168 
1169  if (self) {
1170  //ROOT's not able to draw GUI concurrently, thanks to global variables and gVirtualX itself.
1171  [self setAllowsConcurrentViewDrawing : NO];
1172  self.delegate = self;
1173  fContentView = glView;
1174  [self setContentView : fContentView];
1175  fDelayedTransient = NO;
1176  fIsDeleted = NO;
1177  fHasFocus = NO;
1178  }
1179 
1180  return self;
1181 }
1182 
1183 //______________________________________________________________________________
1185 {
1186  [fShapeCombineMask release];
1187  [super dealloc];
1188 }
1189 
1190 //______________________________________________________________________________
1191 - (BOOL) fIsDeleted
1192 {
1193  return fIsDeleted;
1194 }
1195 
1196 //______________________________________________________________________________
1197 - (void) setContentView:(NSView *)cv
1198 {
1199  [super setContentView:cv];
1200  if ([cv isKindOfClass:[QuartzView class]])
1201  fContentView = (QuartzView *)cv;
1202  else
1203  fContentView = nil;
1204 }
1205 
1206 //______________________________________________________________________________
1207 - (void) setFIsDeleted : (BOOL) deleted
1208 {
1209  fIsDeleted = deleted;
1210 }
1211 
1212 #pragma mark - Forwaring: I want to forward a lot of property setters/getters to the content view.
1213 
1214 //______________________________________________________________________________
1215 - (void) forwardInvocation : (NSInvocation *) anInvocation
1216 {
1217  if (!fContentView)
1218  return;
1219 
1220  if ([fContentView respondsToSelector : [anInvocation selector]]) {
1221  [anInvocation invokeWithTarget : fContentView];
1222  } else {
1223  [super forwardInvocation : anInvocation];
1224  }
1225 }
1226 
1227 //______________________________________________________________________________
1228 - (NSMethodSignature*) methodSignatureForSelector : (SEL) selector
1229 {
1230  NSMethodSignature *signature = [super methodSignatureForSelector : selector];
1231 
1232  if (!signature) {
1233  if (fContentView)
1234  signature = [fContentView methodSignatureForSelector : selector];
1235  }
1236 
1237  return signature;
1238 }
1239 
1240 //______________________________________________________________________________
1241 - (void) addTransientWindow : (QuartzWindow *) window
1242 {
1243  //Transient window: all the popups (menus, dialogs, popups, comboboxes, etc.)
1244  //always should be on the top of its 'parent' window.
1245  //To enforce this ordering, I have to connect such windows with parent/child
1246  //relation (it's not the same as a view hierarchy - both child and parent
1247  //windows are top-level windows).
1248 
1249  assert(window != nil && "-addTransientWindow:, parameter 'window' is nil");
1250 
1251  window.fMainWindow = self;
1252 
1253  if (window.fMapState != kIsViewable) {
1254  //If I add it as child, it'll immediately make a window visible
1255  //and this thing sucks.
1256  window.fDelayedTransient = YES;
1257  } else {
1258  [self addChildWindow : window ordered : NSWindowAbove];
1259  window.fDelayedTransient = NO;
1260  }
1261 }
1262 
1263 //______________________________________________________________________________
1264 - (void) makeKeyAndOrderFront : (id) sender
1265 {
1266 #pragma unused(sender)
1267 
1268  //The more I know Cocoa, the less I like it.
1269  //Window behavior between spaces is a total mess.
1270  //Set the window to join all spaces.
1271 #ifdef MAC_OS_X_VERSION_10_9
1272  [self setCollectionBehavior : NSWindowCollectionBehaviorMoveToActiveSpace];
1273 #else
1274  [self setCollectionBehavior : NSWindowCollectionBehaviorCanJoinAllSpaces];
1275 #endif
1276  //now bring it to the front, it will appear on the active space.
1277  [super makeKeyAndOrderFront : self];
1278  //then reset the collection behavior to default, so the window
1279  [self setCollectionBehavior : NSWindowCollectionBehaviorDefault];
1280 }
1281 
1282 //______________________________________________________________________________
1283 - (void) setFDelayedTransient : (BOOL) d
1284 {
1285  fDelayedTransient = d;
1286 }
1287 
1288 //______________________________________________________________________________
1290 {
1291  return fShapeCombineMask;
1292 }
1293 
1294 //______________________________________________________________________________
1295 - (void) setFShapeCombineMask : (QuartzImage *) mask
1296 {
1297  if (mask != fShapeCombineMask) {
1298  [fShapeCombineMask release];
1299  if (mask) {
1300  fShapeCombineMask = [mask retain];
1301  //TODO: Check window's shadow???
1302  }
1303  }
1304 }
1305 
1306 #pragma mark - X11Drawable's protocol.
1307 
1308 //______________________________________________________________________________
1309 - (BOOL) fIsPixmap
1310 {
1311  //Never.
1312  return NO;
1313 }
1314 
1315 //______________________________________________________________________________
1317 {
1318  //Never.
1319  return NO;
1320 }
1321 
1322 //______________________________________________________________________________
1323 - (int) fX
1324 {
1325  return X11::GlobalXCocoaToROOT(self.frame.origin.x);
1326 }
1327 
1328 //______________________________________________________________________________
1329 - (int) fY
1330 {
1331  return X11::GlobalYCocoaToROOT(self.frame.origin.y + self.frame.size.height);
1332 }
1333 
1334 //______________________________________________________________________________
1335 - (unsigned) fWidth
1336 {
1337  return self.frame.size.width;
1338 }
1339 
1340 //______________________________________________________________________________
1341 - (unsigned) fHeight
1342 {
1343  //NSWindow's frame (height component) also includes title-bar.
1344  //So I have to use content view's height.
1345  //Obviously, there is a "hole" == 22 pixels.
1346  assert(fContentView != nil && "-fHeight:, content view is nil");
1347 
1348  return fContentView.frame.size.height;
1349 }
1350 
1351 //______________________________________________________________________________
1352 - (void) setDrawableSize : (NSSize) newSize
1353 {
1354  //Can not simply do self.frame.size = newSize.
1355  assert(!(newSize.width < 0) && "-setDrawableSize:, width is negative");
1356  assert(!(newSize.height < 0) && "-setDrawableSize:, height is negative");
1357 
1358  NSRect frame = self.frame;
1359  //dY is potentially a titlebar height.
1360  const CGFloat dY = fContentView ? frame.size.height - fContentView.frame.size.height : 0.;
1361  //Adjust the frame.
1362  frame.origin.y = frame.origin.y + frame.size.height - newSize.height - dY;
1363  frame.size = newSize;
1364  frame.size.height += dY;
1365  [self setFrame : frame display : YES];
1366 }
1367 
1368 //______________________________________________________________________________
1369 - (void) setX : (int) x Y : (int) y width : (unsigned) w height : (unsigned) h
1370 {
1371  NSSize newSize = {};
1372  newSize.width = w;
1373  newSize.height = h;
1374  [self setContentSize : newSize];
1375 
1376  //Check how this is affected by title bar's height.
1377  NSPoint topLeft = {};
1378  topLeft.x = X11::GlobalXROOTToCocoa(x);
1379  topLeft.y = X11::GlobalYROOTToCocoa(y);
1380 
1381  [self setFrameTopLeftPoint : topLeft];
1382 }
1383 
1384 //______________________________________________________________________________
1385 - (void) setX : (int) x Y : (int) y
1386 {
1387  NSPoint topLeft = {};
1388  topLeft.x = X11::GlobalXROOTToCocoa(x);
1389  topLeft.y = X11::GlobalYROOTToCocoa(y);
1390 
1391  [self setFrameTopLeftPoint : topLeft];
1392 }
1393 
1394 //______________________________________________________________________________
1395 - (void) copy : (NSObject<X11Drawable> *) src area : (X11::Rectangle) area withMask : (QuartzImage *) mask
1396  clipOrigin : (X11::Point) clipXY toPoint : (X11::Point) dstPoint
1397 {
1398  if (!fContentView)
1399  return;
1400 
1401  [fContentView copy : src area : area withMask : mask clipOrigin : clipXY toPoint : dstPoint];
1402 }
1403 
1404 //______________________________________________________________________________
1405 - (unsigned char *) readColorBits : (X11::Rectangle) area
1406 {
1407  if (!fContentView)
1408  return nullptr;
1409 
1410  return [fContentView readColorBits : area];
1411 }
1412 
1413 #pragma mark - X11Window protocol's implementation.
1414 
1415 //______________________________________________________________________________
1416 - (QuartzView *) fParentView
1417 {
1418  return nil;
1419 }
1420 
1421 //______________________________________________________________________________
1422 - (void) setFParentView : (QuartzView *) parent
1423 {
1424 #pragma unused(parent)
1425 }
1426 
1427 //______________________________________________________________________________
1428 - (NSView<X11Window> *) fContentView
1429 {
1430  return fContentView;
1431 }
1432 
1433 //______________________________________________________________________________
1435 {
1436  return self;
1437 }
1438 
1439 //... many forwards to fContentView.
1440 
1441 //______________________________________________________________________________
1442 - (void) setFBackgroundPixel : (unsigned long) backgroundColor
1443 {
1444  if (!fContentView)
1445  return;
1446 
1447  if (!fShapeCombineMask) {
1448  CGFloat rgba[] = {0., 0., 0., 1.};
1449  X11::PixelToRGB(backgroundColor, rgba);
1450 
1451  [self setBackgroundColor : [NSColor colorWithColorSpace : [NSColorSpace deviceRGBColorSpace] components : rgba count : 4]];
1452  }
1453 
1454  fContentView.fBackgroundPixel = backgroundColor;
1455 }
1456 
1457 //______________________________________________________________________________
1458 - (unsigned long) fBackgroundPixel
1459 {
1460  if (!fContentView)
1461  return 0;
1462 
1464 }
1465 
1466 //______________________________________________________________________________
1467 - (int) fMapState
1468 {
1469  //Top-level window can be only kIsViewable or kIsUnmapped (not unviewable).
1470  if (!fContentView)
1471  return kIsUnmapped;
1472 
1473  if ([fContentView isHidden])
1474  return kIsUnmapped;
1475 
1476  return kIsViewable;
1477 }
1478 
1479 //______________________________________________________________________________
1480 - (void) addChild : (NSView<X11Window> *) child
1481 {
1482  assert(child != nil && "-addChild:, parameter 'child' is nil");
1483 
1484  if (!fContentView) {
1485  //This can happen only in case of re-parent operation.
1486  assert([child isKindOfClass : [QuartzView class]] &&
1487  "-addChild: gl view in a top-level window as content view is not supported");
1488 
1489  fContentView = (QuartzView *)child;
1490  [self setContentView : child];
1491  fContentView.fParentView = nil;
1492  } else
1493  [fContentView addChild : child];
1494 }
1495 
1496 //______________________________________________________________________________
1497 - (void) getAttributes : (WindowAttributes_t *) attr
1498 {
1499  if (!fContentView)
1500  return;
1501 
1502  assert(attr && "-getAttributes:, parameter 'attr' is nil");
1503 
1504  X11::GetWindowAttributes(self, attr);
1505 }
1506 
1507 //______________________________________________________________________________
1508 - (void) setAttributes : (const SetWindowAttributes_t *) attr
1509 {
1510  assert(attr != 0 && "-setAttributes:, parameter 'attr' is null");
1511 
1512 #ifdef DEBUG_ROOT_COCOA
1513  log_attributes(attr, self.fID);
1514 #endif
1515 
1516  X11::SetWindowAttributes(attr, self);
1517 }
1518 
1519 //______________________________________________________________________________
1521 {
1522  if (!fContentView)
1523  return;
1524 
1525  const Util::AutoreleasePool pool;
1526 
1527  [fContentView setHidden : NO];
1528  [self makeKeyAndOrderFront : self];
1530 
1531  if (fDelayedTransient) {
1532  fDelayedTransient = NO;
1533  [fMainWindow addChildWindow : self ordered : NSWindowAbove];
1534  }
1535 }
1536 
1537 //______________________________________________________________________________
1539 {
1540  if (!fContentView)
1541  return;
1542 
1543  const Util::AutoreleasePool pool;
1544 
1545  [fContentView setHidden : NO];
1546  [self makeKeyAndOrderFront : self];
1548 
1549  if (fDelayedTransient) {
1550  fDelayedTransient = NO;
1551  [fMainWindow addChildWindow : self ordered : NSWindowAbove];
1552  }
1553 }
1554 
1555 //______________________________________________________________________________
1557 {
1558  if (!fContentView)
1559  return;
1560 
1561  const Util::AutoreleasePool pool;
1562 
1565 }
1566 
1567 //______________________________________________________________________________
1569 {
1570  if (!fContentView)
1571  return;
1572 
1573  [fContentView setHidden : YES];
1574  [self orderOut : self];
1575 
1576  if (fMainWindow && !fDelayedTransient) {
1577  [fMainWindow removeChildWindow : self];
1578  fMainWindow = nil;
1579  }
1580 }
1581 
1582 #pragma mark - Events.
1583 
1584 //______________________________________________________________________________
1585 - (void) sendEvent : (NSEvent *) theEvent
1586 {
1587  //With XQuartz, if you open a menu and try to move a window without closing this menu,
1588  //window does not move, menu closes, and after that you can start draggin a window again.
1589  //With Cocoa I can not do such a thing (window WILL move), but still can report button release event
1590  //to close a menu.
1591  if (!fContentView)
1592  return;
1593 
1594  if (theEvent.type == Details::kLeftMouseDown || theEvent.type == Details::kRightMouseDown) {
1595  bool generateFakeRelease = false;
1596 
1597  const NSPoint windowPoint = [theEvent locationInWindow];
1598 
1599  if (windowPoint.x <= 4 || windowPoint.x >= self.fWidth - 4)
1600  generateFakeRelease = true;
1601 
1602  if (windowPoint.y <= 4 || windowPoint.y >= self.fHeight - 4)
1603  generateFakeRelease = true;
1604 
1605  const NSPoint viewPoint = [fContentView convertPoint : windowPoint fromView : nil];
1606 
1607  if (viewPoint.y <= 0 && windowPoint.y >= 0)
1608  generateFakeRelease = true;
1609 
1610  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
1611  "-sendEvent:, gVirtualX is either null or not of TGCocoa type");
1612 
1613  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
1614  if (vx->GetEventTranslator()->HasPointerGrab() && generateFakeRelease) {
1616  theEvent.type == Details::kLeftMouseDown ?
1617  kButton1 : kButton3);
1618  //Yes, ignore this event completely (this means, you are not able to immediately start
1619  //resizing a window, if some popup is open. Actually, this is more or less
1620  //the same as with XQuartz and X11 version.
1621  return;
1622  }
1623  }
1624 
1625  [super sendEvent : theEvent];
1626 }
1627 
1628 #pragma mark - NSWindowDelegate's methods.
1629 
1630 //______________________________________________________________________________
1631 - (BOOL) windowShouldClose : (id) sender
1632 {
1633 #pragma unused(sender)
1634  if (!fContentView)
1635  return NO;
1636 
1637  if ([[self childWindows] count])
1638  return NO;
1639 
1640  //Prepare client message for a window.
1641  Event_t closeEvent = {};
1642  closeEvent.fWindow = fContentView.fID;
1643  closeEvent.fType = kClientMessage;
1644  closeEvent.fFormat = 32;//Taken from GUI classes.
1645  closeEvent.fHandle = TGCocoa::fgDeleteWindowAtom;
1646  closeEvent.fUser[0] = TGCocoa::fgDeleteWindowAtom;
1647  //Place it into the queue.
1648  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
1649  "-windowShouldClose:, gVirtualX is either null or has a type different from TGCocoa");
1650  ((TGCocoa *)gVirtualX)->SendEvent(fContentView.fID, &closeEvent);
1651 
1652  //Do not let AppKit to close a window,
1653  //ROOT will do.
1654  return NO;
1655 }
1656 
1657 //______________________________________________________________________________
1658 - (void) windowDidBecomeKey : (NSNotification *) aNotification
1659 {
1660 #pragma unused(aNotification)
1661 
1662  if (!fContentView)
1663  return;
1664 
1666  fHasFocus = YES;
1667  //
1668  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
1669  "-windowDidBecomeKey:, gVirtualX is null or not of TGCocoa type");
1670  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
1672  }
1673 }
1674 
1675 
1676 //______________________________________________________________________________
1677 - (void) windowDidResignKey : (NSNotification *) aNotification
1678 {
1679 #pragma unused(aNotification)
1680  fHasFocus = NO;
1681 }
1682 
1683 @end
1684 
1685 #pragma mark - Passive key grab info.
1686 
1687 @implementation PassiveKeyGrab
1688 
1689 //______________________________________________________________________________
1690 - (id) initWithKey : (unichar) keyCode modifiers : (NSUInteger) modifiers
1691 {
1692  if (self = [super init]) {
1693  fKeyCode = keyCode;
1694  fModifiers = modifiers;
1695  }
1696 
1697  return self;
1698 }
1699 
1700 //______________________________________________________________________________
1701 - (BOOL) matchKey : (unichar) keyCode modifiers : (NSUInteger) modifiers
1702 {
1703  return keyCode == fKeyCode && modifiers == fModifiers;
1704 }
1705 
1706 //______________________________________________________________________________
1707 - (BOOL) matchKey : (unichar) keyCode
1708 {
1709  return keyCode == fKeyCode;
1710 }
1711 
1712 //______________________________________________________________________________
1713 - (unichar) fKeyCode
1714 {
1715  return fKeyCode;
1716 }
1717 
1718 //______________________________________________________________________________
1719 - (NSUInteger) fModifiers
1720 {
1721  return fModifiers;
1722 }
1723 
1724 @end
1725 
1726 #pragma mark - X11 property emulation.
1727 
1728 @interface QuartzWindowProperty : NSObject {
1729  NSData *fPropertyData;
1730  Atom_t fType;
1731  unsigned fFormat;
1732 }
1733 
1734 @property (nonatomic, readonly) Atom_t fType;
1735 
1736 @end
1737 
1738 @implementation QuartzWindowProperty
1739 
1740 @synthesize fType;
1741 
1742 //______________________________________________________________________________
1743 - (id) initWithData : (unsigned char *) data size : (unsigned) dataSize type : (Atom_t) type format : (unsigned) format
1744 {
1745  if (self = [super init]) {
1746  //Memory is zero-initialized, but just to make it explicit:
1747  fPropertyData = nil;
1748  fType = 0;
1749  fFormat = 0;
1750 
1751  [self resetPropertyData : data size : dataSize type : type format : format];
1752  }
1753 
1754  return self;
1755 }
1756 
1757 //______________________________________________________________________________
1758 - (void) dealloc
1759 {
1760  [fPropertyData release];
1761 
1762  [super dealloc];
1763 }
1764 
1765 //______________________________________________________________________________
1766 - (void) resetPropertyData : (unsigned char *) data size : (unsigned) dataSize
1767  type : (Atom_t) type format : (unsigned) format
1768 {
1769  [fPropertyData release];
1770 
1771  fFormat = format;
1772  if (format == 16)
1773  dataSize *= 2;
1774  else if (format == 32)
1775  dataSize *= 4;
1776 
1777  fPropertyData = [[NSData dataWithBytes : data length : dataSize] retain];
1778 
1779  fType = type;
1780 }
1781 
1782 //______________________________________________________________________________
1783 - (NSData *) fPropertyData
1784 {
1785  return fPropertyData;
1786 }
1787 
1788 //______________________________________________________________________________
1789 - (unsigned) fFormat
1790 {
1791  return fFormat;
1792 }
1793 
1794 @end
1795 
1796 #pragma mark - QuartzView.
1797 
1798 //
1799 //QuartzView is a children view (also is a content view for a top-level QuartzWindow).
1800 //
1801 
1802 @implementation QuartzView
1803 
1804 @synthesize fID;
1805 @synthesize fContext;
1806 /////////////////////
1807 //SetWindowAttributes_t/WindowAttributes_t
1808 @synthesize fEventMask;
1809 @synthesize fClass;
1810 @synthesize fDepth;
1811 @synthesize fBitGravity;
1812 @synthesize fWinGravity;
1813 @synthesize fBackgroundPixel;
1814 @synthesize fOverrideRedirect;
1815 //SetWindowAttributes_t/WindowAttributes_t
1816 /////////////////////
1817 @synthesize fHasFocus;
1818 @synthesize fParentView;
1819 
1820 @synthesize fPassiveGrabButton;
1821 @synthesize fPassiveGrabEventMask;
1822 @synthesize fPassiveGrabKeyModifiers;
1823 @synthesize fActiveGrabEventMask;
1824 @synthesize fPassiveGrabOwnerEvents;
1825 @synthesize fSnapshotDraw;
1826 @synthesize fCurrentCursor;
1827 @synthesize fIsDNDAware;
1828 
1829 #pragma mark - Lifetime.
1830 
1831 //______________________________________________________________________________
1832 - (id) initWithFrame : (NSRect) frame windowAttributes : (const SetWindowAttributes_t *)attr
1833 {
1834  if (self = [super initWithFrame : frame]) {
1835  //Make this explicit (though memory is zero initialized).
1836  fBackBuffer = nil;
1837  fID = 0;
1838 
1839  //Passive grab parameters.
1840  fPassiveGrabButton = -1;//0 is kAnyButton.
1843 
1844  fPassiveKeyGrabs = [[NSMutableArray alloc] init];
1845 
1846  [self setCanDrawConcurrently : NO];
1847 
1848  [self setHidden : YES];
1849  //Actually, check if view need this.
1850  //
1851  if (attr)
1852  X11::SetWindowAttributes(attr, self);
1853 
1855  fX11Properties = [[NSMutableDictionary alloc] init];
1856 
1859  fActiveGrabOwnerEvents = YES;
1860  }
1861 
1862  return self;
1863 }
1864 
1865 //______________________________________________________________________________
1866 - (void) dealloc
1867 {
1868  [fBackBuffer release];
1869  [fPassiveKeyGrabs release];
1870  [fX11Properties release];
1871  [fBackgroundPixmap release];
1872  [super dealloc];
1873 }
1874 
1875 #pragma mark - Tracking area.
1876 
1877 //Tracking area is required to ... track mouse motion events inside a view.
1878 
1879 //______________________________________________________________________________
1880 - (void) updateTrackingAreas
1881 {
1882  [super updateTrackingAreas];
1883 
1884  if (!fID)
1885  return;
1886 
1887  const Util::AutoreleasePool pool;
1888 
1889  if (NSArray *trackingArray = [self trackingAreas]) {
1890  const NSUInteger size = [trackingArray count];
1891  for (NSUInteger i = 0; i < size; ++i) {
1892  NSTrackingArea * const t = [trackingArray objectAtIndex : i];
1893  [self removeTrackingArea : t];
1894  }
1895  }
1896 
1897  const NSUInteger trackerOptions = NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited |
1898  NSTrackingActiveInActiveApp | NSTrackingInVisibleRect |
1899  NSTrackingEnabledDuringMouseDrag | NSTrackingCursorUpdate;
1900 
1901  NSRect frame = {};
1902  frame.size.width = self.fWidth;
1903  frame.size.height = self.fHeight;
1904 
1905  NSTrackingArea * const tracker = [[NSTrackingArea alloc] initWithRect : frame
1906  options : trackerOptions owner : self userInfo : nil];
1907  [self addTrackingArea : tracker];
1908  [tracker release];
1909 }
1910 
1911 //______________________________________________________________________________
1912 - (void) updateTrackingAreasAfterRaise
1913 {
1914  [self updateTrackingAreas];
1915 
1916  for (QuartzView *childView in [self subviews])
1917  [childView updateTrackingAreasAfterRaise];
1918 }
1919 
1920 #pragma mark - X11Drawable protocol.
1921 
1922 //______________________________________________________________________________
1923 - (BOOL) fIsPixmap
1924 {
1925  return NO;
1926 }
1927 
1928 //______________________________________________________________________________
1930 {
1931  return NO;
1932 }
1933 
1934 //______________________________________________________________________________
1935 - (int) fX
1936 {
1937  return self.frame.origin.x;
1938 }
1939 
1940 //______________________________________________________________________________
1941 - (int) fY
1942 {
1943  return self.frame.origin.y;
1944 }
1945 
1946 //______________________________________________________________________________
1947 - (unsigned) fWidth
1948 {
1949  return self.frame.size.width;
1950 }
1951 
1952 //______________________________________________________________________________
1953 - (unsigned) fHeight
1954 {
1955  return self.frame.size.height;
1956 }
1957 
1958 //______________________________________________________________________________
1959 - (void) setDrawableSize : (NSSize) newSize
1960 {
1961  assert(!(newSize.width < 0) && "-setDrawableSize, width is negative");
1962  assert(!(newSize.height < 0) && "-setDrawableSize, height is negative");
1963 
1964  //This will cause redraw(?)
1965 
1966  //In X11, resize changes the size, but upper-left corner is not changed.
1967  //In Cocoa, bottom-left is fixed.
1968  NSRect frame = self.frame;
1969  frame.size = newSize;
1970 
1971  self.frame = frame;
1972 }
1973 
1974 //______________________________________________________________________________
1975 - (void) setX : (int) x Y : (int) y width : (unsigned) w height : (unsigned) h
1976 {
1977  NSRect newFrame = {};
1978  newFrame.origin.x = x;
1979  newFrame.origin.y = y;
1980  newFrame.size.width = w;
1981  newFrame.size.height = h;
1982 
1983  self.frame = newFrame;
1984 }
1985 
1986 //______________________________________________________________________________
1987 - (void) setX : (int) x Y : (int) y
1988 {
1989  NSRect newFrame = self.frame;
1990  newFrame.origin.x = x;
1991  newFrame.origin.y = y;
1992 
1993  self.frame = newFrame;
1994 }
1995 
1996 //______________________________________________________________________________
1997 - (void) copyImage : (QuartzImage *) srcImage area : (X11::Rectangle) area
1998  withMask : (QuartzImage *) mask clipOrigin : (X11::Point) clipXY
1999  toPoint : (X11::Point) dstPoint
2000 {
2001  //Check parameters.
2002  assert(srcImage != nil &&
2003  "-copyImage:area:withMask:clipOrigin:toPoint:, parameter 'srcImage' is nil");
2004  assert(srcImage.fImage != nil &&
2005  "-copyImage:area:withMask:clipOrigin:toPoint:, srcImage.fImage is nil");
2006 
2007  //Check self.
2008  assert(self.fContext != 0 &&
2009  "-copyImage:area:withMask:clipOrigin:toPoint:, self.fContext is null");
2010 
2011  if (!X11::AdjustCropArea(srcImage, area)) {
2012  NSLog(@"QuartzView: -copyImage:area:withMask:clipOrigin:toPoint:,"
2013  " srcRect and copyRect do not intersect");
2014  return;
2015  }
2016 
2017  //No RAII for subImage, since it can be really subimage or image itself and
2018  //in these cases there is no need to release image.
2019  CGImageRef subImage = 0;
2020  bool needSubImage = false;
2021  if (area.fX || area.fY || area.fWidth != srcImage.fWidth || area.fHeight != srcImage.fHeight) {
2022  needSubImage = true;
2023  subImage = X11::CreateSubImage(srcImage, area);
2024  if (!subImage) {
2025  NSLog(@"QuartzView: -copyImage:area:withMask:clipOrigin:toPoint:,"
2026  " subimage creation failed");
2027  return;
2028  }
2029  } else
2030  subImage = srcImage.fImage;
2031 
2032  //Save context state.
2033  const Quartz::CGStateGuard ctxGuard(self.fContext);
2034 
2035  //Scale and translate to undo isFlipped.
2036  CGContextTranslateCTM(self.fContext, 0., self.fHeight);
2037  CGContextScaleCTM(self.fContext, 1., -1.);
2038  //Set clip mask on a context.
2039 
2040  if (mask) {
2041  assert(mask.fImage != nil &&
2042  "-copyImage:area:withMask:clipOrigin:toPoint:, mask.fImage is nil");
2043  assert(CGImageIsMask(mask.fImage) == true &&
2044  "-copyImage:area:withMask:clipOrigin:toPoint:, mask.fImage is not a mask");
2045  //clipXY.fY = X11::LocalYROOTToCocoa(self, clipXY.fY + mask.fHeight);
2046  const CGFloat clipY = X11::LocalYROOTToCocoa(self, CGFloat(clipXY.fY) + mask.fHeight);
2047  //const CGRect clipRect = CGRectMake(clipXY.fX, clipXY.fY, mask.fWidth, mask.fHeight);
2048  const CGRect clipRect = CGRectMake(clipXY.fX, clipY, mask.fWidth, mask.fHeight);
2049  CGContextClipToMask(self.fContext, clipRect, mask.fImage);
2050  }
2051 
2052  //Convert from X11 to Cocoa (as soon as we scaled y * -1).
2053  //dstPoint.fY = X11::LocalYROOTToCocoa(self, dstPoint.fY + area.fHeight);
2054  const CGFloat dstY = X11::LocalYROOTToCocoa(self, CGFloat(dstPoint.fY) + area.fHeight);
2055  //const CGRect imageRect = CGRectMake(dstPoint.fX, dstPoint.fY, area.fWidth, area.fHeight);
2056  const CGRect imageRect = CGRectMake(dstPoint.fX, dstY, area.fWidth, area.fHeight);
2057  CGContextDrawImage(self.fContext, imageRect, subImage);
2058 
2059  if (needSubImage)
2060  CGImageRelease(subImage);
2061 }
2062 
2063 //______________________________________________________________________________
2064 - (void) copyView : (QuartzView *) srcView area : (X11::Rectangle) area toPoint : (X11::Point) dstPoint
2065 {
2066  //To copy one "window" to another "window", I have to ask source QuartzView to draw intself into
2067  //bitmap, and copy this bitmap into the destination view.
2068 
2069  assert(srcView != nil && "-copyView:area:toPoint:, parameter 'srcView' is nil");
2070 
2071  const NSRect frame = [srcView frame];
2072  //imageRep is in autorelease pool now.
2073  NSBitmapImageRep * const imageRep = [srcView bitmapImageRepForCachingDisplayInRect : frame];
2074  if (!imageRep) {
2075  NSLog(@"QuartzView: -copyView:area:toPoint failed");
2076  return;
2077  }
2078 
2079  assert(srcView != nil && "-copyView:area:toPoint:, parameter 'srcView' is nil");
2080  assert(self.fContext != 0 && "-copyView:area:toPoint, self.fContext is null");
2081 
2082  //It can happen, that src and self are the same.
2083  //cacheDisplayInRect calls drawRect with bitmap context
2084  //(and this will reset self.fContext: I have to save/restore it.
2085  CGContextRef ctx = srcView.fContext;
2086  srcView.fSnapshotDraw = YES;
2087  [srcView cacheDisplayInRect : frame toBitmapImageRep : imageRep];
2088  srcView.fSnapshotDraw = NO;
2089  srcView.fContext = ctx;
2090 
2091  const CGRect subImageRect = CGRectMake(area.fX, area.fY, area.fWidth, area.fHeight);
2092  const Util::CFScopeGuard<CGImageRef> subImage(CGImageCreateWithImageInRect(imageRep.CGImage, subImageRect));
2093 
2094  if (!subImage.Get()) {
2095  NSLog(@"QuartzView: -copyView:area:toPoint, CGImageCreateWithImageInRect failed");
2096  return;
2097  }
2098 
2099  const Quartz::CGStateGuard ctxGuard(self.fContext);
2100  const CGRect imageRect = CGRectMake(dstPoint.fX,
2101  [self visibleRect].size.height - (CGFloat(dstPoint.fY) + area.fHeight),
2102  area.fWidth, area.fHeight);
2103 
2104  CGContextTranslateCTM(self.fContext, 0., [self visibleRect].size.height);
2105  CGContextScaleCTM(self.fContext, 1., -1.);
2106 
2107  CGContextDrawImage(self.fContext, imageRect, subImage.Get());
2108 }
2109 
2110 //______________________________________________________________________________
2111 - (void) copyPixmap : (QuartzPixmap *) srcPixmap area : (X11::Rectangle) area
2112  withMask : (QuartzImage *) mask clipOrigin : (X11::Point) clipXY toPoint : (X11::Point) dstPoint
2113 {
2114  //Check parameters.
2115  assert(srcPixmap != nil && "-copyPixmap:area:withMask:clipOrigin:toPoint:, parameter 'srcPixmap' is nil");
2116 
2117  if (!X11::AdjustCropArea(srcPixmap, area)) {
2118  NSLog(@"QuartzView: -copyPixmap:area:withMask:clipOrigin:toPoint,"
2119  " no intersection between pixmap rectangle and cropArea");
2120  return;
2121  }
2122 
2123  //Check self.
2124  assert(self.fContext != 0 &&
2125  "-copyPixmap:area:withMask:clipOrigin:toPoint:, self.fContext is null");
2126 
2127  //Save context state.
2128  const Quartz::CGStateGuard ctxGuard(self.fContext);
2129 
2130  CGContextTranslateCTM(self.fContext, 0., self.frame.size.height);//???
2131  CGContextScaleCTM(self.fContext, 1., -1.);
2132 
2133  const Util::CFScopeGuard<CGImageRef> imageFromPixmap([srcPixmap createImageFromPixmap]);
2134  assert(imageFromPixmap.Get() != 0 &&
2135  "-copyPixmap:area:withMask:clipOrigin:toPoint:, createImageFromPixmap failed");
2136 
2137  CGImageRef subImage = 0;
2138  bool needSubImage = false;
2139  if (area.fX || area.fY || area.fWidth != srcPixmap.fWidth || area.fHeight != srcPixmap.fHeight) {
2140  needSubImage = true;
2141  const CGRect subImageRect = CGRectMake(area.fX, area.fY, area.fHeight, area.fWidth);
2142  subImage = CGImageCreateWithImageInRect(imageFromPixmap.Get(), subImageRect);
2143  if (!subImage) {
2144  NSLog(@"QuartzView: -copyImage:area:withMask:clipOrigin:toPoint:,"
2145  " subimage creation failed");
2146  return;
2147  }
2148  } else
2149  subImage = imageFromPixmap.Get();
2150 
2151  if (mask) {
2152  assert(mask.fImage != nil &&
2153  "-copyPixmap:area:withMask:clipOrigin:toPoint:, mask.fImage is nil");
2154  assert(CGImageIsMask(mask.fImage) == true &&
2155  "-copyPixmap:area:withMask:clipOrigin:toPoint:, mask.fImage is not a mask");
2156 
2157  //clipXY.fY = X11::LocalYROOTToCocoa(self, clipXY.fY + mask.fHeight);
2158  const CGFloat clipY = X11::LocalYROOTToCocoa(self, CGFloat(clipXY.fY) + mask.fHeight);
2159  //const CGRect clipRect = CGRectMake(clipXY.fX, clipXY.fY, mask.fWidth, mask.fHeight);
2160  const CGRect clipRect = CGRectMake(clipXY.fX, clipY, mask.fWidth, mask.fHeight);
2161  CGContextClipToMask(self.fContext, clipRect, mask.fImage);
2162  }
2163 
2164  //dstPoint.fY = X11::LocalYCocoaToROOT(self, dstPoint.fY + area.fHeight);
2165  const CGFloat dstY = X11::LocalYCocoaToROOT(self, CGFloat(dstPoint.fY) + area.fHeight);
2166  const CGRect imageRect = CGRectMake(dstPoint.fX, dstY, area.fWidth, area.fHeight);
2167  CGContextDrawImage(self.fContext, imageRect, imageFromPixmap.Get());
2168 
2169  if (needSubImage)
2170  CGImageRelease(subImage);
2171 }
2172 
2173 
2174 //______________________________________________________________________________
2175 - (void) copyImage : (QuartzImage *) srcImage area : (X11::Rectangle) area
2176  toPoint : (X11::Point) dstPoint
2177 {
2178  assert(srcImage != nil && "-copyImage:area:toPoint:, parameter 'srcImage' is nil");
2179  assert(srcImage.fImage != nil && "-copyImage:area:toPoint:, srcImage.fImage is nil");
2180  assert(self.fContext != 0 && "-copyImage:area:toPoint:, fContext is null");
2181 
2182  if (!X11::AdjustCropArea(srcImage, area)) {
2183  NSLog(@"QuartzView: -copyImage:area:toPoint, image and copy area do not intersect");
2184  return;
2185  }
2186 
2187  CGImageRef subImage = 0;
2188  bool needSubImage = false;
2189  if (area.fX || area.fY || area.fWidth != srcImage.fWidth || area.fHeight != srcImage.fHeight) {
2190  needSubImage = true;
2191  subImage = X11::CreateSubImage(srcImage, area);
2192  if (!subImage) {
2193  NSLog(@"QuartzView: -copyImage:area:toPoint:, subimage creation failed");
2194  return;
2195  }
2196  } else
2197  subImage = srcImage.fImage;
2198 
2199  const Quartz::CGStateGuard ctxGuard(self.fContext);
2200 
2201  CGContextTranslateCTM(self.fContext, 0., self.fHeight);
2202  CGContextScaleCTM(self.fContext, 1., -1.);
2203 
2204  //dstPoint.fY = X11::LocalYCocoaToROOT(self, dstPoint.fY + area.fHeight);
2205  const CGFloat dstY = X11::LocalYCocoaToROOT(self, CGFloat(dstPoint.fY) + area.fHeight);
2206  //const CGRect imageRect = CGRectMake(dstPoint.fX, dstPoint.fY, area.fWidth, area.fHeight);
2207  const CGRect imageRect = CGRectMake(dstPoint.fX, dstY, area.fWidth, area.fHeight);
2208  CGContextDrawImage(self.fContext, imageRect, subImage);
2209 
2210  if (needSubImage)
2211  CGImageRelease(subImage);
2212 }
2213 
2214 //______________________________________________________________________________
2215 - (void) copy : (NSObject<X11Drawable> *) src area : (X11::Rectangle) area
2216  withMask : (QuartzImage *)mask clipOrigin : (X11::Point) clipXY toPoint : (X11::Point) dstPoint
2217 {
2218  assert(src != nil && "-copy:area:withMask:clipOrigin:toPoint:, parameter 'src' is nil");
2219  assert(area.fWidth && area.fHeight && "-copy:area:withMask:clipOrigin:toPoint:, area to copy is empty");
2220 
2221  if ([src isKindOfClass : [QuartzWindow class]]) {
2222  //Forget about mask (can I have it???)
2223  QuartzWindow * const qw = (QuartzWindow *)src;
2224  //Will not work with OpenGL.
2225  [self copyView : (QuartzView *)qw.fContentView area : area toPoint : dstPoint];
2226  } else if ([src isKindOfClass : [QuartzView class]]) {
2227  //Forget about mask (can I have it???)
2228  [self copyView : (QuartzView *)src area : area toPoint : dstPoint];
2229  } else if ([src isKindOfClass : [QuartzPixmap class]]) {
2230  [self copyPixmap : (QuartzPixmap *)src area : area withMask : mask clipOrigin : clipXY toPoint : dstPoint];
2231  } else if ([src isKindOfClass : [QuartzImage class]]) {
2232  [self copyImage : (QuartzImage *)src area : area withMask : mask clipOrigin : clipXY toPoint : dstPoint];
2233  } else {
2234  assert(0 && "-copy:area:withMask:clipOrigin:toPoint:, src is of unknown type");
2235  }
2236 }
2237 
2238 //______________________________________________________________________________
2239 - (unsigned char *) readColorBits : (X11::Rectangle) area
2240 {
2241  //This is quite a bad idea - to read pixels back from a view,
2242  //but our GUI does exactly this. In case of Cocoa it's expensive
2243  //and not guaranteed to work.
2244 
2245  assert(area.fWidth && area.fHeight && "-readColorBits:, area to copy is empty");
2246 
2247  //int, not unsigned or something - to keep it simple.
2248  const NSRect visRect = [self visibleRect];
2249  const X11::Rectangle srcRect(int(visRect.origin.x), int(visRect.origin.y),
2250  unsigned(visRect.size.width), unsigned(visRect.size.height));
2251 
2252  if (!X11::AdjustCropArea(srcRect, area)) {
2253  NSLog(@"QuartzView: -readColorBits:, visible rect of view and copy area do not intersect");
2254  return nullptr;
2255  }
2256 
2257  //imageRep is autoreleased.
2258  NSBitmapImageRep * const imageRep = [self bitmapImageRepForCachingDisplayInRect : visRect];
2259  if (!imageRep) {
2260  NSLog(@"QuartzView: -readColorBits:, bitmapImageRepForCachingDisplayInRect failed");
2261  return nullptr;
2262  }
2263 
2264  CGContextRef ctx = self.fContext; //Save old context if any.
2265  [self cacheDisplayInRect : visRect toBitmapImageRep : imageRep];
2266  self.fContext = ctx; //Restore old context.
2267  //
2268  const NSInteger bitsPerPixel = [imageRep bitsPerPixel];
2269 
2270  assert(bitsPerPixel == 32 && "-readColorBits:, no alpha channel???");
2271  const NSInteger bytesPerRow = [imageRep bytesPerRow];
2272  unsigned dataWidth = bytesPerRow / (bitsPerPixel / 8);//assume an octet :(
2273 
2274  unsigned char *srcData = nullptr;
2275  std::vector<unsigned char> downscaled;
2276  if ([[NSScreen mainScreen] backingScaleFactor] > 1 && imageRep.CGImage) {
2277  downscaled = X11::DownscaledImageData(area.fWidth, area.fHeight, imageRep.CGImage);
2278  if (downscaled.size())
2279  srcData = &downscaled[0];
2280  dataWidth = area.fWidth;
2281  } else
2282  srcData = [imageRep bitmapData];
2283 
2284  if (!srcData) {
2285  NSLog(@"QuartzView: -readColorBits:, failed to obtain backing store contents");
2286  return nullptr;
2287  }
2288 
2289  //We have a source data now. Let's allocate buffer for ROOT's GUI and convert source data.
2290  unsigned char *data = nullptr;
2291 
2292  try {
2293  data = new unsigned char[area.fWidth * area.fHeight * 4];//bgra?
2294  } catch (const std::bad_alloc &) {
2295  NSLog(@"QuartzView: -readColorBits:, memory allocation failed");
2296  return nullptr;
2297  }
2298 
2299  unsigned char *dstPixel = data;
2300  const unsigned char *line = srcData + area.fY * dataWidth * 4;
2301  const unsigned char *srcPixel = line + area.fX * 4;
2302 
2303  for (unsigned i = 0; i < area.fHeight; ++i) {
2304  for (unsigned j = 0; j < area.fWidth; ++j, srcPixel += 4, dstPixel += 4) {
2305  dstPixel[0] = srcPixel[2];
2306  dstPixel[1] = srcPixel[1];
2307  dstPixel[2] = srcPixel[0];
2308  dstPixel[3] = srcPixel[3];
2309  }
2310 
2311  line += dataWidth * 4;
2312  srcPixel = line + area.fX * 4;
2313  }
2314 
2315  return data;
2316 }
2317 
2318 //______________________________________________________________________________
2319 - (void) setFBackgroundPixmap : (QuartzImage *) pixmap
2320 {
2321  if (fBackgroundPixmap != pixmap) {
2322  [fBackgroundPixmap release];
2323  if (pixmap)
2324  fBackgroundPixmap = [pixmap retain];
2325  else
2326  fBackgroundPixmap = nil;
2327  }
2328 }
2329 
2330 //______________________________________________________________________________
2332 {
2333  //I do not autorelease, screw this idiom!
2334 
2335  return fBackgroundPixmap;
2336 }
2337 
2338 //______________________________________________________________________________
2339 - (int) fMapState
2340 {
2341  if ([self isHidden])
2342  return kIsUnmapped;
2343 
2344  for (QuartzView *parent = fParentView; parent; parent = parent.fParentView) {
2345  if ([parent isHidden])
2346  return kIsUnviewable;
2347  }
2348 
2349  return kIsViewable;
2350 }
2351 
2352 //______________________________________________________________________________
2353 - (BOOL) fHasFocus
2354 {
2355  //With the latest update clang became a bit more stupid.
2356  //Let's write a stupid useless cargo cult code
2357  //to make IT SHUT THE F... UP.
2358  (void)fHasFocus;
2359  return NO;
2360 }
2361 
2362 //______________________________________________________________________________
2363 - (void) setFHasFocus : (BOOL) focus
2364 {
2365 #pragma unused(focus)
2366  //With the latest update clang became a bit more stupid.
2367  //Let's write a stupid useless cargo cult code
2368  //to make IT SHUT THE F... UP.
2369  (void)fHasFocus;
2370 }
2371 
2372 //______________________________________________________________________________
2374 {
2375  return fBackBuffer;//No autorelease, I know the object's lifetime myself.
2376 }
2377 
2378 //______________________________________________________________________________
2379 - (void) setFBackBuffer : (QuartzPixmap *) backBuffer
2380 {
2381  if (fBackBuffer != backBuffer) {
2382  [fBackBuffer release];
2383 
2384  if (backBuffer)
2385  fBackBuffer = [backBuffer retain];
2386  else
2387  fBackBuffer = nil;
2388  }
2389 }
2390 
2391 //______________________________________________________________________________
2392 - (NSView<X11Window> *) fContentView
2393 {
2394  return self;
2395 }
2396 
2397 //______________________________________________________________________________
2399 {
2400  return (QuartzWindow *)[self window];
2401 }
2402 
2403 //______________________________________________________________________________
2405 {
2407 }
2408 
2409 //______________________________________________________________________________
2411 {
2413 }
2414 
2415 //______________________________________________________________________________
2416 - (void) activateGrab : (unsigned) eventMask ownerEvents : (BOOL) ownerEvents
2417 {
2419  fActiveGrabEventMask = eventMask;
2420  fActiveGrabOwnerEvents = ownerEvents;
2421 }
2422 
2423 //______________________________________________________________________________
2425 {
2428  fActiveGrabOwnerEvents = YES;
2429 }
2430 
2431 //______________________________________________________________________________
2432 - (BOOL) acceptsCrossingEvents : (unsigned) eventMask
2433 {
2434  bool accepts = fEventMask & eventMask;
2435 
2436  //In ROOT passive grabs are always with owner_events == true.
2438  accepts = accepts || (fPassiveGrabEventMask & eventMask);
2439 
2442  accepts = accepts || (fActiveGrabOwnerEvents & eventMask);
2443  else
2444  accepts = fActiveGrabOwnerEvents & eventMask;
2445  }
2446 
2447  return accepts;
2448 }
2449 
2450 //______________________________________________________________________________
2451 - (void) addChild : (NSView<X11Window> *) child
2452 {
2453  assert(child != nil && "-addChild:, parameter 'child' is nil");
2454 
2455  [self addSubview : child];
2456  child.fParentView = self;
2457 }
2458 
2459 //______________________________________________________________________________
2460 - (void) getAttributes : (WindowAttributes_t *) attr
2461 {
2462  assert(attr != 0 && "-getAttributes:, parameter 'attr' is null");
2463 
2464  X11::GetWindowAttributes(self, attr);
2465 }
2466 
2467 //______________________________________________________________________________
2468 - (void) setAttributes : (const SetWindowAttributes_t *)attr
2469 {
2470  assert(attr != 0 && "-setAttributes:, parameter 'attr' is null");
2471 
2472 #ifdef DEBUG_ROOT_COCOA
2473  log_attributes(attr, fID);
2474 #endif
2475 
2476  X11::SetWindowAttributes(attr, self);
2477 }
2478 
2479 //______________________________________________________________________________
2481 {
2482  //Move view to the top of subviews.
2483  QuartzView * const parent = fParentView;
2484  [self removeFromSuperview];
2485  [parent addSubview : self];
2486  [self setHidden : NO];
2487 }
2488 
2489 //______________________________________________________________________________
2491 {
2492  [self setHidden : NO];
2493 }
2494 
2495 //______________________________________________________________________________
2497 {
2498  for (QuartzView * v in [self subviews])
2499  [v setHidden : NO];
2500 }
2501 
2502 //______________________________________________________________________________
2504 {
2505  [self setHidden : YES];
2506 }
2507 
2508 //______________________________________________________________________________
2510 {
2511  return fIsOverlapped;
2512 }
2513 
2514 //______________________________________________________________________________
2515 - (void) setOverlapped : (BOOL) overlap
2516 {
2517  fIsOverlapped = overlap;
2518  for (NSView<X11Window> *child in [self subviews])
2519  [child setOverlapped : overlap];
2520 }
2521 
2522 //______________________________________________________________________________
2524 {
2525  //Now, I can not remove window and add it ...
2526  //For example, if you click on a tab, this:
2527  //1. Creates (potentially) a passive button grab
2528  //2. Raises this tab - changes the window order.
2529  //3. On a button release - grab is release.
2530  //The tough problem is, if I remove a view from subviews
2531  //and add it ... it will never receve the
2532  //release event thus a grab will 'hang' on
2533  //view leading to bugs and artifacts.
2534  //So instead I have to ... SORT!!!!!
2535 
2536  using namespace X11;//Comparators.
2537 
2538  for (QuartzView *sibling in [fParentView subviews]) {
2539  if (self == sibling)
2540  continue;
2541  if ([sibling isHidden])
2542  continue;
2543 
2544  if (NSEqualRects(sibling.frame, self.frame)) {
2545  [sibling setOverlapped : YES];
2546  [sibling setHidden : YES];
2547  }
2548  }
2549 
2550  [self setOverlapped : NO];
2551  //
2552  [self setHidden : NO];
2553  //
2554  [fParentView sortSubviewsUsingFunction : CompareViewsToRaise context : (void *)self];
2555  //
2556  [self updateTrackingAreasAfterRaise];
2557  //
2558  [self setNeedsDisplay : YES];
2559 }
2560 
2561 //______________________________________________________________________________
2563 {
2564  //See comment about sorting in -raiseWindow.
2565 
2566  using namespace X11;
2567 
2568  NSEnumerator * const reverseEnumerator = [[fParentView subviews] reverseObjectEnumerator];
2569  for (QuartzView *sibling in reverseEnumerator) {
2570  if (sibling == self)
2571  continue;
2572 
2573  if (NSEqualRects(sibling.frame, self.frame)) {
2574  [sibling setOverlapped : NO];
2575  //
2576  [sibling setHidden : NO];
2577  //
2578  [sibling setNeedsDisplay : YES];
2579  [self setOverlapped : YES];
2580  //
2581  [self setHidden : YES];
2582  //
2583  break;
2584  }
2585  }
2586 
2587  [fParentView sortSubviewsUsingFunction : CompareViewsToLower context : (void*)self];
2588 }
2589 
2590 //______________________________________________________________________________
2591 - (BOOL) isFlipped
2592 {
2593  //Now view's placement, geometry, moving and resizing can be
2594  //done with ROOT's (X11) coordinates without conversion - we're are 'flipped'.
2595  return YES;
2596 }
2597 
2598 //______________________________________________________________________________
2600 {
2601  if (self.fMapState == kIsViewable || fIsOverlapped == YES) {
2603  assert(dynamic_cast<TGCocoa *>(gVirtualX) &&
2604  "-configureNotifyTree, gVirtualX is either null or has type different from TGCocoa");
2605  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2606  vx->GetEventTranslator()->GenerateConfigureNotifyEvent(self, self.frame);
2607  }
2608 
2609  for (NSView<X11Window> *v in [self subviews])
2610  [v configureNotifyTree];
2611  }
2612 }
2613 
2614 #pragma mark - Key grabs.
2615 
2616 //______________________________________________________________________________
2617 - (void) addPassiveKeyGrab : (unichar) keyCode modifiers : (NSUInteger) modifiers
2618 {
2619  [self removePassiveKeyGrab : keyCode modifiers : modifiers];
2620  PassiveKeyGrab * const newGrab = [[PassiveKeyGrab alloc] initWithKey : keyCode
2621  modifiers : modifiers];
2622  [fPassiveKeyGrabs addObject : newGrab];
2623  [newGrab release];
2624 }
2625 
2626 //______________________________________________________________________________
2627 - (void) removePassiveKeyGrab : (unichar) keyCode modifiers : (NSUInteger) modifiers
2628 {
2629  const NSUInteger count = [fPassiveKeyGrabs count];
2630  for (NSUInteger i = 0; i < count; ++i) {
2631  PassiveKeyGrab *grab = [fPassiveKeyGrabs objectAtIndex : i];
2632  if ([grab matchKey : keyCode modifiers : modifiers]) {
2633  [fPassiveKeyGrabs removeObjectAtIndex : i];
2634  break;
2635  }
2636  }
2637 }
2638 
2639 //______________________________________________________________________________
2640 - (PassiveKeyGrab *) findPassiveKeyGrab : (unichar) keyCode modifiers : (NSUInteger) modifiers
2641 {
2642  NSEnumerator * const enumerator = [fPassiveKeyGrabs objectEnumerator];
2643  while (PassiveKeyGrab *grab = (PassiveKeyGrab *)[enumerator nextObject]) {
2644  if ([grab matchKey : keyCode modifiers : modifiers])
2645  return grab;
2646  }
2647 
2648  return nil;
2649 }
2650 
2651 //______________________________________________________________________________
2652 - (PassiveKeyGrab *) findPassiveKeyGrab : (unichar) keyCode
2653 {
2654  //Do not check modifiers.
2655  NSEnumerator * const enumerator = [fPassiveKeyGrabs objectEnumerator];
2656  while (PassiveKeyGrab *grab = (PassiveKeyGrab *)[enumerator nextObject]) {
2657  if ([grab matchKey : keyCode])
2658  return grab;
2659  }
2660 
2661  return nil;
2662 }
2663 
2664 #pragma mark - Painting mechanics.
2665 
2666 //______________________________________________________________________________
2667 - (void) drawRect : (NSRect) dirtyRect
2668 {
2669 #pragma unused(dirtyRect)
2670 
2671  using namespace X11;
2672 
2673  if (fID) {
2674  if (TGWindow * const window = gClient->GetWindowById(fID)) {
2675  //It's never painted, parent renders child. true == check the parent also.
2676  if (ViewIsTextViewFrame(self, true) ||ViewIsHtmlViewFrame(self, true))
2677  return;
2678 
2679  NSGraphicsContext * const nsContext = [NSGraphicsContext currentContext];
2680  assert(nsContext != nil && "-drawRect:, currentContext returned nil");
2681 
2682  TGCocoa * const vx = (TGCocoa *)gVirtualX;
2683  vx->CocoaDrawON();
2684 
2685  fContext = (CGContextRef)[nsContext graphicsPort];
2686  assert(fContext != 0 && "-drawRect:, graphicsPort returned null");
2687 
2688  const Quartz::CGStateGuard ctxGuard(fContext);
2689 
2690  //Non-rectangular windows.
2693 
2694  if (window->InheritsFrom("TGContainer"))//It always has an ExposureMask.
2695  vx->GetEventTranslator()->GenerateExposeEvent(self, [self visibleRect]);
2696 
2697  if (fEventMask & kExposureMask) {
2698  if (ViewIsTextView(self)) {
2699  //Send Expose event, using child view (this is how it's done in GUI :( ).
2700  NSView<X11Window> * const viewFrame = FrameForTextView(self);
2701  if (viewFrame)//Now we set fExposedRegion for TGView.
2702  vx->GetEventTranslator()->GenerateExposeEvent(viewFrame, [viewFrame visibleRect]);
2703  }
2704 
2705  if (ViewIsHtmlView(self)) {
2706  NSView<X11Window> *const viewFrame = FrameForHtmlView(self);
2707  if (viewFrame)
2708  vx->GetEventTranslator()->GenerateExposeEvent(viewFrame, [viewFrame visibleRect]);
2709  }
2710 
2711  //Ask ROOT's widget/window to draw itself.
2712  gClient->NeedRedraw(window, kTRUE);
2713 
2714  if (!fSnapshotDraw && !ViewIsTextView(self) && !ViewIsHtmlView(self)) {
2715  //If Cocoa repaints widget, cancel all ROOT's "outside of paint event"
2716  //rendering into this widget ... Except it's a text view :)
2717  gClient->CancelRedraw(window);
2719  }
2720  }
2721 
2722  if (fBackBuffer) {
2723  //Very "special" window.
2724  const X11::Rectangle copyArea(0, 0, fBackBuffer.fWidth, fBackBuffer.fHeight);
2725  [self copy : fBackBuffer area : copyArea withMask : nil
2726  clipOrigin : X11::Point() toPoint : X11::Point()];
2727  }
2728 
2729  vx->CocoaDrawOFF();
2730 #ifdef DEBUG_ROOT_COCOA
2731  CGContextSetRGBStrokeColor(fContext, 1., 0., 0., 1.);
2732  CGContextStrokeRect(fContext, dirtyRect);
2733 #endif
2734 
2735  fContext = 0;
2736  } else {
2737 #ifdef DEBUG_ROOT_COCOA
2738  NSLog(@"QuartzView: -drawRect: method, no window for id %u was found", fID);
2739 #endif
2740  }
2741  }
2742 }
2743 
2744 #pragma mark - Geometry.
2745 
2746 //______________________________________________________________________________
2747 - (void) setFrame : (NSRect) newFrame
2748 {
2749  //In case of TBrowser, setFrame started infinite recursion:
2750  //HandleConfigure for embedded main frame emits signal, slot
2751  //calls layout, layout calls setFrame -> HandleConfigure and etc. etc.
2752  if (NSEqualRects(newFrame, self.frame))
2753  return;
2754 
2755  [super setFrame : newFrame];
2756 }
2757 
2758 //______________________________________________________________________________
2759 - (void) setFrameSize : (NSSize) newSize
2760 {
2761  //Check, if setFrameSize calls setFrame.
2762 
2763  [super setFrameSize : newSize];
2764 
2765  if ((fEventMask & kStructureNotifyMask) && (self.fMapState == kIsViewable || fIsOverlapped == YES)) {
2766  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2767  "setFrameSize:, gVirtualX is either null or has a type, different from TGCocoa");
2768  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2769  vx->GetEventTranslator()->GenerateConfigureNotifyEvent(self, self.frame);
2770  }
2771 
2772  [self setNeedsDisplay : YES];//?
2773 }
2774 
2775 #pragma mark - Event handling.
2776 
2777 //______________________________________________________________________________
2778 - (void) mouseDown : (NSEvent *) theEvent
2779 {
2780  assert(fID != 0 && "-mouseDown:, fID is 0");
2781 
2782  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2783  "-mouseDown:, gVirtualX is either null or has a type, different from TGCocoa");
2784  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2785  vx->GetEventTranslator()->GenerateButtonPressEvent(self, theEvent, kButton1);
2786 }
2787 
2788 //______________________________________________________________________________
2789 - (void) scrollWheel : (NSEvent*) theEvent
2790 {
2791  assert(fID != 0 && "-scrollWheel:, fID is 0");
2792 
2793 
2794  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2795  "-scrollWheel:, gVirtualX is either null or has a type, different from TGCocoa");
2796 
2797  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2798  const CGFloat deltaY = [theEvent deltaY];
2799  if (deltaY < 0) {
2800  vx->GetEventTranslator()->GenerateButtonPressEvent(self, theEvent, kButton5);
2801  vx->GetEventTranslator()->GenerateButtonReleaseEvent(self, theEvent, kButton5);
2802  } else if (deltaY > 0) {
2803  vx->GetEventTranslator()->GenerateButtonPressEvent(self, theEvent, kButton4);
2804  vx->GetEventTranslator()->GenerateButtonReleaseEvent(self, theEvent, kButton4);
2805  }
2806 }
2807 
2808 #ifdef DEBUG_ROOT_COCOA
2809 //______________________________________________________________________________
2810 - (void) printViewInformation
2811 {
2812  assert(fID != 0 && "-printWindowInformation, fID is 0");
2813  const TGWindow * const window = gClient->GetWindowById(fID);
2814  assert(window != 0 && "printWindowInformation, window not found");
2815 
2816  NSLog(@"-----------------View %u info:---------------------", fID);
2817  NSLog(@"ROOT's window class is %s", window->IsA()->GetName());
2818  NSLog(@"event mask is:");
2819  print_mask_info(fEventMask);
2820  NSLog(@"grab mask is:");
2821  print_mask_info(fPassiveGrabEventMask);
2822  NSLog(@"view's geometry: x == %g, y == %g, w == %g, h == %g", self.frame.origin.x,
2823  self.frame.origin.y, self.frame.size.width, self.frame.size.height);
2824  NSLog(@"----------------End of view info------------------");
2825 }
2826 #endif
2827 
2828 //______________________________________________________________________________
2829 - (void) rightMouseDown : (NSEvent *) theEvent
2830 {
2831  assert(fID != 0 && "-rightMouseDown:, fID is 0");
2832 
2833 #ifdef DEBUG_ROOT_COCOA
2834  [self printViewInformation];
2835 #endif
2836 
2837  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2838  "-rightMouseDown:, gVirtualX is either null or has type different from TGCocoa");
2839  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2840  vx->GetEventTranslator()->GenerateButtonPressEvent(self, theEvent, kButton3);
2841 }
2842 
2843 //______________________________________________________________________________
2844 - (void) otherMouseDown : (NSEvent *) theEvent
2845 {
2846  assert(fID != 0 && "-otherMouseDown:, fID is 0");
2847 
2848  //Funny enough, [theEvent buttonNumber] is not the same thing as button masked in [NSEvent pressedMouseButtons],
2849  //button number actually is a kind of right operand for bitshift for pressedMouseButtons.
2850  if ([theEvent buttonNumber] == 2) {//this '2' will correspond to '4' in pressedMouseButtons.
2851  //I do not care about mouse buttons after left/right/wheel - ROOT does not have
2852  //any code for this.
2853  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2854  "-otherMouseDown:, gVirtualX is either null or has type different from TGCocoa");
2855  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2856  vx->GetEventTranslator()->GenerateButtonPressEvent(self, theEvent, kButton2);
2857  }
2858 }
2859 
2860 //______________________________________________________________________________
2861 - (void) mouseUp : (NSEvent *) theEvent
2862 {
2863  assert(fID != 0 && "-mouseUp:, fID is 0");
2864 
2865  assert(dynamic_cast<TGCocoa *>(gVirtualX) &&
2866  "-mouseUp:, gVirtualX is either null or has type different from TGCocoa");
2867  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2868  vx->GetEventTranslator()->GenerateButtonReleaseEvent(self, theEvent, kButton1);
2869 }
2870 
2871 //______________________________________________________________________________
2872 - (void) rightMouseUp : (NSEvent *) theEvent
2873 {
2874 
2875  assert(fID != 0 && "-rightMouseUp:, fID is 0");
2876 
2877  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2878  "-rightMouseUp:, gVirtualX is either null or has type different from TGCocoa");
2879 
2880  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2881  vx->GetEventTranslator()->GenerateButtonReleaseEvent(self, theEvent, kButton3);
2882 }
2883 
2884 //______________________________________________________________________________
2885 - (void) otherMouseUp : (NSEvent *) theEvent
2886 {
2887  assert(fID != 0 && "-otherMouseUp:, fID is 0");
2888 
2889  //Here I assume it's always kButton2.
2890  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2891  "-otherMouseUp:, gVirtualX is either null or has type different from TGCocoa");
2892  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2893  vx->GetEventTranslator()->GenerateButtonReleaseEvent(self, theEvent, kButton2);
2894 }
2895 
2896 //______________________________________________________________________________
2897 - (void) mouseEntered : (NSEvent *) theEvent
2898 {
2899  assert(fID != 0 && "-mouseEntered:, fID is 0");
2900  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2901  "-mouseEntered:, gVirtualX is null or not of TGCocoa type");
2902 
2903  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2904  vx->GetEventTranslator()->GenerateCrossingEvent(theEvent);
2905 }
2906 
2907 //______________________________________________________________________________
2908 - (void) mouseExited : (NSEvent *) theEvent
2909 {
2910  assert(fID != 0 && "-mouseExited:, fID is 0");
2911 
2912  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2913  "-mouseExited:, gVirtualX is null or not of TGCocoa type");
2914 
2915  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2916  vx->GetEventTranslator()->GenerateCrossingEvent(theEvent);
2917 }
2918 
2919 //______________________________________________________________________________
2920 - (void) mouseMoved : (NSEvent *) theEvent
2921 {
2922  assert(fID != 0 && "-mouseMoved:, fID is 0");
2923 
2924  if (fParentView)//Suppress events in all views, except the top-level one.
2925  return;
2926 
2927  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2928  "-mouseMoved:, gVirtualX is null or not of TGCocoa type");
2929 
2930  TGCocoa *vx = static_cast<TGCocoa *>(gVirtualX);
2932 }
2933 
2934 //______________________________________________________________________________
2935 - (void) mouseDragged : (NSEvent *) theEvent
2936 {
2937  assert(fID != 0 && "-mouseDragged:, fID is 0");
2938 
2939  TGCocoa * const vx = dynamic_cast<TGCocoa *>(gVirtualX);
2940  assert(vx != 0 && "-mouseDragged:, gVirtualX is null or not of TGCocoa type");
2941 
2943 }
2944 
2945 //______________________________________________________________________________
2946 - (void) rightMouseDragged : (NSEvent *) theEvent
2947 {
2948  assert(fID != 0 && "-rightMouseDragged:, fID is 0");
2949 
2950  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2951  "-rightMouseDragged:, gVirtualX is null or not of TGCocoa type");
2952 
2953  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2955 }
2956 
2957 //______________________________________________________________________________
2958 - (void) otherMouseDragged : (NSEvent *) theEvent
2959 {
2960  assert(fID != 0 && "-otherMouseDragged:, fID is 0");
2961 
2962  if ([theEvent buttonNumber] == 2) {
2963  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2964  "-otherMouseDragged:, gVirtualX is null or not of TGCocoa type");
2965  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2967  }
2968 }
2969 
2970 //______________________________________________________________________________
2971 - (void) keyDown : (NSEvent *) theEvent
2972 {
2973  assert(fID != 0 && "-keyDown:, fID is 0");
2974 
2975  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2976  "-keyDown:, gVirtualX is null or not of TGCocoa type");
2977 
2978  NSView<X11Window> *eventView = self;
2979  if (NSView<X11Window> *pointerView = X11::FindViewUnderPointer())
2980  eventView = pointerView;
2981 
2982  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2983  vx->GetEventTranslator()->GenerateKeyPressEvent(eventView, theEvent);
2984 }
2985 
2986 //______________________________________________________________________________
2987 - (void) keyUp : (NSEvent *) theEvent
2988 {
2989  assert(fID != 0 && "-keyUp:, fID is 0");
2990 
2991  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
2992  "-keyUp:, gVirtualX is null or not of TGCocoa type");
2993 
2994  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
2995  NSView<X11Window> *eventView = self;
2996  if (NSView<X11Window> *pointerView = X11::FindViewUnderPointer())
2997  eventView = pointerView;
2998 
2999  vx->GetEventTranslator()->GenerateKeyReleaseEvent(eventView, theEvent);
3000 }
3001 
3002 #pragma mark - First responder stuff.
3003 
3004 //______________________________________________________________________________
3005 - (BOOL) acceptsFirstMouse : (NSEvent *) theEvent
3006 {
3007 #pragma unused(theEvent)
3008  return YES;
3009 }
3010 
3011 //______________________________________________________________________________
3012 - (BOOL) acceptsFirstResponder
3013 {
3014  return YES;
3015 }
3016 
3017 #pragma mark - Cursors.
3018 
3019 //______________________________________________________________________________
3020 - (void) setFCurrentCursor : (ECursor) cursor
3021 {
3022  if (cursor != fCurrentCursor) {
3023  fCurrentCursor = cursor;
3024  [self.fQuartzWindow invalidateCursorRectsForView : self];
3025  }
3026 }
3027 
3028 //______________________________________________________________________________
3029 - (NSCursor *) createCustomCursor
3030 {
3031  const char *pngFileName = 0;
3032 
3033  switch (fCurrentCursor) {
3034  case kMove:
3035  pngFileName = "move_cursor.png";
3036  break;
3037  case kArrowHor:
3038  pngFileName = "hor_arrow_cursor.png";
3039  break;
3040  case kArrowVer:
3041  pngFileName = "ver_arrow_cursor.png";
3042  break;
3043  case kArrowRight:
3044  pngFileName = "right_arrow_cursor.png";
3045  break;
3046  case kRotate:
3047  pngFileName = "rotate.png";
3048  break;
3049  case kBottomLeft:
3050  case kTopRight:
3051  pngFileName = "top_right_cursor.png";
3052  break;
3053  case kTopLeft:
3054  case kBottomRight:
3055  pngFileName = "top_left_cursor.png";
3056  break;
3057  default:;
3058  }
3059 
3060  if (pngFileName) {
3061  const char * const path = gSystem->Which(TROOT::GetIconPath(), pngFileName, kReadPermission);
3062  const Util::ScopedArray<const char> arrayGuard(path);
3063 
3064  if (!path || path[0] == 0) {
3065  //File was not found.
3066  return nil;
3067  }
3068 
3069  NSString *nsPath = [NSString stringWithFormat : @"%s", path];//in autorelease pool.
3070  NSImage * const cursorImage = [[NSImage alloc] initWithContentsOfFile : nsPath];
3071 
3072  if (!cursorImage)
3073  return nil;
3074 
3075  NSPoint hotSpot = X11::GetCursorHotStop(cursorImage, fCurrentCursor);
3076  NSCursor * const customCursor = [[[NSCursor alloc] initWithImage : cursorImage
3077  hotSpot : hotSpot] autorelease];
3078 
3079  [cursorImage release];
3080 
3081  return customCursor;
3082  }
3083 
3084  return nil;
3085 }
3086 
3087 //______________________________________________________________________________
3088 - (void) resetCursorRects
3089 {
3090  if (NSCursor * const cursor = X11::CreateCursor(fCurrentCursor))
3091  [self addCursorRect : self.visibleRect cursor : cursor];
3092 }
3093 
3094 //______________________________________________________________________________
3095 - (void) cursorUpdate
3096 {
3097  if (NSCursor * const cursor = X11::CreateCursor(fCurrentCursor)) {
3098  // NB: [window invalidateCursorRectsForView] called here has the
3099  // same problem as commented below in -cursorUpdate:.
3100  [cursor set];
3101  }
3102 }
3103 
3104 //______________________________________________________________________________
3105 - (void) cursorUpdate : (NSEvent *) event
3106 {
3107 #pragma unused(event)
3108  // It looks like [NSCursor set] method does not work properly when called from
3109  // cursorUpdate:, having, say, a parent frame with 'arrow' cursor and a child (completely
3110  // filling its parent's area) with 'cross', it happens the 'cross' cursor is not always
3111  // set correctly, for example:
3112  // if we have a TCanvas and resize it, cursor is 'arrow' inside this canvas,
3113  // though it must be 'cross'. This all, as it always happesn with "thinking different"
3114  // Apple is somehow related to run loop or something. As always, it's not documented,
3115  // so Apple can continue to think different. The idea with performSelector comes from:
3116  // http://stackoverflow.com/questions/8430236/nscursor-set-method-has-no-effect
3117  // Or may be it's just a bug:
3118  // http://stackoverflow.com/questions/13901232/nscursor-set-not-working-on-unfocused-window
3119  [self performSelector : @selector(cursorUpdate) withObject : nil afterDelay : 0.05f];
3120 }
3121 
3122 #pragma mark - Emulated X11 properties.
3123 
3124 //______________________________________________________________________________
3125 - (void) setProperty : (const char *) propName data : (unsigned char *) propData
3126  size : (unsigned) dataSize forType : (Atom_t) dataType format : (unsigned) format
3127 {
3128  assert(propName != 0 && "-setProperty:data:size:forType:, parameter 'propName' is null");
3129  assert(propData != 0 && "-setProperty:data:size:forType:, parameter 'propData' is null");
3130  assert(dataSize != 0 && "-setProperty:data:size:forType:, parameter 'dataSize' is 0");
3131 
3132  NSString * const key = [NSString stringWithCString : propName encoding : NSASCIIStringEncoding];
3133  QuartzWindowProperty * property = (QuartzWindowProperty *)[fX11Properties valueForKey : key];
3134 
3135  //At the moment (and I think this will never change) TGX11 always calls XChangeProperty with PropModeReplace.
3136  if (property)
3137  [property resetPropertyData : propData size : dataSize type : dataType format : format];
3138  else {
3139  //No property found, add a new one.
3140  property = [[QuartzWindowProperty alloc] initWithData : propData size : dataSize
3141  type : dataType format : format];
3142  [fX11Properties setObject : property forKey : key];
3143  [property release];
3144  }
3145 }
3146 
3147 //______________________________________________________________________________
3148 - (BOOL) hasProperty : (const char *) propName
3149 {
3150  assert(propName != 0 && "-hasProperty:, propName parameter is null");
3151 
3152  NSString * const key = [NSString stringWithCString : propName encoding : NSASCIIStringEncoding];
3153  QuartzWindowProperty * const property = (QuartzWindowProperty *)[fX11Properties valueForKey : key];
3154 
3155  return property != nil;
3156 }
3157 
3158 //______________________________________________________________________________
3159 - (unsigned char *) getProperty : (const char *) propName returnType : (Atom_t *) type
3160  returnFormat : (unsigned *) format nElements : (unsigned *) nElements
3161 {
3162  assert(propName != 0 &&
3163  "-getProperty:returnType:returnFormat:nElements:, parameter 'propName' is null");
3164  assert(type != 0 &&
3165  "-getProperty:returnType:returnFormat:nElements:, parameter 'type' is null");
3166  assert(format != 0 &&
3167  "-getProperty:returnType:returnFormat:nElements:, parameter 'format' is null");
3168  assert(nElements != 0 &&
3169  "-getProperty:returnType:returnFormat:nElements:, parameter 'nElements' is null");
3170 
3171  NSString * const key = [NSString stringWithCString : propName encoding : NSASCIIStringEncoding];
3172  QuartzWindowProperty * const property = (QuartzWindowProperty *)[fX11Properties valueForKey : key];
3173  assert(property != 0 &&
3174  "-getProperty:returnType:returnFormat:nElements, property not found");
3175 
3176  NSData * const propData = property.fPropertyData;
3177 
3178  const NSUInteger dataSize = [propData length];
3179  unsigned char *buff = 0;
3180  try {
3181  buff = new unsigned char[dataSize]();
3182  } catch (const std::bad_alloc &) {
3183  //Hmm, can I log, if new failed? :)
3184  NSLog(@"QuartzWindow: -getProperty:returnType:returnFormat:nElements:,"
3185  " memory allocation failed");
3186  return 0;
3187  }
3188 
3189  [propData getBytes : buff length : dataSize];
3190  *format = property.fFormat;
3191 
3192  *nElements = dataSize;
3193 
3194  if (*format == 16)
3195  *nElements= dataSize / 2;
3196  else if (*format == 32)
3197  *nElements = dataSize / 4;
3198 
3199  *type = property.fType;
3200 
3201  return buff;
3202 }
3203 
3204 //______________________________________________________________________________
3205 - (void) removeProperty : (const char *) propName
3206 {
3207  assert(propName != 0 && "-removeProperty:, parameter 'propName' is null");
3208 
3209  NSString * const key = [NSString stringWithCString : propName
3210  encoding : NSASCIIStringEncoding];
3211  [fX11Properties removeObjectForKey : key];
3212 }
3213 
3214 //DND
3215 //______________________________________________________________________________
3216 - (NSDragOperation) draggingEntered : (id<NSDraggingInfo>) sender
3217 {
3218  NSPasteboard * const pasteBoard = [sender draggingPasteboard];
3219  const NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
3220 
3221  if ([[pasteBoard types] containsObject : NSFilenamesPboardType] && (sourceDragMask & NSDragOperationCopy))
3222  return NSDragOperationCopy;
3223 
3224  return NSDragOperationNone;
3225 }
3226 
3227 //______________________________________________________________________________
3228 - (BOOL) performDragOperation : (id<NSDraggingInfo>) sender
3229 {
3230  //We can drag some files (images, pdfs, source code files) from
3231  //finder to ROOT's window (mainly TCanvas or text editor).
3232  //The logic is totally screwed here :((( - ROOT will try to
3233  //read a property of some window (not 'self', unfortunately) -
3234  //this works since on Window all data is in a global clipboard
3235  //(on X11 it simply does not work at all).
3236  //I'm attaching the file name as a property for the top level window,
3237  //there is no other way to make this data accessible for ROOT.
3238 
3239  NSPasteboard * const pasteBoard = [sender draggingPasteboard];
3240  const NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
3241 
3242  if ([[pasteBoard types] containsObject : NSFilenamesPboardType] && (sourceDragMask & NSDragOperationCopy)) {
3243 
3244  //Here I try to put string ("file://....") into window's property to make
3245  //it accesible from ROOT's GUI.
3246  const Atom_t textUriAtom = gVirtualX->InternAtom("text/uri-list", kFALSE);
3247 
3248  NSArray * const files = [pasteBoard propertyListForType : NSFilenamesPboardType];
3249  for (NSString *path in files) {
3250  //ROOT can not process several files, use the first one.
3251  NSString * const item = [@"file://" stringByAppendingString : path];
3252  //Yes, only ASCII encoding, but after all, ROOT's not able to work with NON-ASCII strings.
3253  const NSUInteger len = [item lengthOfBytesUsingEncoding : NSASCIIStringEncoding] + 1;
3254  try {
3255  std::vector<unsigned char> propertyData(len);
3256  [item getCString : (char *)&propertyData[0] maxLength : propertyData.size()
3257  encoding : NSASCIIStringEncoding];
3258  //There is no any guarantee, that this will ever work, logic in TGDNDManager is totally crazy.
3259  NSView<X11Window> * const targetView = self.fQuartzWindow.fContentView;
3260  [targetView setProperty : "_XC_DND_DATA" data : &propertyData[0]
3261  size : propertyData.size() forType : textUriAtom format : 8];
3262  } catch (const std::bad_alloc &) {
3263  //Hehe, can I log something in case of bad_alloc??? ;)
3264  NSLog(@"QuartzView: -performDragOperation:, memory allocation failed");
3265  return NO;
3266  }
3267 
3268  break;
3269  }
3270 
3271  //Property is attached now.
3272 
3273  //Gdk on windows creates three events on file drop (WM_DROPFILES): XdndEnter, XdndPosition, XdndDrop.
3274  //1. Dnd enter.
3275  Event_t event1 = {};
3276  event1.fType = kClientMessage;
3277  event1.fWindow = fID;
3278  event1.fHandle = gVirtualX->InternAtom("XdndEnter", kFALSE);
3279  event1.fUser[0] = long(fID);
3280  event1.fUser[2] = textUriAtom;//gVirtualX->InternAtom("text/uri-list", kFALSE);
3281  //
3282  gVirtualX->SendEvent(fID, &event1);
3283 
3284  //2. Dnd position.
3285  Event_t event2 = {};
3286  event2.fType = kClientMessage;
3287  event2.fWindow = fID;
3288  event2.fHandle = gVirtualX->InternAtom("XdndPosition", kFALSE);
3289  event2.fUser[0] = long(fID);
3290  event2.fUser[2] = 0;//Here I have to pack x and y for drop coordinates, shifting by 16 bits.
3291  NSPoint dropPoint = [sender draggingLocation];
3292  //convertPointFromBase is deprecated.
3293  //dropPoint = [self convertPointFromBase : dropPoint];
3294  dropPoint = [self convertPoint : dropPoint fromView : nil];
3295  //
3296  dropPoint = X11::TranslateToScreen(self, dropPoint);
3297  event2.fUser[2] = UShort_t(dropPoint.y) | (UShort_t(dropPoint.x) << 16);
3298 
3299  gVirtualX->SendEvent(fID, &event2);
3300 
3301  Event_t event3 = {};
3302  event3.fType = kClientMessage;
3303  event3.fWindow = fID;
3304  event3.fHandle = gVirtualX->InternAtom("XdndDrop", kFALSE);
3305 
3306  gVirtualX->SendEvent(fID, &event3);
3307  }
3308 
3309  return YES;//Always ok, even if file type is not supported - no need in "animation".
3310 }
3311 
3312 @end
std::vector< unsigned char > DownscaledImageData(unsigned w, unsigned h, CGImageRef image)
int GlobalXCocoaToROOT(CGFloat xCocoa)
BOOL fOverrideRedirect
Definition: QuartzWindow.h:161
void GenerateConfigureNotifyEvent(NSView< X11Window > *view, const NSRect &newFrame)
Definition: X11Events.mm:1149
QuartzWindow * CreateTopLevelWindow(Int_t x, Int_t y, UInt_t w, UInt_t h, UInt_t border, Int_t depth, UInt_t clss, void *visual, SetWindowAttributes_t *attr, UInt_t)
Definition: QuartzWindow.mm:53
NSView< X11Window > * FindViewForPointerEvent(NSEvent *pointerEvent)
void GetRootWindowAttributes(WindowAttributes_t *attr)
unsigned long fBackgroundPixel
Definition: QuartzWindow.h:97
void GeneratePointerMotionEvent(NSEvent *theEvent)
Definition: X11Events.mm:1246
void configureNotifyTree()
unsigned fPassiveGrabEventMask
Definition: QuartzWindow.h:167
bool LockFocus(NSView< X11Window > *view)
ROOT::MacOSX::Util::CFScopeGuard< CGImageRef > fImage
Definition: QuartzPixmap.h:95
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
void GetWindowAttributes(NSObject< X11Window > *window, WindowAttributes_t *dst)
TLine * line
QuartzWindow * fQuartzWindow
Definition: QuartzWindow.h:108
UInt_t Mask_t
Definition: GuiTypes.h:40
ECursor fCurrentCursor
Definition: QuartzWindow.h:172
ULong_t fBackingPixel
Definition: GuiTypes.h:125
QuartzWindow * FindWindowInPoint(Int_t x, Int_t y)
void mapSubwindows()
void GenerateKeyReleaseEvent(NSView< X11Window > *eventView, NSEvent *theEvent)
Definition: X11Events.mm:1303
static const TString & GetIconPath()
Get the icon path in the installation. Static utility function.
Definition: TROOT.cxx:2907
const Mask_t kButtonMotionMask
Definition: GuiTypes.h:163
const Mask_t kWACursor
Definition: GuiTypes.h:153
unsigned short UShort_t
Definition: RtypesCore.h:36
NSView< X11Window > * FindDNDAwareViewInPoint(NSView *parentView, Window_t dragWinID, Window_t inputWinID, Int_t x, Int_t y, Int_t maxDepth)
bool AdjustCropArea(const Rectangle &srcRect, Rectangle &cropArea)
TH1 * h
Definition: legend2.C:5
const Mask_t kLeaveWindowMask
Definition: GuiTypes.h:167
const Mask_t kWABackPixmap
Definition: GuiTypes.h:138
BOOL fIsDNDAware
Definition: QuartzWindow.h:173
const Mask_t kWABorderPixel
Definition: GuiTypes.h:141
const Mask_t kWABitGravity
Definition: GuiTypes.h:143
int LocalYCocoaToROOT(NSView< X11Window > *parentView, CGFloat yCocoa)
QuartzImage * fShapeCombineMask
Definition: QuartzWindow.h:38
void unmapWindow()
#define gClient
Definition: TGClient.h:166
int Int_t
Definition: RtypesCore.h:41
const Mask_t kWABackingStore
Definition: GuiTypes.h:145
BOOL fIsOpenGLWidget()
virtual char * Which(const char *search, const char *file, EAccessMode mode=kFileExists)
Find location of file in a search path.
Definition: TSystem.cxx:1518
NSView< X11Window > * fContentView
Definition: QuartzWindow.h:235
NSUInteger fModifiers()
unsigned fWidth()
unsigned char * readColorBits:(ROOT::MacOSX::X11::Rectangle area)
QuartzPixmap * fBackBuffer
Definition: QuartzWindow.h:175
#define NULL
Definition: RtypesCore.h:88
static std::string format(double x, double y, int digits, int width)
ECursor
Definition: TVirtualX.h:44
NSCursor * CreateCustomCursor(ECursor currentCursor)
Window_t fWindow
Definition: GuiTypes.h:175
const NSUInteger kTitledWindowMask
BOOL fIsOpenGLWidget()
const NSUInteger kResizableWindowMask
int GlobalYROOTToCocoa(CGFloat yROOT)
void GenerateButtonPressEvent(NSView< X11Window > *eventView, NSEvent *theEvent, EMouseButton btn)
Definition: X11Events.mm:1259
const Mask_t kWABorderPixmap
Definition: GuiTypes.h:140
unsigned fHeight
Definition: QuartzPixmap.h:93
ULong_t fBackgroundPixel
Definition: GuiTypes.h:94
const Mask_t kPointerMotionMask
Definition: GuiTypes.h:162
void addChild:(NSView< X11Window > *child)
Bool_t fMapInstalled
Definition: GuiTypes.h:128
void SetWindowAttributes(const SetWindowAttributes_t *attr, NSObject< X11Window > *window)
QuartzView * fParentView
Definition: QuartzWindow.h:164
NSMutableDictionary * fX11Properties
Definition: QuartzWindow.h:179
Double_t x[n]
Definition: legend1.C:17
NSPoint GetCursorHotStop(NSImage *image, ECursor cursor)
NSPoint TranslateCoordinates(NSView< X11Window > *fromView, NSView< X11Window > *toView, NSPoint sourcePoint)
QuartzImage * fBackgroundPixmap
Definition: QuartzWindow.h:180
NSPoint ConvertPointFromBaseToScreen(NSWindow *window, NSPoint windowPoint)
ULong_t fBackingPlanes
Definition: GuiTypes.h:124
Handle_t fHandle
Definition: GuiTypes.h:184
QuartzWindow * FindWindowForPointerEvent(NSEvent *pointerEvent)
Handle_t Atom_t
Definition: GuiTypes.h:36
Colormap_t fColormap
Definition: GuiTypes.h:127
unsigned fHeight
Definition: QuartzPixmap.h:38
ROOT::MacOSX::X11::PointerGrab fCurrentGrabType
Definition: QuartzWindow.h:182
QuartzWindow * fQuartzWindow
Definition: QuartzWindow.h:236
CGImageRef CreateSubImage(QuartzImage *image, const Rectangle &area)
ROOT::MacOSX::X11::Rectangle GetDisplayGeometry() const
Definition: TGCocoa.mm:550
const Mask_t kWAColormap
Definition: GuiTypes.h:152
void lowerWindow()
NSPoint TranslateFromScreen(NSPoint point, NSView< X11Window > *to)
void CocoaDrawOFF()
Definition: TGCocoa.mm:4405
NSPoint ConvertPointFromScreenToBase(NSPoint screenPoint, NSWindow *window)
const NSUInteger kClosableWindowMask
const Mask_t kWABackingPlanes
Definition: GuiTypes.h:146
const NSUInteger kMiniaturizableWindowMask
int GlobalXROOTToCocoa(CGFloat xROOT)
const Mask_t kButtonPressMask
Definition: GuiTypes.h:160
NSView< X11Window > * FindViewUnderPointer()
BOOL fHasFocus
Definition: QuartzWindow.h:163
NSPoint TranslateToScreen(NSView< X11Window > *from, NSPoint point)
NSView< X11Window > * FrameForTextView(NSView< X11Window > *textView)
const NSEventType kLeftMouseDown
Long_t fAllEventMasks
Definition: GuiTypes.h:130
int GlobalYCocoaToROOT(CGFloat yCocoa)
bool ViewIsHtmlViewFrame(NSView< X11Window > *view, bool checkParent)
void activatePassiveGrab()
void GenerateExposeEvent(NSView< X11Window > *view, const NSRect &exposedRect)
Definition: X11Events.mm:1176
void setOverlapped:(BOOL overlap)
const Mask_t kWAEventMask
Definition: GuiTypes.h:150
R__EXTERN TSystem * gSystem
Definition: TSystem.h:539
const Mask_t kWASaveUnder
Definition: GuiTypes.h:149
SVector< double, 2 > v
Definition: Dict.h:5
static Atom_t fgDeleteWindowAtom
Definition: TGCocoa.h:469
EGEventType fType
Definition: GuiTypes.h:174
QuartzWindow * FindWindowUnderPointer()
unsigned fHeight()
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:436
virtual const char * GetName() const
Return unique name, used in SavePrimitive methods.
Definition: TGWindow.cxx:221
unsigned fWidth
Definition: QuartzPixmap.h:92
const Mask_t kExposureMask
Definition: GuiTypes.h:164
unsigned int UInt_t
Definition: RtypesCore.h:42
QuartzView * fParentView
Definition: QuartzWindow.h:106
QuartzView * CreateChildView(QuartzView *parent, Int_t x, Int_t y, UInt_t w, UInt_t h, UInt_t border, Int_t depth, UInt_t clss, void *visual, SetWindowAttributes_t *attr, UInt_t wtype)
Definition: QuartzWindow.mm:82
BOOL fIsOverlapped()
void UnlockFocus(NSView< X11Window > *view)
void PixelToRGB(Pixel_t pixelColor, CGFloat *rgb)
Definition: X11Colors.mm:920
long fEventMask
Definition: QuartzWindow.h:155
void RemoveGraphicsOperationsForWindow(Window_t wid)
Definition: X11Buffer.mm:674
unsigned fID
Definition: QuartzWindow.h:153
#define gVirtualX
Definition: TVirtualX.h:350
int LocalYROOTToCocoa(NSView< X11Window > *parentView, CGFloat yROOT)
bool ViewIsTextView(unsigned viewID)
const Bool_t kFALSE
Definition: RtypesCore.h:92
unsigned fWidth
Definition: QuartzPixmap.h:37
PyObject * fType
const Mask_t kEnterWindowMask
Definition: GuiTypes.h:166
BOOL fPassiveGrabOwnerEvents
Definition: QuartzWindow.h:170
CGContextRef fContext
Definition: QuartzWindow.h:154
unsigned fWidth()
QuartzWindow * fMainWindow
Definition: QuartzWindow.h:33
BOOL fSnapshotDraw
Definition: QuartzWindow.h:171
const Mask_t kStructureNotifyMask
Definition: GuiTypes.h:165
static Int_t init()
bool ViewIsHtmlView(unsigned viewID)
NSView< X11Window > * FrameForHtmlView(NSView< X11Window > *htmlView)
bool ScreenPointIsInView(NSView< X11Window > *view, Int_t x, Int_t y)
const Mask_t kButtonReleaseMask
Definition: GuiTypes.h:161
const NSEventType kRightMouseDown
int type
Definition: TGX11.cxx:120
const Mask_t kWAOverrideRedirect
Definition: GuiTypes.h:148
unsigned long ULong_t
Definition: RtypesCore.h:51
void GenerateCrossingEvent(NSEvent *theEvent)
Definition: X11Events.mm:1194
Window_t fRoot
Definition: GuiTypes.h:119
Double_t y[n]
Definition: legend1.C:17
const Mask_t kWAWinGravity
Definition: GuiTypes.h:144
void WindowLostFocus(Window_t winID)
void ClipToShapeMask(NSView< X11Window > *view, CGContextRef ctx)
const NSUInteger kBorderlessWindowMask
NSCursor * CreateCursor(ECursor currentCursor)
Long_t fUser[5]
Definition: GuiTypes.h:186
unsigned long fBackgroundPixel
Definition: QuartzWindow.h:160
unsigned fPassiveGrabKeyModifiers
Definition: QuartzWindow.h:168
ROOT::MacOSX::X11::CommandBuffer * GetCommandBuffer() const
Definition: TGCocoa.mm:4393
BOOL fDelayedTransient
Definition: QuartzWindow.h:37
typedef void((*Func_t)())
Bool_t fOverrideRedirect
Definition: GuiTypes.h:133
Handle_t Window_t
Definition: GuiTypes.h:28
Int_t fFormat
Definition: GuiTypes.h:185
This class implements TVirtualX interface for MacOS X, using Cocoa and Quartz 2D. ...
Definition: TGCocoa.h:58
NSComparisonResult CompareViewsToLower(id view1, id view2, void *context)
QuartzView * fContentView
Definition: QuartzWindow.h:36
const Mask_t kWABorderWidth
Definition: GuiTypes.h:142
void GenerateKeyPressEvent(NSView< X11Window > *eventView, NSEvent *theEvent)
Definition: X11Events.mm:1287
NSComparisonResult CompareViewsToRaise(id view1, id view2, void *context)
BOOL fActiveGrabOwnerEvents
Definition: QuartzWindow.h:184
const Mask_t kWABackPixel
Definition: GuiTypes.h:139
double result[121]
const Mask_t kWABackingPixel
Definition: GuiTypes.h:147
const Mask_t kWADontPropagate
Definition: GuiTypes.h:151
bool ViewIsTextViewFrame(NSView< X11Window > *view, bool checkParent)
void raiseWindow()
const Bool_t kTRUE
Definition: RtypesCore.h:91
void CocoaDrawON()
Definition: TGCocoa.mm:4399
Long_t fYourEventMask
Definition: GuiTypes.h:131
unsigned fActiveGrabEventMask
Definition: QuartzWindow.h:169
ROOT::MacOSX::X11::EventTranslator * GetEventTranslator() const
Definition: TGCocoa.mm:4387
void GenerateFocusChangeEvent(NSView< X11Window > *eventView)
Definition: X11Events.mm:1323
unsigned fHeight()
int fPassiveGrabButton
Definition: QuartzWindow.h:166
void GetWindowGeometry(NSObject< X11Window > *win, WindowAttributes_t *dst)
NSMutableArray * fPassiveKeyGrabs
Definition: QuartzWindow.h:176
void activateImplicitGrab()
void GenerateButtonReleaseEvent(NSView< X11Window > *eventView, NSEvent *theEvent, EMouseButton btn)
Definition: X11Events.mm:1272