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