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