Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGGC.cxx
Go to the documentation of this file.
1 // @(#)root/gui:$Id$
2 // Author: Fons Rademakers 20/9/2000
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, 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 //////////////////////////////////////////////////////////////////////////
13 // //
14 // TGGC and TGGCPool //
15 // //
16 // Encapsulate a graphics context used in the low level graphics. //
17 // TGGCPool provides a pool of graphics contexts. //
18 // //
19 //////////////////////////////////////////////////////////////////////////
20 
21 #include "TGClient.h"
22 #include "TGGC.h"
23 #include "TVirtualX.h"
24 #include "THashTable.h"
25 #include "TColor.h"
26 #include "TROOT.h"
27 #include "Riostream.h"
28 #include <string.h>
29 
30 
31 ClassImp(TGGC);
32 
33 ////////////////////////////////////////////////////////////////////////////////
34 /// Create a graphics context (only called via TGGCPool::GetGC()).
35 
36 TGGC::TGGC(GCValues_t *values, Bool_t)
37 {
38  fContext = 0;
39  if (values) {
40  fValues = *values;
41  fContext = gVirtualX->CreateGC(gVirtualX->GetDefaultRootWindow(), values);
42  if (values->fMask & kGCDashList) {
43  if (values->fDashLen > (Int_t)sizeof(fValues.fDashes))
44  Warning("TGGC", "dash list can have only up to %ld elements",
45  (Long_t)sizeof(fValues.fDashes));
46  fValues.fDashLen = TMath::Min(values->fDashLen, (Int_t)sizeof(fValues.fDashes));
47  gVirtualX->SetDashes(fContext, fValues.fDashOffset, fValues.fDashes,
48  fValues.fDashLen);
49  }
50  } else {
51  fValues = {};
52  fContext = 0;
53  }
54  SetRefCount(1);
55 }
56 
57 ////////////////////////////////////////////////////////////////////////////////
58 /// Create a graphics context, registers GC in GCPool.
59 
60 TGGC::TGGC(GCValues_t *values)
61 {
62  fContext = 0;
63  // case of default ctor at program startup before gClient exists
64  if (!values) {
65  fValues = {};
66  fContext = 0;
67  SetRefCount(1);
68  return;
69  }
70 
71  if (gClient)
72  gClient->GetGC(values, kTRUE);
73  else {
74  fContext = 0;
75  Error("TGGC", "TGClient not yet initialized, should never happen");
76  }
77 }
78 
79 ////////////////////////////////////////////////////////////////////////////////
80 /// Copy a graphics context.
81 
82 TGGC::TGGC(const TGGC &g) : TObject(g), TRefCnt()
83 {
84  fValues = g.fValues;
85  if (g.fContext) {
86  fContext = gVirtualX->CreateGC(gVirtualX->GetDefaultRootWindow(), &fValues);
87  if (fValues.fMask & kGCDashList)
88  gVirtualX->SetDashes(fContext, fValues.fDashOffset, fValues.fDashes,
89  fValues.fDashLen);
90  } else
91  fContext = 0;
92  SetRefCount(1);
93 
94  if (gClient)
95  gClient->GetGCPool()->fList->Add(this);
96 }
97 
98 ////////////////////////////////////////////////////////////////////////////////
99 /// Delete graphics context.
100 
101 TGGC::~TGGC()
102 {
103  if (gClient)
104  gClient->GetGCPool()->ForceFreeGC(this);
105 
106  if (fContext)
107  gVirtualX->DeleteGC(fContext);
108 }
109 
110 ////////////////////////////////////////////////////////////////////////////////
111 /// Graphics context assignment operator.
112 
113 TGGC &TGGC::operator=(const TGGC &rhs)
114 {
115  if (this != &rhs) {
116  if (!fContext && gClient) {
117  TGGC *gc = gClient->GetGCPool()->FindGC(this);
118  if (!gc)
119  gClient->GetGCPool()->fList->Add(this);
120  }
121  if (fContext)
122  gVirtualX->DeleteGC(fContext);
123  TObject::operator=(rhs);
124  fValues = rhs.fValues;
125  fContext = gVirtualX->CreateGC(gVirtualX->GetDefaultRootWindow(), &fValues);
126  if (fValues.fMask & kGCDashList)
127  gVirtualX->SetDashes(fContext, fValues.fDashOffset, fValues.fDashes,
128  fValues.fDashLen);
129  }
130  return *this;
131 }
132 
133 ////////////////////////////////////////////////////////////////////////////////
134 /// Not inline due to a bug in g++ 2.96 20000731 (Red Hat Linux 7.0).
135 
136 GContext_t TGGC::operator()() const
137 {
138  return fContext;
139 }
140 
141 ////////////////////////////////////////////////////////////////////////////////
142 /// Update values + mask.
143 
144 void TGGC::UpdateValues(GCValues_t *values)
145 {
146  fValues.fMask |= values->fMask;
147 
148  for (Mask_t bit = 1; bit <= fValues.fMask; bit <<= 1) {
149  switch (bit & values->fMask) {
150  default:
151  case 0:
152  continue;
153  case kGCFunction:
154  fValues.fFunction = values->fFunction;
155  break;
156  case kGCPlaneMask:
157  fValues.fPlaneMask = values->fPlaneMask;
158  break;
159  case kGCForeground:
160  fValues.fForeground = values->fForeground;
161  break;
162  case kGCBackground:
163  fValues.fBackground = values->fBackground;
164  break;
165  case kGCLineWidth:
166  fValues.fLineWidth = values->fLineWidth;
167  break;
168  case kGCLineStyle:
169  fValues.fLineStyle = values->fLineStyle;
170  break;
171  case kGCCapStyle:
172  fValues.fCapStyle = values->fCapStyle;
173  break;
174  case kGCJoinStyle:
175  fValues.fJoinStyle = values->fJoinStyle;
176  break;
177  case kGCFillStyle:
178  fValues.fFillStyle = values->fFillStyle;
179  break;
180  case kGCFillRule:
181  fValues.fFillRule = values->fFillRule;
182  break;
183  case kGCTile:
184  fValues.fTile = values->fTile;
185  break;
186  case kGCStipple:
187  fValues.fStipple = values->fStipple;
188  break;
189  case kGCTileStipXOrigin:
190  fValues.fTsXOrigin = values->fTsXOrigin;
191  break;
192  case kGCTileStipYOrigin:
193  fValues.fTsYOrigin = values->fTsYOrigin;
194  break;
195  case kGCFont:
196  fValues.fFont = values->fFont;
197  break;
198  case kGCSubwindowMode:
199  fValues.fSubwindowMode = values->fSubwindowMode;
200  break;
201  case kGCGraphicsExposures:
202  fValues.fGraphicsExposures = values->fGraphicsExposures;
203  break;
204  case kGCClipXOrigin:
205  fValues.fClipXOrigin = values->fClipXOrigin;
206  break;
207  case kGCClipYOrigin:
208  fValues.fClipYOrigin = values->fClipYOrigin;
209  break;
210  case kGCClipMask:
211  fValues.fClipMask = values->fClipMask;
212  break;
213  case kGCDashOffset:
214  fValues.fDashOffset = values->fDashOffset;
215  break;
216  case kGCDashList:
217  if (values->fDashLen > (Int_t)sizeof(fValues.fDashes))
218  Warning("UpdateValues", "dash list can have only up to %ld elements",
219  (Long_t)sizeof(fValues.fDashes));
220  fValues.fDashLen = TMath::Min(values->fDashLen, (Int_t)sizeof(fValues.fDashes));
221  memcpy(fValues.fDashes, values->fDashes, fValues.fDashLen);
222  break;
223  case kGCArcMode:
224  fValues.fArcMode = values->fArcMode;
225  break;
226  }
227  }
228 }
229 
230 ////////////////////////////////////////////////////////////////////////////////
231 /// Set attributes as specified in the values structure.
232 
233 void TGGC::SetAttributes(GCValues_t *values)
234 {
235  if (!fContext && gClient) {
236  TGGC *gc = gClient->GetGCPool()->FindGC(this);
237  if (!gc)
238  gClient->GetGCPool()->fList->Add(this);
239  }
240 
241  if (fContext)
242  gVirtualX->ChangeGC(fContext, values);
243  else
244  fContext = gVirtualX->CreateGC(gVirtualX->GetDefaultRootWindow(), values);
245  UpdateValues(values);
246  if (values->fMask & kGCDashList)
247  gVirtualX->SetDashes(fContext, fValues.fDashOffset, fValues.fDashes,
248  fValues.fDashLen);
249 }
250 
251 ////////////////////////////////////////////////////////////////////////////////
252 /// Set graphics context drawing function.
253 
254 void TGGC::SetFunction(EGraphicsFunction v)
255 {
256  GCValues_t values;
257  values.fFunction = v;
258  values.fMask = kGCFunction;
259  SetAttributes(&values);
260 }
261 
262 ////////////////////////////////////////////////////////////////////////////////
263 /// Set plane mask.
264 
265 void TGGC::SetPlaneMask(ULong_t v)
266 {
267  GCValues_t values;
268  values.fPlaneMask = v;
269  values.fMask = kGCPlaneMask;
270  SetAttributes(&values);
271 }
272 
273 ////////////////////////////////////////////////////////////////////////////////
274 /// Set foreground color.
275 
276 void TGGC::SetForeground(ULong_t v)
277 {
278  GCValues_t values;
279  values.fForeground = v;
280  values.fMask = kGCForeground;
281  SetAttributes(&values);
282 }
283 
284 ////////////////////////////////////////////////////////////////////////////////
285 /// Set background color.
286 
287 void TGGC::SetBackground(ULong_t v)
288 {
289  GCValues_t values;
290  values.fBackground = v;
291  values.fMask = kGCBackground;
292  SetAttributes(&values);
293 }
294 
295 ////////////////////////////////////////////////////////////////////////////////
296 /// Set line width.
297 
298 void TGGC::SetLineWidth(Int_t v)
299 {
300  GCValues_t values;
301  values.fLineWidth = v;
302  values.fMask = kGCLineWidth;
303  SetAttributes(&values);
304 }
305 
306 ////////////////////////////////////////////////////////////////////////////////
307 /// Set line style (kLineSolid, kLineOnOffDash, kLineDoubleDash).
308 
309 void TGGC::SetLineStyle(Int_t v)
310 {
311  GCValues_t values;
312  values.fLineStyle = v;
313  values.fMask = kGCLineStyle;
314  SetAttributes(&values);
315 }
316 
317 ////////////////////////////////////////////////////////////////////////////////
318 /// Set cap style (kCapNotLast, kCapButt, kCapRound, kCapProjecting).
319 
320 void TGGC::SetCapStyle(Int_t v)
321 {
322  GCValues_t values;
323  values.fCapStyle = v;
324  values.fMask = kGCCapStyle;
325  SetAttributes(&values);
326 }
327 
328 ////////////////////////////////////////////////////////////////////////////////
329 /// Set line join style (kJoinMiter, kJoinRound, kJoinBevel).
330 
331 void TGGC::SetJoinStyle(Int_t v)
332 {
333  GCValues_t values;
334  values.fJoinStyle = v;
335  values.fMask = kGCJoinStyle;
336  SetAttributes(&values);
337 }
338 
339 ////////////////////////////////////////////////////////////////////////////////
340 /// Set fill style (kFillSolid, kFillTiled, kFillStippled,
341 /// kFillOpaeueStippled).
342 
343 void TGGC::SetFillStyle(Int_t v)
344 {
345  GCValues_t values;
346  values.fFillStyle = v;
347  values.fMask = kGCFillStyle;
348  SetAttributes(&values);
349 }
350 
351 ////////////////////////////////////////////////////////////////////////////////
352 /// Set fill rule (kEvenOddRule, kWindingRule).
353 
354 void TGGC::SetFillRule(Int_t v)
355 {
356  GCValues_t values;
357  values.fFillRule = v;
358  values.fMask = kGCFillRule;
359  SetAttributes(&values);
360 }
361 
362 ////////////////////////////////////////////////////////////////////////////////
363 /// Set tile pixmap for tiling operations.
364 
365 void TGGC::SetTile(Pixmap_t v)
366 {
367  GCValues_t values;
368  values.fTile = v;
369  values.fMask = kGCTile;
370  SetAttributes(&values);
371 }
372 
373 ////////////////////////////////////////////////////////////////////////////////
374 /// Set 1 plane pixmap for stippling.
375 
376 void TGGC::SetStipple(Pixmap_t v)
377 {
378  GCValues_t values;
379  values.fStipple = v;
380  values.fMask = kGCStipple;
381  SetAttributes(&values);
382 }
383 
384 ////////////////////////////////////////////////////////////////////////////////
385 /// X offset for tile or stipple operations.
386 
387 void TGGC::SetTileStipXOrigin(Int_t v)
388 {
389  GCValues_t values;
390  values.fTsXOrigin = v;
391  values.fMask = kGCTileStipXOrigin;
392  SetAttributes(&values);
393 }
394 
395 ////////////////////////////////////////////////////////////////////////////////
396 /// Y offset for tile or stipple operations.
397 
398 void TGGC::SetTileStipYOrigin(Int_t v)
399 {
400  GCValues_t values;
401  values.fTsYOrigin = v;
402  values.fMask = kGCTileStipYOrigin;
403  SetAttributes(&values);
404 }
405 
406 ////////////////////////////////////////////////////////////////////////////////
407 /// Set font.
408 
409 void TGGC::SetFont(FontH_t v)
410 {
411  GCValues_t values;
412  values.fFont = v;
413  values.fMask = kGCFont;
414  SetAttributes(&values);
415 }
416 
417 ////////////////////////////////////////////////////////////////////////////////
418 /// Set sub window mode (kClipByChildren, kIncludeInferiors).
419 
420 void TGGC::SetSubwindowMode(Int_t v)
421 {
422  GCValues_t values;
423  values.fSubwindowMode = v;
424  values.fMask = kGCSubwindowMode;
425  SetAttributes(&values);
426 }
427 
428 ////////////////////////////////////////////////////////////////////////////////
429 /// True if graphics exposure should be generated.
430 
431 void TGGC::SetGraphicsExposures(Bool_t v)
432 {
433  GCValues_t values;
434  values.fGraphicsExposures = v;
435  values.fMask = kGCGraphicsExposures;
436  SetAttributes(&values);
437 }
438 
439 ////////////////////////////////////////////////////////////////////////////////
440 /// X origin for clipping.
441 
442 void TGGC::SetClipXOrigin(Int_t v)
443 {
444  GCValues_t values;
445  values.fClipXOrigin = v;
446  values.fMask = kGCClipXOrigin;
447  SetAttributes(&values);
448 }
449 
450 ////////////////////////////////////////////////////////////////////////////////
451 /// Y origin for clipping.
452 
453 void TGGC::SetClipYOrigin(Int_t v)
454 {
455  GCValues_t values;
456  values.fClipYOrigin = v;
457  values.fMask = kGCClipYOrigin;
458  SetAttributes(&values);
459 }
460 
461 ////////////////////////////////////////////////////////////////////////////////
462 /// Bitmap for clipping.
463 
464 void TGGC::SetClipMask(Pixmap_t v)
465 {
466  GCValues_t values;
467  values.fClipMask = v;
468  values.fMask = kGCClipMask;
469  SetAttributes(&values);
470 }
471 
472 ////////////////////////////////////////////////////////////////////////////////
473 /// Patterned/dashed line offset.
474 
475 void TGGC::SetDashOffset(Int_t v)
476 {
477  GCValues_t values;
478  values.fDashOffset = v;
479  values.fMask = kGCDashOffset;
480  SetAttributes(&values);
481 }
482 
483 ////////////////////////////////////////////////////////////////////////////////
484 /// Set dash pattern. First use SetDashOffset() if not 0.
485 
486 void TGGC::SetDashList(const char v[], Int_t len)
487 {
488  GCValues_t values;
489  if (len > (Int_t)sizeof(values.fDashes))
490  Warning("SetDashList", "dash list can have only up to %ld elements",
491  (Long_t)sizeof(values.fDashes));
492  values.fDashLen = TMath::Min(len, (Int_t)sizeof(values.fDashes));
493  memcpy(values.fDashes, v, values.fDashLen);
494  values.fMask = kGCDashList;
495  SetAttributes(&values);
496 }
497 
498 ////////////////////////////////////////////////////////////////////////////////
499 /// Set arc mode (kArcChord, kArcPieSlice).
500 
501 void TGGC::SetArcMode(Int_t v)
502 {
503  GCValues_t values;
504  values.fArcMode = v;
505  values.fMask = kGCArcMode;
506  SetAttributes(&values);
507 }
508 
509 ////////////////////////////////////////////////////////////////////////////////
510 /// Print graphics contexts info.
511 
512 void TGGC::Print(Option_t *) const
513 {
514  Printf("TGGC: mask = %x, handle = %lx, ref cnt = %u", fValues.fMask,
515  fContext, References());
516 }
517 
518 ////////////////////////////////////////////////////////////////////////////////
519 /// Returns GC mask as a string - used in SavePrimitive().
520 
521 TString TGGC::GetMaskString() const
522 {
523  TString mask;
524 
525  Mask_t fmask = GetMask();
526 
527  if (fmask & kGCFunction) {
528  if (mask.Length() == 0) mask = "kGCFunction";
529  else mask += " | kGCFunction";
530  }
531  if (fmask & kGCPlaneMask) {
532  if (mask.Length() == 0) mask = "kGCPlaneMask";
533  else mask += " | kGCPlaneMask";
534  }
535  if (fmask & kGCForeground) {
536  if (mask.Length() == 0) mask = "kGCForeground";
537  else mask += " | kGCForeground";
538  }
539  if (fmask & kGCBackground) {
540  if (mask.Length() == 0) mask = "kGCBackground";
541  else mask += " | kGCBackground";
542  }
543  if (fmask & kGCLineWidth) {
544  if (mask.Length() == 0) mask = "kGCLineWidth";
545  else mask += " | kGCLineWidth";
546  }
547  if (fmask & kGCLineStyle) {
548  if (mask.Length() == 0) mask = "kGCLineStyle";
549  else mask += " | kGCLineStyle";
550  }
551  if (fmask & kGCCapStyle) {
552  if (mask.Length() == 0) mask = "kGCCapStyle";
553  else mask += " | kGCCapStyle";
554  }
555  if (fmask & kGCJoinStyle) {
556  if (mask.Length() == 0) mask = "kGCJoinStyle";
557  else mask += " | kGCJoinStyle";
558  }
559  if (fmask & kGCFillStyle) {
560  if (mask.Length() == 0) mask = "kGCFillStyle";
561  else mask += " | kGCFillStyle";
562  }
563  if (fmask & kGCFillRule) {
564  if (mask.Length() == 0) mask = "kGCFillRule";
565  else mask += " | kGCFillRule";
566  }
567  if (fmask & kGCTile) {
568  if (mask.Length() == 0) mask = "kGCTile";
569  else mask += " | kGCTile";
570  }
571  if (fmask & kGCStipple) {
572  if (mask.Length() == 0) mask = "kGCStipple";
573  else mask += " | kGCStipple";
574  }
575  if (fmask & kGCTileStipXOrigin) {
576  if (mask.Length() == 0) mask = "kGCTileStipXOrigin";
577  else mask += " | kGCTileStipXOrigin";
578  }
579  if (fmask & kGCTileStipYOrigin) {
580  if (mask.Length() == 0) mask = "kGCTileStipYOrigin";
581  else mask += " | kGCTileStipYOrigin";
582  }
583  if (fmask & kGCFont) {
584  if (mask.Length() == 0) mask = "kGCFont";
585  else mask += " | kGCFont";
586  }
587  if (fmask & kGCSubwindowMode) {
588  if (mask.Length() == 0) mask = "kGCSubwindowMode";
589  else mask += " | kGCSubwindowMode";
590  }
591  if (fmask & kGCGraphicsExposures) {
592  if (mask.Length() == 0) mask = "kGCGraphicsExposures";
593  else mask += " | kGCGraphicsExposures";
594  }
595  if (fmask & kGCClipXOrigin) {
596  if (mask.Length() == 0) mask = "kGCClipXOrigin";
597  else mask += " | kGCClipXOrigin";
598  }
599  if (fmask & kGCClipYOrigin) {
600  if (mask.Length() == 0) mask = "kGCClipYOrigin";
601  else mask += " | kGCClipYOrigin";
602  }
603  if (fmask & kGCClipMask) {
604  if (mask.Length() == 0) mask = "kGCClipMask";
605  else mask += " | kGCClipMask";
606  }
607  if (fmask & kGCDashOffset) {
608  if (mask.Length() == 0) mask = "kGCDashOffset";
609  else mask += " | kGCDashOffset";
610  }
611  if (fmask & kGCDashList) {
612  if (mask.Length() == 0) mask = "kGCDashList";
613  else mask += " | kGCDashList";
614  }
615  if (fmask & kGCArcMode) {
616  if (mask.Length() == 0) mask = "kGCArcMode";
617  else mask += " | kGCArcMode";
618  }
619  return mask;
620 }
621 
622 ////////////////////////////////////////////////////////////////////////////////
623 /// Save graphics context info as a C++ statement(s) on output stream out
624 
625 void TGGC::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/)
626 {
627  if (gROOT->ClassSaved(TGGC::Class())) {
628  out << std::endl;
629  } else {
630  // declare graphics context object to reflect required user changes
631  out << std::endl;
632  out << " TGGC *uGC; // will reflect user GC changes" << std::endl;
633  }
634 
635  Mask_t fmask = GetMask();
636 
637  const char *colorname;
638  TString valname;
639  char quote ='"';
640  ULong_t color;
641 
642  valname = TString::Format("val%s", option);
643 
644  out << " // graphics context changes" << std::endl;
645  //out << " TGGC *uGC" << option << ";" << std::endl;
646  out << " GCValues_t " << valname.Data() << ";" << std::endl;
647  out << " " << valname.Data() << ".fMask = " << GetMaskString() << ";" << std::endl;
648 
649  for (Mask_t bit = 1; bit <= fmask; bit <<= 1) {
650  switch (bit & fmask) {
651  default:
652  case 0:
653  continue;
654  case kGCFunction:
655  out << " " << valname.Data() << ".fFunction = ";
656  switch (GetFunction()) {
657  case kGXclear:
658  out << "kGXclear";
659  break;
660  case kGXand:
661  out << "kGXand";
662  break;
663  case kGXandReverse:
664  out << "kGXandReverse";
665  break;
666  case kGXcopy:
667  out << "kGXcopy";
668  break;
669  case kGXandInverted:
670  out << "kGXandInverted";
671  break;
672  case kGXnoop:
673  out << "kGXnoop";
674  break;
675  case kGXxor:
676  out << "kGXxor";
677  break;
678  case kGXor:
679  out << "kGXor";
680  break;
681  case kGXnor:
682  out << "kGXnor";
683  break;
684  case kGXequiv:
685  out << "kGXequiv";
686  break;
687  case kGXinvert:
688  out << "kGXinvert";
689  break;
690  case kGXorReverse:
691  out << "kGXorReverse";
692  break;
693  case kGXcopyInverted:
694  out << "kGXcopyInverted";
695  break;
696  case kGXorInverted:
697  out << "kGXorInverted";
698  break;
699  case kGXnand:
700  out << "kGXnand";
701  break;
702  case kGXset:
703  out << "kGXset";
704  break;
705  }
706  out << ";" << std::endl;
707  break;
708  case kGCPlaneMask:
709  out << " " << valname.Data() << ".fPlaneMask = " << GetPlaneMask() << ";" << std::endl;
710  break;
711  case kGCForeground:
712  color = GetForeground();
713  colorname = TColor::PixelAsHexString(color);
714  out << " gClient->GetColorByName(" << quote << colorname << quote
715  << "," << valname.Data() << ".fForeground);" << std::endl;
716  break;
717  case kGCBackground:
718  color = GetBackground();
719  colorname = TColor::PixelAsHexString(color);
720  out << " gClient->GetColorByName(" << quote << colorname << quote
721  << "," << valname.Data() << ".fBackground);" << std::endl;
722  break;
723  case kGCLineWidth:
724  out << " " << valname.Data() << ".fLineWidth = " << GetLineWidth() << ";" << std::endl;
725  break;
726  case kGCLineStyle:
727  out << " " << valname.Data() << ".fLineStyle = ";
728  switch (GetLineStyle()) {
729  case kLineSolid:
730  out << "kLineSolid";
731  break;
732  case kLineOnOffDash:
733  out << "kLineOnOffDash";
734  break;
735  case kLineDoubleDash:
736  out << "kLineDoubleDash";
737  break;
738  }
739  out << ";" << std::endl;
740  break;
741  case kGCCapStyle:
742  out << " " << valname.Data() << ".fCapStyle = ";
743  switch (GetCapStyle()) {
744  case kCapNotLast:
745  out << "kCapNotLast";
746  break;
747  case kCapButt:
748  out << "kCapButt";
749  break;
750  case kCapRound:
751  out << "kCapRound";
752  break;
753  case kCapProjecting:
754  out << "kCapProjecting";
755  break;
756  }
757  out << ";" << std::endl;
758  break;
759  case kGCJoinStyle:
760  out << " " << valname.Data() << ".fJoinStyle = ";
761  switch (GetJoinStyle()) {
762  case kJoinMiter:
763  out << "kJoinMiter";
764  break;
765  case kJoinRound:
766  out << "kJoinRound";
767  break;
768  case kJoinBevel:
769  out << "kJoinBevel";
770  break;
771  }
772  out << ";" << std::endl;
773  break;
774  case kGCFillStyle:
775  out << " " << valname.Data() << ".fFillStyle = ";
776  switch (GetFillStyle()) {
777  case kFillSolid:
778  out << "kFillSolid";
779  break;
780  case kFillTiled:
781  out << "kFillTiled";
782  break;
783  case kFillStippled:
784  out << "kFillStippled";
785  break;
786  case kFillOpaqueStippled:
787  out << "kFillOpaqueStippled";
788  break;
789  }
790  out << ";" << std::endl;
791  break;
792  case kGCFillRule:
793  out << " " << valname.Data() << ".fFillRule = ";
794  switch (GetFillRule()) {
795  case kEvenOddRule:
796  out << "kEvenOddRule";
797  break;
798  case kWindingRule:
799  out << "kWindingRule";
800  break;
801  }
802  out << ";" << std::endl;
803  break;
804  case kGCTile:
805  out << " " << valname.Data() << ".fTile = " << GetTile() << ";" << std::endl;
806  break;
807  case kGCStipple:
808  out << " " << valname.Data() << ".fStipple = " << GetStipple() << ";" << std::endl;
809  break;
810  case kGCTileStipXOrigin:
811  out << " " << valname.Data() << ".fTsXOrigin = " << GetTileStipXOrigin() << ";" << std::endl;
812  break;
813  case kGCTileStipYOrigin:
814  out << " " << valname.Data() << ".fTsYOrigin = " << GetTileStipYOrigin() << ";" << std::endl;
815  break;
816  case kGCFont:
817  out << " " << valname.Data() << ".fFont = ufont->GetFontHandle();" << std::endl;
818  break;
819  case kGCSubwindowMode:
820  out << " " << valname.Data() << ".fSubwindowMode = ";
821  switch (GetSubwindowMode()) {
822  case kClipByChildren:
823  out << "kClipByChildren";
824  break;
825  case kIncludeInferiors:
826  out << "kIncludeInferiors";
827  break;
828  }
829  out << ";" << std::endl;
830  break;
831  case kGCGraphicsExposures:
832  out << " " << valname.Data() << ".fGraphicsExposures = ";
833  if (GetGraphicsExposures())
834  out << "kTRUE";
835  else
836  out << "kFALSE";
837  out << ";" << std::endl;
838  break;
839  case kGCClipXOrigin:
840  out << " " << valname.Data() << ".fClipXOrigin = " << GetClipXOrigin() << ";" << std::endl;
841  break;
842  case kGCClipYOrigin:
843  out << " " << valname.Data() << ".fClipYOrigin = " << GetClipYOrigin() << ";" << std::endl;
844  break;
845  case kGCClipMask:
846  out << " " << valname.Data() << ".fClipMask = " << GetClipMask() << ";" << std::endl;
847  break;
848  case kGCDashOffset:
849  out << " " << valname.Data() << ".fDashOffset = " << GetDashOffset() << ";" << std::endl;
850  break;
851  case kGCDashList:
852  if (GetDashLen() > (Int_t)sizeof(GetDashes()))
853  Warning("TGGC::SavePrimitive", "dash list can have only up to %ld elements",
854  (Long_t)sizeof(GetDashes()));
855  out << " " << valname.Data() << ".fDashLen = "
856  << TMath::Min(GetDashLen(),(Int_t)sizeof(GetDashes())) << ";" << std::endl;
857  out << " memcpy(GetDashes()," << valname.Data() << ".fDashes,"
858  << valname.Data() << ".fDashLen);" << std::endl;
859  break;
860  case kGCArcMode:
861  out << " " << valname.Data() << ".fArcMode = ";
862  switch (GetArcMode()) {
863  case kArcChord:
864  out << "kArcChord";
865  break;
866  case kArcPieSlice:
867  out << "kArcPieSlice";
868  break;
869  }
870  out << ";" << std::endl;
871  break;
872  }
873  }
874  out << " uGC = gClient->GetGC(&" << valname.Data() << ", kTRUE);" << std::endl;
875 }
876 
877 
878 ClassImp(TGGCPool);
879 
880 ////////////////////////////////////////////////////////////////////////////////
881 /// Create graphics context pool.
882 
883 TGGCPool::TGGCPool(TGClient *client)
884 {
885  fClient = client;
886  fList = new THashTable;
887  fList->SetOwner();
888 }
889 
890 ////////////////////////////////////////////////////////////////////////////////
891 /// Delete graphics context pool.
892 
893 TGGCPool::~TGGCPool()
894 {
895  delete fList;
896 }
897 
898 ////////////////////////////////////////////////////////////////////////////////
899 /// Force remove graphics context from list. Is only called via ~TGGC().
900 
901 void TGGCPool::ForceFreeGC(const TGGC *gct)
902 {
903  TGGC *gc = (TGGC *) fList->FindObject(gct);
904 
905  if (gc) {
906  if (gc->References() > 1)
907  Error("ForceFreeGC", "removed a shared graphics context\n"
908  "best to use graphics contexts via the TGGCPool()");
909  fList->Remove(gc);
910  }
911 }
912 
913 ////////////////////////////////////////////////////////////////////////////////
914 /// Delete graphics context if it is not used anymore.
915 
916 void TGGCPool::FreeGC(const TGGC *gct)
917 {
918  TGGC *gc = (TGGC *) fList->FindObject(gct);
919 
920  if (gc) {
921  if (gc->RemoveReference() == 0) {
922  fList->Remove(gc);
923  delete gc;
924  }
925  }
926 }
927 
928 ////////////////////////////////////////////////////////////////////////////////
929 /// Delete graphics context if it is not used anymore.
930 
931 void TGGCPool::FreeGC(GContext_t gct)
932 {
933  TIter next(fList);
934 
935  while (TGGC *gc = (TGGC *) next()) {
936  if (gc->fContext == gct) {
937  if (gc->RemoveReference() == 0) {
938  fList->Remove(gc);
939  delete gc;
940  return;
941  }
942  }
943  }
944 }
945 
946 ////////////////////////////////////////////////////////////////////////////////
947 /// Find graphics context. Returns 0 in case gc is not found.
948 
949 TGGC *TGGCPool::FindGC(const TGGC *gct)
950 {
951  return (TGGC*) fList->FindObject(gct);
952 }
953 
954 ////////////////////////////////////////////////////////////////////////////////
955 /// Find graphics context based on its GContext_t handle. Returns 0
956 /// in case gc is not found.
957 
958 TGGC *TGGCPool::FindGC(GContext_t gct)
959 {
960  TIter next(fList);
961 
962  while (TGGC *gc = (TGGC *) next()) {
963  if (gc->fContext == gct)
964  return gc;
965  }
966  return 0;
967 }
968 
969 ////////////////////////////////////////////////////////////////////////////////
970 /// returns graphics context based on its GContext_t handle.
971 
972 TGGC *TGGCPool::GetGC(GContext_t gct)
973 {
974  GCValues_t gval;
975  gVirtualX->GetGCValues(gct, gval);
976  return GetGC(&gval, kTRUE);
977 }
978 
979 ////////////////////////////////////////////////////////////////////////////////
980 /// Get the best matching graphics context depending on values.
981 /// If rw is false only a readonly, not modifiable graphics context
982 /// is returned. If rw is true a new modifiable graphics context is
983 /// returned.
984 
985 TGGC *TGGCPool::GetGC(GCValues_t *values, Bool_t rw)
986 {
987  TGGC *gc, *best_match = 0;
988  Int_t matching_bits, best_matching_bits = -1;
989  Bool_t exact = kFALSE;
990 
991  if (!values)
992  rw = kTRUE;
993 
994  if (!rw) {
995 
996  // First, try to find an exact matching GC.
997  // If no one found, then use the closest one.
998 
999  TIter next(fList);
1000 
1001  while ((gc = (TGGC *) next())) {
1002  matching_bits = MatchGC(gc, values);
1003  if (matching_bits > best_matching_bits) {
1004  best_matching_bits = matching_bits;
1005  best_match = gc;
1006  if ((gc->fValues.fMask & values->fMask) == values->fMask) {
1007  exact = kTRUE;
1008  break;
1009  }
1010  }
1011  }
1012 
1013  if (best_match) {
1014  if (gDebug > 0)
1015  Printf("<TGGCPool::GetGC>: %smatching GC found\n", exact ? "exact " : "");
1016  best_match->AddReference();
1017  if (!exact) {
1018  // add missing values to the best_match'ing GC...
1019  UpdateGC(best_match, values);
1020  }
1021  return best_match;
1022  }
1023  }
1024 
1025  gc = new TGGC(values, kTRUE);
1026 
1027  fList->Add(gc);
1028 
1029  return gc;
1030 }
1031 
1032 ////////////////////////////////////////////////////////////////////////////////
1033 /// Try to find matching graphics context. On success returns the amount
1034 /// of matching bits (which may be zero if masks have no common bits),
1035 /// -1 on failure (when there are common bits but not a single match).
1036 
1037 Int_t TGGCPool::MatchGC(const TGGC *gc, GCValues_t *values)
1038 {
1039  Mask_t bit, common_bits;
1040  Int_t matching_bits = -1;
1041  Bool_t match = kFALSE;
1042  const GCValues_t *gcv = &gc->fValues;
1043 
1044  common_bits = values->fMask & gcv->fMask;
1045 
1046  if (common_bits == 0) return 0; // no common bits, a possible
1047  // candidate anyway.
1048 
1049  // Careful, check first the tile and stipple mask bits, as these
1050  // influence nearly all other GC functions... (do the same for
1051  // some other such bits as GCFunction, etc...). Perhaps we should
1052  // allow only exact GC matches.
1053 
1054  if (gcv->fMask & kGCTile)
1055  if ((gcv->fTile != kNone) && !(values->fMask & kGCTile)) return -1;
1056  if (values->fMask & kGCTile)
1057  if ((values->fTile != kNone) && !(gcv->fMask & kGCTile)) return -1;
1058  if (gcv->fMask & kGCStipple)
1059  if ((gcv->fStipple != kNone) && !(values->fMask & kGCStipple)) return -1;
1060  if (values->fMask & kGCStipple)
1061  if ((values->fStipple != kNone) && !(gcv->fMask & kGCStipple)) return -1;
1062 
1063  for (bit = 1; bit <= common_bits; bit <<= 1) {
1064  switch (bit & common_bits) {
1065  default:
1066  case 0:
1067  continue;
1068  case kGCFunction:
1069  match = (values->fFunction == gcv->fFunction);
1070  break;
1071  case kGCPlaneMask:
1072  match = (values->fPlaneMask == gcv->fPlaneMask);
1073  break;
1074  case kGCForeground:
1075  match = (values->fForeground == gcv->fForeground);
1076  break;
1077  case kGCBackground:
1078  match = (values->fBackground == gcv->fBackground);
1079  break;
1080  case kGCLineWidth:
1081  match = (values->fLineWidth == gcv->fLineWidth);
1082  break;
1083  case kGCLineStyle:
1084  match = (values->fLineStyle == gcv->fLineStyle);
1085  break;
1086  case kGCCapStyle:
1087  match = (values->fCapStyle == gcv->fCapStyle);
1088  break;
1089  case kGCJoinStyle:
1090  match = (values->fJoinStyle == gcv->fJoinStyle);
1091  break;
1092  case kGCFillStyle:
1093  match = (values->fFillStyle == gcv->fFillStyle);
1094  break;
1095  case kGCFillRule:
1096  match = (values->fFillRule == gcv->fFillRule);
1097  break;
1098  case kGCTile:
1099  match = (values->fTile == gcv->fTile);
1100  break;
1101  case kGCStipple:
1102  match = (values->fStipple == gcv->fStipple);
1103  break;
1104  case kGCTileStipXOrigin:
1105  match = (values->fTsXOrigin == gcv->fTsXOrigin);
1106  break;
1107  case kGCTileStipYOrigin:
1108  match = (values->fTsYOrigin == gcv->fTsYOrigin);
1109  break;
1110  case kGCFont:
1111  match = (values->fFont == gcv->fFont);
1112  break;
1113  case kGCSubwindowMode:
1114  match = (values->fSubwindowMode == gcv->fSubwindowMode);
1115  break;
1116  case kGCGraphicsExposures:
1117  match = (values->fGraphicsExposures == gcv->fGraphicsExposures);
1118  break;
1119  case kGCClipXOrigin:
1120  match = (values->fClipXOrigin == gcv->fClipXOrigin);
1121  break;
1122  case kGCClipYOrigin:
1123  match = (values->fClipYOrigin == gcv->fClipYOrigin);
1124  break;
1125  case kGCClipMask:
1126  match = (values->fClipMask == gcv->fClipMask);
1127  break;
1128  case kGCDashOffset:
1129  match = (values->fDashOffset == gcv->fDashOffset);
1130  break;
1131  case kGCDashList:
1132  if (values->fDashLen == gcv->fDashLen)
1133  match = (strncmp(values->fDashes, gcv->fDashes, gcv->fDashLen) == 0);
1134  break;
1135  case kGCArcMode:
1136  match = (values->fArcMode == gcv->fArcMode);
1137  break;
1138  }
1139  if (!match)
1140  return -1;
1141  matching_bits++;
1142  match = kFALSE;
1143  }
1144 
1145  return matching_bits;
1146 }
1147 
1148 ////////////////////////////////////////////////////////////////////////////////
1149 /// Update graphics context with the values spcified in values->fMask.
1150 
1151 void TGGCPool::UpdateGC(TGGC *gc, GCValues_t *values)
1152 {
1153  gc->SetAttributes(values);
1154 }
1155 
1156 ////////////////////////////////////////////////////////////////////////////////
1157 /// List all graphics contexts in the pool.
1158 
1159 void TGGCPool::Print(Option_t *) const
1160 {
1161  fList->Print();
1162 }