Logo ROOT   6.12/07
Reference Guide
X11Buffer.mm
Go to the documentation of this file.
1 // @(#)root/graf2d:$Id$
2 // Author: Timur Pocheptsov 29/02/2012
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2012, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 //#define NDEBUG
13 
14 #include <stdexcept>
15 #include <cstring>
16 #include <cassert>
17 #include <memory>
18 
19 #include <Cocoa/Cocoa.h>
20 
21 #include "ROOTOpenGLView.h"
22 #include "CocoaPrivate.h"
23 #include "QuartzWindow.h"
24 #include "QuartzPixmap.h"
25 #include "QuartzUtils.h"
26 #include "X11Drawable.h"
27 #include "X11Buffer.h"
28 #include "TGWindow.h"
29 #include "TGClient.h"
30 #include "TGCocoa.h"
31 
32 namespace ROOT {
33 namespace MacOSX {
34 namespace X11 {
35 
36 //______________________________________________________________________________
38  : fID(wid),
39  fGC(gc)
40 {
41 }
42 
43 //______________________________________________________________________________
45  : fID(wid),
46  fGC()
47 {
48 }
49 
50 //______________________________________________________________________________
52 {
53 }
54 
55 //______________________________________________________________________________
56 void Command::Execute(CGContextRef /*ctx*/)const
57 {
58 }
59 
60 //______________________________________________________________________________
62 {
63  return wid == fID;
64 }
65 
66 //______________________________________________________________________________
68 {
69  return false;
70 }
71 
72 //______________________________________________________________________________
73 DrawLine::DrawLine(Drawable_t wid, const GCValues_t &gc, const Point &p1, const Point &p2)
74  : Command(wid, gc),
75  fP1(p1),
76  fP2(p2)
77 {
78 }
79 
80 //______________________________________________________________________________
81 void DrawLine::Execute()const
82 {
83  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
84  "Execute, gVirtualX is either null or not of TGCocoa type");
85  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
86  vx->DrawLineAux(fID, fGC, fP1.fX, fP1.fY, fP2.fX, fP2.fY);
87 }
88 
89 //______________________________________________________________________________
91  const Segment_t *segments, Int_t nSegments)
92  : Command(wid, gc)
93 {
94  assert(segments != 0 && "DrawSegments, segments parameter is null");
95  assert(nSegments > 0 && "DrawSegments, nSegments <= 0");
96 
97  fSegments.assign(segments, segments + nSegments);
98 }
99 
100 //______________________________________________________________________________
102 {
103  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
104  "Execute, gVirtualX is either null or not of TGCocoa type");
105  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
106  vx->DrawSegmentsAux(fID, fGC, &fSegments[0], (Int_t)fSegments.size());
107 }
108 
109 //______________________________________________________________________________
111  : Command(wid),
112  fArea(area)
113 {
114 }
115 
116 //______________________________________________________________________________
118 {
119  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
120  "Execute, gVirtualX is either null or not of TGCocoa type");
121  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
123 }
124 
125 //______________________________________________________________________________
127  const Rectangle_t &area, const Point &dstPoint)
128  : Command(dst, gc),
129  fSrc(src),
130  fArea(area),
131  fDstPoint(dstPoint)
132 {
133 }
134 
135 //______________________________________________________________________________
136 bool CopyArea::HasOperand(Drawable_t drawable)const
137 {
138  return fID == drawable || fSrc == drawable || fGC.fClipMask == drawable;
139 }
140 
141 //______________________________________________________________________________
142 void CopyArea::Execute()const
143 {
144  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
145  "Execute, gVirtualX is either null or not of TGCocoa type");
146 
147  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
150 }
151 
152 //______________________________________________________________________________
153 DrawString::DrawString(Drawable_t wid, const GCValues_t &gc, const Point &point,
154  const std::string &text)
155  : Command(wid, gc),
156  fPoint(point),
157  fText(text)
158 {
159 }
160 
161 //______________________________________________________________________________
163 {
164  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
165  "Execute, gVirtualX is either null or not of TGCocoa type");
166 
167  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
168  vx->DrawStringAux(fID, fGC, fPoint.fX, fPoint.fY, fText.c_str(), fText.length());
169 }
170 
171 //______________________________________________________________________________
173  const Rectangle_t &rectangle)
174  : Command(wid, gc),
175  fRectangle(rectangle)
176 {
177 }
178 
179 //______________________________________________________________________________
181 {
182  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
183  "Execute, gVirtualX is either null or not of TGCocoa type");
184 
185  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
188 }
189 
190 //______________________________________________________________________________
192  const Point_t *points, Int_t nPoints)
193  : Command(wid, gc)
194 {
195  assert(points != 0 && "FillPolygon, points parameter is null");
196  assert(nPoints > 0 && "FillPolygon, nPoints <= 0");
197 
198  fPolygon.assign(points, points + nPoints);
199 }
200 
201 //______________________________________________________________________________
203 {
204  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
205  "Execute, gVirtualX is either null or not of TGCocoa type");
206 
207  ((TGCocoa *)gVirtualX)->FillPolygonAux(fID, fGC, &fPolygon[0], (Int_t)fPolygon.size());
208 }
209 
210 //______________________________________________________________________________
212  const Rectangle_t &rectangle)
213  : Command(wid, gc),
214  fRectangle(rectangle)
215 {
216 }
217 
218 //______________________________________________________________________________
220 {
221  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
222  "Execute, gVirtualX is either null or not of TGCocoa type");
223 
224  TGCocoa * const vx = static_cast<TGCocoa *>(gVirtualX);
227 }
228 
229 //______________________________________________________________________________
231  : Command(view.fID),
232  fView(view)
233 {
234  assert(view != nil && "UpdateWindow, view parameter is nil");//view.fID will be also 0.
235 }
236 
237 //______________________________________________________________________________
239 {
240  assert(fView.fContext != 0 && "Execute, view.fContext is null");
241 
242  if (QuartzPixmap *pixmap = fView.fBackBuffer)
243  [fView copy : pixmap area : Rectangle(0, 0, pixmap.fWidth, pixmap.fHeight)
244  withMask : nil clipOrigin : Point() toPoint : Point()];
245 }
246 
247 //______________________________________________________________________________
249  : Command(pixmap, GCValues_t())
250 {
251 }
252 
253 //______________________________________________________________________________
255 {
256  assert(dynamic_cast<TGCocoa *>(gVirtualX) != 0 &&
257  "Execute, gVirtualX is either null or not of TGCocoa type");
258 
259  ((TGCocoa *)gVirtualX)->DeletePixmapAux(fID);
260 }
261 
262 //______________________________________________________________________________
263 DrawBoxXor::DrawBoxXor(Window_t windowID, const Point &p1, const Point &p2)
264  : Command(windowID, GCValues_t()),
265  fP1(p1),
266  fP2(p2)
267 {
268  if (fP1.fX > fP2.fX)
269  std::swap(fP1.fX, fP2.fX);
270  if (fP1.fY > fP2.fY)
271  std::swap(fP1.fY, fP2.fY);
272 }
273 
274 //______________________________________________________________________________
276 {
277  //Noop.
278 }
279 
280 //______________________________________________________________________________
281 void DrawBoxXor::Execute(CGContextRef ctx)const
282 {
283  //
284  assert(ctx != 0 && "Execute, ctx parameter is null");
285 
286  CGContextSetRGBStrokeColor(ctx, 0., 0., 0., 1.);
287  CGContextSetLineWidth(ctx, 1.);
288 
289  CGContextStrokeRect(ctx, CGRectMake(fP1.fX, fP1.fY, fP2.fX - fP1.fX, fP2.fY - fP1.fY));
290 }
291 
292 //______________________________________________________________________________
294  : Command(windowID, GCValues_t()),
295  fP1(p1),
296  fP2(p2)
297 {
298 }
299 
300 //______________________________________________________________________________
302 {
303  //Noop.
304 }
305 
306 //______________________________________________________________________________
307 void DrawLineXor::Execute(CGContextRef ctx)const
308 {
309  //
310  assert(ctx != 0 && "Execute, ctx parameter is null");
311 
312  CGContextSetRGBStrokeColor(ctx, 0., 0., 0., 1.);
313  CGContextSetLineWidth(ctx, 1.);
314 
315  CGContextBeginPath(ctx);
316  CGContextMoveToPoint(ctx, fP1.fX, fP1.fY);
317  CGContextAddLineToPoint(ctx, fP2.fX, fP2.fY);
318  CGContextStrokePath(ctx);
319 }
320 
321 //______________________________________________________________________________
323 {
324 }
325 
326 //______________________________________________________________________________
328 {
329  ClearCommands();
330  ClearXOROperations();
331 }
332 
333 //______________________________________________________________________________
335  Int_t y1, Int_t x2, Int_t y2)
336 {
337  try {
338  //if this throws, I do not care.
339  std::unique_ptr<DrawLine> cmd(new DrawLine(wid, gc, Point(x1, y1), Point(x2, y2)));
340  fCommands.push_back(cmd.get());//this can throw.
341  cmd.release();
342  } catch (const std::exception &) {
343  throw;
344  }
345 }
346 
347 //______________________________________________________________________________
349  const Segment_t *segments, Int_t nSegments)
350 {
351  assert(segments != 0 && "AddDrawSegments, segments parameter is null");
352  assert(nSegments > 0 && "AddDrawSegments, nSegments <= 0");
353 
354  try {
355  std::unique_ptr<DrawSegments> cmd(new DrawSegments(wid, gc, segments, nSegments));
356  fCommands.push_back(cmd.get());
357  cmd.release();
358  } catch (const std::exception &) {
359  throw;
360  }
361 }
362 
363 //______________________________________________________________________________
365 {
366  try {
367  Rectangle_t r = {};//To be replaced with X11::Rectangle.
368  r.fX = x;
369  r.fY = y;
370  r.fWidth = (UShort_t)w;
371  r.fHeight = (UShort_t)h;
372  std::unique_ptr<ClearArea> cmd(new ClearArea(wid, r));//Can throw, nothing leaks.
373  fCommands.push_back(cmd.get());//this can throw.
374  cmd.release();
375  } catch (const std::exception &) {
376  throw;
377  }
378 }
379 
380 //______________________________________________________________________________
382  Int_t srcX, Int_t srcY, UInt_t width, UInt_t height,
383  Int_t dstX, Int_t dstY)
384 {
385  try {
386  Rectangle_t area = {};
387  area.fX = srcX;
388  area.fY = srcY;
389  area.fWidth = (UShort_t)width;
390  area.fHeight = (UShort_t)height;
391  //Can throw, nothing leaks.
392  std::unique_ptr<CopyArea> cmd(new CopyArea(src, dst, gc, area, Point(dstX, dstY)));
393  fCommands.push_back(cmd.get());//this can throw.
394  cmd.release();
395  } catch (const std::exception &) {
396  throw;
397  }
398 }
399 
400 //______________________________________________________________________________
402  const char *text, Int_t len)
403 {
404  try {
405  if (len < 0)//Negative length can come from caller.
406  len = std::strlen(text);
407  const std::string substr(text, len);//Can throw.
408  std::unique_ptr<DrawString> cmd(new DrawString(wid, gc, Point(x, y), substr));//Can throw.
409  fCommands.push_back(cmd.get());//can throw.
410  cmd.release();
411  } catch (const std::exception &) {
412  throw;
413  }
414 }
415 
416 //______________________________________________________________________________
418  Int_t x, Int_t y, UInt_t w, UInt_t h)
419 {
420  try {
421  Rectangle_t r = {};
422  r.fX = x;
423  r.fY = y;
424  r.fWidth = (UShort_t)w;
425  r.fHeight = (UShort_t)h;
426  std::unique_ptr<FillRectangle> cmd(new FillRectangle(wid, gc, r));
427  fCommands.push_back(cmd.get());
428  cmd.release();
429  } catch (const std::exception &) {
430  throw;
431  }
432 }
433 
434 //______________________________________________________________________________
436  Int_t x, Int_t y, UInt_t w, UInt_t h)
437 {
438  try {
439  Rectangle_t r = {};
440  r.fX = x;
441  r.fY = y;
442  r.fWidth = (UShort_t)w;
443  r.fHeight = (UShort_t)h;
444  std::unique_ptr<DrawRectangle> cmd(new DrawRectangle(wid, gc, r));
445  fCommands.push_back(cmd.get());
446  cmd.release();
447  } catch (const std::exception &) {
448  throw;
449  }
450 }
451 
452 //______________________________________________________________________________
454  const Point_t *polygon, Int_t nPoints)
455 {
456  assert(polygon != 0 && "AddFillPolygon, polygon parameter is null");
457  assert(nPoints > 0 && "AddFillPolygon, nPoints <= 0");
458 
459  try {
460  std::unique_ptr<FillPolygon> cmd(new FillPolygon(wid, gc, polygon, nPoints));
461  fCommands.push_back(cmd.get());
462  cmd.release();
463  } catch (const std::exception &) {
464  throw;
465  }
466 }
467 
468 //______________________________________________________________________________
470 {
471  assert(view != nil && "AddUpdateWindow, view parameter is nil");
472 
473  try {
474  std::unique_ptr<UpdateWindow> cmd(new UpdateWindow(view));
475  fCommands.push_back(cmd.get());
476  cmd.release();
477  } catch (const std::exception &) {
478  throw;
479  }
480 }
481 
482 //______________________________________________________________________________
484 {
485  try {
486  std::unique_ptr<DeletePixmap> cmd(new DeletePixmap(pixmapID));
487  fCommands.push_back(cmd.get());
488  cmd.release();
489  } catch (const std::exception &) {
490  throw;
491  }
492 }
493 
494 //______________________________________________________________________________
496 {
497  try {
498  std::unique_ptr<DrawBoxXor> cmd(new DrawBoxXor(windowID, Point(x1, y1), Point(x2, y2)));
499  fXorOps.push_back(cmd.get());
500  cmd.release();
501  } catch (const std::exception &) {
502  throw;
503  }
504 }
505 
506 //______________________________________________________________________________
508 {
509  try {
510  std::unique_ptr<DrawLineXor> cmd(new DrawLineXor(windowID, Point(x1, y1), Point(x2, y2)));
511  fXorOps.push_back(cmd.get());
512  cmd.release();
513  } catch (const std::exception &) {
514  throw;
515  }
516 }
517 
518 //______________________________________________________________________________
520 {
521  assert(impl != 0 && "Flush, impl parameter is null");
522 
523  //Basic es-guarantee: state is unknown, but valid, no
524  //resource leaks, no locked focus.
525 
526  //All magic is here.
527  CGContextRef prevContext = 0;
528  CGContextRef currContext = 0;
529  QuartzView *prevView = nil;
530 
531  for (size_type i = 0, e = fCommands.size(); i < e; ++i) {
532  const Command *cmd = fCommands[i];
533  if (!cmd)//Command was deleted by RemoveOperation/RemoveGraphicsOperation.
534  continue;
535 
536  NSObject<X11Drawable> *drawable = impl->GetDrawable(cmd->fID);
537  if (drawable.fIsPixmap) {
538  cmd->Execute();//Can throw, ok.
539  continue;
540  }
541 
542  QuartzView *view = (QuartzView *)impl->GetWindow(cmd->fID).fContentView;
543 
544  if (prevView != view)
545  ClipOverlaps(view);//Can throw, ok.
546 
547  prevView = view;
548 
549  try {
550  if ([view lockFocusIfCanDraw]) {
551  NSGraphicsContext *nsContext = [NSGraphicsContext currentContext];
552  assert(nsContext != nil && "Flush, currentContext is nil");
553  currContext = (CGContextRef)[nsContext graphicsPort];
554  assert(currContext != 0 && "Flush, graphicsPort is null");//remove this assert?
555 
556  view.fContext = currContext;
557  if (prevContext && prevContext != currContext)
558  CGContextFlush(prevContext);
559  prevContext = currContext;
560 
561  const Quartz::CGStateGuard ctxGuard(currContext);
562 
563  //Clip regions first.
564  if (fClippedRegion.size())
565  CGContextClipToRects(currContext, &fClippedRegion[0], fClippedRegion.size());
566 
567  //Now add also shape combine mask.
569  ClipToShapeMask(view, currContext);
570 
571  cmd->Execute();//This can throw, we should restore as much as we can here.
572 
573  if (view.fBackBuffer) {
574  //Very "special" window.
575  const Rectangle copyArea(0, 0, view.fBackBuffer.fWidth, view.fBackBuffer.fHeight);
576  [view copy : view.fBackBuffer area : copyArea
577  withMask : nil clipOrigin : Point() toPoint : Point()];
578  }
579 
580  [view unlockFocus];
581 
582  view.fContext = 0;
583  }
584  } catch (const std::exception &) {
585  //Focus was locked, roll-back:
586  [view unlockFocus];
587  //View's context was modified, roll-back:
588  view.fContext = 0;
589  //Re-throw, something really bad happened (std::bad_alloc).
590  throw;
591  }
592  }
593 
594  if (currContext)
595  CGContextFlush(currContext);
596 
597  ClearCommands();
598 }
599 
600 //______________________________________________________________________________
602 {
603  assert(impl != 0 && "FlushXOROps, impl parameter is null");
604 
605  if (!fXorOps.size())
606  return;
607 
608  //I assume here, that all XOR ops in one iteration (one Update call) must
609  //be for the same window (if not, there is no normal way to implement this at all).
610 
611  NSObject<X11Drawable> *drawable = impl->GetDrawable(fXorOps[0]->fID);
612 
613  assert([drawable isKindOfClass : [QuartzView class]] &&
614  "FlushXOROps, drawable must be of type QuartzView");
615 
616  QuartzView *view = (QuartzView *)drawable;
617 
618  if ([view lockFocusIfCanDraw]) {
619  NSGraphicsContext *nsContext = [NSGraphicsContext currentContext];
620  assert(nsContext != nil && "FlushXOROps, currentContext is nil");
621  CGContextRef currContext = (CGContextRef)[nsContext graphicsPort];
622  assert(currContext != 0 && "FlushXOROps, graphicsPort is null");//remove this assert?
623 
624  const Quartz::CGStateGuard ctxGuard(currContext);//ctx guard.
625 
626  CGContextSetAllowsAntialiasing(currContext, false);
627 
628  view.fContext = currContext;
629 
630  if (view.fBackBuffer) {//back buffer has canvas' contents.
631  //Very "special" window.
632  const Rectangle copyArea(0, 0, view.fBackBuffer.fWidth, view.fBackBuffer.fHeight);
633  [view copy : view.fBackBuffer area : copyArea
634  withMask : nil clipOrigin : Point() toPoint : Point()];
635  }
636 
637  //Now, do "XOR" drawings.
638  for (size_type i = 0, e = fXorOps.size(); i < e; ++i) {
639  if (fXorOps[i]) {
640  fXorOps[i]->Execute(currContext);
641  }
642  }
643 
644  [view unlockFocus];
645  view.fContext = 0;
646 
647  CGContextFlush(currContext);
648 
649  CGContextSetAllowsAntialiasing(currContext, true);
650  }
651 
652  ClearXOROperations();
653 }
654 
655 //______________________________________________________________________________
657 {
658  for (size_type i = 0; i < fCommands.size(); ++i) {
659  if (fCommands[i] && fCommands[i]->HasOperand(drawable)) {
660  delete fCommands[i];
661  fCommands[i] = 0;
662  }
663  }
664 
665  for (size_type i = 0; i < fXorOps.size(); ++i) {
666  if (fXorOps[i] && fXorOps[i]->HasOperand(drawable)) {
667  delete fXorOps[i];
668  fXorOps[i] = 0;
669  }
670  }
671 }
672 
673 //______________________________________________________________________________
675 {
676  for (size_type i = 0; i < fCommands.size(); ++i) {
677  if (fCommands[i] && fCommands[i]->HasOperand(wid) &&
678  fCommands[i]->IsGraphicsCommand())
679  {
680  delete fCommands[i];
681  fCommands[i] = 0;
682  }
683  }
684 }
685 
686 //______________________________________________________________________________
688 {
689  for (size_type i = 0; i < fCommands.size(); ++i) {
690  if (fXorOps[i] && fXorOps[i]->HasOperand(wid)) {
691  delete fXorOps[i];
692  fXorOps[i] = 0;
693  }
694  }
695 }
696 
697 //______________________________________________________________________________
699 {
700  for (size_type i = 0, e = fCommands.size(); i < e; ++i)
701  delete fCommands[i];
702 
703  fCommands.clear();
704 }
705 
706 //______________________________________________________________________________
708 {
709  for (size_type i = 0, e = fXorOps.size(); i < e; ++i)
710  delete fXorOps[i];
711 
712  fXorOps.clear();
713 }
714 
715 //Clipping machinery.
716 
717 namespace {
718 
719 //________________________________________________________________________________________
720 bool RectsOverlap(const NSRect &r1, const NSRect &r2)
721 {
722  if (r2.origin.x >= r1.origin.x + r1.size.width)
723  return false;
724  if (r2.origin.x + r2.size.width <= r1.origin.x)
725  return false;
726  if (r2.origin.y >= r1.origin.y + r1.size.height)
727  return false;
728  if (r2.origin.y + r2.size.height <= r1.origin.y)
729  return false;
730 
731  return true;
732 }
733 
734 }
735 
736 //______________________________________________________________________________
738 {
739  //QuartzViews do not have backing store.
740  //But ROOT calls gClient->NeedRedraw ignoring
741  //children or overlapping siblings. This leads
742  //to obvious problems, for example, parent
743  //erasing every child inside while repainting itself.
744  //To fix this and emulate window with backing store
745  //without real backing store, I'm calculating the
746  //area of a view this is visible and not overlapped.
747 
748  //Who can overlap our view?
749  //1. Its own siblings and, probably, siblings of its ancestors.
750  //2. Children views.
751 
752  assert(view != nil && "ClipOverlaps, view parameter is nil");
753 
754  typedef std::vector<QuartzView *>::reverse_iterator reverse_iterator;
755  typedef std::vector<CGRect>::iterator rect_iterator;
756 
757  fRectsToClip.clear();
758  fClippedRegion.clear();
759 
760  //Check siblings and ancestors' siblings:
761 
762  //1. Remember the whole branch starting from our view
763  //up to a top-level window.
764  fViewBranch.clear();
765  for (QuartzView *v = view; v; v = v.fParentView)
766  fViewBranch.push_back(v);
767 
768  //We do not need content view, since it does not have any siblings.
769  if (fViewBranch.size())
770  fViewBranch.pop_back();
771 
772  //For every fViewBranch[i] in our branch, we're looking for overlapping siblings.
773  //Calculations are in view.fParentView's coordinate system.
774 
775  WidgetRect clipRect;
776  NSRect frame1 = {};
777 
778  const NSRect frame2 = view.frame;
779 
780  for (reverse_iterator it = fViewBranch.rbegin(), eIt = fViewBranch.rend(); it != eIt; ++it) {
781  QuartzView *ancestorView = *it;//This is either one of ancestors, or a view itself.
782  bool doCheck = false;
783  for (QuartzView *sibling in [ancestorView.fParentView subviews]) {
784  if (ancestorView == sibling) {
785  //View has its children in an array, and for every subviews[i] in this array,
786  //only views with index > i can overlap subviews[i].
787  doCheck = true;//all views after this must be checked.
788  continue;
789  } else if (!doCheck || sibling.fMapState != kIsViewable) {
790  continue;
791  }
792 
793  frame1 = sibling.frame;
794 
795  if (!frame1.size.width || !frame1.size.height)
796  continue;
797 
798  frame1.origin = [sibling.fParentView convertPoint : frame1.origin
799  toView : view.fParentView];
800 
801  //Check if two rects intersect.
802  if (RectsOverlap(frame2, frame1)) {
803  //Substruct frame1 from our view's rect.
804  clipRect.fX1 = frame1.origin.x;
805  clipRect.fX2 = clipRect.fX1 + frame1.size.width;
806  clipRect.fY1 = frame1.origin.y;
807  clipRect.fY2 = clipRect.fY1 + frame1.size.height;
808  fRectsToClip.push_back(clipRect);
809  }
810  }
811  }
812 
813  //Substruct children.
814 
815  for (QuartzView *child in [view subviews]) {
816  if (child.fMapState != kIsViewable)
817  continue;
818 
819  frame1 = child.frame;
820 
821  if (!frame1.size.width || !frame1.size.height)
822  continue;
823 
824  if (view.fParentView)//view can also be a content view.
825  frame1.origin = [view convertPoint : frame1.origin toView : view.fParentView];
826 
827  if (RectsOverlap(frame2, frame1)) {
828  clipRect.fX1 = frame1.origin.x;
829  clipRect.fX2 = clipRect.fX1 + frame1.size.width;
830  clipRect.fY1 = frame1.origin.y;
831  clipRect.fY2 = clipRect.fY1 + frame1.size.height;
832  fRectsToClip.push_back(clipRect);
833  }
834  }
835 
836  if (fRectsToClip.size()) {
837  //Now, if we have any rectanges to substruct them from our view's frame,
838  //we are building a set of rectangles, which represents visible part of view.
839 
840  WidgetRect rect(frame2.origin.x, frame2.origin.y, frame2.origin.x + frame2.size.width,
841  frame2.origin.y + frame2.size.height);
842 
843  BuildClipRegion(rect);
844 
845  if (view.fParentView) {
846  //To able to use this set of rectangles with CGContextClipToRects,
847  //convert them (if needed) into view's own coordinate system.
848  rect_iterator recIt = fClippedRegion.begin(), eIt = fClippedRegion.end();
849  for (; recIt != eIt; ++recIt) {
850  if (!recIt->size.width && !recIt->size.height) {
851  //This is a special 'empty' rectangle, which means our view is completely hidden.
852  assert(fClippedRegion.size() == 1 && "ClipOverlaps, internal logic error");
853  break;
854  }
855  recIt->origin = NSPointToCGPoint([view.fParentView convertPoint :
856  NSPointFromCGPoint(recIt->origin) toView : view]);
857  }
858  }
859  }
860 }
861 
862 namespace {
863 
864 typedef std::vector<int>::iterator int_iterator;
865 
866 //_____________________________________________________________________________________________________
867 int_iterator BinarySearchLeft(int_iterator first, int_iterator last, int value)
868 {
869  if (first == last)
870  return last;
871 
872  const int_iterator it = std::lower_bound(first, last, value);
873  assert(it != last && (it == first || *it == value) && "internal logic error");
874 
875  //If value < *first, return last (not found).
876  return it == first && *it != value ? last : it;
877 }
878 
879 //_____________________________________________________________________________________________________
880 int_iterator BinarySearchRight(int_iterator first, int_iterator last, int value)
881 {
882  if (first == last)
883  return last;
884 
885  const int_iterator it = std::lower_bound(first, last, value);
886  assert((it == last || *it == value) && "internal logic error");
887 
888  return it;
889 }
890 
891 }//unnamed namespace.
892 
893 //_____________________________________________________________________________________________________
895 {
896  //Input requirements:
897  // 1) all rects are valid (non-empty and x1 < x2, y1 < y2);
898  // 2) all rects intersect with widget's rect.
899  //I do not check these conditions here, this is done when filling rectsToClip.
900 
901  //I did not find any reasonable algorithm (have to search better?),
902  //code in gdk and pixman has to many dependencies and is lib-specific +
903  //they require input to be quite special:
904  // a) no overlaps (in my case I have overlaps)
905  // b) sorted in a special way.
906  //To convert my input into such a format
907  //means to implement everything myself (for example, to work out overlaps).
908 
909  //Also, my case is more simple: gdk and pixman substract region (== set of rectangles)
910  //from another region, I have to substract region from _one_ rectangle.
911 
912  //This is quite straightforward implementation - I'm calculation rectangles, which are part of
913  //a widget's rect, not hidden by any of fRectsToClip.
914 
915  typedef std::vector<WidgetRect>::const_iterator rect_const_iterator;
916 
917  assert(fRectsToClip.size() != 0 && "BuildClipRegion, nothing to clip");
918 
919  fClippedRegion.clear();
920  fXBounds.clear();
921  fYBounds.clear();
922 
923  //[First, we "cut" the original rect into stripes.
924  rect_const_iterator recIt = fRectsToClip.begin(), endIt = fRectsToClip.end();
925  for (; recIt != endIt; ++recIt) {
926  if (recIt->fX1 <= rect.fX1 && recIt->fX2 >= rect.fX2 &&
927  recIt->fY1 <= rect.fY1 && recIt->fY2 >= rect.fY2) {
928  //this rect completely overlaps our view, not need to calculate anything at all.
929  fClippedRegion.push_back(CGRectMake(0., 0., 0., 0.));
930  return;
931  }
932 
933  if (recIt->fX1 > rect.fX1)//recIt->x1 is always < rect.x2 (input validation).
934  fXBounds.push_back(recIt->fX1);
935 
936  if (recIt->fX2 < rect.fX2)//recIt->x2 is always > rect.x1 (input validation).
937  fXBounds.push_back(recIt->fX2);
938 
939  if (recIt->fY1 > rect.fY1)
940  fYBounds.push_back(recIt->fY1);
941 
942  if (recIt->fY2 < rect.fY2)
943  fYBounds.push_back(recIt->fY2);
944  }
945 
946  std::sort(fXBounds.begin(), fXBounds.end());
947  std::sort(fYBounds.begin(), fYBounds.end());
948 
949  //We do not need duplicates.
950  const int_iterator xBoundsEnd = std::unique(fXBounds.begin(), fXBounds.end());
951  const int_iterator yBoundsEnd = std::unique(fYBounds.begin(), fYBounds.end());
952  //Rectangle is now "cut into pieces"].
953 
954  const size_type nXBands = size_type(xBoundsEnd - fXBounds.begin()) + 1;
955  const size_type nYBands = size_type(yBoundsEnd - fYBounds.begin()) + 1;
956 
957  fGrid.assign(nXBands * nYBands, false);
958 
959  //Mark the overlapped parts.
960  recIt = fRectsToClip.begin(), endIt = fRectsToClip.end();
961  for (; recIt != endIt; ++recIt) {
962  const int_iterator left = BinarySearchLeft(fXBounds.begin(), xBoundsEnd, recIt->fX1);
963  const size_type firstXBand = left == xBoundsEnd ? 0 : left - fXBounds.begin() + 1;
964 
965  const int_iterator right = BinarySearchRight(fXBounds.begin(), xBoundsEnd, recIt->fX2);
966  const size_type lastXBand = right - fXBounds.begin() + 1;
967 
968  const int_iterator bottom = BinarySearchLeft(fYBounds.begin(), yBoundsEnd, recIt->fY1);
969  const size_type firstYBand = bottom == yBoundsEnd ? 0 : bottom - fYBounds.begin() + 1;
970 
971  const int_iterator top = BinarySearchRight(fYBounds.begin(), yBoundsEnd, recIt->fY2);
972  const size_type lastYBand = top - fYBounds.begin() + 1;
973 
974  for (size_type i = firstYBand; i < lastYBand; ++i) {
975  const size_type baseIndex = i * nXBands;
976  for (size_type j = firstXBand; j < lastXBand; ++j)
977  fGrid[baseIndex + j] = true;
978  }
979  }
980 
981  //I do not merge rectangles.
982  //Search for non-overlapped parts and create rectangles for them.
983  CGRect newRect = {};
984 
985  for (size_type i = 0; i < nYBands; ++i) {
986  const size_type baseIndex = i * nXBands;
987  for (size_type j = 0; j < nXBands; ++j) {
988  if (!fGrid[baseIndex + j]) {
989  newRect.origin.x = j ? fXBounds[j - 1] : rect.fX1;
990  newRect.origin.y = i ? fYBounds[i - 1] : rect.fY1;
991 
992  newRect.size.width = (j == nXBands - 1 ? rect.fX2 : fXBounds[j]) - newRect.origin.x;
993  newRect.size.height = (i == nYBands - 1 ? rect.fY2 : fYBounds[i]) - newRect.origin.y;
994 
995  fClippedRegion.push_back(newRect);
996  }
997  }
998  }
999 
1000  if (!fClippedRegion.size())//Completely hidden
1001  fClippedRegion.push_back(CGRectMake(0., 0., 0., 0.));
1002 }
1003 
1004 }//X11
1005 }//MacOSX
1006 }//ROOT
UShort_t fWidth
Definition: GuiTypes.h:362
DrawRectangle(Drawable_t wid, const GCValues_t &gc, const Rectangle_t &rectangle)
Definition: X11Buffer.mm:211
void RemoveOperationsForDrawable(Drawable_t wid)
Definition: X11Buffer.mm:656
virtual void Execute() const =0
Short_t fY
Definition: GuiTypes.h:361
DrawLine(Drawable_t wid, const GCValues_t &gc, const Point &p1, const Point &p2)
Definition: X11Buffer.mm:73
UShort_t fHeight
Definition: GuiTypes.h:362
void DrawSegmentsAux(Drawable_t wid, const GCValues_t &gcVals, const Segment_t *segments, Int_t nSegments)
Definition: TGCocoa.mm:1731
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
FillRectangle(Drawable_t wid, const GCValues_t &gc, const Rectangle_t &rectangle)
Definition: X11Buffer.mm:172
DrawLineXor(Window_t windowID, const Point &p1, const Point &p2)
Definition: X11Buffer.mm:293
void swap(TDirectoryEntry &e1, TDirectoryEntry &e2) noexcept
bool HasOperand(Drawable_t drawable) const
Definition: X11Buffer.mm:136
unsigned short UShort_t
Definition: RtypesCore.h:36
TH1 * h
Definition: legend2.C:5
void DrawRectangleAux(Drawable_t wid, const GCValues_t &gcVals, Int_t x, Int_t y, UInt_t w, UInt_t h)
Definition: TGCocoa.mm:1784
virtual bool IsGraphicsCommand() const
Definition: X11Buffer.mm:67
DrawBoxXor(Window_t windowID, const Point &p1, const Point &p2)
Definition: X11Buffer.mm:263
QuartzImage * fShapeCombineMask
Definition: QuartzWindow.h:38
void RemoveXORGraphicsOperationsForWindow(Window_t wid)
Definition: X11Buffer.mm:687
NSObject< X11Window > * GetWindow(Window_t windowID) const
int Int_t
Definition: RtypesCore.h:41
void BuildClipRegion(const WidgetRect &rect)
Definition: X11Buffer.mm:894
Handle_t Drawable_t
Definition: GuiTypes.h:30
const GCValues_t fGC
Definition: X11Buffer.h:50
QuartzPixmap * fBackBuffer
Definition: QuartzWindow.h:176
Pixmap_t fClipMask
Definition: GuiTypes.h:246
void AddDrawLineXor(Window_t windowID, Int_t x1, Int_t y1, Int_t x2, Int_t y2)
Definition: X11Buffer.mm:507
DrawString(Drawable_t wid, const GCValues_t &gc, const Point &point, const std::string &text)
Definition: X11Buffer.mm:153
void ClearAreaAux(Window_t wid, Int_t x, Int_t y, UInt_t w, UInt_t h)
Definition: TGCocoa.mm:2257
Command(Drawable_t wid)
Definition: X11Buffer.mm:44
QuartzView * fParentView
Definition: QuartzWindow.h:165
static const double x2[5]
DeletePixmap(Pixmap_t pixmap)
Definition: X11Buffer.mm:248
Double_t x[n]
Definition: legend1.C:17
void AddFillRectangle(Drawable_t wid, const GCValues_t &gc, Int_t x, Int_t y, UInt_t w, UInt_t h)
Definition: X11Buffer.mm:417
void DrawLineAux(Drawable_t wid, const GCValues_t &gcVals, Int_t x1, Int_t y1, Int_t x2, Int_t y2)
Definition: TGCocoa.mm:1646
static double p2(double t, double a, double b, double c)
unsigned fHeight
Definition: QuartzPixmap.h:38
void AddDrawString(Drawable_t wid, const GCValues_t &gc, Int_t x, Int_t y, const char *text, Int_t len)
Definition: X11Buffer.mm:401
QuartzWindow * fQuartzWindow
Definition: QuartzWindow.h:238
DrawSegments(Drawable_t wid, const GCValues_t &gc, const Segment_t *segments, Int_t nSegments)
Definition: X11Buffer.mm:90
void FillRectangleAux(Drawable_t wid, const GCValues_t &gcVals, Int_t x, Int_t y, UInt_t w, UInt_t h)
Definition: TGCocoa.mm:1860
std::vector< Segment_t > fSegments
Definition: X11Buffer.h:84
void AddDrawLine(Drawable_t wid, const GCValues_t &gc, Int_t x1, Int_t y1, Int_t x2, Int_t y2)
Definition: X11Buffer.mm:334
Short_t fX
Definition: GuiTypes.h:361
const std::string fText
Definition: X11Buffer.h:130
void CopyAreaAux(Drawable_t src, Drawable_t dst, const GCValues_t &gc, Int_t srcX, Int_t srcY, UInt_t width, UInt_t height, Int_t dstX, Int_t dstY)
Definition: TGCocoa.mm:2085
point * points
Definition: X3DBuffer.c:20
const Drawable_t fSrc
Definition: X11Buffer.h:110
void Flush(Details::CocoaPrivate *impl)
Definition: X11Buffer.mm:519
ROOT::R::TRInterface & r
Definition: Object.C:4
void DrawStringAux(Drawable_t wid, const GCValues_t &gc, Int_t x, Int_t y, const char *s, Int_t len)
Definition: TGCocoa.mm:2166
SVector< double, 2 > v
Definition: Dict.h:5
NSObject< X11Drawable > * GetDrawable(Drawable_t drawableD) const
Definition: CocoaPrivate.mm:91
const Rectangle_t fRectangle
Definition: X11Buffer.h:145
const Rectangle_t fArea
Definition: X11Buffer.h:97
CopyArea(Drawable_t src, Drawable_t dst, const GCValues_t &gc, const Rectangle_t &area, const Point &dstPoint)
Definition: X11Buffer.mm:126
void AddDrawSegments(Drawable_t wid, const GCValues_t &gc, const Segment_t *segments, Int_t nSegments)
Definition: X11Buffer.mm:348
virtual bool HasOperand(Drawable_t drawable) const
Definition: X11Buffer.mm:61
unsigned int UInt_t
Definition: RtypesCore.h:42
FillPolygon(Drawable_t wid, const GCValues_t &gc, const Point_t *points, Int_t nPoints)
Definition: X11Buffer.mm:191
static double p1(double t, double a, double b)
void RemoveGraphicsOperationsForWindow(Window_t wid)
Definition: X11Buffer.mm:674
lv DrawLine(0.33, 0.0, 0.33, 1.0)
#define gVirtualX
Definition: TVirtualX.h:350
unsigned fWidth
Definition: QuartzPixmap.h:37
const Drawable_t fID
Definition: X11Buffer.h:49
std::vector< Command * >::size_type size_type
Definition: X11Buffer.h:244
void ClipOverlaps(QuartzView *view)
Definition: X11Buffer.mm:737
CGContextRef fContext
Definition: QuartzWindow.h:155
static const double x1[5]
ClearArea(Window_t wid, const Rectangle_t &area)
Definition: X11Buffer.mm:110
void FlushXOROps(Details::CocoaPrivate *impl)
Definition: X11Buffer.mm:601
void AddClearArea(Window_t wid, Int_t x, Int_t y, UInt_t w, UInt_t h)
Definition: X11Buffer.mm:364
TText * text
std::vector< Point_t > fPolygon
Definition: X11Buffer.h:160
const Rectangle_t fArea
Definition: X11Buffer.h:111
Double_t y[n]
Definition: legend1.C:17
void AddFillPolygon(Drawable_t wid, const GCValues_t &gc, const Point_t *polygon, Int_t nPoints)
Definition: X11Buffer.mm:453
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
Definition: TRolke.cxx:630
void ClipToShapeMask(NSView< X11Window > *view, CGContextRef ctx)
UpdateWindow(QuartzView *view)
Definition: X11Buffer.mm:230
void AddDrawRectangle(Drawable_t wid, const GCValues_t &gc, Int_t x, Int_t y, UInt_t w, UInt_t h)
Definition: X11Buffer.mm:435
Handle_t Window_t
Definition: GuiTypes.h:28
This class implements TVirtualX interface for MacOS X, using Cocoa and Quartz 2D. ...
Definition: TGCocoa.h:58
Handle_t Pixmap_t
Definition: GuiTypes.h:29
void AddDeletePixmap(Pixmap_t pixmap)
Definition: X11Buffer.mm:483
void AddCopyArea(Drawable_t src, Drawable_t dst, const GCValues_t &gc, Int_t srcX, Int_t srcY, UInt_t width, UInt_t height, Int_t dstX, Int_t dstY)
Definition: X11Buffer.mm:381
Definition: first.py:1
void AddUpdateWindow(QuartzView *view)
Definition: X11Buffer.mm:469
void AddDrawBoxXor(Window_t windowID, Int_t x1, Int_t y1, Int_t x2, Int_t y2)
Definition: X11Buffer.mm:495