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