From a9cfb83bb09bebf69f1c5680d3aff8d5eef844b9 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 10 Mar 2026 13:02:28 +0100 Subject: [PATCH 01/37] [x11] change management of window handles Move from plain array to unordered_map. So pointer on XWindow_t will not change if new window will be created later. Idea to use this pointer later as main handle for graphics operation - while using window id will costs locking of the mutex which need to be introduced later for threads safety --- graf2d/x11/inc/TGX11.h | 40 +++--- graf2d/x11/src/TGX11.cxx | 302 ++++++++++++++++----------------------- 2 files changed, 147 insertions(+), 195 deletions(-) diff --git a/graf2d/x11/inc/TGX11.h b/graf2d/x11/inc/TGX11.h index 17c524175761d..f9f7495e0fe43 100644 --- a/graf2d/x11/inc/TGX11.h +++ b/graf2d/x11/inc/TGX11.h @@ -13,6 +13,7 @@ #define ROOT_TGX11 #include "TVirtualX.h" +#include #ifdef Status // Convert Status from a CPP macro to a typedef: @@ -80,13 +81,12 @@ class TExMap; class TGX11 : public TVirtualX { private: - Int_t fMaxNumberOfWindows; ///< Maximum number of windows - XWindow_t *fWindows; ///< List of windows + std::unordered_map fWindows; // map of windows TExMap *fColors; ///< Hash list of colors Cursor fCursors[kNumCursors]; ///< List of cursors void *fXEvent; ///< Current native (X11) event - void CloseWindow1(); + Int_t AddWindowHandle(); void ClearPixmap(Drawable *pix); void CopyWindowtoPixmap(Drawable *pix, Int_t xpos, Int_t ypos); void FindBestVisual(); @@ -163,15 +163,6 @@ class TGX11 : public TVirtualX { void ClosePixmap() override; void CloseWindow() override; void CopyPixmap(Int_t wid, Int_t xpos, Int_t ypos) override; - void DrawBox(Int_t x1, Int_t y1, Int_t x2, Int_t y2, EBoxMode mode) override; - void DrawCellArray(Int_t x1, Int_t y1, Int_t x2, Int_t y2, Int_t nx, Int_t ny, Int_t *ic) override; - void DrawFillArea(Int_t n, TPoint *xy) override; - void DrawLine(Int_t x1, Int_t y1, Int_t x2, Int_t y2) override; - void DrawPolyLine(Int_t n, TPoint *xy) override; - void DrawLinesSegments(Int_t n, TPoint *xy) override; - void DrawPolyMarker(Int_t n, TPoint *xy) override; - void DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn, const char *text, ETextMode mode) override; - void DrawText(Int_t, Int_t, Float_t, Float_t, const wchar_t *, ETextMode) override {} void GetCharacterUp(Float_t &chupx, Float_t &chupy) override; Int_t GetDoubleBuffer(Int_t wid) override; void GetGeometry(Int_t wid, Int_t &x, Int_t &y, UInt_t &w, UInt_t &h) override; @@ -208,6 +199,15 @@ class TGX11 : public TVirtualX { void SetDoubleBufferOFF() override; void SetDoubleBufferON() override; void SetDrawMode(EDrawMode mode) override; + void Sync(Int_t mode) override; + void UpdateWindow(Int_t mode) override; + void Warp(Int_t ix, Int_t iy, Window_t id = 0) override; + Int_t WriteGIF(char *name) override; + void WritePixmap(Int_t wid, UInt_t w, UInt_t h, char *pxname) override; + Window_t GetCurrentWindow() const override; + Int_t SupportsExtension(const char *ext) const override; + + //---- Methods used for old graphics ----- void SetFillColor(Color_t cindex) override; void SetFillStyle(Style_t style) override; void SetLineColor(Color_t cindex) override; @@ -225,13 +225,15 @@ class TGX11 : public TVirtualX { void SetTextFont(Font_t fontnumber) override; void SetTextMagnitude(Float_t mgn=1) override { fTextMagnitude = mgn;} void SetTextSize(Float_t textsize) override; - void Sync(Int_t mode) override; - void UpdateWindow(Int_t mode) override; - void Warp(Int_t ix, Int_t iy, Window_t id = 0) override; - Int_t WriteGIF(char *name) override; - void WritePixmap(Int_t wid, UInt_t w, UInt_t h, char *pxname) override; - Window_t GetCurrentWindow() const override; - Int_t SupportsExtension(const char *ext) const override; + void DrawBox(Int_t x1, Int_t y1, Int_t x2, Int_t y2, EBoxMode mode) override; + void DrawCellArray(Int_t x1, Int_t y1, Int_t x2, Int_t y2, Int_t nx, Int_t ny, Int_t *ic) override; + void DrawFillArea(Int_t n, TPoint *xy) override; + void DrawLine(Int_t x1, Int_t y1, Int_t x2, Int_t y2) override; + void DrawPolyLine(Int_t n, TPoint *xy) override; + void DrawLinesSegments(Int_t n, TPoint *xy) override; + void DrawPolyMarker(Int_t n, TPoint *xy) override; + void DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn, const char *text, ETextMode mode) override; + void DrawText(Int_t, Int_t, Float_t, Float_t, const wchar_t *, ETextMode) override {} //---- Methods used for GUI ----- void GetWindowAttributes(Window_t id, WindowAttributes_t &attr) override; diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index 9ba0fc6849e8f..79dcb85f19a8c 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -180,7 +180,6 @@ TGX11::TGX11() fColormap = 0; fBlackPixel = 0; fWhitePixel = 0; - fWindows = nullptr; fColors = nullptr; fXEvent = new XEvent; fRedDiv = -1; @@ -194,7 +193,6 @@ TGX11::TGX11() fDepth = 0; fHasTTFonts = kFALSE; fHasXft = kFALSE; - fMaxNumberOfWindows = 10; fTextAlignH = 1; fTextAlignV = 1; fTextAlign = 7; @@ -229,18 +227,12 @@ TGX11::TGX11(const char *name, const char *title) : TVirtualX(name, title) fDepth = 0; fHasTTFonts = kFALSE; fHasXft = kFALSE; - fMaxNumberOfWindows = 10; fTextAlignH = 1; fTextAlignV = 1; fTextAlign = 7; fTextMagnitude = 1; for (i = 0; i < kNumCursors; i++) fCursors[i] = 0; - //fWindows = new XWindow_t[fMaxNumberOfWindows]; - fWindows = (XWindow_t*) TStorage::Alloc(fMaxNumberOfWindows*sizeof(XWindow_t)); - for (i = 0; i < fMaxNumberOfWindows; i++) - fWindows[i].fOpen = 0; - fColors = new TExMap; } @@ -277,26 +269,26 @@ TGX11::TGX11(const TGX11 &org) : TVirtualX(org) fDrawMode = org.fDrawMode; fXEvent = new XEvent; - fMaxNumberOfWindows = org.fMaxNumberOfWindows; - //fWindows = new XWindow_t[fMaxNumberOfWindows]; - fWindows = (XWindow_t*) TStorage::Alloc(fMaxNumberOfWindows*sizeof(XWindow_t)); - for (i = 0; i < fMaxNumberOfWindows; i++) { - fWindows[i].fOpen = org.fWindows[i].fOpen; - fWindows[i].fDoubleBuffer = org.fWindows[i].fDoubleBuffer; - fWindows[i].fIsPixmap = org.fWindows[i].fIsPixmap; - fWindows[i].fDrawing = org.fWindows[i].fDrawing; - fWindows[i].fWindow = org.fWindows[i].fWindow; - fWindows[i].fBuffer = org.fWindows[i].fBuffer; - fWindows[i].fWidth = org.fWindows[i].fWidth; - fWindows[i].fHeight = org.fWindows[i].fHeight; - fWindows[i].fClip = org.fWindows[i].fClip; - fWindows[i].fXclip = org.fWindows[i].fXclip; - fWindows[i].fYclip = org.fWindows[i].fYclip; - fWindows[i].fWclip = org.fWindows[i].fWclip; - fWindows[i].fHclip = org.fWindows[i].fHclip; - fWindows[i].fNewColors = org.fWindows[i].fNewColors; - fWindows[i].fNcolors = org.fWindows[i].fNcolors; - fWindows[i].fShared = org.fWindows[i].fShared; + for(auto & iter : org.fWindows) { + auto &tgt = fWindows[iter.first]; // entry created + auto &src = iter.second; + tgt.fOpen = src.fOpen; + tgt.fDoubleBuffer = src.fDoubleBuffer; + tgt.fIsPixmap = src.fIsPixmap; + tgt.fDrawing = src.fDrawing; + tgt.fWindow = src.fWindow; + tgt.fBuffer = src.fBuffer; + tgt.fWidth = src.fWidth; + tgt.fHeight = src.fHeight; + tgt.fClip = src.fClip; + tgt.fXclip = src.fXclip; + tgt.fYclip = src.fYclip; + tgt.fWclip = src.fWclip; + tgt.fHclip = src.fHclip; + // FIXME: copy of pointer on may lead to double delete!!! + tgt.fNewColors = src.fNewColors; + tgt.fNcolors = src.fNcolors; + tgt.fShared = src.fShared; } for (i = 0; i < kNumCursors; i++) @@ -323,7 +315,6 @@ TGX11::TGX11(const TGX11 &org) : TVirtualX(org) TGX11::~TGX11() { delete (XEvent*)fXEvent; - if (fWindows) TStorage::Dealloc(fWindows); if (!fColors) return; Long64_t key, value; @@ -439,7 +430,7 @@ void TGX11::ClearWindow() void TGX11::ClosePixmap() { - CloseWindow1(); + CloseWindow(); } //////////////////////////////////////////////////////////////////////////////// @@ -447,48 +438,54 @@ void TGX11::ClosePixmap() void TGX11::CloseWindow() { - if (gCws->fShared) - gCws->fOpen = 0; - else - CloseWindow1(); - - // Never close connection. TApplication takes care of that - // if (!gCws) Close(); // close X when no open window left -} - -//////////////////////////////////////////////////////////////////////////////// -/// Delete current window. + if (gCws->fShared) { + // case of Qt window + if (gCws->fBuffer) + XFreePixmap((Display*)fDisplay, gCws->fBuffer); -void TGX11::CloseWindow1() -{ - int wid; + if (gCws->fNewColors) { + if (fRedDiv == -1) + XFreeColors((Display*)fDisplay, fColormap, gCws->fNewColors, gCws->fNcolors, 0); + delete [] gCws->fNewColors; + gCws->fNewColors = nullptr; + } + } else { + if (gCws->fIsPixmap) + XFreePixmap((Display*)fDisplay, gCws->fWindow); + else + XDestroyWindow((Display*)fDisplay, gCws->fWindow); - if (gCws->fIsPixmap) - XFreePixmap((Display*)fDisplay, gCws->fWindow); - else - XDestroyWindow((Display*)fDisplay, gCws->fWindow); + if (gCws->fBuffer) + XFreePixmap((Display*)fDisplay, gCws->fBuffer); - if (gCws->fBuffer) XFreePixmap((Display*)fDisplay, gCws->fBuffer); + if (gCws->fNewColors) { + if (fRedDiv == -1) + XFreeColors((Display*)fDisplay, fColormap, gCws->fNewColors, gCws->fNcolors, 0); + delete [] gCws->fNewColors; + gCws->fNewColors = nullptr; + } - if (gCws->fNewColors) { - if (fRedDiv == -1) - XFreeColors((Display*)fDisplay, fColormap, gCws->fNewColors, gCws->fNcolors, 0); - delete [] gCws->fNewColors; - gCws->fNewColors = nullptr; + XFlush((Display*)fDisplay); } - XFlush((Display*)fDisplay); - gCws->fOpen = 0; - // make first window in list the current window - for (wid = 0; wid < fMaxNumberOfWindows; wid++) - if (fWindows[wid].fOpen) { - gCws = &fWindows[wid]; - return; + for (auto iter = fWindows.begin(); iter != fWindows.end(); ++iter) + if (&iter->second == gCws) { + fWindows.erase(iter); + gCws = nullptr; + break; } - gCws = nullptr; + if (gCws) + Fatal("CloseWindow", "Not found gCws in list of windows"); + + // select first from active windows + for (auto iter = fWindows.begin(); iter != fWindows.end(); ++iter) + if (iter->second.fOpen) { + gCws = &iter->second; + return; + } } //////////////////////////////////////////////////////////////////////////////// @@ -1264,6 +1261,41 @@ Int_t TGX11::OpenDisplay(void *disp) return 0; } + +//////////////////////////////////////////////////////////////////////////////// +/// Add new window handle +/// Only for private usage + +Int_t TGX11::AddWindowHandle() +{ + Int_t maxid = 0; + for (auto & iter : fWindows) { + if (!iter.second.fOpen) { + iter.second.fOpen = 1; + return iter.first; + } + if (iter.first > maxid) + maxid = iter.first; + } + + if (fWindows.size() == (size_t) maxid) { + // all ids are in use - just add maximal+1 + maxid++; + } else + for (int id = 1; id < maxid; id++) { + if (fWindows.count(id) == 0) { + maxid = id; + break; + } + } + + + fWindows[maxid].fOpen = 1; + return maxid; +} + + + //////////////////////////////////////////////////////////////////////////////// /// Open a new pixmap. /// @@ -1273,35 +1305,19 @@ Int_t TGX11::OpenPixmap(unsigned int w, unsigned int h) { Window root; unsigned int wval, hval; - int xx, yy, i, wid; + int xx, yy; unsigned int ww, hh, border, depth; wval = w; hval = h; // Select next free window number - -again: - for (wid = 0; wid < fMaxNumberOfWindows; wid++) - if (!fWindows[wid].fOpen) { - fWindows[wid].fOpen = 1; - gCws = &fWindows[wid]; - break; - } - - if (wid == fMaxNumberOfWindows) { - int newsize = fMaxNumberOfWindows + 10; - fWindows = (XWindow_t*) TStorage::ReAlloc(fWindows, newsize*sizeof(XWindow_t), - fMaxNumberOfWindows*sizeof(XWindow_t)); - for (i = fMaxNumberOfWindows; i < newsize; i++) - fWindows[i].fOpen = 0; - fMaxNumberOfWindows = newsize; - goto again; - } + int wid = AddWindowHandle(); + gCws = &fWindows[wid]; gCws->fWindow = XCreatePixmap((Display*)fDisplay, fRootWin, wval, hval, fDepth); XGetGeometry((Display*)fDisplay, gCws->fWindow, &root, &xx, &yy, &ww, &hh, &border, &depth); - for (i = 0; i < kMAXGC; i++) + for (int i = 0; i < kMAXGC; i++) XSetClipMask((Display*)fDisplay, gGClist[i], None); SetColor(gGCpxmp, 0); @@ -1331,7 +1347,6 @@ Int_t TGX11::InitWindow(ULong_t win) { XSetWindowAttributes attributes; ULong_t attr_mask = 0; - int wid; int xval, yval; unsigned int wval, hval, border, depth; Window root; @@ -1342,24 +1357,9 @@ Int_t TGX11::InitWindow(ULong_t win) // Select next free window number -again: - for (wid = 0; wid < fMaxNumberOfWindows; wid++) - if (!fWindows[wid].fOpen) { - fWindows[wid].fOpen = 1; - fWindows[wid].fDoubleBuffer = 0; - gCws = &fWindows[wid]; - break; - } - - if (wid == fMaxNumberOfWindows) { - int newsize = fMaxNumberOfWindows + 10; - fWindows = (XWindow_t*) TStorage::ReAlloc(fWindows, newsize*sizeof(XWindow_t), - fMaxNumberOfWindows*sizeof(XWindow_t)); - for (int i = fMaxNumberOfWindows; i < newsize; i++) - fWindows[i].fOpen = 0; - fMaxNumberOfWindows = newsize; - goto again; - } + int wid = AddWindowHandle(); + gCws = &fWindows[wid]; + gCws->fDoubleBuffer = 0; // Create window @@ -1406,28 +1406,10 @@ Int_t TGX11::InitWindow(ULong_t win) Int_t TGX11::AddWindow(ULong_t qwid, UInt_t w, UInt_t h) { - Int_t wid; - // Select next free window number - -again: - for (wid = 0; wid < fMaxNumberOfWindows; wid++) - if (!fWindows[wid].fOpen) { - fWindows[wid].fOpen = 1; - fWindows[wid].fDoubleBuffer = 0; - gCws = &fWindows[wid]; - break; - } - - if (wid == fMaxNumberOfWindows) { - int newsize = fMaxNumberOfWindows + 10; - fWindows = (XWindow_t*) TStorage::ReAlloc(fWindows, newsize*sizeof(XWindow_t), - fMaxNumberOfWindows*sizeof(XWindow_t)); - for (int i = fMaxNumberOfWindows; i < newsize; i++) - fWindows[i].fOpen = 0; - fMaxNumberOfWindows = newsize; - goto again; - } + int wid = AddWindowHandle(); + gCws = &fWindows[wid]; + gCws->fDoubleBuffer = 0; gCws->fWindow = qwid; @@ -1446,31 +1428,13 @@ Int_t TGX11::AddWindow(ULong_t qwid, UInt_t w, UInt_t h) } //////////////////////////////////////////////////////////////////////////////// -/// Remove a window created by Qt (like CloseWindow1()). +/// Remove a window created by Qt (like CloseWindow()). void TGX11::RemoveWindow(ULong_t qwid) { - SelectWindow((int)qwid); - - if (gCws->fBuffer) XFreePixmap((Display*)fDisplay, gCws->fBuffer); - - if (gCws->fNewColors) { - if (fRedDiv == -1) - XFreeColors((Display*)fDisplay, fColormap, gCws->fNewColors, gCws->fNcolors, 0); - delete [] gCws->fNewColors; - gCws->fNewColors = nullptr; - } + SelectWindow((int) qwid); - gCws->fOpen = 0; - - // make first window in list the current window - for (Int_t wid = 0; wid < fMaxNumberOfWindows; wid++) - if (fWindows[wid].fOpen) { - gCws = &fWindows[wid]; - return; - } - - gCws = nullptr; + CloseWindow(); } //////////////////////////////////////////////////////////////////////////////// @@ -1947,7 +1911,6 @@ int TGX11::ResizePixmap(int wid, unsigned int w, unsigned int h) void TGX11::ResizeWindow(Int_t wid) { - int i; int xval=0, yval=0; Window win, root=0; unsigned int wval=0, hval=0, border=0, depth=0; @@ -1971,11 +1934,13 @@ void TGX11::ResizeWindow(Int_t wid) XFreePixmap((Display*)fDisplay,gTws->fBuffer); gTws->fBuffer = XCreatePixmap((Display*)fDisplay, fRootWin, wval, hval, fDepth); } - for (i = 0; i < kMAXGC; i++) XSetClipMask((Display*)fDisplay, gGClist[i], None); + for (int i = 0; i < kMAXGC; i++) + XSetClipMask((Display*)fDisplay, gGClist[i], None); SetColor(gGCpxmp, 0); XFillRectangle((Display*)fDisplay, gTws->fBuffer, *gGCpxmp, 0, 0, wval, hval); SetColor(gGCpxmp, 1); - if (gTws->fDoubleBuffer) gTws->fDrawing = gTws->fBuffer; + if (gTws->fDoubleBuffer) + gTws->fDrawing = gTws->fBuffer; } gTws->fWidth = wval; gTws->fHeight = hval; @@ -1986,22 +1951,25 @@ void TGX11::ResizeWindow(Int_t wid) void TGX11::SelectWindow(int wid) { - XRectangle region; - int i; + if (fWindows.count(wid) == 0) + return; - if (wid < 0 || wid >= fMaxNumberOfWindows || !fWindows[wid].fOpen) return; + auto &handle = fWindows[wid]; + if (!handle.fOpen) + return; - gCws = &fWindows[wid]; + gCws = &handle; if (gCws->fClip && !gCws->fIsPixmap && !gCws->fDoubleBuffer) { + XRectangle region; region.x = gCws->fXclip; region.y = gCws->fYclip; region.width = gCws->fWclip; region.height = gCws->fHclip; - for (i = 0; i < kMAXGC; i++) + for (int i = 0; i < kMAXGC; i++) XSetClipRectangles((Display*)fDisplay, gGClist[i], 0, 0, ®ion, 1, YXBanded); } else { - for (i = 0; i < kMAXGC; i++) + for (int i = 0; i < kMAXGC; i++) XSetClipMask((Display*)fDisplay, gGClist[i], None); } } @@ -2120,8 +2088,8 @@ void TGX11::SetCursor(Int_t wid, ECursor cursor) void TGX11::SetDoubleBuffer(int wid, int mode) { if (wid == 999) { - for (int i = 0; i < fMaxNumberOfWindows; i++) { - gTws = &fWindows[i]; + for (auto & iter : fWindows) { + gTws = &iter.second; if (gTws->fOpen) { switch (mode) { case 1 : @@ -2135,7 +2103,8 @@ void TGX11::SetDoubleBuffer(int wid, int mode) } } else { gTws = &fWindows[wid]; - if (!gTws->fOpen) return; + if (!gTws->fOpen) + return; switch (mode) { case 1 : SetDoubleBufferON(); @@ -3673,28 +3642,9 @@ Pixmap_t TGX11::CreatePixmapFromData(unsigned char * /*bits*/, UInt_t /*width*/, Int_t TGX11::AddPixmap(ULong_t pixid, UInt_t w, UInt_t h) { - Int_t wid = 0; - - // Select next free window number - for (; wid < fMaxNumberOfWindows; ++wid) - if (!fWindows[wid].fOpen) - break; + Int_t wid = AddWindowHandle(); - if (wid == fMaxNumberOfWindows) { - Int_t newsize = fMaxNumberOfWindows + 10; - fWindows = (XWindow_t*) TStorage::ReAlloc( - fWindows, newsize * sizeof(XWindow_t), - fMaxNumberOfWindows*sizeof(XWindow_t) - ); - - for (Int_t i = fMaxNumberOfWindows; i < newsize; ++i) - fWindows[i].fOpen = 0; - - fMaxNumberOfWindows = newsize; - } - - fWindows[wid].fOpen = 1; - gCws = fWindows + wid; + gCws = &fWindows[wid]; gCws->fWindow = pixid; gCws->fDrawing = gCws->fWindow; gCws->fBuffer = 0; From ed2cd60dd45016c00f9f431c05b633d99c13e557 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 11 Mar 2026 07:18:30 +0100 Subject: [PATCH 02/37] [x11] introduce new methods in TVirtualX interface First provide window context for each active window. Window context should allow access per-window functionality fully independent from each other As a first interfaces declare methods to change attributes. --- core/base/inc/TVirtualX.h | 63 +++++++++++++++++++++++-------------- core/base/src/TVirtualX.cxx | 51 ++++++++++++++++++++++++++++++ core/gui/inc/GuiTypes.h | 1 + 3 files changed, 91 insertions(+), 24 deletions(-) diff --git a/core/base/inc/TVirtualX.h b/core/base/inc/TVirtualX.h index 6ab0aea521a81..bab9e6d1d34da 100644 --- a/core/base/inc/TVirtualX.h +++ b/core/base/inc/TVirtualX.h @@ -67,13 +67,26 @@ class TVirtualX : public TNamed, public TAttLine, public TAttFill, public TAttTe virtual void CreateOpenGLContext(Int_t wid=0); virtual void DeleteOpenGLContext(Int_t wid=0); - //---- OpenGL related stuff, required only with R__HAS_COCOA ---- - virtual Double_t GetOpenGLScalingFactor(); - virtual Window_t CreateOpenGLWindow(Window_t parentID, UInt_t width, UInt_t height, const std::vector > &format); - virtual Handle_t CreateOpenGLContext(Window_t windowID, Handle_t sharedContext); - virtual Bool_t MakeOpenGLContextCurrent(Handle_t ctx, Window_t windowID); - virtual Handle_t GetCurrentOpenGLContext(); - virtual void FlushOpenGLBuffer(Handle_t ctx); + + //---- Old graphics interface ----- + + void SetFillColor(Color_t cindex) override; + void SetFillStyle(Style_t style) override; + void SetLineColor(Color_t cindex) override; + virtual void SetLineType(Int_t n, Int_t *dash); + void SetLineStyle(Style_t linestyle) override; + void SetLineWidth(Width_t width) override; + void SetMarkerColor(Color_t cindex) override; + void SetMarkerSize(Float_t markersize) override; + void SetMarkerStyle(Style_t markerstyle) override; + virtual void SetOpacity(Int_t percent); + virtual void SetRGB(Int_t cindex, Float_t r, Float_t g, Float_t b); + void SetTextAlign(Short_t talign=11) override; + void SetTextColor(Color_t cindex) override; + virtual Int_t SetTextFont(char *fontname, ETextSetMode mode); + void SetTextFont(Font_t fontnumber) override; + virtual void SetTextMagnitude(Float_t mgn); + void SetTextSize(Float_t textsize) override; virtual void DrawBox(Int_t x1, Int_t y1, Int_t x2, Int_t y2, EBoxMode mode); virtual void DrawCellArray(Int_t x1, Int_t y1, Int_t x2, Int_t y2, @@ -87,6 +100,25 @@ class TVirtualX : public TNamed, public TAttLine, public TAttFill, public TAttTe ETextMode mode); virtual void DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn, const wchar_t *text, ETextMode mode); + + //---- New graphics interface ----- + + virtual WinContext_t GetWindowContext(Int_t wid); + virtual void SetAttFill(WinContext_t wctxt, const TAttFill &att); + virtual void SetAttLine(WinContext_t wctxt, const TAttLine &att); + virtual void SetAttMarker(WinContext_t wctxt, const TAttMarker &att); + virtual void SetAttText(WinContext_t wctxt, const TAttText &att); + virtual void SetDrawMode(WinContext_t wctxt, EDrawMode mode); + + + //---- OpenGL related stuff, required only with R__HAS_COCOA ---- + virtual Double_t GetOpenGLScalingFactor(); + virtual Window_t CreateOpenGLWindow(Window_t parentID, UInt_t width, UInt_t height, const std::vector > &format); + virtual Handle_t CreateOpenGLContext(Window_t windowID, Handle_t sharedContext); + virtual Bool_t MakeOpenGLContextCurrent(Handle_t ctx, Window_t windowID); + virtual Handle_t GetCurrentOpenGLContext(); + virtual void FlushOpenGLBuffer(Handle_t ctx); + virtual UInt_t ExecCommand(TGWin32Command *code); virtual void GetCharacterUp(Float_t &chupx, Float_t &chupy); EDrawMode GetDrawMode() { return fDrawMode; } @@ -129,23 +161,6 @@ class TVirtualX : public TNamed, public TAttLine, public TAttFill, public TAttTe virtual void SetDoubleBufferOFF(); virtual void SetDoubleBufferON(); virtual void SetDrawMode(EDrawMode mode); - void SetFillColor(Color_t cindex) override; - void SetFillStyle(Style_t style) override; - void SetLineColor(Color_t cindex) override; - virtual void SetLineType(Int_t n, Int_t *dash); - void SetLineStyle(Style_t linestyle) override; - void SetLineWidth(Width_t width) override; - void SetMarkerColor(Color_t cindex) override; - void SetMarkerSize(Float_t markersize) override; - void SetMarkerStyle(Style_t markerstyle) override; - virtual void SetOpacity(Int_t percent); - virtual void SetRGB(Int_t cindex, Float_t r, Float_t g, Float_t b); - void SetTextAlign(Short_t talign=11) override; - void SetTextColor(Color_t cindex) override; - virtual Int_t SetTextFont(char *fontname, ETextSetMode mode); - void SetTextFont(Font_t fontnumber) override; - virtual void SetTextMagnitude(Float_t mgn); - void SetTextSize(Float_t textsize) override; virtual void Sync(Int_t mode); virtual void UpdateWindow(Int_t mode); virtual void Warp(Int_t ix, Int_t iy, Window_t id = 0); diff --git a/core/base/src/TVirtualX.cxx b/core/base/src/TVirtualX.cxx index 3de70acf015be..9e6b19d0886f7 100644 --- a/core/base/src/TVirtualX.cxx +++ b/core/base/src/TVirtualX.cxx @@ -378,6 +378,57 @@ void TVirtualX::DrawText(Int_t /*x*/, Int_t /*y*/, Float_t /*angle*/, { } +//////////////////////////////////////////////////////////////////////////////// +/// Get window drawing context +/// Should remain valid until window exists + +WinContext_t TVirtualX::GetWindowContext(Int_t /* wid */) +{ + return (WinContext_t) 0; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set fill attributes for specified window + +void TVirtualX::SetAttFill(WinContext_t /* wctxt */, const TAttFill & /* att */) +{ + +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set line attributes for specified window + +void TVirtualX::SetAttLine(WinContext_t /* wctxt */, const TAttLine & /* att */) +{ + +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set marker attributes for specified window + +void TVirtualX::SetAttMarker(WinContext_t /* wctxt */, const TAttMarker & /* att */) +{ + +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set text attributes for specified window + +void TVirtualX::SetAttText(WinContext_t /* wctxt */, const TAttText & /* att */) +{ + +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Set window draw mode + +void TVirtualX::SetDrawMode(WinContext_t /* wctxt */, EDrawMode /* mode */) +{ + +} + + //////////////////////////////////////////////////////////////////////////////// /// Executes the command "code" coming from the other threads (Win32) diff --git a/core/gui/inc/GuiTypes.h b/core/gui/inc/GuiTypes.h index 41052a7a403de..ac522ea3702eb 100644 --- a/core/gui/inc/GuiTypes.h +++ b/core/gui/inc/GuiTypes.h @@ -27,6 +27,7 @@ typedef ULongptr_t Handle_t; ///< Generic resource handle typedef Handle_t Display_t; ///< Display handle typedef Handle_t Visual_t; ///< Visual handle typedef Handle_t Window_t; ///< Window handle +typedef Handle_t WinContext_t; ///< Window drawing context typedef Handle_t Pixmap_t; ///< Pixmap handle typedef Handle_t Drawable_t; ///< Drawable handle typedef Handle_t Region_t; ///< Region handle From a68110e21a27bacec4c8876420cc2b2da9bbbb06 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 11 Mar 2026 07:19:46 +0100 Subject: [PATCH 03/37] [tgx11] provide independent list of GC objects per window So one can set different drawing attributes independently for each window. --- graf2d/x11/inc/TGX11.h | 10 ++ graf2d/x11/src/TGX11.cxx | 202 ++++++++++++++++++++++++++++++++------- 2 files changed, 175 insertions(+), 37 deletions(-) diff --git a/graf2d/x11/inc/TGX11.h b/graf2d/x11/inc/TGX11.h index f9f7495e0fe43..6c1b7d1df5f8a 100644 --- a/graf2d/x11/inc/TGX11.h +++ b/graf2d/x11/inc/TGX11.h @@ -63,6 +63,8 @@ struct XWindow_t { ULong_t *fNewColors; ///< new image colors (after processing) Int_t fNcolors; ///< number of different colors Bool_t fShared; ///< notify when window is shared + void *fGClist; ///< list of GC object, individual for each window + TVirtualX::EDrawMode fDrawMode; ///< current draw mode }; /// Description of a X11 color. @@ -235,6 +237,14 @@ class TGX11 : public TVirtualX { void DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn, const char *text, ETextMode mode) override; void DrawText(Int_t, Int_t, Float_t, Float_t, const wchar_t *, ETextMode) override {} + //---- Methods used for new graphics ----- + WinContext_t GetWindowContext(Int_t wid) override; + void SetAttFill(WinContext_t wctxt, const TAttFill &att) override; + void SetAttLine(WinContext_t wctxt, const TAttLine &att) override; + void SetAttMarker(WinContext_t wctxt, const TAttMarker &att) override; + void SetAttText(WinContext_t wctxt, const TAttText &att) override; + void SetDrawMode(WinContext_t wctxt, EDrawMode mode) override; + //---- Methods used for GUI ----- void GetWindowAttributes(Window_t id, WindowAttributes_t &attr) override; void MapWindow(Window_t id) override; diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index 79dcb85f19a8c..5fa6ad71e9462 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -86,15 +86,17 @@ const Int_t kBIGGEST_RGB_VALUE = 65535; // // Primitives Graphic Contexts global for all windows // -const int kMAXGC = 7; +const int kMAXGC = 7, + kGCline = 0, kGCmark = 1, kGCfill = 2, + kGCtext = 3, kGCinvt = 4, kGCdash = 5, kGCpxmp = 6; static GC gGClist[kMAXGC]; -static GC *gGCline = &gGClist[0]; // PolyLines -static GC *gGCmark = &gGClist[1]; // PolyMarker -static GC *gGCfill = &gGClist[2]; // Fill areas -static GC *gGCtext = &gGClist[3]; // Text -static GC *gGCinvt = &gGClist[4]; // Inverse text -static GC *gGCdash = &gGClist[5]; // Dashed lines -static GC *gGCpxmp = &gGClist[6]; // Pixmap management +static GC *gGCline = &gGClist[kGCline]; // PolyLines +static GC *gGCmark = &gGClist[kGCmark]; // PolyMarker +static GC *gGCfill = &gGClist[kGCfill]; // Fill areas +static GC *gGCtext = &gGClist[kGCtext]; // Text +static GC *gGCinvt = &gGClist[kGCinvt]; // Inverse text +static GC *gGCdash = &gGClist[kGCinvt]; // Dashed lines +static GC *gGCpxmp = &gGClist[kGCpxmp]; // Pixmap management static GC gGCecho; // Input echo @@ -468,6 +470,12 @@ void TGX11::CloseWindow() XFlush((Display*)fDisplay); } + auto lGC = (GC *) gCws->fGClist; + for (int i = 0; i < kMAXGC; ++i) + XFreeGC((Display*)fDisplay, lGC[i]); + ::operator delete(gCws->fGClist); + gCws->fGClist = nullptr; + gCws->fOpen = 0; for (auto iter = fWindows.begin(); iter != fWindows.end(); ++iter) @@ -1290,7 +1298,27 @@ Int_t TGX11::AddWindowHandle() } - fWindows[maxid].fOpen = 1; + auto &ctxt = fWindows[maxid]; + ctxt.fOpen = 1; + ctxt.fDrawMode = TVirtualX::kCopy; + ctxt.fGClist = ::operator new(kMAXGC * sizeof(GC)); + auto lGC = (GC *) ctxt.fGClist; + for (int n = 0; n < kMAXGC; ++n) + lGC[n] = XCreateGC((Display*)fDisplay, fVisRootWin, 0, nullptr); + + XGCValues values; + if (XGetGCValues((Display*)fDisplay, lGC[kGCtext], GCForeground|GCBackground, &values)) { + XSetForeground((Display*)fDisplay, lGC[kGCinvt], values.background); + XSetBackground((Display*)fDisplay, lGC[kGCinvt], values.foreground); + } else { + Error("AddWindowHandle", "cannot get GC values"); + } + + // Turn-off GraphicsExpose and NoExpose event reporting for the pixmap + // manipulation GC, this to prevent these events from being stacked up + // without ever being processed and thereby wasting a lot of memory. + XSetGraphicsExposures((Display*)fDisplay, lGC[kGCpxmp], False); + return maxid; } @@ -1317,12 +1345,15 @@ Int_t TGX11::OpenPixmap(unsigned int w, unsigned int h) gCws->fWindow = XCreatePixmap((Display*)fDisplay, fRootWin, wval, hval, fDepth); XGetGeometry((Display*)fDisplay, gCws->fWindow, &root, &xx, &yy, &ww, &hh, &border, &depth); - for (int i = 0; i < kMAXGC; i++) + auto lGC = (GC *) gCws->fGClist; + for (int i = 0; i < kMAXGC; i++) { XSetClipMask((Display*)fDisplay, gGClist[i], None); + XSetClipMask((Display*)fDisplay, lGC[i], None); + } - SetColor(gGCpxmp, 0); - XFillRectangle((Display*)fDisplay, gCws->fWindow, *gGCpxmp, 0, 0, ww, hh); - SetColor(gGCpxmp, 1); + SetColor(lGC + kGCpxmp, 0); + XFillRectangle((Display*)fDisplay, gCws->fWindow, lGC[kGCpxmp], 0, 0, ww, hh); + SetColor(lGC + kGCpxmp, 1); // Initialise the window structure gCws->fDrawing = gCws->fWindow; @@ -1849,11 +1880,16 @@ void TGX11::RescaleWindow(int wid, unsigned int w, unsigned int h) XFreePixmap((Display*)fDisplay,gTws->fBuffer); gTws->fBuffer = XCreatePixmap((Display*)fDisplay, fRootWin, w, h, fDepth); } - for (i = 0; i < kMAXGC; i++) XSetClipMask((Display*)fDisplay, gGClist[i], None); - SetColor(gGCpxmp, 0); - XFillRectangle( (Display*)fDisplay, gTws->fBuffer, *gGCpxmp, 0, 0, w, h); - SetColor(gGCpxmp, 1); - if (gTws->fDoubleBuffer) gTws->fDrawing = gTws->fBuffer; + auto lGC = (GC *) gTws->fGClist; + for (i = 0; i < kMAXGC; i++) { + XSetClipMask((Display*)fDisplay, gGClist[i], None); + XSetClipMask((Display*)fDisplay, lGC[i], None); + } + SetColor(lGC + kGCpxmp, 0); + XFillRectangle((Display*)fDisplay, gTws->fBuffer, lGC[kGCpxmp], 0, 0, w, h); + SetColor(lGC + kGCpxmp, 1); + if (gTws->fDoubleBuffer) + gTws->fDrawing = gTws->fBuffer; } gTws->fWidth = w; gTws->fHeight = h; @@ -1891,12 +1927,16 @@ int TGX11::ResizePixmap(int wid, unsigned int w, unsigned int h) } XGetGeometry((Display*)fDisplay, gTws->fWindow, &root, &xx, &yy, &ww, &hh, &border, &depth); - for (i = 0; i < kMAXGC; i++) + auto lGC = (GC *) gTws->fGClist; + + for (i = 0; i < kMAXGC; i++) { XSetClipMask((Display*)fDisplay, gGClist[i], None); + XSetClipMask((Display*)fDisplay, lGC[i], None); + } - SetColor(gGCpxmp, 0); - XFillRectangle((Display*)fDisplay, gTws->fWindow, *gGCpxmp, 0, 0, ww, hh); - SetColor(gGCpxmp, 1); + SetColor(lGC + kGCpxmp, 0); + XFillRectangle((Display*)fDisplay, gTws->fWindow, lGC[kGCpxmp], 0, 0, ww, hh); + SetColor(lGC + kGCpxmp, 1); // Initialise the window structure gTws->fDrawing = gTws->fWindow; @@ -1934,8 +1974,11 @@ void TGX11::ResizeWindow(Int_t wid) XFreePixmap((Display*)fDisplay,gTws->fBuffer); gTws->fBuffer = XCreatePixmap((Display*)fDisplay, fRootWin, wval, hval, fDepth); } - for (int i = 0; i < kMAXGC; i++) + auto lGC = (GC *) gTws->fGClist; + for (int i = 0; i < kMAXGC; i++) { XSetClipMask((Display*)fDisplay, gGClist[i], None); + XSetClipMask((Display*)fDisplay, lGC[i], None); + } SetColor(gGCpxmp, 0); XFillRectangle((Display*)fDisplay, gTws->fBuffer, *gGCpxmp, 0, 0, wval, hval); SetColor(gGCpxmp, 1); @@ -1960,17 +2003,23 @@ void TGX11::SelectWindow(int wid) gCws = &handle; + auto lGC = (GC *) gCws->fGClist; + if (gCws->fClip && !gCws->fIsPixmap && !gCws->fDoubleBuffer) { XRectangle region; region.x = gCws->fXclip; region.y = gCws->fYclip; region.width = gCws->fWclip; region.height = gCws->fHclip; - for (int i = 0; i < kMAXGC; i++) + for (int i = 0; i < kMAXGC; i++) { XSetClipRectangles((Display*)fDisplay, gGClist[i], 0, 0, ®ion, 1, YXBanded); + XSetClipRectangles((Display*)fDisplay, lGC[i], 0, 0, ®ion, 1, YXBanded); + } } else { - for (int i = 0; i < kMAXGC; i++) + for (int i = 0; i < kMAXGC; i++) { XSetClipMask((Display*)fDisplay, gGClist[i], None); + XSetClipMask((Display*)fDisplay, lGC[i], None); + } } } @@ -2002,9 +2051,12 @@ void TGX11::SetClipOFF(int wid) { gTws = &fWindows[wid]; gTws->fClip = 0; + auto lGC = (GC *) gTws->fGClist; - for (int i = 0; i < kMAXGC; i++) + for (int i = 0; i < kMAXGC; i++) { XSetClipMask( (Display*)fDisplay, gGClist[i], None ); + XSetClipMask( (Display*)fDisplay, lGC[i], None ); + } } //////////////////////////////////////////////////////////////////////////////// @@ -2016,7 +2068,6 @@ void TGX11::SetClipOFF(int wid) void TGX11::SetClipRegion(int wid, int x, int y, unsigned int w, unsigned int h) { - gTws = &fWindows[wid]; gTws->fXclip = x; gTws->fYclip = y; @@ -2029,8 +2080,11 @@ void TGX11::SetClipRegion(int wid, int x, int y, unsigned int w, unsigned int h) region.y = gTws->fYclip; region.width = gTws->fWclip; region.height = gTws->fHclip; - for (int i = 0; i < kMAXGC; i++) + auto lGC = (GC *) gTws->fGClist; + for (int i = 0; i < kMAXGC; i++) { XSetClipRectangles((Display*)fDisplay, gGClist[i], 0, 0, ®ion, 1, YXBanded); + XSetClipRectangles((Display*)fDisplay, lGC[i], 0, 0, ®ion, 1, YXBanded); + } } } @@ -2131,15 +2185,20 @@ void TGX11::SetDoubleBufferOFF() void TGX11::SetDoubleBufferON() { - if (gTws->fDoubleBuffer || gTws->fIsPixmap) return; + if (gTws->fDoubleBuffer || gTws->fIsPixmap) + return; + auto lGC = (GC *) gTws->fGClist; if (!gTws->fBuffer) { gTws->fBuffer = XCreatePixmap((Display*)fDisplay, fRootWin, gTws->fWidth, gTws->fHeight, fDepth); - SetColor(gGCpxmp, 0); - XFillRectangle((Display*)fDisplay, gTws->fBuffer, *gGCpxmp, 0, 0, gTws->fWidth, gTws->fHeight); - SetColor(gGCpxmp, 1); + SetColor(lGC + kGCpxmp, 0); + XFillRectangle((Display*)fDisplay, gTws->fBuffer, lGC[kGCpxmp], 0, 0, gTws->fWidth, gTws->fHeight); + SetColor(lGC + kGCpxmp, 1); + } + for (int i = 0; i < kMAXGC; i++) { + XSetClipMask((Display*)fDisplay, gGClist[i], None); + XSetClipMask((Display*)fDisplay, lGC[i], None); } - for (int i = 0; i < kMAXGC; i++) XSetClipMask((Display*)fDisplay, gGClist[i], None); gTws->fDoubleBuffer = 1; gTws->fDrawing = gTws->fBuffer; } @@ -2156,19 +2215,29 @@ void TGX11::SetDoubleBufferON() void TGX11::SetDrawMode(EDrawMode mode) { - int i; if (fDisplay) { + auto lGC = (GC *) gCws->fGClist; + switch (mode) { case kCopy: - for (i = 0; i < kMAXGC; i++) XSetFunction((Display*)fDisplay, gGClist[i], GXcopy); + for (int i = 0; i < kMAXGC; i++) { + XSetFunction((Display*)fDisplay, gGClist[i], GXcopy); + XSetFunction((Display*)fDisplay, lGC[i], GXcopy); + } break; case kXor: - for (i = 0; i < kMAXGC; i++) XSetFunction((Display*)fDisplay, gGClist[i], GXxor); + for (int i = 0; i < kMAXGC; i++) { + XSetFunction((Display*)fDisplay, gGClist[i], GXxor); + XSetFunction((Display*)fDisplay, lGC[i], GXxor); + } break; case kInvert: - for (i = 0; i < kMAXGC; i++) XSetFunction((Display*)fDisplay, gGClist[i], GXinvert); + for (int i = 0; i < kMAXGC; i++) { + XSetFunction((Display*)fDisplay, gGClist[i], GXinvert); + XSetFunction((Display*)fDisplay, lGC[i], GXinvert); + } break; } } @@ -3675,3 +3744,62 @@ Int_t TGX11::SupportsExtension(const char *ext) const return -1; return XQueryExtension((Display*)fDisplay, ext, &major_opcode, &first_event, &first_error); } + + +WinContext_t TGX11::GetWindowContext(Int_t wid) +{ + auto &ctxt = fWindows[wid]; + return (WinContext_t) &ctxt; +} + +void TGX11::SetAttFill(WinContext_t wctxt, const TAttFill &att) +{ + auto ctxt = (XWindow_t *) wctxt; + if (!ctxt) + return; + (void) att; +} + +void TGX11::SetAttLine(WinContext_t wctxt, const TAttLine &att) +{ + auto ctxt = (XWindow_t *) wctxt; + if (!ctxt) + return; + (void) att; +} + +void TGX11::SetAttMarker(WinContext_t wctxt, const TAttMarker &att) +{ + auto ctxt = (XWindow_t *) wctxt; + if (!ctxt) + return; + (void) att; +} + +void TGX11::SetAttText(WinContext_t wctxt, const TAttText &att) +{ + auto ctxt = (XWindow_t *) wctxt; + if (!ctxt) + return; + (void) att; +} + + +void TGX11::SetDrawMode(WinContext_t wctxt, EDrawMode mode) +{ + auto ctxt = (XWindow_t *) wctxt; + if (!ctxt) + return; + + auto lGC = (GC *) ctxt->fGClist; + + auto gxmode = GXcopy; + if (mode == kXor) + gxmode = GXxor; + else if (mode == kInvert) + gxmode = GXinvert; + for (int i = 0; i < kMAXGC; i++) + XSetFunction((Display*)fDisplay, lGC[i], gxmode); + + ctxt->fDrawMode = mode; +} From d220b491c94fcca9873ceba4a6f7263dc2f8d1a4 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 11 Mar 2026 09:36:48 +0100 Subject: [PATCH 04/37] [tgx11] move XWindow_t declaration to source file Allows to use native X11 types without casting. List of windows now defined as: ``` std::unordered_map> fWindows ``` --- graf2d/x11/inc/TGX11.h | 27 +---- graf2d/x11/src/TGX11.cxx | 243 ++++++++++++++++++++------------------- 2 files changed, 129 insertions(+), 141 deletions(-) diff --git a/graf2d/x11/inc/TGX11.h b/graf2d/x11/inc/TGX11.h index 6c1b7d1df5f8a..4316aa5bbe752 100644 --- a/graf2d/x11/inc/TGX11.h +++ b/graf2d/x11/inc/TGX11.h @@ -14,6 +14,7 @@ #include "TVirtualX.h" #include +#include #ifdef Status // Convert Status from a CPP macro to a typedef: @@ -45,28 +46,6 @@ struct RXSetWindowAttributes; struct RXVisualInfo; struct RVisual; -/// Description of a X11 window. -struct XWindow_t { - Int_t fOpen; ///< 1 if the window is open, 0 if not - Int_t fDoubleBuffer; ///< 1 if the double buffer is on, 0 if not - Int_t fIsPixmap; ///< 1 if pixmap, 0 if not - Drawable fDrawing; ///< drawing area, equal to window or buffer - Drawable fWindow; ///< X11 window - Drawable fBuffer; ///< pixmap used for double buffer - UInt_t fWidth; ///< width of the window - UInt_t fHeight; ///< height of the window - Int_t fClip; ///< 1 if the clipping is on - Int_t fXclip; ///< x coordinate of the clipping rectangle - Int_t fYclip; ///< y coordinate of the clipping rectangle - UInt_t fWclip; ///< width of the clipping rectangle - UInt_t fHclip; ///< height of the clipping rectangle - ULong_t *fNewColors; ///< new image colors (after processing) - Int_t fNcolors; ///< number of different colors - Bool_t fShared; ///< notify when window is shared - void *fGClist; ///< list of GC object, individual for each window - TVirtualX::EDrawMode fDrawMode; ///< current draw mode -}; - /// Description of a X11 color. struct XColor_t { ULong_t fPixel; ///< color pixel value @@ -79,11 +58,13 @@ struct XColor_t { class TExMap; +struct XWindow_t; + class TGX11 : public TVirtualX { private: - std::unordered_map fWindows; // map of windows + std::unordered_map> fWindows; // map of windows TExMap *fColors; ///< Hash list of colors Cursor fCursors[kNumCursors]; ///< List of cursors void *fXEvent; ///< Current native (X11) event diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index 5fa6ad71e9462..3b05660bba224 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -76,12 +76,7 @@ extern int XRotDrawAlignedImageString(Display*, XFontStruct*, float, extern XPoint *XRotTextExtents(Display*, XFontStruct*, float, int, int, char*, int); -//---- globals -static XWindow_t *gCws; // gCws: pointer to the current window -static XWindow_t *gTws; // gTws: temporary pointer - -const Int_t kBIGGEST_RGB_VALUE = 65535; // // Primitives Graphic Contexts global for all windows @@ -100,6 +95,38 @@ static GC *gGCpxmp = &gGClist[kGCpxmp]; // Pixmap management static GC gGCecho; // Input echo + +/// Description of a X11 window. +struct XWindow_t { + Int_t fOpen = 0; ///< 1 if the window is open, 0 if not + Int_t fDoubleBuffer = 0; ///< 1 if the double buffer is on, 0 if not + Int_t fIsPixmap = 0; ///< 1 if pixmap, 0 if not + Drawable fDrawing = 0; ///< drawing area, equal to window or buffer + Drawable fWindow = 0; ///< X11 window + Drawable fBuffer = 0; ///< pixmap used for double buffer + UInt_t fWidth = 0; ///< width of the window + UInt_t fHeight = 0; ///< height of the window + Int_t fClip = 0; ///< 1 if the clipping is on + Int_t fXclip = 0; ///< x coordinate of the clipping rectangle + Int_t fYclip = 0; ///< y coordinate of the clipping rectangle + UInt_t fWclip = 0; ///< width of the clipping rectangle + UInt_t fHclip = 0; ///< height of the clipping rectangle + ULong_t *fNewColors = 0; ///< new image colors (after processing) + Int_t fNcolors = 0; ///< number of different colors + Bool_t fShared = 0; ///< notify when window is shared + GC fGClist[kMAXGC]; ///< list of GC object, individual for each window + TVirtualX::EDrawMode fDrawMode; ///< current draw mode +}; + + +//---- globals + +static XWindow_t *gCws; // gCws: pointer to the current window +static XWindow_t *gTws; // gTws: temporary pointer + +const Int_t kBIGGEST_RGB_VALUE = 65535; + + static Int_t gFillHollow; // Flag if fill style is hollow static Pixmap gFillPattern = 0; // Fill pattern @@ -243,8 +270,6 @@ TGX11::TGX11(const char *name, const char *title) : TVirtualX(name, title) TGX11::TGX11(const TGX11 &org) : TVirtualX(org) { - int i; - fDisplay = org.fDisplay; fScreenNumber = org.fScreenNumber; fVisual = org.fVisual; @@ -271,29 +296,32 @@ TGX11::TGX11(const TGX11 &org) : TVirtualX(org) fDrawMode = org.fDrawMode; fXEvent = new XEvent; - for(auto & iter : org.fWindows) { - auto &tgt = fWindows[iter.first]; // entry created - auto &src = iter.second; - tgt.fOpen = src.fOpen; - tgt.fDoubleBuffer = src.fDoubleBuffer; - tgt.fIsPixmap = src.fIsPixmap; - tgt.fDrawing = src.fDrawing; - tgt.fWindow = src.fWindow; - tgt.fBuffer = src.fBuffer; - tgt.fWidth = src.fWidth; - tgt.fHeight = src.fHeight; - tgt.fClip = src.fClip; - tgt.fXclip = src.fXclip; - tgt.fYclip = src.fYclip; - tgt.fWclip = src.fWclip; - tgt.fHclip = src.fHclip; + for(auto & pair : org.fWindows) { + fWindows.emplace(pair.first, std::make_unique()); + auto &tgt = fWindows[pair.first]; // entry created + auto &src = pair.second; + tgt->fOpen = src->fOpen; + tgt->fDoubleBuffer = src->fDoubleBuffer; + tgt->fIsPixmap = src->fIsPixmap; + tgt->fDrawing = src->fDrawing; + tgt->fWindow = src->fWindow; + tgt->fBuffer = src->fBuffer; + tgt->fWidth = src->fWidth; + tgt->fHeight = src->fHeight; + tgt->fClip = src->fClip; + tgt->fXclip = src->fXclip; + tgt->fYclip = src->fYclip; + tgt->fWclip = src->fWclip; + tgt->fHclip = src->fHclip; // FIXME: copy of pointer on may lead to double delete!!! - tgt.fNewColors = src.fNewColors; - tgt.fNcolors = src.fNcolors; - tgt.fShared = src.fShared; + tgt->fNewColors = src->fNewColors; + tgt->fNcolors = src->fNcolors; + tgt->fShared = src->fShared; + for (int i = 0; i < kMAXGC; ++i) + tgt->fGClist[i] = src->fGClist[i]; } - for (i = 0; i < kNumCursors; i++) + for (int i = 0; i < kNumCursors; i++) fCursors[i] = org.fCursors[i]; fColors = new TExMap; @@ -470,16 +498,13 @@ void TGX11::CloseWindow() XFlush((Display*)fDisplay); } - auto lGC = (GC *) gCws->fGClist; for (int i = 0; i < kMAXGC; ++i) - XFreeGC((Display*)fDisplay, lGC[i]); - ::operator delete(gCws->fGClist); - gCws->fGClist = nullptr; + XFreeGC((Display*)fDisplay, gCws->fGClist[i]); gCws->fOpen = 0; for (auto iter = fWindows.begin(); iter != fWindows.end(); ++iter) - if (&iter->second == gCws) { + if (iter->second.get() == gCws) { fWindows.erase(iter); gCws = nullptr; break; @@ -490,8 +515,8 @@ void TGX11::CloseWindow() // select first from active windows for (auto iter = fWindows.begin(); iter != fWindows.end(); ++iter) - if (iter->second.fOpen) { - gCws = &iter->second; + if (iter->second->fOpen) { + gCws = iter->second.get(); return; } } @@ -501,7 +526,7 @@ void TGX11::CloseWindow() void TGX11::CopyPixmap(int wid, int xpos, int ypos) { - gTws = &fWindows[wid]; + gTws = fWindows[wid].get(); XCopyArea((Display*)fDisplay, gTws->fDrawing, gCws->fDrawing, *gGCpxmp, 0, 0, gTws->fWidth, gTws->fHeight, xpos, ypos); @@ -976,7 +1001,7 @@ void *TGX11::GetGC(Int_t which) const Int_t TGX11::GetDoubleBuffer(int wid) { - gTws = &fWindows[wid]; + gTws = fWindows[wid].get(); if (!gTws->fOpen) return -1; else @@ -1006,7 +1031,7 @@ void TGX11::GetGeometry(int wid, int &x, int &y, unsigned int &w, unsigned int & unsigned int border, depth; unsigned int width, height; - gTws = &fWindows[wid]; + gTws = fWindows[wid].get(); XGetGeometry((Display*)fDisplay, gTws->fWindow, &root, &x, &y, &width, &height, &border, &depth); XTranslateCoordinates((Display*)fDisplay, gTws->fWindow, fRootWin, @@ -1101,7 +1126,7 @@ void TGX11::GetTextExtent(UInt_t &w, UInt_t &h, char *mess) Window_t TGX11::GetWindowID(int wid) { - return (Window_t) fWindows[wid].fWindow; + return (Window_t) fWindows[wid]->fWindow; } //////////////////////////////////////////////////////////////////////////////// @@ -1113,7 +1138,7 @@ Window_t TGX11::GetWindowID(int wid) void TGX11::MoveWindow(Int_t wid, Int_t x, Int_t y) { - gTws = &fWindows[wid]; + gTws = fWindows[wid].get(); if (!gTws->fOpen) return; XMoveWindow((Display*)fDisplay, gTws->fWindow, x, y); @@ -1277,13 +1302,13 @@ Int_t TGX11::OpenDisplay(void *disp) Int_t TGX11::AddWindowHandle() { Int_t maxid = 0; - for (auto & iter : fWindows) { - if (!iter.second.fOpen) { - iter.second.fOpen = 1; - return iter.first; + for (auto & pair : fWindows) { + if (!pair.second->fOpen) { + pair.second->fOpen = 1; + return pair.first; } - if (iter.first > maxid) - maxid = iter.first; + if (pair.first > maxid) + maxid = pair.first; } if (fWindows.size() == (size_t) maxid) { @@ -1297,19 +1322,18 @@ Int_t TGX11::AddWindowHandle() } } + fWindows.emplace(maxid, std::make_unique()); - auto &ctxt = fWindows[maxid]; - ctxt.fOpen = 1; - ctxt.fDrawMode = TVirtualX::kCopy; - ctxt.fGClist = ::operator new(kMAXGC * sizeof(GC)); - auto lGC = (GC *) ctxt.fGClist; + auto ctxt = fWindows[maxid].get(); + ctxt->fOpen = 1; + ctxt->fDrawMode = TVirtualX::kCopy; for (int n = 0; n < kMAXGC; ++n) - lGC[n] = XCreateGC((Display*)fDisplay, fVisRootWin, 0, nullptr); + ctxt->fGClist[n] = XCreateGC((Display*)fDisplay, fVisRootWin, 0, nullptr); XGCValues values; - if (XGetGCValues((Display*)fDisplay, lGC[kGCtext], GCForeground|GCBackground, &values)) { - XSetForeground((Display*)fDisplay, lGC[kGCinvt], values.background); - XSetBackground((Display*)fDisplay, lGC[kGCinvt], values.foreground); + if (XGetGCValues((Display*)fDisplay, ctxt->fGClist[kGCtext], GCForeground|GCBackground, &values)) { + XSetForeground((Display*)fDisplay, ctxt->fGClist[kGCinvt], values.background); + XSetBackground((Display*)fDisplay, ctxt->fGClist[kGCinvt], values.foreground); } else { Error("AddWindowHandle", "cannot get GC values"); } @@ -1317,7 +1341,7 @@ Int_t TGX11::AddWindowHandle() // Turn-off GraphicsExpose and NoExpose event reporting for the pixmap // manipulation GC, this to prevent these events from being stacked up // without ever being processed and thereby wasting a lot of memory. - XSetGraphicsExposures((Display*)fDisplay, lGC[kGCpxmp], False); + XSetGraphicsExposures((Display*)fDisplay, ctxt->fGClist[kGCpxmp], False); return maxid; } @@ -1340,20 +1364,19 @@ Int_t TGX11::OpenPixmap(unsigned int w, unsigned int h) // Select next free window number int wid = AddWindowHandle(); - gCws = &fWindows[wid]; + gCws = fWindows[wid].get(); gCws->fWindow = XCreatePixmap((Display*)fDisplay, fRootWin, wval, hval, fDepth); XGetGeometry((Display*)fDisplay, gCws->fWindow, &root, &xx, &yy, &ww, &hh, &border, &depth); - auto lGC = (GC *) gCws->fGClist; for (int i = 0; i < kMAXGC; i++) { XSetClipMask((Display*)fDisplay, gGClist[i], None); - XSetClipMask((Display*)fDisplay, lGC[i], None); + XSetClipMask((Display*)fDisplay, gCws->fGClist[i], None); } - SetColor(lGC + kGCpxmp, 0); - XFillRectangle((Display*)fDisplay, gCws->fWindow, lGC[kGCpxmp], 0, 0, ww, hh); - SetColor(lGC + kGCpxmp, 1); + SetColor(&gCws->fGClist[kGCpxmp], 0); + XFillRectangle((Display*)fDisplay, gCws->fWindow, gCws->fGClist[kGCpxmp], 0, 0, ww, hh); + SetColor(&gCws->fGClist[kGCpxmp], 1); // Initialise the window structure gCws->fDrawing = gCws->fWindow; @@ -1389,7 +1412,7 @@ Int_t TGX11::InitWindow(ULong_t win) // Select next free window number int wid = AddWindowHandle(); - gCws = &fWindows[wid]; + gCws = fWindows[wid].get(); gCws->fDoubleBuffer = 0; // Create window @@ -1439,7 +1462,7 @@ Int_t TGX11::AddWindow(ULong_t qwid, UInt_t w, UInt_t h) { // Select next free window number int wid = AddWindowHandle(); - gCws = &fWindows[wid]; + gCws = fWindows[wid].get(); gCws->fDoubleBuffer = 0; gCws->fWindow = qwid; @@ -1864,9 +1887,7 @@ Int_t TGX11::RequestString(int x, int y, char *text) void TGX11::RescaleWindow(int wid, unsigned int w, unsigned int h) { - int i; - - gTws = &fWindows[wid]; + gTws = fWindows[wid].get(); if (!gTws->fOpen) return; // don't do anything when size did not change @@ -1880,14 +1901,13 @@ void TGX11::RescaleWindow(int wid, unsigned int w, unsigned int h) XFreePixmap((Display*)fDisplay,gTws->fBuffer); gTws->fBuffer = XCreatePixmap((Display*)fDisplay, fRootWin, w, h, fDepth); } - auto lGC = (GC *) gTws->fGClist; - for (i = 0; i < kMAXGC; i++) { + for (int i = 0; i < kMAXGC; i++) { XSetClipMask((Display*)fDisplay, gGClist[i], None); - XSetClipMask((Display*)fDisplay, lGC[i], None); + XSetClipMask((Display*)fDisplay, gTws->fGClist[i], None); } - SetColor(lGC + kGCpxmp, 0); - XFillRectangle((Display*)fDisplay, gTws->fBuffer, lGC[kGCpxmp], 0, 0, w, h); - SetColor(lGC + kGCpxmp, 1); + SetColor(&gTws->fGClist[kGCpxmp], 0); + XFillRectangle((Display*)fDisplay, gTws->fBuffer, gTws->fGClist[kGCpxmp], 0, 0, w, h); + SetColor(&gTws->fGClist[kGCpxmp], 1); if (gTws->fDoubleBuffer) gTws->fDrawing = gTws->fBuffer; } @@ -1910,7 +1930,7 @@ int TGX11::ResizePixmap(int wid, unsigned int w, unsigned int h) wval = w; hval = h; - gTws = &fWindows[wid]; + gTws = fWindows[wid].get(); // don't do anything when size did not change // if (gTws->fWidth == wval && gTws->fHeight == hval) return 0; @@ -1927,16 +1947,14 @@ int TGX11::ResizePixmap(int wid, unsigned int w, unsigned int h) } XGetGeometry((Display*)fDisplay, gTws->fWindow, &root, &xx, &yy, &ww, &hh, &border, &depth); - auto lGC = (GC *) gTws->fGClist; - for (i = 0; i < kMAXGC; i++) { XSetClipMask((Display*)fDisplay, gGClist[i], None); - XSetClipMask((Display*)fDisplay, lGC[i], None); + XSetClipMask((Display*)fDisplay, gTws->fGClist[i], None); } - SetColor(lGC + kGCpxmp, 0); - XFillRectangle((Display*)fDisplay, gTws->fWindow, lGC[kGCpxmp], 0, 0, ww, hh); - SetColor(lGC + kGCpxmp, 1); + SetColor(&gTws->fGClist[kGCpxmp], 0); + XFillRectangle((Display*)fDisplay, gTws->fWindow, gTws->fGClist[kGCpxmp], 0, 0, ww, hh); + SetColor(&gTws->fGClist[kGCpxmp], 1); // Initialise the window structure gTws->fDrawing = gTws->fWindow; @@ -1955,7 +1973,7 @@ void TGX11::ResizeWindow(Int_t wid) Window win, root=0; unsigned int wval=0, hval=0, border=0, depth=0; - gTws = &fWindows[wid]; + gTws = fWindows[wid].get(); win = gTws->fWindow; @@ -1974,14 +1992,13 @@ void TGX11::ResizeWindow(Int_t wid) XFreePixmap((Display*)fDisplay,gTws->fBuffer); gTws->fBuffer = XCreatePixmap((Display*)fDisplay, fRootWin, wval, hval, fDepth); } - auto lGC = (GC *) gTws->fGClist; for (int i = 0; i < kMAXGC; i++) { XSetClipMask((Display*)fDisplay, gGClist[i], None); - XSetClipMask((Display*)fDisplay, lGC[i], None); + XSetClipMask((Display*)fDisplay, gTws->fGClist[i], None); } - SetColor(gGCpxmp, 0); - XFillRectangle((Display*)fDisplay, gTws->fBuffer, *gGCpxmp, 0, 0, wval, hval); - SetColor(gGCpxmp, 1); + SetColor(&gTws->fGClist[kGCpxmp], 0); + XFillRectangle((Display*)fDisplay, gTws->fBuffer, gTws->fGClist[kGCpxmp], 0, 0, wval, hval); + SetColor(&gTws->fGClist[kGCpxmp], 1); if (gTws->fDoubleBuffer) gTws->fDrawing = gTws->fBuffer; } @@ -1997,13 +2014,10 @@ void TGX11::SelectWindow(int wid) if (fWindows.count(wid) == 0) return; - auto &handle = fWindows[wid]; - if (!handle.fOpen) + if (!fWindows[wid]->fOpen) return; - gCws = &handle; - - auto lGC = (GC *) gCws->fGClist; + gCws = fWindows[wid].get(); if (gCws->fClip && !gCws->fIsPixmap && !gCws->fDoubleBuffer) { XRectangle region; @@ -2013,12 +2027,12 @@ void TGX11::SelectWindow(int wid) region.height = gCws->fHclip; for (int i = 0; i < kMAXGC; i++) { XSetClipRectangles((Display*)fDisplay, gGClist[i], 0, 0, ®ion, 1, YXBanded); - XSetClipRectangles((Display*)fDisplay, lGC[i], 0, 0, ®ion, 1, YXBanded); + XSetClipRectangles((Display*)fDisplay, gCws->fGClist[i], 0, 0, ®ion, 1, YXBanded); } } else { for (int i = 0; i < kMAXGC; i++) { XSetClipMask((Display*)fDisplay, gGClist[i], None); - XSetClipMask((Display*)fDisplay, lGC[i], None); + XSetClipMask((Display*)fDisplay, gCws->fGClist[i], None); } } } @@ -2049,13 +2063,12 @@ void TGX11::SetCharacterUp(Float_t chupx, Float_t chupy) void TGX11::SetClipOFF(int wid) { - gTws = &fWindows[wid]; + gTws = fWindows[wid].get(); gTws->fClip = 0; - auto lGC = (GC *) gTws->fGClist; for (int i = 0; i < kMAXGC; i++) { XSetClipMask( (Display*)fDisplay, gGClist[i], None ); - XSetClipMask( (Display*)fDisplay, lGC[i], None ); + XSetClipMask( (Display*)fDisplay, gTws->fGClist[i], None ); } } @@ -2068,7 +2081,7 @@ void TGX11::SetClipOFF(int wid) void TGX11::SetClipRegion(int wid, int x, int y, unsigned int w, unsigned int h) { - gTws = &fWindows[wid]; + gTws = fWindows[wid].get(); gTws->fXclip = x; gTws->fYclip = y; gTws->fWclip = w; @@ -2080,10 +2093,9 @@ void TGX11::SetClipRegion(int wid, int x, int y, unsigned int w, unsigned int h) region.y = gTws->fYclip; region.width = gTws->fWclip; region.height = gTws->fHclip; - auto lGC = (GC *) gTws->fGClist; for (int i = 0; i < kMAXGC; i++) { XSetClipRectangles((Display*)fDisplay, gGClist[i], 0, 0, ®ion, 1, YXBanded); - XSetClipRectangles((Display*)fDisplay, lGC[i], 0, 0, ®ion, 1, YXBanded); + XSetClipRectangles((Display*)fDisplay, gTws->fGClist[i], 0, 0, ®ion, 1, YXBanded); } } } @@ -2126,7 +2138,7 @@ void TGX11::SetColor(void *gci, int ci) void TGX11::SetCursor(Int_t wid, ECursor cursor) { - gTws = &fWindows[wid]; + gTws = fWindows[wid].get(); XDefineCursor((Display*)fDisplay, gTws->fWindow, fCursors[cursor]); } @@ -2142,8 +2154,8 @@ void TGX11::SetCursor(Int_t wid, ECursor cursor) void TGX11::SetDoubleBuffer(int wid, int mode) { if (wid == 999) { - for (auto & iter : fWindows) { - gTws = &iter.second; + for (auto & pair : fWindows) { + gTws = pair.second.get(); if (gTws->fOpen) { switch (mode) { case 1 : @@ -2156,7 +2168,7 @@ void TGX11::SetDoubleBuffer(int wid, int mode) } } } else { - gTws = &fWindows[wid]; + gTws = fWindows[wid].get(); if (!gTws->fOpen) return; switch (mode) { @@ -2187,17 +2199,16 @@ void TGX11::SetDoubleBufferON() { if (gTws->fDoubleBuffer || gTws->fIsPixmap) return; - auto lGC = (GC *) gTws->fGClist; if (!gTws->fBuffer) { gTws->fBuffer = XCreatePixmap((Display*)fDisplay, fRootWin, gTws->fWidth, gTws->fHeight, fDepth); - SetColor(lGC + kGCpxmp, 0); - XFillRectangle((Display*)fDisplay, gTws->fBuffer, lGC[kGCpxmp], 0, 0, gTws->fWidth, gTws->fHeight); - SetColor(lGC + kGCpxmp, 1); + SetColor(&gTws->fGClist[kGCpxmp], 0); + XFillRectangle((Display*)fDisplay, gTws->fBuffer, gTws->fGClist[kGCpxmp], 0, 0, gTws->fWidth, gTws->fHeight); + SetColor(&gTws->fGClist[kGCpxmp], 1); } for (int i = 0; i < kMAXGC; i++) { XSetClipMask((Display*)fDisplay, gGClist[i], None); - XSetClipMask((Display*)fDisplay, lGC[i], None); + XSetClipMask((Display*)fDisplay, gTws->fGClist[i], None); } gTws->fDoubleBuffer = 1; gTws->fDrawing = gTws->fBuffer; @@ -2216,27 +2227,26 @@ void TGX11::SetDoubleBufferON() void TGX11::SetDrawMode(EDrawMode mode) { if (fDisplay) { - auto lGC = (GC *) gCws->fGClist; switch (mode) { case kCopy: for (int i = 0; i < kMAXGC; i++) { XSetFunction((Display*)fDisplay, gGClist[i], GXcopy); - XSetFunction((Display*)fDisplay, lGC[i], GXcopy); + XSetFunction((Display*)fDisplay, gCws->fGClist[i], GXcopy); } break; case kXor: for (int i = 0; i < kMAXGC; i++) { XSetFunction((Display*)fDisplay, gGClist[i], GXxor); - XSetFunction((Display*)fDisplay, lGC[i], GXxor); + XSetFunction((Display*)fDisplay, gCws->fGClist[i], GXxor); } break; case kInvert: for (int i = 0; i < kMAXGC; i++) { XSetFunction((Display*)fDisplay, gGClist[i], GXinvert); - XSetFunction((Display*)fDisplay, lGC[i], GXinvert); + XSetFunction((Display*)fDisplay, gCws->fGClist[i], GXinvert); } break; } @@ -3348,7 +3358,7 @@ void TGX11::WritePixmap(int wid, unsigned int w, unsigned int h, char *pxname) wval = w; hval = h; - gTws = &fWindows[wid]; + gTws = fWindows[wid].get(); XWriteBitmapFile((Display*)fDisplay, pxname, gTws->fDrawing, wval, hval, -1, -1); } @@ -3713,7 +3723,7 @@ Int_t TGX11::AddPixmap(ULong_t pixid, UInt_t w, UInt_t h) { Int_t wid = AddWindowHandle(); - gCws = &fWindows[wid]; + gCws = fWindows[wid].get(); gCws->fWindow = pixid; gCws->fDrawing = gCws->fWindow; gCws->fBuffer = 0; @@ -3748,8 +3758,7 @@ Int_t TGX11::SupportsExtension(const char *ext) const WinContext_t TGX11::GetWindowContext(Int_t wid) { - auto &ctxt = fWindows[wid]; - return (WinContext_t) &ctxt; + return (WinContext_t) fWindows[wid].get(); } void TGX11::SetAttFill(WinContext_t wctxt, const TAttFill &att) @@ -3791,15 +3800,13 @@ void TGX11::SetDrawMode(WinContext_t wctxt, EDrawMode mode) if (!ctxt) return; - auto lGC = (GC *) ctxt->fGClist; - auto gxmode = GXcopy; if (mode == kXor) gxmode = GXxor; else if (mode == kInvert) gxmode = GXinvert; for (int i = 0; i < kMAXGC; i++) - XSetFunction((Display*)fDisplay, lGC[i], gxmode); + XSetFunction((Display*)fDisplay, ctxt->fGClist[i], gxmode); ctxt->fDrawMode = mode; } From 3d515c0d741f14fa1f4d919bc51dfac0e3ac45e0 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 11 Mar 2026 10:25:47 +0100 Subject: [PATCH 05/37] [tgx11] remove unused RemovePixmap/ClearPixmap methods --- graf2d/x11/inc/TGX11.h | 2 -- graf2d/x11/src/TGX11.cxx | 21 --------------------- 2 files changed, 23 deletions(-) diff --git a/graf2d/x11/inc/TGX11.h b/graf2d/x11/inc/TGX11.h index 4316aa5bbe752..7c09b2bf687a6 100644 --- a/graf2d/x11/inc/TGX11.h +++ b/graf2d/x11/inc/TGX11.h @@ -70,14 +70,12 @@ class TGX11 : public TVirtualX { void *fXEvent; ///< Current native (X11) event Int_t AddWindowHandle(); - void ClearPixmap(Drawable *pix); void CopyWindowtoPixmap(Drawable *pix, Int_t xpos, Int_t ypos); void FindBestVisual(); void FindUsableVisual(RXVisualInfo *vlist, Int_t nitems); void PutImage(Int_t offset, Int_t itran, Int_t x0, Int_t y0, Int_t nx, Int_t ny, Int_t xmin, Int_t ymin, Int_t xmax, Int_t ymax, UChar_t *image, Drawable_t id); - void RemovePixmap(Drawable *pix); void SetColor(void *gc, Int_t ci); void SetFillStyleIndex(Int_t style, Int_t fasi); void SetInput(Int_t inp); diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index 3b05660bba224..c779ac87dfc28 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -421,20 +421,6 @@ void TGX11::QueryColors(Colormap cmap, RXColor *color, Int_t ncolors) } } -//////////////////////////////////////////////////////////////////////////////// -/// Clear the pixmap pix. - -void TGX11::ClearPixmap(Drawable *pix) -{ - Window root; - int xx, yy; - unsigned int ww, hh, border, depth; - XGetGeometry((Display*)fDisplay, *pix, &root, &xx, &yy, &ww, &hh, &border, &depth); - SetColor(gGCpxmp, 0); - XFillRectangle((Display*)fDisplay, *pix, *gGCpxmp, 0 ,0 ,ww ,hh); - SetColor(gGCpxmp, 1); - XFlush((Display*)fDisplay); -} //////////////////////////////////////////////////////////////////////////////// /// Clear current window. @@ -1513,13 +1499,6 @@ void TGX11::QueryPointer(Int_t &ix, Int_t &iy) iy = root_y_return; } -//////////////////////////////////////////////////////////////////////////////// -/// Remove the pixmap pix. - -void TGX11::RemovePixmap(Drawable *pix) -{ - XFreePixmap((Display*)fDisplay,*pix); -} //////////////////////////////////////////////////////////////////////////////// /// Request Locator position. From 4c8d013beceed3d8cee489ed06e20eda0b80f756 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 11 Mar 2026 13:01:54 +0100 Subject: [PATCH 06/37] [tcanvas] change draw mode after select drawable In TCanvas::Feedback() method first select fCanvasID before changing draw mode. Only becase of global GC attributes it was possible before. If GC allocated per window - one should do it correctly --- graf2d/gpad/src/TCanvas.cxx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/graf2d/gpad/src/TCanvas.cxx b/graf2d/gpad/src/TCanvas.cxx index 3f93d1e548dd6..2164222d104f9 100644 --- a/graf2d/gpad/src/TCanvas.cxx +++ b/graf2d/gpad/src/TCanvas.cxx @@ -1126,16 +1126,14 @@ void TCanvas::ExecuteEvent(Int_t event, Int_t px, Int_t py) void TCanvas::FeedbackMode(Bool_t set) { - if (IsWeb()) + if (IsWeb() || (fCanvasID == -1)) return; - if (set) { - SetDoubleBuffer(0); // turn off double buffer mode - gVirtualX->SetDrawMode(TVirtualX::kInvert); // set the drawing mode to XOR mode - } else { - SetDoubleBuffer(1); // turn on double buffer mode - gVirtualX->SetDrawMode(TVirtualX::kCopy); // set drawing mode back to normal (copy) mode - } + if (fPainter) + fPainter->SelectDrawable(fCanvasID); + gVirtualX->SetDrawMode(set ? TVirtualX::kInvert : TVirtualX::kCopy); // set the drawing mode to XOR mode + + SetDoubleBuffer(set ? 0 : 1); // switch double buffer } //////////////////////////////////////////////////////////////////////////////// From 474ddefce7a260032cd54a66d72093391c15ed75 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 11 Mar 2026 13:07:13 +0100 Subject: [PATCH 07/37] [tgx11] use in all places window GCs for pixmap operation --- graf2d/x11/src/TGX11.cxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index c779ac87dfc28..84347eb19f977 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -434,10 +434,10 @@ void TGX11::ClearWindow() XClearWindow((Display*)fDisplay, gCws->fDrawing); XFlush((Display*)fDisplay); } else { - SetColor(gGCpxmp, 0); - XFillRectangle((Display*)fDisplay, gCws->fDrawing, *gGCpxmp, + SetColor(&gCws->fGClist[kGCpxmp], 0); + XFillRectangle((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCpxmp], 0, 0, gCws->fWidth, gCws->fHeight); - SetColor(gGCpxmp, 1); + SetColor(&gCws->fGClist[kGCpxmp], 1); } } @@ -514,7 +514,7 @@ void TGX11::CopyPixmap(int wid, int xpos, int ypos) { gTws = fWindows[wid].get(); - XCopyArea((Display*)fDisplay, gTws->fDrawing, gCws->fDrawing, *gGCpxmp, 0, 0, gTws->fWidth, + XCopyArea((Display*)fDisplay, gTws->fDrawing, gCws->fDrawing, gTws->fGClist[kGCpxmp], 0, 0, gTws->fWidth, gTws->fHeight, xpos, ypos); XFlush((Display*)fDisplay); } @@ -2985,7 +2985,7 @@ void TGX11::SetOpacity(Int_t percent) } // put image back in pixmap on server - XPutImage((Display*)fDisplay, gCws->fDrawing, *gGCpxmp, image, 0, 0, 0, 0, + XPutImage((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCpxmp], image, 0, 0, 0, 0, gCws->fWidth, gCws->fHeight); XFlush((Display*)fDisplay); @@ -3295,7 +3295,7 @@ void TGX11::UpdateWindow(int mode) { if (gCws->fDoubleBuffer) { XCopyArea((Display*)fDisplay, gCws->fDrawing, gCws->fWindow, - *gGCpxmp, 0, 0, gCws->fWidth, gCws->fHeight, 0, 0); + gCws->fGClist[kGCpxmp], 0, 0, gCws->fWidth, gCws->fHeight, 0, 0); } if (mode == 1) { XFlush((Display*)fDisplay); From 15da0a4c4bd68eb9f4622e5df8047983416bbbe2 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 11 Mar 2026 13:09:46 +0100 Subject: [PATCH 08/37] [tgx11] fully exclude global gGCpxmp context Only window-specific contexts are used Remove unused method CopyWindowtoPixmap --- graf2d/x11/inc/TGX11.h | 1 - graf2d/x11/src/TGX11.cxx | 21 +-------------------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/graf2d/x11/inc/TGX11.h b/graf2d/x11/inc/TGX11.h index 7c09b2bf687a6..742e9affb83a5 100644 --- a/graf2d/x11/inc/TGX11.h +++ b/graf2d/x11/inc/TGX11.h @@ -70,7 +70,6 @@ class TGX11 : public TVirtualX { void *fXEvent; ///< Current native (X11) event Int_t AddWindowHandle(); - void CopyWindowtoPixmap(Drawable *pix, Int_t xpos, Int_t ypos); void FindBestVisual(); void FindUsableVisual(RXVisualInfo *vlist, Int_t nitems); void PutImage(Int_t offset, Int_t itran, Int_t x0, Int_t y0, Int_t nx, diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index 84347eb19f977..647599ca9dda6 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -91,7 +91,7 @@ static GC *gGCfill = &gGClist[kGCfill]; // Fill areas static GC *gGCtext = &gGClist[kGCtext]; // Text static GC *gGCinvt = &gGClist[kGCinvt]; // Inverse text static GC *gGCdash = &gGClist[kGCinvt]; // Dashed lines -static GC *gGCpxmp = &gGClist[kGCpxmp]; // Pixmap management +// static GC *gGCpxmp = &gGClist[kGCpxmp]; // Pixmap management static GC gGCecho; // Input echo @@ -519,20 +519,6 @@ void TGX11::CopyPixmap(int wid, int xpos, int ypos) XFlush((Display*)fDisplay); } -//////////////////////////////////////////////////////////////////////////////// -/// Copy area of current window in the pixmap pix. - -void TGX11::CopyWindowtoPixmap(Drawable *pix, int xpos, int ypos ) -{ - Window root; - int xx, yy; - unsigned int ww, hh, border, depth; - - XGetGeometry((Display*)fDisplay, *pix, &root, &xx, &yy, &ww, &hh, &border, &depth); - XCopyArea((Display*)fDisplay, gCws->fDrawing, *pix, *gGCpxmp, xpos, ypos, ww, hh, 0, 0); - XFlush((Display*)fDisplay); -} - //////////////////////////////////////////////////////////////////////////////// /// Draw a box. /// @@ -1169,11 +1155,6 @@ Int_t TGX11::OpenDisplay(void *disp) Error("OpenDisplay", "cannot get GC values"); } - // Turn-off GraphicsExpose and NoExpose event reporting for the pixmap - // manipulation GC, this to prevent these events from being stacked up - // without ever being processed and thereby wasting a lot of memory. - XSetGraphicsExposures((Display*)fDisplay, *gGCpxmp, False); - // Create input echo graphic context XGCValues echov; echov.foreground = fBlackPixel; From f5ae82282a5f1e8038ec4aca6b314c529fd46223 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 11 Mar 2026 15:37:21 +0100 Subject: [PATCH 09/37] [tgx11] provide per-window line and fill attributes management --- graf2d/x11/src/TGX11.cxx | 118 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 3 deletions(-) diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index 647599ca9dda6..3c03812ec8c94 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -115,7 +115,17 @@ struct XWindow_t { Int_t fNcolors = 0; ///< number of different colors Bool_t fShared = 0; ///< notify when window is shared GC fGClist[kMAXGC]; ///< list of GC object, individual for each window - TVirtualX::EDrawMode fDrawMode; ///< current draw mode + TVirtualX::EDrawMode fDrawMode = TVirtualX::kCopy; ///< current draw mode + TAttLine fAttLine = {-1, -1, -1}; ///< current line attributes + Int_t lineWidth = 0; ///< X11 line width + Int_t lineStyle = LineSolid; ///< X11 line style + std::vector dashList; ///< X11 array for dashes + Int_t dashLength = 0; ///< total length of dashes + Int_t dashOffset = 0; ///< current dash offset + TAttFill fAttFill = {-1, -1}; ///< current fill attributes + Int_t fillHollow = 0; ///< X11 fill method + Int_t fillFasi = 0; ///< selected fasi pattern + Pixmap fillPattern = 0; ///< current initialized fill pattern }; @@ -319,6 +329,9 @@ TGX11::TGX11(const TGX11 &org) : TVirtualX(org) tgt->fShared = src->fShared; for (int i = 0; i < kMAXGC; ++i) tgt->fGClist[i] = src->fGClist[i]; + tgt->fDrawMode = src->fDrawMode; + tgt->fAttLine = src->fAttLine; + tgt->fAttFill = src->fAttFill; } for (int i = 0; i < kNumCursors; i++) @@ -487,6 +500,11 @@ void TGX11::CloseWindow() for (int i = 0; i < kMAXGC; ++i) XFreeGC((Display*)fDisplay, gCws->fGClist[i]); + if (gCws->fillPattern != 0) { + XFreePixmap((Display*)fDisplay, gCws->fillPattern); + gCws->fillPattern = 0; + } + gCws->fOpen = 0; for (auto iter = fWindows.begin(); iter != fWindows.end(); ++iter) @@ -3726,7 +3744,48 @@ void TGX11::SetAttFill(WinContext_t wctxt, const TAttFill &att) auto ctxt = (XWindow_t *) wctxt; if (!ctxt) return; - (void) att; + + Int_t cindex = att.GetFillColor(); + if (!gStyle->GetFillColor() && cindex > 1) + cindex = 0; + if (cindex >= 0) + SetColor(&ctxt->fGClist[kGCfill], Int_t(cindex)); + ctxt->fAttFill.SetFillColor(cindex); + + Int_t style = att.GetFillStyle() / 1000; + Int_t fasi = att.GetFillStyle() % 1000; + Int_t stn = (fasi >= 1 && fasi <=25) ? fasi : 2; + ctxt->fAttFill.SetFillStyle(style * 1000 + fasi); + + switch (style) { + case 1: // solid + ctxt->fillHollow = 0; + XSetFillStyle((Display*)fDisplay, ctxt->fGClist[kGCfill], FillSolid); + break; + + case 2: // pattern + ctxt->fillHollow = 1; + break; + + case 3: // hatch + ctxt->fillHollow = 0; + XSetFillStyle((Display*)fDisplay, ctxt->fGClist[kGCfill], FillStippled); + + if (stn != ctxt->fillFasi) { + if (ctxt->fillPattern != 0) + XFreePixmap((Display*)fDisplay, ctxt->fillPattern); + + ctxt->fillPattern = XCreateBitmapFromData((Display*)fDisplay, fRootWin, + (const char*)gStipples[stn], 16, 16); + + XSetStipple((Display*)fDisplay, ctxt->fGClist[kGCfill], ctxt->fillPattern); + ctxt->fillFasi = stn; + } + break; + + default: + ctxt->fillHollow = 1; + } } void TGX11::SetAttLine(WinContext_t wctxt, const TAttLine &att) @@ -3734,7 +3793,60 @@ void TGX11::SetAttLine(WinContext_t wctxt, const TAttLine &att) auto ctxt = (XWindow_t *) wctxt; if (!ctxt) return; - (void) att; + + if (ctxt->fAttLine.GetLineStyle() != att.GetLineStyle()) { //set style index only if different + if (att.GetLineStyle() <= 1) + ctxt->dashList.clear(); + else if (att.GetLineStyle() == 2) + ctxt->dashList = { 3, 3 }; + else if (att.GetLineStyle() == 3) + ctxt->dashList = { 1, 2 }; + else if (att.GetLineStyle() == 4) { + ctxt->dashList = { 3, 4, 1, 4} ; + } else { + TString st = (TString)gStyle->GetLineStyleString(att.GetLineStyle()); + auto tokens = st.Tokenize(" "); + Int_t nt = tokens->GetEntries(); + ctxt->dashList.resize(nt); + for (Int_t j = 0; j < nt; ++j) { + Int_t it; + sscanf(tokens->At(j)->GetName(), "%d", &it); + ctxt->dashList[j] = (Int_t) (it/4); + } + delete tokens; + } + ctxt->dashLength = 0; + for (auto elem : ctxt->dashList) + ctxt->dashLength += elem; + ctxt->dashOffset = 0; + ctxt->lineStyle = ctxt->dashList.size() == 0 ? LineSolid : LineOnOffDash; + } + + if (ctxt->fAttLine.GetLineWidth() != att.GetLineWidth()) { + ctxt->lineWidth = att.GetLineWidth(); + if (ctxt->lineStyle == LineSolid) { + if (ctxt->lineWidth == 1) + ctxt->lineWidth = 0; + } else { + if (ctxt->lineWidth == 0) + ctxt->lineWidth = 1; + } + } + + if (ctxt->lineWidth >= 0) { + XSetLineAttributes((Display*)fDisplay, ctxt->fGClist[kGCline], ctxt->lineWidth, + ctxt->lineStyle, gCapStyle, gJoinStyle); + if (ctxt->lineStyle == LineOnOffDash) + XSetLineAttributes((Display*)fDisplay, ctxt->fGClist[kGCdash], ctxt->lineWidth, + ctxt->lineStyle, gCapStyle, gJoinStyle); + } + + if (att.GetLineColor() >= 0) { + SetColor(&ctxt->fGClist[kGCline], (Int_t) att.GetLineColor()); + SetColor(&ctxt->fGClist[kGCdash], (Int_t) att.GetLineColor()); + } + + ctxt->fAttLine = att; } void TGX11::SetAttMarker(WinContext_t wctxt, const TAttMarker &att) From 5b4c930a3ff1ffd48a92403dff5d59d4acbebfef Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 11 Mar 2026 16:00:28 +0100 Subject: [PATCH 10/37] [tgx11] use new line/fill styles method for generic methods So setting line/fill style to TGX11 will change attributes for currently selected window. Comment out most of members --- graf2d/x11/src/TGX11.cxx | 101 +++++++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 36 deletions(-) diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index 3c03812ec8c94..081868fc67af4 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -87,7 +87,7 @@ const int kMAXGC = 7, static GC gGClist[kMAXGC]; static GC *gGCline = &gGClist[kGCline]; // PolyLines static GC *gGCmark = &gGClist[kGCmark]; // PolyMarker -static GC *gGCfill = &gGClist[kGCfill]; // Fill areas +// static GC *gGCfill = &gGClist[kGCfill]; // Fill areas static GC *gGCtext = &gGClist[kGCtext]; // Text static GC *gGCinvt = &gGClist[kGCinvt]; // Inverse text static GC *gGCdash = &gGClist[kGCinvt]; // Dashed lines @@ -137,8 +137,8 @@ static XWindow_t *gTws; // gTws: temporary pointer const Int_t kBIGGEST_RGB_VALUE = 65535; -static Int_t gFillHollow; // Flag if fill style is hollow -static Pixmap gFillPattern = 0; // Fill pattern +// static Int_t gFillHollow; // Flag if fill style is hollow +// static Pixmap gFillPattern = 0; // Fill pattern // // Text management @@ -169,14 +169,14 @@ static int gMarkerJoinStyle = JoinRound; // // Keep style values for line GC // -static int gLineWidth = 0; -static int gLineStyle = LineSolid; +// static int gLineWidth = 0; +// static int gLineStyle = LineSolid; static int gCapStyle = CapButt; static int gJoinStyle = JoinMiter; -static char gDashList[10]; -static int gDashLength = 0; -static int gDashOffset = 0; -static int gDashSize = 0; +// static char gDashList[10]; +// static int gDashLength = 0; +// static int gDashOffset = 0; +// static int gDashSize = 0; // // Event masks @@ -553,11 +553,11 @@ void TGX11::DrawBox(int x1, int y1, int x2, int y2, EBoxMode mode) switch (mode) { case kHollow: - XDrawRectangle((Display*)fDisplay, gCws->fDrawing, *gGCline, x, y, w, h); + XDrawRectangle((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCline], x, y, w, h); break; case kFilled: - XFillRectangle((Display*)fDisplay, gCws->fDrawing, *gGCfill, x, y, w, h); + XFillRectangle((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCfill], x, y, w, h); break; default: @@ -591,10 +591,10 @@ void TGX11::DrawCellArray(int x1, int y1, int x2, int y2, int nx, int ny, int *i for (j = 0; j < ny; j++) { icol = ic[i+(nx*j)]; if (icol != current_icol) { - XSetForeground((Display*)fDisplay, *gGCfill, GetColor(icol).fPixel); + XSetForeground((Display*)fDisplay, gCws->fGClist[kGCfill], GetColor(icol).fPixel); current_icol = icol; } - XFillRectangle((Display*)fDisplay, gCws->fDrawing, *gGCfill, ix, iy, w, h); + XFillRectangle((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCfill], ix, iy, w, h); iy = iy-h; } ix = ix+w; @@ -611,11 +611,11 @@ void TGX11::DrawFillArea(int n, TPoint *xy) { XPoint *xyp = (XPoint*)xy; - if (gFillHollow) - XDrawLines((Display*)fDisplay, gCws->fDrawing, *gGCfill, xyp, n, CoordModeOrigin); + if (gCws->fillHollow) + XDrawLines((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCfill], xyp, n, CoordModeOrigin); else { - XFillPolygon((Display*)fDisplay, gCws->fDrawing, *gGCfill, + XFillPolygon((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCfill], xyp, n, Nonconvex, CoordModeOrigin); } } @@ -628,11 +628,11 @@ void TGX11::DrawFillArea(int n, TPoint *xy) void TGX11::DrawLine(Int_t x1, Int_t y1, Int_t x2, Int_t y2) { - if (gLineStyle == LineSolid) - XDrawLine((Display*)fDisplay, gCws->fDrawing, *gGCline, x1, y1, x2, y2); + if (gCws->lineStyle == LineSolid) + XDrawLine((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCline], x1, y1, x2, y2); else { - XSetDashes((Display*)fDisplay, *gGCdash, gDashOffset, gDashList, gDashSize); - XDrawLine((Display*)fDisplay, gCws->fDrawing, *gGCdash, x1, y1, x2, y2); + XSetDashes((Display*)fDisplay, gCws->fGClist[kGCdash], gCws->dashOffset, gCws->dashList.data(), gCws->dashList.size()); + XDrawLine((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCdash], x1, y1, x2, y2); } } @@ -661,13 +661,12 @@ void TGX11::DrawPolyLine(int n, TPoint *xy) DrawPolyLine( npt, &xy[ibeg] ); } } else if (n > 1) { - if (gLineStyle == LineSolid) - XDrawLines((Display*)fDisplay, gCws->fDrawing, *gGCline, xyp, n, CoordModeOrigin); + if (gCws->lineStyle == LineSolid) + XDrawLines((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCline], xyp, n, CoordModeOrigin); else { int i; - XSetDashes((Display*)fDisplay, *gGCdash, - gDashOffset, gDashList, gDashSize); - XDrawLines((Display*)fDisplay, gCws->fDrawing, *gGCdash, xyp, n, CoordModeOrigin); + XSetDashes((Display*)fDisplay, gCws->fGClist[kGCdash], gCws->dashOffset, gCws->dashList.data(), gCws->dashList.size()); + XDrawLines((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCdash], xyp, n, CoordModeOrigin); // calculate length of line to update dash offset for (i = 1; i < n; i++) { @@ -675,16 +674,16 @@ void TGX11::DrawPolyLine(int n, TPoint *xy) int dy = xyp[i].y - xyp[i-1].y; if (dx < 0) dx = - dx; if (dy < 0) dy = - dy; - gDashOffset += dx > dy ? dx : dy; + gCws->dashOffset += dx > dy ? dx : dy; } - gDashOffset %= gDashLength; + gCws->dashOffset %= gCws->dashLength; } } else { int px,py; px=xyp[0].x; py=xyp[0].y; XDrawPoint((Display*)fDisplay, gCws->fDrawing, - gLineStyle == LineSolid ? *gGCline : *gGCdash, px, py); + gCws->lineStyle == LineSolid ? gCws->fGClist[kGCline] : gCws->fGClist[kGCdash], px, py); } } @@ -706,11 +705,11 @@ void TGX11::DrawLinesSegments(Int_t n, TPoint *xy) iend = TMath::Min(n, iend + kMaxSegments); } } else if (n > 0) { - if (gLineStyle == LineSolid) - XDrawSegments((Display*)fDisplay, gCws->fDrawing, *gGCline, (XSegment *) xy, n); + if (gCws->lineStyle == LineSolid) + XDrawSegments((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCline], (XSegment *) xy, n); else { - XSetDashes((Display*)fDisplay, *gGCdash, gDashOffset, gDashList, gDashSize); - XDrawSegments((Display*)fDisplay, gCws->fDrawing, *gGCdash, (XSegment *) xy, n); + XSetDashes((Display*)fDisplay, gCws->fGClist[kGCdash], gCws->dashOffset, gCws->dashList.data(), gCws->dashList.size()); + XDrawSegments((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCdash], (XSegment *) xy, n); } } } @@ -2237,6 +2236,11 @@ void TGX11::SetDrawMode(EDrawMode mode) void TGX11::SetFillColor(Color_t cindex) { + TAttFill::SetFillColor(cindex); + + SetAttFill((WinContext_t) gCws, *this); + +/* if (!gStyle->GetFillColor() && cindex > 1) cindex = 0; if (cindex >= 0) SetColor(gGCfill, Int_t(cindex)); fFillColor = cindex; @@ -2246,6 +2250,7 @@ void TGX11::SetFillColor(Color_t cindex) XFreePixmap((Display*)fDisplay, gFillPattern); gFillPattern = 0; } + */ } //////////////////////////////////////////////////////////////////////////////// @@ -2256,11 +2261,16 @@ void TGX11::SetFillColor(Color_t cindex) void TGX11::SetFillStyle(Style_t fstyle) { - if (fFillStyle == fstyle) return; + TAttFill::SetFillStyle(fstyle); + + SetAttFill((WinContext_t) gCws, *this); + +/* if (fFillStyle == fstyle) return; fFillStyle = fstyle; Int_t style = fstyle/1000; Int_t fasi = fstyle%1000; SetFillStyleIndex(style,fasi); + */ } //////////////////////////////////////////////////////////////////////////////// @@ -2268,6 +2278,7 @@ void TGX11::SetFillStyle(Style_t fstyle) void TGX11::SetFillStyleIndex(Int_t style, Int_t fasi) { +/* static int current_fasi = 0; fFillStyle = 1000*style + fasi; @@ -2304,6 +2315,7 @@ void TGX11::SetFillStyleIndex(Int_t style, Int_t fasi) default: gFillHollow = 1; } +*/ } //////////////////////////////////////////////////////////////////////////////// @@ -2334,8 +2346,10 @@ void TGX11::SetLineColor(Color_t cindex) TAttLine::SetLineColor(cindex); - SetColor(gGCline, Int_t(cindex)); - SetColor(gGCdash, Int_t(cindex)); + SetAttLine((WinContext_t) gCws, *this); + + //SetColor(gGCline, Int_t(cindex)); + //SetColor(gGCdash, Int_t(cindex)); } //////////////////////////////////////////////////////////////////////////////// @@ -2351,6 +2365,7 @@ void TGX11::SetLineColor(Color_t cindex) void TGX11::SetLineType(int n, int *dash) { + /* if (n <= 0) { gLineStyle = LineSolid; XSetLineAttributes((Display*)fDisplay, *gGCline, gLineWidth, @@ -2370,6 +2385,7 @@ void TGX11::SetLineType(int n, int *dash) XSetLineAttributes((Display*)fDisplay, *gGCdash, gLineWidth, gLineStyle, gCapStyle, gJoinStyle); } + */ } //////////////////////////////////////////////////////////////////////////////// @@ -2377,6 +2393,11 @@ void TGX11::SetLineType(int n, int *dash) void TGX11::SetLineStyle(Style_t lstyle) { + TAttLine::SetLineStyle(lstyle); + + SetAttLine((WinContext_t) gCws, *this); +/* + static Int_t dashed[2] = {3,3}; static Int_t dotted[2] = {1,2}; static Int_t dasheddotted[4] = {3,4,1,4}; @@ -2407,6 +2428,7 @@ void TGX11::SetLineStyle(Style_t lstyle) delete tokens; } } +*/ } //////////////////////////////////////////////////////////////////////////////// @@ -2414,8 +2436,14 @@ void TGX11::SetLineStyle(Style_t lstyle) /// /// \param [in] width : line width in pixels -void TGX11::SetLineWidth(Width_t width ) +void TGX11::SetLineWidth(Width_t width) { + TAttLine::SetLineWidth(width); + + SetAttLine((WinContext_t) gCws, *this); + +/* + if (fLineWidth == width) return; fLineWidth = width; @@ -2428,6 +2456,7 @@ void TGX11::SetLineWidth(Width_t width ) gLineStyle, gCapStyle, gJoinStyle); XSetLineAttributes((Display*)fDisplay, *gGCdash, gLineWidth, gLineStyle, gCapStyle, gJoinStyle); +*/ } //////////////////////////////////////////////////////////////////////////////// From 70bd1bb765c86e287cff1389486f0ad678a57ca7 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 11 Mar 2026 16:55:29 +0100 Subject: [PATCH 11/37] [tgx11] change marker attributes handling Allocate marker attributes per window, comment aout global gMarker structures --- graf2d/x11/src/TGX11.cxx | 578 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 536 insertions(+), 42 deletions(-) diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index 081868fc67af4..ba78bd287726a 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -86,7 +86,7 @@ const int kMAXGC = 7, kGCtext = 3, kGCinvt = 4, kGCdash = 5, kGCpxmp = 6; static GC gGClist[kMAXGC]; static GC *gGCline = &gGClist[kGCline]; // PolyLines -static GC *gGCmark = &gGClist[kGCmark]; // PolyMarker +// static GC *gGCmark = &gGClist[kGCmark]; // PolyMarker // static GC *gGCfill = &gGClist[kGCfill]; // Fill areas static GC *gGCtext = &gGClist[kGCtext]; // Text static GC *gGCinvt = &gGClist[kGCinvt]; // Inverse text @@ -126,6 +126,12 @@ struct XWindow_t { Int_t fillHollow = 0; ///< X11 fill method Int_t fillFasi = 0; ///< selected fasi pattern Pixmap fillPattern = 0; ///< current initialized fill pattern + TAttMarker fAttMarker = { -1, -1, -1 }; ///< current marker attribute + Int_t markerType = 0; ///< 4 differen kinds of marker + Int_t markerSize = 0; ///< size of simple markers + std::vector markerShape; ///< marker shape points + Int_t markerLineWidth = 0; + }; @@ -155,13 +161,13 @@ static Int_t gCurrentFontNumber = 0; // Current font number in gFont[] // // Markers // -const Int_t kMAXMK = 100; -static struct { - int type; - int n; - XPoint xy[kMAXMK]; -} gMarker; // Point list to draw marker -static int gMarkerLineWidth = 0; +// const Int_t kMAXMK = 100; +// static struct { +// int type; +// int n; +// XPoint xy[kMAXMK]; +// } gMarker; // Point list to draw marker +// static int gMarkerLineWidth = 0; static int gMarkerLineStyle = LineSolid; static int gMarkerCapStyle = CapRound; static int gMarkerJoinStyle = JoinRound; @@ -725,60 +731,59 @@ void TGX11::DrawPolyMarker(int n, TPoint *xy) { XPoint *xyp = (XPoint*)xy; - if (gMarker.n <= 0) { + if ((gCws->markerShape.size() == 0) && (gCws->markerSize <= 0)) { const int kNMAX = 1000000; int nt = n/kNMAX; for (int it=0;it<=nt;it++) { if (it < nt) { - XDrawPoints((Display*)fDisplay, gCws->fDrawing, *gGCmark, &xyp[it*kNMAX], kNMAX, CoordModeOrigin); + XDrawPoints((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], &xyp[it*kNMAX], kNMAX, CoordModeOrigin); } else { - XDrawPoints((Display*)fDisplay, gCws->fDrawing, *gGCmark, &xyp[it*kNMAX], n-it*kNMAX, CoordModeOrigin); + XDrawPoints((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], &xyp[it*kNMAX], n-it*kNMAX, CoordModeOrigin); } } } else { - int r = gMarker.n / 2; + int r = gCws->markerSize / 2; + auto &shape = gCws->markerShape; int m; for (m = 0; m < n; m++) { int hollow = 0; - switch (gMarker.type) { - int i; - + switch (gCws->markerType) { case 0: // hollow circle - XDrawArc((Display*)fDisplay, gCws->fDrawing, *gGCmark, - xyp[m].x - r, xyp[m].y - r, gMarker.n, gMarker.n, 0, 360*64); + XDrawArc((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], + xyp[m].x - r, xyp[m].y - r, gCws->markerSize, gCws->markerSize, 0, 360*64); break; case 1: // filled circle - XFillArc((Display*)fDisplay, gCws->fDrawing, *gGCmark, - xyp[m].x - r, xyp[m].y - r, gMarker.n, gMarker.n, 0, 360*64); + XFillArc((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], + xyp[m].x - r, xyp[m].y - r, gCws->markerSize, gCws->markerSize, 0, 360*64); break; case 2: // hollow polygon hollow = 1; case 3: // filled polygon - for (i = 0; i < gMarker.n; i++) { - gMarker.xy[i].x += xyp[m].x; - gMarker.xy[i].y += xyp[m].y; + for (size_t i = 0; i < shape.size(); i++) { + shape[i].x += xyp[m].x; + shape[i].y += xyp[m].y; } if (hollow) - XDrawLines((Display*)fDisplay, gCws->fDrawing, *gGCmark, - gMarker.xy, gMarker.n, CoordModeOrigin); + XDrawLines((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], + shape.data(), shape.size(), CoordModeOrigin); else - XFillPolygon((Display*)fDisplay, gCws->fDrawing, *gGCmark, - gMarker.xy, gMarker.n, Nonconvex, CoordModeOrigin); - for (i = 0; i < gMarker.n; i++) { - gMarker.xy[i].x -= xyp[m].x; - gMarker.xy[i].y -= xyp[m].y; + XFillPolygon((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], + shape.data(), shape.size(), Nonconvex, CoordModeOrigin); + for (size_t i = 0; i < shape.size(); i++) { + shape[i].x -= xyp[m].x; + shape[i].y -= xyp[m].y; } break; case 4: // segmented line - for (i = 0; i < gMarker.n; i += 2) - XDrawLine((Display*)fDisplay, gCws->fDrawing, *gGCmark, - xyp[m].x + gMarker.xy[i].x, xyp[m].y + gMarker.xy[i].y, - xyp[m].x + gMarker.xy[i+1].x, xyp[m].y + gMarker.xy[i+1].y); + for (size_t i = 0; i < shape.size(); i += 2) + XDrawLine((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], + xyp[m].x + shape[i].x, xyp[m].y + shape[i].y, + xyp[m].x + shape[i+1].x, xyp[m].y + shape[i+1].y); break; } } @@ -2468,7 +2473,7 @@ void TGX11::SetMarkerColor(Color_t cindex) TAttMarker::SetMarkerColor(cindex); - SetColor(gGCmark, Int_t(cindex)); + SetAttMarker((WinContext_t) gCws, *this); } //////////////////////////////////////////////////////////////////////////////// @@ -2478,12 +2483,9 @@ void TGX11::SetMarkerColor(Color_t cindex) void TGX11::SetMarkerSize(Float_t msize) { - if (msize == fMarkerSize) return; - - fMarkerSize = msize; - if (msize < 0) return; + TAttMarker::SetMarkerSize(msize); - SetMarkerStyle(-fMarkerStyle); + SetAttMarker((WinContext_t) gCws, *this); } //////////////////////////////////////////////////////////////////////////////// @@ -2503,6 +2505,7 @@ void TGX11::SetMarkerSize(Float_t msize) void TGX11::SetMarkerType(int type, int n, RXPoint *xy) { + /* gMarker.type = type; gMarker.n = n < kMAXMK ? n : kMAXMK; if (gMarker.type >= 2) { @@ -2511,6 +2514,7 @@ void TGX11::SetMarkerType(int type, int n, RXPoint *xy) gMarker.xy[i].y = xy[i].y; } } + */ } //////////////////////////////////////////////////////////////////////////////// @@ -2518,6 +2522,11 @@ void TGX11::SetMarkerType(int type, int n, RXPoint *xy) void TGX11::SetMarkerStyle(Style_t markerstyle) { + TAttMarker::SetMarkerStyle(markerstyle); + + SetAttMarker((WinContext_t) gCws, *this); +/* + if (fMarkerStyle == markerstyle) return; static RXPoint shape[30]; fMarkerStyle = TMath::Abs(markerstyle); @@ -2540,7 +2549,6 @@ void TGX11::SetMarkerStyle(Style_t markerstyle) shape[1].x = im; shape[1].y = 0; shape[2].x = 0 ; shape[2].y = -im; shape[3].x = 0 ; shape[3].y = im; - SetMarkerType(4,4,shape); } else if (markerstyle == 3 || markerstyle == 31) { // * shaped marker shape[0].x = -im; shape[0].y = 0; @@ -2552,7 +2560,6 @@ void TGX11::SetMarkerStyle(Style_t markerstyle) shape[5].x = im; shape[5].y = im; shape[6].x = -im; shape[6].y = im; shape[7].x = im; shape[7].y = -im; - SetMarkerType(4,8,shape); } else if (markerstyle == 4 || markerstyle == 24) { // O shaped marker SetMarkerType(0,im*2,shape); @@ -2956,6 +2963,7 @@ void TGX11::SetMarkerStyle(Style_t markerstyle) // single dot SetMarkerType(0,0,shape); } +*/ } //////////////////////////////////////////////////////////////////////////////// @@ -3883,7 +3891,493 @@ void TGX11::SetAttMarker(WinContext_t wctxt, const TAttMarker &att) auto ctxt = (XWindow_t *) wctxt; if (!ctxt) return; - (void) att; + + SetColor(&ctxt->fGClist[kGCmark], att.GetMarkerColor()); + + Bool_t changed = (att.GetMarkerSize() != ctxt->fAttMarker.GetMarkerSize()) || + (att.GetMarkerStyle() != ctxt->fAttMarker.GetMarkerStyle()); + + ctxt->fAttMarker = att; + + if (!changed) + return; + + Int_t markerstyle = TAttMarker::GetMarkerStyleBase(att.GetMarkerStyle()); + ctxt->markerLineWidth = TAttMarker::GetMarkerLineWidth(att.GetMarkerStyle()); + + // The fast pixel markers need to be treated separately + if (markerstyle == 1 || markerstyle == 6 || markerstyle == 7) { + XSetLineAttributes((Display*)fDisplay, ctxt->fGClist[kGCmark], 0, LineSolid, CapButt, JoinMiter); + } else { + XSetLineAttributes((Display*)fDisplay, ctxt->fGClist[kGCmark], ctxt->markerLineWidth, + gMarkerLineStyle, gMarkerCapStyle, gMarkerJoinStyle); + } + + Float_t MarkerSizeReduced = att.GetMarkerSize() - TMath::Floor(ctxt->markerLineWidth/2.)/4.; + Int_t im = Int_t(4*MarkerSizeReduced + 0.5); + auto &shape = ctxt->markerShape; + ctxt->markerSize = 0; + ctxt->markerType = 0; + if (markerstyle == 2) { + // + shaped marker + shape.resize(4); + shape[0].x = -im; shape[0].y = 0; + shape[1].x = im; shape[1].y = 0; + shape[2].x = 0 ; shape[2].y = -im; + shape[3].x = 0 ; shape[3].y = im; + ctxt->markerType = 4; + } else if (markerstyle == 3 || markerstyle == 31) { + // * shaped marker + shape.resize(8); + shape[0].x = -im; shape[0].y = 0; + shape[1].x = im; shape[1].y = 0; + shape[2].x = 0 ; shape[2].y = -im; + shape[3].x = 0 ; shape[3].y = im; + im = Int_t(0.707*Float_t(im) + 0.5); + shape[4].x = -im; shape[4].y = -im; + shape[5].x = im; shape[5].y = im; + shape[6].x = -im; shape[6].y = im; + shape[7].x = im; shape[7].y = -im; + ctxt->markerType = 4; + } else if (markerstyle == 4 || markerstyle == 24) { + // O shaped marker + ctxt->markerType = 0; + ctxt->markerSize = im*2; + } else if (markerstyle == 5) { + // X shaped marker + shape.resize(4); + im = Int_t(0.707*Float_t(im) + 0.5); + shape[0].x = -im; shape[0].y = -im; + shape[1].x = im; shape[1].y = im; + shape[2].x = -im; shape[2].y = im; + shape[3].x = im; shape[3].y = -im; + ctxt->markerType = 4; + } else if (markerstyle == 6) { + // + shaped marker (with 1 pixel) + shape.resize(4); + shape[0].x = -1 ; shape[0].y = 0; + shape[1].x = 1 ; shape[1].y = 0; + shape[2].x = 0 ; shape[2].y = -1; + shape[3].x = 0 ; shape[3].y = 1; + ctxt->markerType = 4; + } else if (markerstyle == 7) { + // . shaped marker (with 9 pixel) + shape.resize(6); + shape[0].x = -1 ; shape[0].y = 1; + shape[1].x = 1 ; shape[1].y = 1; + shape[2].x = -1 ; shape[2].y = 0; + shape[3].x = 1 ; shape[3].y = 0; + shape[4].x = -1 ; shape[4].y = -1; + shape[5].x = 1 ; shape[5].y = -1; + ctxt->markerType = 4; + } else if (markerstyle == 8 || markerstyle == 20) { + // O shaped marker (filled) + ctxt->markerType = 1; + ctxt->markerSize = im*2; + } else if (markerstyle == 21) { + // full square + shape.resize(5); + shape[0].x = -im; shape[0].y = -im; + shape[1].x = im; shape[1].y = -im; + shape[2].x = im; shape[2].y = im; + shape[3].x = -im; shape[3].y = im; + shape[4].x = -im; shape[4].y = -im; + ctxt->markerType = 3; + } else if (markerstyle == 22) { + // full triangle up + shape.resize(4); + shape[0].x = -im; shape[0].y = im; + shape[1].x = im; shape[1].y = im; + shape[2].x = 0; shape[2].y = -im; + shape[3].x = -im; shape[3].y = im; + ctxt->markerType = 3; + } else if (markerstyle == 23) { + // full triangle down + shape.resize(4); + shape[0].x = 0; shape[0].y = im; + shape[1].x = im; shape[1].y = -im; + shape[2].x = -im; shape[2].y = -im; + shape[3].x = 0; shape[3].y = im; + ctxt->markerType = 3; + } else if (markerstyle == 25) { + // open square + shape.resize(5); + shape[0].x = -im; shape[0].y = -im; + shape[1].x = im; shape[1].y = -im; + shape[2].x = im; shape[2].y = im; + shape[3].x = -im; shape[3].y = im; + shape[4].x = -im; shape[4].y = -im; + ctxt->markerType = 2; + } else if (markerstyle == 26) { + // open triangle up + shape.resize(4); + shape[0].x = -im; shape[0].y = im; + shape[1].x = im; shape[1].y = im; + shape[2].x = 0; shape[2].y = -im; + shape[3].x = -im; shape[3].y = im; + ctxt->markerType = 2; + } else if (markerstyle == 27) { + // open losange + shape.resize(5); + Int_t imx = Int_t(2.66*MarkerSizeReduced + 0.5); + shape[0].x =-imx; shape[0].y = 0; + shape[1].x = 0; shape[1].y = -im; + shape[2].x = imx; shape[2].y = 0; + shape[3].x = 0; shape[3].y = im; + shape[4].x =-imx; shape[4].y = 0; + ctxt->markerType = 2; + } else if (markerstyle == 28) { + // open cross + shape.resize(13); + Int_t imx = Int_t(1.33*MarkerSizeReduced + 0.5); + shape[0].x = -im; shape[0].y =-imx; + shape[1].x =-imx; shape[1].y =-imx; + shape[2].x =-imx; shape[2].y = -im; + shape[3].x = imx; shape[3].y = -im; + shape[4].x = imx; shape[4].y =-imx; + shape[5].x = im; shape[5].y =-imx; + shape[6].x = im; shape[6].y = imx; + shape[7].x = imx; shape[7].y = imx; + shape[8].x = imx; shape[8].y = im; + shape[9].x =-imx; shape[9].y = im; + shape[10].x=-imx; shape[10].y= imx; + shape[11].x= -im; shape[11].y= imx; + shape[12].x= -im; shape[12].y=-imx; + ctxt->markerType = 2; + } else if (markerstyle == 29) { + // full star pentagone + shape.resize(11); + Int_t im1 = Int_t(0.66*MarkerSizeReduced + 0.5); + Int_t im2 = Int_t(2.00*MarkerSizeReduced + 0.5); + Int_t im3 = Int_t(2.66*MarkerSizeReduced + 0.5); + Int_t im4 = Int_t(1.33*MarkerSizeReduced + 0.5); + shape[0].x = -im; shape[0].y = im4; + shape[1].x =-im2; shape[1].y =-im1; + shape[2].x =-im3; shape[2].y = -im; + shape[3].x = 0; shape[3].y =-im2; + shape[4].x = im3; shape[4].y = -im; + shape[5].x = im2; shape[5].y =-im1; + shape[6].x = im; shape[6].y = im4; + shape[7].x = im4; shape[7].y = im4; + shape[8].x = 0; shape[8].y = im; + shape[9].x =-im4; shape[9].y = im4; + shape[10].x= -im; shape[10].y= im4; + ctxt->markerType = 3; + } else if (markerstyle == 30) { + // open star pentagone + shape.resize(11); + Int_t im1 = Int_t(0.66*MarkerSizeReduced + 0.5); + Int_t im2 = Int_t(2.00*MarkerSizeReduced + 0.5); + Int_t im3 = Int_t(2.66*MarkerSizeReduced + 0.5); + Int_t im4 = Int_t(1.33*MarkerSizeReduced + 0.5); + shape[0].x = -im; shape[0].y = im4; + shape[1].x =-im2; shape[1].y =-im1; + shape[2].x =-im3; shape[2].y = -im; + shape[3].x = 0; shape[3].y =-im2; + shape[4].x = im3; shape[4].y = -im; + shape[5].x = im2; shape[5].y =-im1; + shape[6].x = im; shape[6].y = im4; + shape[7].x = im4; shape[7].y = im4; + shape[8].x = 0; shape[8].y = im; + shape[9].x =-im4; shape[9].y = im4; + shape[10].x= -im; shape[10].y= im4; + ctxt->markerType = 2; + } else if (markerstyle == 32) { + // open triangle down + shape.resize(4); + shape[0].x = 0; shape[0].y = im; + shape[1].x = im; shape[1].y = -im; + shape[2].x = -im; shape[2].y = -im; + shape[3].x = 0; shape[3].y = im; + ctxt->markerType = 2; + } else if (markerstyle == 33) { + // full losange + shape.resize(5); + Int_t imx = Int_t(2.66*MarkerSizeReduced + 0.5); + shape[0].x =-imx; shape[0].y = 0; + shape[1].x = 0; shape[1].y = -im; + shape[2].x = imx; shape[2].y = 0; + shape[3].x = 0; shape[3].y = im; + shape[4].x =-imx; shape[4].y = 0; + ctxt->markerType = 3; + } else if (markerstyle == 34) { + // full cross + shape.resize(13); + Int_t imx = Int_t(1.33*MarkerSizeReduced + 0.5); + shape[0].x = -im; shape[0].y =-imx; + shape[1].x =-imx; shape[1].y =-imx; + shape[2].x =-imx; shape[2].y = -im; + shape[3].x = imx; shape[3].y = -im; + shape[4].x = imx; shape[4].y =-imx; + shape[5].x = im; shape[5].y =-imx; + shape[6].x = im; shape[6].y = imx; + shape[7].x = imx; shape[7].y = imx; + shape[8].x = imx; shape[8].y = im; + shape[9].x =-imx; shape[9].y = im; + shape[10].x=-imx; shape[10].y= imx; + shape[11].x= -im; shape[11].y= imx; + shape[12].x= -im; shape[12].y=-imx; + ctxt->markerType = 3; + } else if (markerstyle == 35) { + // diamond with cross + shape.resize(8); + shape[0].x =-im; shape[0].y = 0; + shape[1].x = 0; shape[1].y = -im; + shape[2].x = im; shape[2].y = 0; + shape[3].x = 0; shape[3].y = im; + shape[4].x =-im; shape[4].y = 0; + shape[5].x = im; shape[5].y = 0; + shape[6].x = 0; shape[6].y = im; + shape[7].x = 0; shape[7].y =-im; + ctxt->markerType = 2; + } else if (markerstyle == 36) { + // square with diagonal cross + shape.resize(8); + shape[0].x = -im; shape[0].y = -im; + shape[1].x = im; shape[1].y = -im; + shape[2].x = im; shape[2].y = im; + shape[3].x = -im; shape[3].y = im; + shape[4].x = -im; shape[4].y = -im; + shape[5].x = im; shape[5].y = im; + shape[6].x = -im; shape[6].y = im; + shape[7].x = im; shape[7].y = -im; + ctxt->markerType = 2; + } else if (markerstyle == 37) { + // open three triangles + shape.resize(10); + Int_t im2 = Int_t(2.0*MarkerSizeReduced + 0.5); + shape[0].x = 0; shape[0].y = 0; + shape[1].x =-im2; shape[1].y = im; + shape[2].x = im2; shape[2].y = im; + shape[3].x = 0; shape[3].y = 0; + shape[4].x =-im2; shape[4].y = -im; + shape[5].x = -im; shape[5].y = 0; + shape[6].x = 0; shape[6].y = 0; + shape[7].x = im; shape[7].y = 0; + shape[8].x = im2; shape[8].y = -im; + shape[9].x = 0; shape[9].y = 0; + ctxt->markerType = 2; + } else if (markerstyle == 38) { + // + shaped marker with octagon + shape.resize(15); + Int_t im2 = Int_t(2.0*MarkerSizeReduced + 0.5); + shape[0].x = -im; shape[0].y = 0; + shape[1].x = -im; shape[1].y =-im2; + shape[2].x =-im2; shape[2].y = -im; + shape[3].x = im2; shape[3].y = -im; + shape[4].x = im; shape[4].y =-im2; + shape[5].x = im; shape[5].y = im2; + shape[6].x = im2; shape[6].y = im; + shape[7].x =-im2; shape[7].y = im; + shape[8].x = -im; shape[8].y = im2; + shape[9].x = -im; shape[9].y = 0; + shape[10].x = im; shape[10].y = 0; + shape[11].x = 0; shape[11].y = 0; + shape[12].x = 0; shape[12].y = -im; + shape[13].x = 0; shape[13].y = im; + shape[14].x = 0; shape[14].y = 0; + ctxt->markerType = 2; + } else if (markerstyle == 39) { + // filled three triangles + shape.resize(9); + Int_t im2 = Int_t(2.0*MarkerSizeReduced + 0.5); + shape[0].x = 0; shape[0].y = 0; + shape[1].x =-im2; shape[1].y = im; + shape[2].x = im2; shape[2].y = im; + shape[3].x = 0; shape[3].y = 0; + shape[4].x =-im2; shape[4].y = -im; + shape[5].x = -im; shape[5].y = 0; + shape[6].x = 0; shape[6].y = 0; + shape[7].x = im; shape[7].y = 0; + shape[8].x = im2; shape[8].y = -im; + ctxt->markerType = 3; + } else if (markerstyle == 40) { + // four open triangles X + shape.resize(13); + Int_t im2 = Int_t(2.0*MarkerSizeReduced + 0.5); + shape[0].x = 0; shape[0].y = 0; + shape[1].x = im2; shape[1].y = im; + shape[2].x = im; shape[2].y = im2; + shape[3].x = 0; shape[3].y = 0; + shape[4].x = im; shape[4].y = -im2; + shape[5].x = im2; shape[5].y = -im; + shape[6].x = 0; shape[6].y = 0; + shape[7].x = -im2; shape[7].y = -im; + shape[8].x = -im; shape[8].y = -im2; + shape[9].x = 0; shape[9].y = 0; + shape[10].x = -im; shape[10].y = im2; + shape[11].x = -im2; shape[11].y = im; + shape[12].x = 0; shape[12].y = 0; + ctxt->markerType = 2; + } else if (markerstyle == 41) { + // four filled triangles X + shape.resize(13); + Int_t im2 = Int_t(2.0*MarkerSizeReduced + 0.5); + shape[0].x = 0; shape[0].y = 0; + shape[1].x = im2; shape[1].y = im; + shape[2].x = im; shape[2].y = im2; + shape[3].x = 0; shape[3].y = 0; + shape[4].x = im; shape[4].y = -im2; + shape[5].x = im2; shape[5].y = -im; + shape[6].x = 0; shape[6].y = 0; + shape[7].x = -im2; shape[7].y = -im; + shape[8].x = -im; shape[8].y = -im2; + shape[9].x = 0; shape[9].y = 0; + shape[10].x = -im; shape[10].y = im2; + shape[11].x = -im2; shape[11].y = im; + shape[12].x = 0; shape[12].y = 0; + ctxt->markerType = 3; + } else if (markerstyle == 42) { + // open double diamonds + shape.resize(9); + Int_t imx = Int_t(MarkerSizeReduced + 0.5); + shape[0].x= 0; shape[0].y= im; + shape[1].x= -imx; shape[1].y= imx; + shape[2].x = -im; shape[2].y = 0; + shape[3].x = -imx; shape[3].y = -imx; + shape[4].x = 0; shape[4].y = -im; + shape[5].x = imx; shape[5].y = -imx; + shape[6].x = im; shape[6].y = 0; + shape[7].x= imx; shape[7].y= imx; + shape[8].x= 0; shape[8].y= im; + ctxt->markerType = 2; + } else if (markerstyle == 43) { + // filled double diamonds + shape.resize(9); + Int_t imx = Int_t(MarkerSizeReduced + 0.5); + shape[0].x = 0; shape[0].y = im; + shape[1].x = -imx; shape[1].y = imx; + shape[2].x = -im; shape[2].y = 0; + shape[3].x = -imx; shape[3].y = -imx; + shape[4].x = 0; shape[4].y = -im; + shape[5].x = imx; shape[5].y = -imx; + shape[6].x = im; shape[6].y = 0; + shape[7].x = imx; shape[7].y = imx; + shape[8].x = 0; shape[8].y = im; + ctxt->markerType = 3; + } else if (markerstyle == 44) { + // open four triangles plus + shape.resize(11); + Int_t im2 = Int_t(2.0*MarkerSizeReduced + 0.5); + shape[0].x = 0; shape[0].y = 0; + shape[1].x = im2; shape[1].y = im; + shape[2].x = -im2; shape[2].y = im; + shape[3].x = im2; shape[3].y = -im; + shape[4].x = -im2; shape[4].y = -im; + shape[5].x = 0; shape[5].y = 0; + shape[6].x = im; shape[6].y = im2; + shape[7].x = im; shape[7].y = -im2; + shape[8].x = -im; shape[8].y = im2; + shape[9].x = -im; shape[9].y = -im2; + shape[10].x = 0; shape[10].y = 0; + ctxt->markerType = 2; + } else if (markerstyle == 45) { + // filled four triangles plus + shape.resize(13); + Int_t im0 = Int_t(0.4*MarkerSizeReduced + 0.5); + Int_t im2 = Int_t(2.0*MarkerSizeReduced + 0.5); + shape[0].x = im0; shape[0].y = im0; + shape[1].x = im2; shape[1].y = im; + shape[2].x = -im2; shape[2].y = im; + shape[3].x = -im0; shape[3].y = im0; + shape[4].x = -im; shape[4].y = im2; + shape[5].x = -im; shape[5].y = -im2; + shape[6].x = -im0; shape[6].y = -im0; + shape[7].x = -im2; shape[7].y = -im; + shape[8].x = im2; shape[8].y = -im; + shape[9].x = im0; shape[9].y = -im0; + shape[10].x = im; shape[10].y = -im2; + shape[11].x = im; shape[11].y = im2; + shape[12].x = im0; shape[12].y = im0; + ctxt->markerType = 3; + } else if (markerstyle == 46) { + // open four triangles X + shape.resize(13); + Int_t im2 = Int_t(2.0*MarkerSizeReduced + 0.5); + shape[0].x = 0; shape[0].y = im2; + shape[1].x = -im2; shape[1].y = im; + shape[2].x = -im; shape[2].y = im2; + shape[3].x = -im2; shape[3].y = 0; + shape[4].x = -im; shape[4].y = -im2; + shape[5].x = -im2; shape[5].y = -im; + shape[6].x = 0; shape[6].y = -im2; + shape[7].x = im2; shape[7].y = -im; + shape[8].x = im; shape[8].y = -im2; + shape[9].x = im2; shape[9].y = 0; + shape[10].x = im; shape[10].y = im2; + shape[11].x = im2; shape[11].y = im; + shape[12].x = 0; shape[12].y = im2; + ctxt->markerType = 2; + } else if (markerstyle == 47) { + // filled four triangles X + shape.resize(13); + Int_t im2 = Int_t(2.0*MarkerSizeReduced + 0.5); + shape[0].x = 0; shape[0].y = im2; + shape[1].x = -im2; shape[1].y = im; + shape[2].x = -im; shape[2].y = im2; + shape[3].x = -im2; shape[3].y = 0; + shape[4].x = -im; shape[4].y = -im2; + shape[5].x = -im2; shape[5].y = -im; + shape[6].x = 0; shape[6].y = -im2; + shape[7].x = im2; shape[7].y = -im; + shape[8].x = im; shape[8].y = -im2; + shape[9].x = im2; shape[9].y = 0; + shape[10].x = im; shape[10].y = im2; + shape[11].x = im2; shape[11].y = im; + shape[12].x = 0; shape[12].y = im2; + ctxt->markerType = 3; + } else if (markerstyle == 48) { + // four filled squares X + shape.resize(17); + Int_t im2 = Int_t(2.0*MarkerSizeReduced + 0.5); + shape[0].x = 0; shape[0].y = im2*1.005; + shape[1].x = -im2; shape[1].y = im; + shape[2].x = -im; shape[2].y = im2; + shape[3].x = -im2; shape[3].y = 0; + shape[4].x = -im; shape[4].y = -im2; + shape[5].x = -im2; shape[5].y = -im; + shape[6].x = 0; shape[6].y = -im2; + shape[7].x = im2; shape[7].y = -im; + shape[8].x = im; shape[8].y = -im2; + shape[9].x = im2; shape[9].y = 0; + shape[10].x = im; shape[10].y = im2; + shape[11].x = im2; shape[11].y = im; + shape[12].x = 0; shape[12].y = im2*0.995; + shape[13].x = im2*0.995; shape[13].y = 0; + shape[14].x = 0; shape[14].y = -im2*0.995; + shape[15].x = -im2*0.995; shape[15].y = 0; + shape[16].x = 0; shape[16].y = im2*0.995; + ctxt->markerType = 3; + } else if (markerstyle == 49) { + // four filled squares plus + shape.resize(17); + Int_t imx = Int_t(1.33*MarkerSizeReduced + 0.5); + shape[0].x =-imx; shape[0].y =-imx*1.005; + shape[1].x =-imx; shape[1].y = -im; + shape[2].x = imx; shape[2].y = -im; + shape[3].x = imx; shape[3].y =-imx; + shape[4].x = im; shape[4].y =-imx; + shape[5].x = im; shape[5].y = imx; + shape[6].x = imx; shape[6].y = imx; + shape[7].x = imx; shape[7].y = im; + shape[8].x =-imx; shape[8].y = im; + shape[9].x =-imx; shape[9].y = imx; + shape[10].x = -im; shape[10].y = imx; + shape[11].x = -im; shape[11].y =-imx; + shape[12].x =-imx; shape[12].y =-imx*0.995; + shape[13].x =-imx; shape[13].y = imx; + shape[14].x = imx; shape[14].y = imx; + shape[15].x = imx; shape[15].y =-imx; + shape[16].x =-imx; shape[16].y =-imx*1.005; + ctxt->markerType = 3; + } else { + // single dot + shape.resize(0); + ctxt->markerType = 0; + ctxt->markerSize = 0; + } + + } void TGX11::SetAttText(WinContext_t wctxt, const TAttText &att) From eda8185906f9f2a5fd5be3ccbb0cc4043463b516 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 11 Mar 2026 17:08:16 +0100 Subject: [PATCH 12/37] [tgx11] use segments for markers Where it make sense - use XDrawSegments for markerS --- graf2d/x11/src/TGX11.cxx | 75 +++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index ba78bd287726a..e33614f89389a 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -90,7 +90,7 @@ static GC *gGCline = &gGClist[kGCline]; // PolyLines // static GC *gGCfill = &gGClist[kGCfill]; // Fill areas static GC *gGCtext = &gGClist[kGCtext]; // Text static GC *gGCinvt = &gGClist[kGCinvt]; // Inverse text -static GC *gGCdash = &gGClist[kGCinvt]; // Dashed lines +// static GC *gGCdash = &gGClist[kGCinvt]; // Dashed lines // static GC *gGCpxmp = &gGClist[kGCpxmp]; // Pixmap management static GC gGCecho; // Input echo @@ -744,47 +744,42 @@ void TGX11::DrawPolyMarker(int n, TPoint *xy) } else { int r = gCws->markerSize / 2; auto &shape = gCws->markerShape; - int m; - for (m = 0; m < n; m++) { - int hollow = 0; - - switch (gCws->markerType) { - case 0: // hollow circle - XDrawArc((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], - xyp[m].x - r, xyp[m].y - r, gCws->markerSize, gCws->markerSize, 0, 360*64); - break; - - case 1: // filled circle - XFillArc((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], - xyp[m].x - r, xyp[m].y - r, gCws->markerSize, gCws->markerSize, 0, 360*64); - break; - - case 2: // hollow polygon - hollow = 1; - case 3: // filled polygon - for (size_t i = 0; i < shape.size(); i++) { - shape[i].x += xyp[m].x; - shape[i].y += xyp[m].y; - } - if (hollow) + for (int m = 0; m < n; m++) { + if (gCws->markerType == 0) { + // hollow circle + XDrawArc((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], + xyp[m].x - r, xyp[m].y - r, gCws->markerSize, gCws->markerSize, 0, 360*64); + } else if (gCws->markerType == 1) { + // filled circle + XFillArc((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], + xyp[m].x - r, xyp[m].y - r, gCws->markerSize, gCws->markerSize, 0, 360*64); + } else { + for (size_t i = 0; i < shape.size(); i++) { + shape[i].x += xyp[m].x; + shape[i].y += xyp[m].y; + } + switch(gCws->markerType) { + case 2: + // hollow polygon XDrawLines((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], shape.data(), shape.size(), CoordModeOrigin); - else + break; + case 3: + // filled polygon XFillPolygon((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], shape.data(), shape.size(), Nonconvex, CoordModeOrigin); - for (size_t i = 0; i < shape.size(); i++) { - shape[i].x -= xyp[m].x; - shape[i].y -= xyp[m].y; - } - break; - - case 4: // segmented line - for (size_t i = 0; i < shape.size(); i += 2) - XDrawLine((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], - xyp[m].x + shape[i].x, xyp[m].y + shape[i].y, - xyp[m].x + shape[i+1].x, xyp[m].y + shape[i+1].y); - break; + break; + case 4: + // segmented line + XDrawSegments((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], + (XSegment *) shape.data(), shape.size()/2); + break; + } + for (size_t i = 0; i < shape.size(); i++) { + shape[i].x -= xyp[m].x; + shape[i].y -= xyp[m].y; + } } } } @@ -2281,7 +2276,7 @@ void TGX11::SetFillStyle(Style_t fstyle) //////////////////////////////////////////////////////////////////////////////// /// Set fill area style index. -void TGX11::SetFillStyleIndex(Int_t style, Int_t fasi) +void TGX11::SetFillStyleIndex(Int_t /* style */, Int_t /* fasi */) { /* static int current_fasi = 0; @@ -2368,7 +2363,7 @@ void TGX11::SetLineColor(Color_t cindex) /// e.g. N=4,DASH=(6,3,1,3) gives a dashed-dotted line with dash length 6 /// and a gap of 7 between dashes -void TGX11::SetLineType(int n, int *dash) +void TGX11::SetLineType(int /* n */, int * /* dash */) { /* if (n <= 0) { @@ -2503,7 +2498,7 @@ void TGX11::SetMarkerSize(Float_t msize) /// - if TYPE == 4 marker is described by segmented line XY /// e.g. TYPE=4,N=4,XY=(-3,0,3,0,0,-3,0,3) sets a plus shape of 7x7 pixels -void TGX11::SetMarkerType(int type, int n, RXPoint *xy) +void TGX11::SetMarkerType(int /* type */, int /* n */, RXPoint * /* xy */) { /* gMarker.type = type; From fa742052713ef7f7dd4df839ff8a552b585b6b6c Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 12 Mar 2026 12:32:16 +0100 Subject: [PATCH 13/37] [tgx11] adjust text attributes handling in plain TGX11 Without TTF support X11 fonts are used. Move text attributes handling to XWindow_t structure, keep only global gTextFont for text size handling. --- graf2d/x11/src/TGX11.cxx | 140 +++++++++++++++++++++++++++++++-------- 1 file changed, 112 insertions(+), 28 deletions(-) diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index e33614f89389a..94807f8258a91 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -88,8 +88,8 @@ static GC gGClist[kMAXGC]; static GC *gGCline = &gGClist[kGCline]; // PolyLines // static GC *gGCmark = &gGClist[kGCmark]; // PolyMarker // static GC *gGCfill = &gGClist[kGCfill]; // Fill areas -static GC *gGCtext = &gGClist[kGCtext]; // Text -static GC *gGCinvt = &gGClist[kGCinvt]; // Inverse text +// static GC *gGCtext = &gGClist[kGCtext]; // Text +// static GC *gGCinvt = &gGClist[kGCinvt]; // Inverse text // static GC *gGCdash = &gGClist[kGCinvt]; // Dashed lines // static GC *gGCpxmp = &gGClist[kGCpxmp]; // Pixmap management @@ -130,8 +130,10 @@ struct XWindow_t { Int_t markerType = 0; ///< 4 differen kinds of marker Int_t markerSize = 0; ///< size of simple markers std::vector markerShape; ///< marker shape points - Int_t markerLineWidth = 0; - + Int_t markerLineWidth = 0; ///< line width used for marker + TAttText fAttText; ///< current text attribute + Int_t textAlign = 0; ///< selected text align + XFontStruct *textFont = nullptr; ///< selected text font }; @@ -799,20 +801,22 @@ void TGX11::DrawPolyMarker(int n, TPoint *xy) void TGX11::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn, const char *text, ETextMode mode) { - XRotSetMagnification(mgn); - if (!text) return; + if (!text || !gCws->textFont || gCws->fAttText.GetTextSize() < 0) + return; + + XRotSetMagnification(mgn); switch (mode) { case kClear: - XRotDrawAlignedString((Display*)fDisplay, gTextFont, angle, - gCws->fDrawing, *gGCtext, x, y, (char*)text, fTextAlign); + XRotDrawAlignedString((Display*)fDisplay, gCws->textFont, angle, + gCws->fDrawing, gCws->fGClist[kGCtext], x, y, (char*)text, gCws->textAlign); break; case kOpaque: - XRotDrawAlignedImageString((Display*)fDisplay, gTextFont, angle, - gCws->fDrawing, *gGCtext, x, y, (char*)text, fTextAlign); + XRotDrawAlignedImageString((Display*)fDisplay, gCws->textFont, angle, + gCws->fDrawing, gCws->fGClist[kGCtext], x, y, (char*)text, gCws->textAlign); break; default: @@ -1164,6 +1168,7 @@ Int_t TGX11::OpenDisplay(void *disp) for (i = 0; i < kMAXGC; i++) gGClist[i] = XCreateGC((Display*)fDisplay, fVisRootWin, 0, nullptr); +/* XGCValues values; if (XGetGCValues((Display*)fDisplay, *gGCtext, GCForeground|GCBackground, &values)) { XSetForeground((Display*)fDisplay, *gGCinvt, values.background); @@ -1171,6 +1176,7 @@ Int_t TGX11::OpenDisplay(void *disp) } else { Error("OpenDisplay", "cannot get GC values"); } +*/ // Create input echo graphic context XGCValues echov; @@ -1735,11 +1741,11 @@ Int_t TGX11::RequestString(int x, int y, char *text) char nbytes; int dx; int i; - XDrawImageString((Display*)fDisplay, gCws->fWindow, *gGCtext, x, y, text, nt); - dx = XTextWidth(gTextFont, text, nt); - XDrawImageString((Display*)fDisplay, gCws->fWindow, *gGCtext, x + dx, y, " ", 1); - dx = pt == 0 ? 0 : XTextWidth(gTextFont, text, pt); - XDrawImageString((Display*)fDisplay, gCws->fWindow, *gGCinvt, + XDrawImageString((Display*)fDisplay, gCws->fWindow, gCws->fGClist[kGCtext], x, y, text, nt); + dx = XTextWidth(gCws->textFont, text, nt); + XDrawImageString((Display*)fDisplay, gCws->fWindow, gCws->fGClist[kGCtext], x + dx, y, " ", 1); + dx = pt == 0 ? 0 : XTextWidth(gCws->textFont, text, pt); + XDrawImageString((Display*)fDisplay, gCws->fWindow, gCws->fGClist[kGCinvt], x + dx, y, pt < len_text ? &text[pt] : " ", 1); XWindowEvent((Display*)fDisplay, gCws->fWindow, gKeybdMask, &event); switch (event.type) { @@ -3154,7 +3160,7 @@ void TGX11::SetRGB(int cindex, float r, float g, float b) void TGX11::SetTextAlign(Short_t talign) { - Int_t txalh = talign/10; +/* Int_t txalh = talign/10; Int_t txalv = talign%10; fTextAlignH = txalh; fTextAlignV = txalv; @@ -3202,8 +3208,14 @@ void TGX11::SetTextAlign(Short_t talign) } break; } + */ - TAttText::SetTextAlign(fTextAlign); + TAttText::SetTextAlign(talign); + + SetAttText((WinContext_t) gCws, *this); + + // FIXME: member fTextAlign conflicts with TAttText::fTextAlign + fTextAlign = gCws->textAlign; } //////////////////////////////////////////////////////////////////////////////// @@ -3214,7 +3226,9 @@ void TGX11::SetTextColor(Color_t cindex) if (cindex < 0) return; TAttText::SetTextColor(cindex); + SetAttText((WinContext_t) gCws, *this); + /* SetColor(gGCtext, Int_t(cindex)); XGCValues values; @@ -3225,6 +3239,7 @@ void TGX11::SetTextColor(Color_t cindex) Error("SetTextColor", "cannot get GC values"); } XSetBackground((Display*)fDisplay, *gGCtext, GetColor(0).fPixel); + */ } //////////////////////////////////////////////////////////////////////////////// @@ -3242,14 +3257,16 @@ Int_t TGX11::SetTextFont(char *fontname, ETextSetMode mode) { char **fontlist; int fontcount; - int i; if (mode == kLoad) { - for (i = 0; i < kMAXFONT; i++) { + for (int i = 0; i < kMAXFONT; i++) { if (strcmp(fontname, gFont[i].name) == 0) { gTextFont = gFont[i].id; - XSetFont((Display*)fDisplay, *gGCtext, gTextFont->fid); - XSetFont((Display*)fDisplay, *gGCinvt, gTextFont->fid); + if (gCws) { + gCws->textFont = gTextFont; + XSetFont((Display*)fDisplay, gCws->fGClist[kGCtext], gCws->textFont->fid); + XSetFont((Display*)fDisplay, gCws->fGClist[kGCinvt], gCws->textFont->fid); + } return 0; } } @@ -3262,8 +3279,6 @@ Int_t TGX11::SetTextFont(char *fontname, ETextSetMode mode) if (gFont[gCurrentFontNumber].id) XFreeFont((Display*)fDisplay, gFont[gCurrentFontNumber].id); gTextFont = XLoadQueryFont((Display*)fDisplay, fontlist[0]); - XSetFont((Display*)fDisplay, *gGCtext, gTextFont->fid); - XSetFont((Display*)fDisplay, *gGCinvt, gTextFont->fid); gFont[gCurrentFontNumber].id = gTextFont; strlcpy(gFont[gCurrentFontNumber].name,fontname,80); gCurrentFontNumber++; @@ -3281,7 +3296,9 @@ Int_t TGX11::SetTextFont(char *fontname, ETextSetMode mode) void TGX11::SetTextFont(Font_t fontnumber) { - fTextFont = fontnumber; + TAttText::SetTextFont(fontnumber); + + SetAttText((WinContext_t) gCws, *this); } //////////////////////////////////////////////////////////////////////////////// @@ -3289,7 +3306,9 @@ void TGX11::SetTextFont(Font_t fontnumber) void TGX11::SetTextSize(Float_t textsize) { - fTextSize = textsize; + TAttText::SetTextSize(textsize); + + SetAttText((WinContext_t) gCws, *this); } //////////////////////////////////////////////////////////////////////////////// @@ -4371,8 +4390,6 @@ void TGX11::SetAttMarker(WinContext_t wctxt, const TAttMarker &att) ctxt->markerType = 0; ctxt->markerSize = 0; } - - } void TGX11::SetAttText(WinContext_t wctxt, const TAttText &att) @@ -4380,7 +4397,74 @@ void TGX11::SetAttText(WinContext_t wctxt, const TAttText &att) auto ctxt = (XWindow_t *) wctxt; if (!ctxt) return; - (void) att; + + Int_t txalh = att.GetTextAlign() / 10; + Int_t txalv = att.GetTextAlign() % 10; + + switch (txalh) { + case 0 : + case 1 : + switch (txalv) { //left + case 1 : + ctxt->textAlign = 7; //bottom + break; + case 2 : + ctxt->textAlign = 4; //center + break; + case 3 : + ctxt->textAlign = 1; //top + break; + } + break; + case 2 : + switch (txalv) { //center + case 1 : + ctxt->textAlign = 8; //bottom + break; + case 2 : + ctxt->textAlign = 5; //center + break; + case 3 : + ctxt->textAlign = 2; //top + break; + } + break; + case 3 : + switch (txalv) { //right + case 1 : + ctxt->textAlign = 9; //bottom + break; + case 2 : + ctxt->textAlign = 6; //center + break; + case 3 : + ctxt->textAlign = 3; //top + break; + } + break; + } + + SetColor(&ctxt->fGClist[kGCtext], att.GetTextColor()); + + XGCValues values; + if (XGetGCValues((Display*)fDisplay, ctxt->fGClist[kGCtext], GCForeground | GCBackground, &values)) { + XSetForeground( (Display*)fDisplay, ctxt->fGClist[kGCinvt], values.background ); + XSetBackground( (Display*)fDisplay, ctxt->fGClist[kGCinvt], values.foreground ); + } else { + Error("SetAttText", "cannot get GC values"); + } + XSetBackground((Display*)fDisplay, ctxt->fGClist[kGCtext], GetColor(0).fPixel); + + // use first existing font + for (int i = 0; i < kMAXFONT; i++) + if (gFont[i].id) { + gCws->textFont = gFont[i].id; + XSetFont((Display*)fDisplay, gCws->fGClist[kGCtext], gCws->textFont->fid); + XSetFont((Display*)fDisplay, gCws->fGClist[kGCinvt], gCws->textFont->fid); + break; + } + + ctxt->fAttText = att; } From 929a150e9a6cdef6f1743245f818b0b26331238c Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 12 Mar 2026 13:13:24 +0100 Subject: [PATCH 14/37] [tgx11ttf] use new methods for text attributes One can add hook there to allocate and initialize there TTF structures. For now keep global members --- graf2d/x11ttf/inc/TGX11TTF.h | 8 ++++++-- graf2d/x11ttf/src/TGX11TTF.cxx | 28 +++++++++------------------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/graf2d/x11ttf/inc/TGX11TTF.h b/graf2d/x11ttf/inc/TGX11TTF.h index 99b4dbae09486..7f0e56ab497ce 100644 --- a/graf2d/x11ttf/inc/TGX11TTF.h +++ b/graf2d/x11ttf/inc/TGX11TTF.h @@ -62,9 +62,13 @@ class TGX11TTF : public TGX11 { const char *text, ETextMode mode) override; void DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn, const wchar_t *text, ETextMode mode) override; - void SetTextFont(Font_t fontnumber) override; + + using TGX11::SetTextFont; Int_t SetTextFont(char *fontname, ETextSetMode mode) override; - void SetTextSize(Float_t textsize) override; + + //---- Methods used for new graphics ----- + void SetAttText(WinContext_t wctxt, const TAttText &att) override; + #ifdef R__HAS_XFT //---- Methods used text/fonts handling via Xft ----- diff --git a/graf2d/x11ttf/src/TGX11TTF.cxx b/graf2d/x11ttf/src/TGX11TTF.cxx index b64bfe1b37cb0..05fd58b545c69 100644 --- a/graf2d/x11ttf/src/TGX11TTF.cxx +++ b/graf2d/x11ttf/src/TGX11TTF.cxx @@ -543,13 +543,16 @@ void TGX11TTF::RenderString(Int_t x, Int_t y, ETextMode mode) //////////////////////////////////////////////////////////////////////////////// /// Set specified font. -void TGX11TTF::SetTextFont(Font_t fontnumber) + +void TGX11TTF::SetAttText(WinContext_t wctxt, const TAttText &att) { - fTextFont = fontnumber; - if (!fHasTTFonts) { - TGX11::SetTextFont(fontnumber); - } else { - TTF::SetTextFont(fontnumber); + // TODO: add to window context custom part for TTF, + // it can be allocated and provided via private interface + TGX11::SetAttText(wctxt, att); + + if (fHasTTFonts) { + TTF::SetTextFont(att.GetTextFont()); + TTF::SetTextSize(att.GetTextSize()); } } @@ -572,19 +575,6 @@ Int_t TGX11TTF::SetTextFont(char *fontname, ETextSetMode mode) } } -//////////////////////////////////////////////////////////////////////////////// -/// Set current text size. - -void TGX11TTF::SetTextSize(Float_t textsize) -{ - fTextSize = textsize; - if (!fHasTTFonts) { - TGX11::SetTextSize(textsize); - } else { - TTF::SetTextSize(textsize); - } -} - #ifdef R__HAS_XFT ///////////////////////////// Xft font methods ///////////////////////////////// From 63bceba7248a87944a89f57a42442c29c251918f Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 12 Mar 2026 13:34:14 +0100 Subject: [PATCH 15/37] [tgx11] exclude usage of gGCline context Last place was PutImage method - used either special window GC or just temporary created GC PutImage is not used at all --- graf2d/x11/src/TGX11.cxx | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index 94807f8258a91..a6f88ee001e6c 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -85,7 +85,7 @@ const int kMAXGC = 7, kGCline = 0, kGCmark = 1, kGCfill = 2, kGCtext = 3, kGCinvt = 4, kGCdash = 5, kGCpxmp = 6; static GC gGClist[kMAXGC]; -static GC *gGCline = &gGClist[kGCline]; // PolyLines +// static GC *gGCline = &gGClist[kGCline]; // PolyLines // static GC *gGCmark = &gGClist[kGCmark]; // PolyMarker // static GC *gGCfill = &gGClist[kGCfill]; // Fill areas // static GC *gGCtext = &gGClist[kGCtext]; // Text @@ -3552,6 +3552,7 @@ Int_t TGX11::WriteGIF(char *name) //////////////////////////////////////////////////////////////////////////////// /// Draw image. +/// Not used, keep for backward compatibility void TGX11::PutImage(Int_t offset,Int_t itran,Int_t x0,Int_t y0,Int_t nx,Int_t ny,Int_t xmin, Int_t ymin,Int_t xmax,Int_t ymax, UChar_t *image,Drawable_t wid) @@ -3562,11 +3563,14 @@ void TGX11::PutImage(Int_t offset,Int_t itran,Int_t x0,Int_t y0,Int_t nx,Int_t n int nlines[256]; XSegment lines[256][maxSegment]; Drawable_t id; + GC lineGC; if (wid) { id = wid; + lineGC = XCreateGC((Display*)fDisplay, fVisRootWin, 0, nullptr); } else { id = gCws->fDrawing; + lineGC = gCws->fGClist[kGCline]; } for (i = 0; i < 256; i++) nlines[i] = 0; @@ -3584,8 +3588,8 @@ void TGX11::PutImage(Int_t offset,Int_t itran,Int_t x0,Int_t y0,Int_t nx,Int_t n lines[icol][n].x1 = xcur; lines[icol][n].y1 = y; lines[icol][n].x2 = x-1; lines[icol][n].y2 = y; if (nlines[icol] == maxSegment) { - SetColor(gGCline,(int)icol+offset); - XDrawSegments((Display*)fDisplay,id,*gGCline,&lines[icol][0], + SetColor(&lineGC, (int)icol+offset); + XDrawSegments((Display*)fDisplay,id,lineGC,&lines[icol][0], maxSegment); nlines[icol] = 0; } @@ -3598,8 +3602,8 @@ void TGX11::PutImage(Int_t offset,Int_t itran,Int_t x0,Int_t y0,Int_t nx,Int_t n lines[icol][n].x1 = xcur; lines[icol][n].y1 = y; lines[icol][n].x2 = x-1; lines[icol][n].y2 = y; if (nlines[icol] == maxSegment) { - SetColor(gGCline,(int)icol+offset); - XDrawSegments((Display*)fDisplay,id,*gGCline,&lines[icol][0], + SetColor(&lineGC, (int)icol+offset); + XDrawSegments((Display*)fDisplay,id,lineGC,&lines[icol][0], maxSegment); nlines[icol] = 0; } @@ -3608,10 +3612,13 @@ void TGX11::PutImage(Int_t offset,Int_t itran,Int_t x0,Int_t y0,Int_t nx,Int_t n for (i = 0; i < 256; i++) { if (nlines[i] != 0) { - SetColor(gGCline,i+offset); - XDrawSegments((Display*)fDisplay,id,*gGCline,&lines[i][0],nlines[i]); + SetColor(&lineGC,i+offset); + XDrawSegments((Display*)fDisplay,id,lineGC,&lines[i][0],nlines[i]); } } + + if (wid) + XFreeGC((Display*)fDisplay, lineGC); } //////////////////////////////////////////////////////////////////////////////// From 146cb1cb90815d92439f3b75d7e7d1a2a5774649 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 12 Mar 2026 13:42:00 +0100 Subject: [PATCH 16/37] [tgx11] fully exclude global context list usage Now only window-special contexts are used --- graf2d/x11/src/TGX11.cxx | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index a6f88ee001e6c..a53c05709f496 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -84,7 +84,7 @@ extern XPoint *XRotTextExtents(Display*, XFontStruct*, float, const int kMAXGC = 7, kGCline = 0, kGCmark = 1, kGCfill = 2, kGCtext = 3, kGCinvt = 4, kGCdash = 5, kGCpxmp = 6; -static GC gGClist[kMAXGC]; +// static GC gGClist[kMAXGC]; // static GC *gGCline = &gGClist[kGCline]; // PolyLines // static GC *gGCmark = &gGClist[kGCmark]; // PolyMarker // static GC *gGCfill = &gGClist[kGCfill]; // Fill areas @@ -986,7 +986,11 @@ void *TGX11::GetGC(Int_t which) const Error("GetGC", "trying to get illegal GC (which = %d)", which); return nullptr; } - return &gGClist[which]; + if (!gCws) { + Error("GetGC", "No current window selected"); + return nullptr; + } + return &gCws->fGClist[which]; } //////////////////////////////////////////////////////////////////////////////// @@ -1165,8 +1169,8 @@ Int_t TGX11::OpenDisplay(void *disp) strlcpy(vendor, XServerVendor((Display*)fDisplay),132); // Create primitives graphic contexts - for (i = 0; i < kMAXGC; i++) - gGClist[i] = XCreateGC((Display*)fDisplay, fVisRootWin, 0, nullptr); + // for (i = 0; i < kMAXGC; i++) + // gGClist[i] = XCreateGC((Display*)fDisplay, fVisRootWin, 0, nullptr); /* XGCValues values; @@ -1360,7 +1364,7 @@ Int_t TGX11::OpenPixmap(unsigned int w, unsigned int h) XGetGeometry((Display*)fDisplay, gCws->fWindow, &root, &xx, &yy, &ww, &hh, &border, &depth); for (int i = 0; i < kMAXGC; i++) { - XSetClipMask((Display*)fDisplay, gGClist[i], None); + // XSetClipMask((Display*)fDisplay, gGClist[i], None); XSetClipMask((Display*)fDisplay, gCws->fGClist[i], None); } @@ -1885,7 +1889,7 @@ void TGX11::RescaleWindow(int wid, unsigned int w, unsigned int h) gTws->fBuffer = XCreatePixmap((Display*)fDisplay, fRootWin, w, h, fDepth); } for (int i = 0; i < kMAXGC; i++) { - XSetClipMask((Display*)fDisplay, gGClist[i], None); + // XSetClipMask((Display*)fDisplay, gGClist[i], None); XSetClipMask((Display*)fDisplay, gTws->fGClist[i], None); } SetColor(&gTws->fGClist[kGCpxmp], 0); @@ -1931,7 +1935,7 @@ int TGX11::ResizePixmap(int wid, unsigned int w, unsigned int h) XGetGeometry((Display*)fDisplay, gTws->fWindow, &root, &xx, &yy, &ww, &hh, &border, &depth); for (i = 0; i < kMAXGC; i++) { - XSetClipMask((Display*)fDisplay, gGClist[i], None); + // XSetClipMask((Display*)fDisplay, gGClist[i], None); XSetClipMask((Display*)fDisplay, gTws->fGClist[i], None); } @@ -1976,7 +1980,7 @@ void TGX11::ResizeWindow(Int_t wid) gTws->fBuffer = XCreatePixmap((Display*)fDisplay, fRootWin, wval, hval, fDepth); } for (int i = 0; i < kMAXGC; i++) { - XSetClipMask((Display*)fDisplay, gGClist[i], None); + // XSetClipMask((Display*)fDisplay, gGClist[i], None); XSetClipMask((Display*)fDisplay, gTws->fGClist[i], None); } SetColor(&gTws->fGClist[kGCpxmp], 0); @@ -2009,12 +2013,12 @@ void TGX11::SelectWindow(int wid) region.width = gCws->fWclip; region.height = gCws->fHclip; for (int i = 0; i < kMAXGC; i++) { - XSetClipRectangles((Display*)fDisplay, gGClist[i], 0, 0, ®ion, 1, YXBanded); + // XSetClipRectangles((Display*)fDisplay, gGClist[i], 0, 0, ®ion, 1, YXBanded); XSetClipRectangles((Display*)fDisplay, gCws->fGClist[i], 0, 0, ®ion, 1, YXBanded); } } else { for (int i = 0; i < kMAXGC; i++) { - XSetClipMask((Display*)fDisplay, gGClist[i], None); + // XSetClipMask((Display*)fDisplay, gGClist[i], None); XSetClipMask((Display*)fDisplay, gCws->fGClist[i], None); } } @@ -2050,7 +2054,7 @@ void TGX11::SetClipOFF(int wid) gTws->fClip = 0; for (int i = 0; i < kMAXGC; i++) { - XSetClipMask( (Display*)fDisplay, gGClist[i], None ); + // XSetClipMask( (Display*)fDisplay, gGClist[i], None ); XSetClipMask( (Display*)fDisplay, gTws->fGClist[i], None ); } } @@ -2077,7 +2081,7 @@ void TGX11::SetClipRegion(int wid, int x, int y, unsigned int w, unsigned int h) region.width = gTws->fWclip; region.height = gTws->fHclip; for (int i = 0; i < kMAXGC; i++) { - XSetClipRectangles((Display*)fDisplay, gGClist[i], 0, 0, ®ion, 1, YXBanded); + // XSetClipRectangles((Display*)fDisplay, gGClist[i], 0, 0, ®ion, 1, YXBanded); XSetClipRectangles((Display*)fDisplay, gTws->fGClist[i], 0, 0, ®ion, 1, YXBanded); } } @@ -2190,7 +2194,7 @@ void TGX11::SetDoubleBufferON() SetColor(&gTws->fGClist[kGCpxmp], 1); } for (int i = 0; i < kMAXGC; i++) { - XSetClipMask((Display*)fDisplay, gGClist[i], None); + // XSetClipMask((Display*)fDisplay, gGClist[i], None); XSetClipMask((Display*)fDisplay, gTws->fGClist[i], None); } gTws->fDoubleBuffer = 1; @@ -2209,26 +2213,26 @@ void TGX11::SetDoubleBufferON() void TGX11::SetDrawMode(EDrawMode mode) { - if (fDisplay) { + if (fDisplay && gCws) { switch (mode) { case kCopy: for (int i = 0; i < kMAXGC; i++) { - XSetFunction((Display*)fDisplay, gGClist[i], GXcopy); + // XSetFunction((Display*)fDisplay, gGClist[i], GXcopy); XSetFunction((Display*)fDisplay, gCws->fGClist[i], GXcopy); } break; case kXor: for (int i = 0; i < kMAXGC; i++) { - XSetFunction((Display*)fDisplay, gGClist[i], GXxor); + // XSetFunction((Display*)fDisplay, gGClist[i], GXxor); XSetFunction((Display*)fDisplay, gCws->fGClist[i], GXxor); } break; case kInvert: for (int i = 0; i < kMAXGC; i++) { - XSetFunction((Display*)fDisplay, gGClist[i], GXinvert); + // XSetFunction((Display*)fDisplay, gGClist[i], GXinvert); XSetFunction((Display*)fDisplay, gCws->fGClist[i], GXinvert); } break; From 196385337b52f2bd1a7023df5153cc7a9eb4a6cc Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 12 Mar 2026 14:05:56 +0100 Subject: [PATCH 17/37] [x11] provide move constructor signature for TGX11 Use when TGX11TTF instance must be created. Copy constructor it too complicated. --- graf2d/x11/inc/TGX11.h | 4 +- graf2d/x11/src/TGX11.cxx | 81 +++++++++++----------------------- graf2d/x11ttf/inc/TGX11TTF.h | 2 +- graf2d/x11ttf/src/TGX11TTF.cxx | 7 ++- 4 files changed, 33 insertions(+), 61 deletions(-) diff --git a/graf2d/x11/inc/TGX11.h b/graf2d/x11/inc/TGX11.h index 742e9affb83a5..be6b94002bdbc 100644 --- a/graf2d/x11/inc/TGX11.h +++ b/graf2d/x11/inc/TGX11.h @@ -132,9 +132,11 @@ class TGX11 : public TVirtualX { void *GetGC(Int_t which) const; XColor_t &GetColor(Int_t cid); + TGX11(TGX11 &&org); + TGX11(const TGX11 &org) = delete; + public: TGX11(); - TGX11(const TGX11 &org); TGX11(const char *name, const char *title); ~TGX11() override; diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index a53c05709f496..192975a3f1a4d 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -278,7 +278,8 @@ TGX11::TGX11(const char *name, const char *title) : TVirtualX(name, title) fTextAlignV = 1; fTextAlign = 7; fTextMagnitude = 1; - for (i = 0; i < kNumCursors; i++) fCursors[i] = 0; + for (i = 0; i < kNumCursors; i++) + fCursors[i] = 0; fColors = new TExMap; } @@ -286,7 +287,7 @@ TGX11::TGX11(const char *name, const char *title) : TVirtualX(name, title) //////////////////////////////////////////////////////////////////////////////// /// Copy constructor. Currently only used by TGX11TTF. -TGX11::TGX11(const TGX11 &org) : TVirtualX(org) +TGX11::TGX11(TGX11 &&org) : TVirtualX(org) { fDisplay = org.fDisplay; fScreenNumber = org.fScreenNumber; @@ -312,51 +313,14 @@ TGX11::TGX11(const TGX11 &org) : TVirtualX(org) fGreenShift = org.fGreenShift; fBlueShift = org.fBlueShift; fDrawMode = org.fDrawMode; - fXEvent = new XEvent; - - for(auto & pair : org.fWindows) { - fWindows.emplace(pair.first, std::make_unique()); - auto &tgt = fWindows[pair.first]; // entry created - auto &src = pair.second; - tgt->fOpen = src->fOpen; - tgt->fDoubleBuffer = src->fDoubleBuffer; - tgt->fIsPixmap = src->fIsPixmap; - tgt->fDrawing = src->fDrawing; - tgt->fWindow = src->fWindow; - tgt->fBuffer = src->fBuffer; - tgt->fWidth = src->fWidth; - tgt->fHeight = src->fHeight; - tgt->fClip = src->fClip; - tgt->fXclip = src->fXclip; - tgt->fYclip = src->fYclip; - tgt->fWclip = src->fWclip; - tgt->fHclip = src->fHclip; - // FIXME: copy of pointer on may lead to double delete!!! - tgt->fNewColors = src->fNewColors; - tgt->fNcolors = src->fNcolors; - tgt->fShared = src->fShared; - for (int i = 0; i < kMAXGC; ++i) - tgt->fGClist[i] = src->fGClist[i]; - tgt->fDrawMode = src->fDrawMode; - tgt->fAttLine = src->fAttLine; - tgt->fAttFill = src->fAttFill; - } + fXEvent = org.fXEvent; org.fXEvent = nullptr; + fColors = org.fColors; org.fColors = nullptr; - for (int i = 0; i < kNumCursors; i++) - fCursors[i] = org.fCursors[i]; + fWindows = std::move(org.fWindows); - fColors = new TExMap; - Long64_t key, value; - TExMapIter it(org.fColors); - while (it.Next(key, value)) { - XColor_t *colo = (XColor_t *) (Long_t)value; - XColor_t *col = new XColor_t; - col->fPixel = colo->fPixel; - col->fRed = colo->fRed; - col->fGreen = colo->fGreen; - col->fBlue = colo->fBlue; - col->fDefined = colo->fDefined; - fColors->Add(key, (Long_t) col); + for (int i = 0; i < kNumCursors; i++) { + fCursors[i] = org.fCursors[i]; + org.fCursors[i] = 0; } } @@ -365,16 +329,22 @@ TGX11::TGX11(const TGX11 &org) : TVirtualX(org) TGX11::~TGX11() { - delete (XEvent*)fXEvent; - - if (!fColors) return; - Long64_t key, value; - TExMapIter it(fColors); - while (it.Next(key, value)) { - XColor_t *col = (XColor_t *) (Long_t)value; - delete col; + if (fXEvent) + delete (XEvent*)fXEvent; + + if (fColors) { + Long64_t key, value; + TExMapIter it(fColors); + while (it.Next(key, value)) { + XColor_t *col = (XColor_t *) (Long_t)value; + delete col; + } + delete fColors; } - delete fColors; + + for (int i = 0; i < kNumCursors; i++) + if (fCursors[i]) + XFreeCursor((Display*)fDisplay, fCursors[i]); } //////////////////////////////////////////////////////////////////////////////// @@ -382,7 +352,8 @@ TGX11::~TGX11() Bool_t TGX11::Init(void *display) { - if (OpenDisplay(display) == -1) return kFALSE; + if (OpenDisplay(display) == -1) + return kFALSE; return kTRUE; } diff --git a/graf2d/x11ttf/inc/TGX11TTF.h b/graf2d/x11ttf/inc/TGX11TTF.h index 7f0e56ab497ce..fe9bafcc766d2 100644 --- a/graf2d/x11ttf/inc/TGX11TTF.h +++ b/graf2d/x11ttf/inc/TGX11TTF.h @@ -54,7 +54,7 @@ class TGX11TTF : public TGX11 { void RenderString(Int_t x, Int_t y, ETextMode mode); public: - TGX11TTF(const TGX11 &org); + TGX11TTF(TGX11 &&org); ~TGX11TTF() override { } Bool_t Init(void *display) override; diff --git a/graf2d/x11ttf/src/TGX11TTF.cxx b/graf2d/x11ttf/src/TGX11TTF.cxx index 05fd58b545c69..4e78d86abbf6d 100644 --- a/graf2d/x11ttf/src/TGX11TTF.cxx +++ b/graf2d/x11ttf/src/TGX11TTF.cxx @@ -148,7 +148,7 @@ static TTFX11Init gTTFX11Init; //////////////////////////////////////////////////////////////////////////////// /// Create copy of TGX11 but now use TrueType fonts. -TGX11TTF::TGX11TTF(const TGX11 &org) : TGX11(org) +TGX11TTF::TGX11TTF(TGX11 &&org) : TGX11(std::move(org)) { SetName("X11TTF"); SetTitle("ROOT interface to X11 with TrueType fonts"); @@ -170,9 +170,8 @@ TGX11TTF::TGX11TTF(const TGX11 &org) : TGX11(org) void TGX11TTF::Activate() { - if (gVirtualX && dynamic_cast(gVirtualX)) { - TGX11 *oldg = (TGX11 *) gVirtualX; - gVirtualX = new TGX11TTF(*oldg); + if (auto oldg = dynamic_cast(gVirtualX)) { + gVirtualX = new TGX11TTF(std::move(*oldg)); delete oldg; } } From c6541f584011f32a192fea8326d0b1b2aae1bc69 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 13 Mar 2026 07:57:25 +0100 Subject: [PATCH 18/37] [x11] introduce draw methods with window context arg So one can specify window where drawing operation is performed --- core/base/inc/TVirtualX.h | 9 ++++ core/base/src/TVirtualX.cxx | 89 +++++++++++++++++++++++++++++++++---- 2 files changed, 89 insertions(+), 9 deletions(-) diff --git a/core/base/inc/TVirtualX.h b/core/base/inc/TVirtualX.h index bab9e6d1d34da..76f84f4b3da24 100644 --- a/core/base/inc/TVirtualX.h +++ b/core/base/inc/TVirtualX.h @@ -110,6 +110,15 @@ class TVirtualX : public TNamed, public TAttLine, public TAttFill, public TAttTe virtual void SetAttText(WinContext_t wctxt, const TAttText &att); virtual void SetDrawMode(WinContext_t wctxt, EDrawMode mode); + virtual void DrawBoxW(WinContext_t wctxt, Int_t x1, Int_t y1, Int_t x2, Int_t y2, EBoxMode mode); + virtual void DrawFillAreaW(WinContext_t wctxt, Int_t n, TPoint *xy); + virtual void DrawLineW(WinContext_t wctxt, Int_t x1, Int_t y1, Int_t x2, Int_t y2); + virtual void DrawPolyLineW(WinContext_t wctxt, Int_t n, TPoint *xy); + virtual void DrawLinesSegmentsW(WinContext_t wctxt, Int_t n, TPoint *xy); + virtual void DrawPolyMarkerW(WinContext_t wctxt, Int_t n, TPoint *xy); + virtual void DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Float_t mgn, const char *text, ETextMode mode); + virtual void DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Float_t mgn, const wchar_t *text, ETextMode mode); + //---- OpenGL related stuff, required only with R__HAS_COCOA ---- virtual Double_t GetOpenGLScalingFactor(); diff --git a/core/base/src/TVirtualX.cxx b/core/base/src/TVirtualX.cxx index 9e6b19d0886f7..d9c412dba2980 100644 --- a/core/base/src/TVirtualX.cxx +++ b/core/base/src/TVirtualX.cxx @@ -390,44 +390,115 @@ WinContext_t TVirtualX::GetWindowContext(Int_t /* wid */) //////////////////////////////////////////////////////////////////////////////// /// Set fill attributes for specified window -void TVirtualX::SetAttFill(WinContext_t /* wctxt */, const TAttFill & /* att */) +void TVirtualX::SetAttFill(WinContext_t /* wctxt */, const TAttFill &att) { - + SetFillColor(att.GetFillColor()); + SetFillStyle(att.GetFillStyle()); } //////////////////////////////////////////////////////////////////////////////// /// Set line attributes for specified window -void TVirtualX::SetAttLine(WinContext_t /* wctxt */, const TAttLine & /* att */) +void TVirtualX::SetAttLine(WinContext_t /* wctxt */, const TAttLine &att) { - + SetLineColor(att.GetLineColor()); + SetLineStyle(att.GetLineStyle()); + SetLineWidth(att.GetLineWidth()); } //////////////////////////////////////////////////////////////////////////////// /// Set marker attributes for specified window -void TVirtualX::SetAttMarker(WinContext_t /* wctxt */, const TAttMarker & /* att */) +void TVirtualX::SetAttMarker(WinContext_t /* wctxt */, const TAttMarker &att) { - + SetMarkerColor(att.GetMarkerColor()); + SetMarkerSize(att.GetMarkerSize()); + SetMarkerStyle(att.GetMarkerStyle()); } //////////////////////////////////////////////////////////////////////////////// /// Set text attributes for specified window -void TVirtualX::SetAttText(WinContext_t /* wctxt */, const TAttText & /* att */) +void TVirtualX::SetAttText(WinContext_t /* wctxt */, const TAttText &att) { + SetTextAlign(att.GetTextAlign()); + SetTextAngle(att.GetTextAngle()); + SetTextColor(att.GetTextColor()); + SetTextSize(att.GetTextSize()); + SetTextFont(att.GetTextFont()); +} +//////////////////////////////////////////////////////////////////////////////// +/// Set window draw mode + +void TVirtualX::SetDrawMode(WinContext_t /* wctxt */, EDrawMode mode) +{ + SetDrawMode(mode); } +//////////////////////////////////////////////////////////////////////////////// +/// Draw box on specified window + +void TVirtualX::DrawBoxW(WinContext_t /* wctxt */, Int_t x1, Int_t y1, Int_t x2, Int_t y2, EBoxMode mode) +{ + DrawBox(x1, y1, x2, y2, mode); +} //////////////////////////////////////////////////////////////////////////////// -/// Set window draw mode +/// Draw fill area on specified window -void TVirtualX::SetDrawMode(WinContext_t /* wctxt */, EDrawMode /* mode */) +void TVirtualX::DrawFillAreaW(WinContext_t /* wctxt */, Int_t n, TPoint *xy) { + DrawFillArea(n, xy); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Draw line on specified window +void TVirtualX::DrawLineW(WinContext_t /* wctxt */, Int_t x1, Int_t y1, Int_t x2, Int_t y2) +{ + DrawLine(x1, y1, x2, y2); } +//////////////////////////////////////////////////////////////////////////////// +/// Draw poly line on specified window + +void TVirtualX::DrawPolyLineW(WinContext_t /* wctxt */, Int_t n, TPoint *xy) +{ + DrawPolyLine(n, xy); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Draw line segments on specified window + +void TVirtualX::DrawLinesSegmentsW(WinContext_t /* wctxt */, Int_t n, TPoint *xy) +{ + DrawLinesSegments(n, xy); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Draw poly marker on specified window + +void TVirtualX::DrawPolyMarkerW(WinContext_t /* wctxt */, Int_t n, TPoint *xy) +{ + DrawPolyMarker(n, xy); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Draw text on specified window + +void TVirtualX::DrawTextW(WinContext_t /* wctxt */, Int_t x, Int_t y, Float_t angle, Float_t mgn, const char *text, ETextMode mode) +{ + DrawText(x, y, angle, mgn, text, mode); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Draw wtext on specified window + +void TVirtualX::DrawTextW(WinContext_t /* wctxt */, Int_t x, Int_t y, Float_t angle, Float_t mgn, const wchar_t *text, ETextMode mode) +{ + DrawText(x, y, angle, mgn, text, mode); +} //////////////////////////////////////////////////////////////////////////////// /// Executes the command "code" coming from the other threads (Win32) From 5e0e9785ece59dddaeb026e5e8b590ffb418b343 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 13 Mar 2026 07:58:16 +0100 Subject: [PATCH 19/37] [tgx11] implement draw methods with window handle Old signatures redirects to new methods --- graf2d/x11/inc/TGX11.h | 9 ++ graf2d/x11/src/TGX11.cxx | 193 ++++++++++++++++++++++++++++----------- 2 files changed, 151 insertions(+), 51 deletions(-) diff --git a/graf2d/x11/inc/TGX11.h b/graf2d/x11/inc/TGX11.h index be6b94002bdbc..3fd5db95d9a97 100644 --- a/graf2d/x11/inc/TGX11.h +++ b/graf2d/x11/inc/TGX11.h @@ -225,6 +225,15 @@ class TGX11 : public TVirtualX { void SetAttText(WinContext_t wctxt, const TAttText &att) override; void SetDrawMode(WinContext_t wctxt, EDrawMode mode) override; + void DrawBoxW(WinContext_t wctxt, Int_t x1, Int_t y1, Int_t x2, Int_t y2, EBoxMode mode) override; + void DrawFillAreaW(WinContext_t wctxt, Int_t n, TPoint *xy) override; + void DrawLineW(WinContext_t wctxt, Int_t x1, Int_t y1, Int_t x2, Int_t y2) override; + void DrawPolyLineW(WinContext_t wctxt, Int_t n, TPoint *xy) override; + void DrawLinesSegmentsW(WinContext_t wctxt, Int_t n, TPoint *xy) override; + void DrawPolyMarkerW(WinContext_t wctxt, Int_t n, TPoint *xy) override; + void DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Float_t mgn, const char *text, ETextMode mode) override; + void DrawTextW(WinContext_t, Int_t, Int_t, Float_t, Float_t, const wchar_t *, ETextMode) override {} + //---- Methods used for GUI ----- void GetWindowAttributes(Window_t id, WindowAttributes_t &attr) override; void MapWindow(Window_t id) override; diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index 192975a3f1a4d..6dfea9fb578d4 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -524,6 +524,19 @@ void TGX11::CopyPixmap(int wid, int xpos, int ypos) void TGX11::DrawBox(int x1, int y1, int x2, int y2, EBoxMode mode) { + DrawBoxW((WinContext_t) gCws, x1, y1, x2, y2, mode); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Draw a box on specified window +/// +/// - mode=0 hollow (kHollow) +/// - mode=1 solid (kSolid) + +void TGX11::DrawBoxW(WinContext_t wctxt, Int_t x1, Int_t y1, Int_t x2, Int_t y2, EBoxMode mode) +{ + auto ctxt = (XWindow_t *) wctxt; + Int_t x = TMath::Min(x1, x2); Int_t y = TMath::Min(y1, y2); Int_t w = TMath::Abs(x2 - x1); @@ -532,11 +545,11 @@ void TGX11::DrawBox(int x1, int y1, int x2, int y2, EBoxMode mode) switch (mode) { case kHollow: - XDrawRectangle((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCline], x, y, w, h); + XDrawRectangle((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCline], x, y, w, h); break; case kFilled: - XFillRectangle((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCfill], x, y, w, h); + XFillRectangle((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCfill], x, y, w, h); break; default: @@ -588,13 +601,25 @@ void TGX11::DrawCellArray(int x1, int y1, int x2, int y2, int nx, int ny, int *i void TGX11::DrawFillArea(int n, TPoint *xy) { - XPoint *xyp = (XPoint*)xy; + DrawFillAreaW((WinContext_t) gCws, n, xy); +} - if (gCws->fillHollow) - XDrawLines((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCfill], xyp, n, CoordModeOrigin); +//////////////////////////////////////////////////////////////////////////////// +/// Fill area described by polygon on specified window +/// +/// \param [in] n number of points +/// \param [in] xy list of points + +void TGX11::DrawFillAreaW(WinContext_t wctxt, Int_t n, TPoint *xy) +{ + auto ctxt = (XWindow_t *) wctxt; + XPoint *xyp = (XPoint *)xy; + + if (ctxt->fillHollow) + XDrawLines((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCfill], xyp, n, CoordModeOrigin); else { - XFillPolygon((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCfill], + XFillPolygon((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCfill], xyp, n, Nonconvex, CoordModeOrigin); } } @@ -607,11 +632,24 @@ void TGX11::DrawFillArea(int n, TPoint *xy) void TGX11::DrawLine(Int_t x1, Int_t y1, Int_t x2, Int_t y2) { - if (gCws->lineStyle == LineSolid) - XDrawLine((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCline], x1, y1, x2, y2); + DrawLineW((WinContext_t) gCws, x1, y1, x2, y2); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Draw a line on specified window. +/// +/// \param [in] x1,y1 : begin of line +/// \param [in] x2,y2 : end of line + +void TGX11::DrawLineW(WinContext_t wctxt, Int_t x1, Int_t y1, Int_t x2, Int_t y2) +{ + auto ctxt = (XWindow_t *) wctxt; + + if (ctxt->lineStyle == LineSolid) + XDrawLine((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCline], x1, y1, x2, y2); else { - XSetDashes((Display*)fDisplay, gCws->fGClist[kGCdash], gCws->dashOffset, gCws->dashList.data(), gCws->dashList.size()); - XDrawLine((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCdash], x1, y1, x2, y2); + XSetDashes((Display*)fDisplay, ctxt->fGClist[kGCdash], ctxt->dashOffset, ctxt->dashList.data(), ctxt->dashList.size()); + XDrawLine((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCdash], x1, y1, x2, y2); } } @@ -623,6 +661,18 @@ void TGX11::DrawLine(Int_t x1, Int_t y1, Int_t x2, Int_t y2) void TGX11::DrawPolyLine(int n, TPoint *xy) { + DrawPolyLineW((WinContext_t) gCws, n, xy); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Draw a line through all points on specified window. +/// +/// \param [in] n number of points +/// \param [in] xy list of points + +void TGX11::DrawPolyLineW(WinContext_t wctxt, Int_t n, TPoint *xy) +{ + auto ctxt = (XWindow_t *) wctxt; XPoint *xyp = (XPoint*)xy; const Int_t kMaxPoints = 1000001; @@ -631,38 +681,36 @@ void TGX11::DrawPolyLine(int n, TPoint *xy) int ibeg = 0; int iend = kMaxPoints - 1; while (iend < n) { - DrawPolyLine( kMaxPoints, &xy[ibeg] ); + DrawPolyLineW(wctxt, kMaxPoints, &xy[ibeg]); ibeg = iend; iend += kMaxPoints - 1; } if (ibeg < n) { int npt = n - ibeg; - DrawPolyLine( npt, &xy[ibeg] ); + DrawPolyLineW(wctxt, npt, &xy[ibeg]); } } else if (n > 1) { - if (gCws->lineStyle == LineSolid) - XDrawLines((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCline], xyp, n, CoordModeOrigin); + if (ctxt->lineStyle == LineSolid) + XDrawLines((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCline], xyp, n, CoordModeOrigin); else { - int i; - XSetDashes((Display*)fDisplay, gCws->fGClist[kGCdash], gCws->dashOffset, gCws->dashList.data(), gCws->dashList.size()); - XDrawLines((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCdash], xyp, n, CoordModeOrigin); + XSetDashes((Display*)fDisplay, ctxt->fGClist[kGCdash], ctxt->dashOffset, ctxt->dashList.data(), ctxt->dashList.size()); + XDrawLines((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCdash], xyp, n, CoordModeOrigin); // calculate length of line to update dash offset - for (i = 1; i < n; i++) { + for (int i = 1; i < n; i++) { int dx = xyp[i].x - xyp[i-1].x; int dy = xyp[i].y - xyp[i-1].y; if (dx < 0) dx = - dx; if (dy < 0) dy = - dy; - gCws->dashOffset += dx > dy ? dx : dy; + ctxt->dashOffset += dx > dy ? dx : dy; } - gCws->dashOffset %= gCws->dashLength; + ctxt->dashOffset %= ctxt->dashLength; } } else { - int px,py; - px=xyp[0].x; - py=xyp[0].y; - XDrawPoint((Display*)fDisplay, gCws->fDrawing, - gCws->lineStyle == LineSolid ? gCws->fGClist[kGCline] : gCws->fGClist[kGCdash], px, py); + int px = xyp[0].x; + int py = xyp[0].y; + XDrawPoint((Display*)fDisplay, ctxt->fDrawing, + ctxt->lineStyle == LineSolid ? ctxt->fGClist[kGCline] : ctxt->fGClist[kGCdash], px, py); } } @@ -674,21 +722,34 @@ void TGX11::DrawPolyLine(int n, TPoint *xy) void TGX11::DrawLinesSegments(Int_t n, TPoint *xy) { + DrawLinesSegmentsW((WinContext_t) gCws, n, xy); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Draws N segments between provided points on specified windows +/// +/// \param [in] n number of segements +/// \param [in] xy list of points, size 2*n + +void TGX11::DrawLinesSegmentsW(WinContext_t wctxt, Int_t n, TPoint *xy) +{ + auto ctxt = (XWindow_t *) wctxt; + const Int_t kMaxSegments = 500000; if (n > kMaxSegments) { Int_t ibeg = 0; Int_t iend = kMaxSegments; while (ibeg < n) { - DrawLinesSegments(iend - ibeg, &xy[ibeg*2]); + DrawLinesSegmentsW(wctxt, iend - ibeg, &xy[ibeg*2]); ibeg = iend; iend = TMath::Min(n, iend + kMaxSegments); } } else if (n > 0) { - if (gCws->lineStyle == LineSolid) - XDrawSegments((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCline], (XSegment *) xy, n); + if (ctxt->lineStyle == LineSolid) + XDrawSegments((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCline], (XSegment *) xy, n); else { - XSetDashes((Display*)fDisplay, gCws->fGClist[kGCdash], gCws->dashOffset, gCws->dashList.data(), gCws->dashList.size()); - XDrawSegments((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCdash], (XSegment *) xy, n); + XSetDashes((Display*)fDisplay, ctxt->fGClist[kGCdash], ctxt->dashOffset, ctxt->dashList.data(), ctxt->dashList.size()); + XDrawSegments((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCdash], (XSegment *) xy, n); } } } @@ -702,50 +763,62 @@ void TGX11::DrawLinesSegments(Int_t n, TPoint *xy) void TGX11::DrawPolyMarker(int n, TPoint *xy) { - XPoint *xyp = (XPoint*)xy; + DrawPolyMarkerW((WinContext_t) gCws, n, xy); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Draw n markers with the current attributes at position x, y on specified window. +/// +/// \param [in] n number of markers to draw +/// \param [in] xy x,y coordinates of markers - if ((gCws->markerShape.size() == 0) && (gCws->markerSize <= 0)) { +void TGX11::DrawPolyMarkerW(WinContext_t wctxt, Int_t n, TPoint *xy) +{ + auto ctxt = (XWindow_t *) wctxt; + XPoint *xyp = (XPoint *) xy; + + if ((ctxt->markerShape.size() == 0) && (ctxt->markerSize <= 0)) { const int kNMAX = 1000000; int nt = n/kNMAX; for (int it=0;it<=nt;it++) { if (it < nt) { - XDrawPoints((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], &xyp[it*kNMAX], kNMAX, CoordModeOrigin); + XDrawPoints((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCmark], &xyp[it*kNMAX], kNMAX, CoordModeOrigin); } else { - XDrawPoints((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], &xyp[it*kNMAX], n-it*kNMAX, CoordModeOrigin); + XDrawPoints((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCmark], &xyp[it*kNMAX], n-it*kNMAX, CoordModeOrigin); } } } else { - int r = gCws->markerSize / 2; - auto &shape = gCws->markerShape; + int r = ctxt->markerSize / 2; + auto &shape = ctxt->markerShape; for (int m = 0; m < n; m++) { - if (gCws->markerType == 0) { + if (ctxt->markerType == 0) { // hollow circle - XDrawArc((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], - xyp[m].x - r, xyp[m].y - r, gCws->markerSize, gCws->markerSize, 0, 360*64); - } else if (gCws->markerType == 1) { + XDrawArc((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCmark], + xyp[m].x - r, xyp[m].y - r, ctxt->markerSize, ctxt->markerSize, 0, 360*64); + } else if (ctxt->markerType == 1) { // filled circle - XFillArc((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], - xyp[m].x - r, xyp[m].y - r, gCws->markerSize, gCws->markerSize, 0, 360*64); + XFillArc((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCmark], + xyp[m].x - r, xyp[m].y - r, ctxt->markerSize, ctxt->markerSize, 0, 360*64); } else { for (size_t i = 0; i < shape.size(); i++) { shape[i].x += xyp[m].x; shape[i].y += xyp[m].y; } - switch(gCws->markerType) { + switch(ctxt->markerType) { case 2: // hollow polygon - XDrawLines((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], + XDrawLines((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCmark], shape.data(), shape.size(), CoordModeOrigin); break; case 3: // filled polygon - XFillPolygon((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], + XFillPolygon((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCmark], shape.data(), shape.size(), Nonconvex, CoordModeOrigin); break; case 4: // segmented line - XDrawSegments((Display*)fDisplay, gCws->fDrawing, gCws->fGClist[kGCmark], + XDrawSegments((Display*)fDisplay, ctxt->fDrawing, ctxt->fGClist[kGCmark], (XSegment *) shape.data(), shape.size()/2); break; } @@ -772,8 +845,26 @@ void TGX11::DrawPolyMarker(int n, TPoint *xy) void TGX11::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn, const char *text, ETextMode mode) { + DrawTextW((WinContext_t) gCws, x, y, angle, mgn, text, mode); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Draw a text string using current font on specified window. +/// +/// \param [in] mode : drawing mode +/// - mode=0 : the background is not drawn (kClear) +/// - mode=1 : the background is drawn (kOpaque) +/// \param [in] x,y : text position +/// \param [in] angle : text angle +/// \param [in] mgn : magnification factor +/// \param [in] text : text string + +void TGX11::DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Float_t mgn, + const char *text, ETextMode mode) +{ + auto ctxt = (XWindow_t *) wctxt; - if (!text || !gCws->textFont || gCws->fAttText.GetTextSize() < 0) + if (!text || !ctxt->textFont || ctxt->fAttText.GetTextSize() < 0) return; XRotSetMagnification(mgn); @@ -781,13 +872,13 @@ void TGX11::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn, switch (mode) { case kClear: - XRotDrawAlignedString((Display*)fDisplay, gCws->textFont, angle, - gCws->fDrawing, gCws->fGClist[kGCtext], x, y, (char*)text, gCws->textAlign); + XRotDrawAlignedString((Display*)fDisplay, ctxt->textFont, angle, + ctxt->fDrawing, ctxt->fGClist[kGCtext], x, y, (char*)text, ctxt->textAlign); break; case kOpaque: - XRotDrawAlignedImageString((Display*)fDisplay, gCws->textFont, angle, - gCws->fDrawing, gCws->fGClist[kGCtext], x, y, (char*)text, gCws->textAlign); + XRotDrawAlignedImageString((Display*)fDisplay, ctxt->textFont, angle, + ctxt->fDrawing, ctxt->fGClist[kGCtext], x, y, (char*)text, ctxt->textAlign); break; default: From 6c8620aa01139730d04d6ad6877334be266fdd35 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 13 Mar 2026 07:59:09 +0100 Subject: [PATCH 20/37] [pad painter] add methods to set complete attributes at once --- core/base/inc/TVirtualPadPainter.h | 9 ++++++ core/base/src/TVirtualPadPainter.cxx | 45 ++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/core/base/inc/TVirtualPadPainter.h b/core/base/inc/TVirtualPadPainter.h index 830d0bc8acb4e..93e507397b609 100644 --- a/core/base/inc/TVirtualPadPainter.h +++ b/core/base/inc/TVirtualPadPainter.h @@ -15,6 +15,10 @@ #include "Rtypes.h" class TVirtualPad; +class TAttFill; +class TAttLine; +class TAttMarker; +class TAttText; class TVirtualPadPainter { public: @@ -75,6 +79,11 @@ class TVirtualPadPainter { virtual void SetMarkerStyle(Style_t /* mstyle */ = 1) {} virtual void SetMarkerSize(Size_t /* msize */ = 1) {} + virtual void SetAttFill(const TAttFill &att); + virtual void SetAttLine(const TAttLine &att); + virtual void SetAttMarker(const TAttMarker &att); + virtual void SetAttText(const TAttText &att); + //This part is an interface to X11 pixmap management and to save sub-pads off-screens for OpenGL. //Currently, must be implemented only for X11/GDI virtual Int_t CreateDrawable(UInt_t w, UInt_t h) = 0;//gVirtualX->OpenPixmap diff --git a/core/base/src/TVirtualPadPainter.cxx b/core/base/src/TVirtualPadPainter.cxx index b8d5fe05fbe8a..7fab0ecb3f9a5 100644 --- a/core/base/src/TVirtualPadPainter.cxx +++ b/core/base/src/TVirtualPadPainter.cxx @@ -11,6 +11,10 @@ #include "TVirtualPadPainter.h" #include "TPluginManager.h" +#include "TAttFill.h" +#include "TAttLine.h" +#include "TAttMarker.h" +#include "TAttText.h" /** \class TVirtualPadPainter @@ -96,3 +100,44 @@ void TVirtualPadPainter::DrawTextUrl(Double_t x, Double_t y, const char *text, c { DrawText(x, y, text, kClear); } + +//////////////////////////////////////////////////////////////////////////////// +/// Set fill attributes + +void TVirtualPadPainter::SetAttFill(const TAttFill &att) +{ + SetFillColor(att.GetFillColor()); + SetFillStyle(att.GetFillStyle()); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set line attributes + +void TVirtualPadPainter::SetAttLine(const TAttLine &att) +{ + SetLineColor(att.GetLineColor()); + SetLineStyle(att.GetLineStyle()); + SetLineWidth(att.GetLineWidth()); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set marker attributes + +void TVirtualPadPainter::SetAttMarker(const TAttMarker &att) +{ + SetMarkerColor(att.GetMarkerColor()); + SetMarkerSize(att.GetMarkerSize()); + SetMarkerStyle(att.GetMarkerStyle()); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set text attributes + +void TVirtualPadPainter::SetAttText(const TAttText &att) +{ + SetTextAlign(att.GetTextAlign()); + SetTextAngle(att.GetTextAngle()); + SetTextColor(att.GetTextColor()); + SetTextSize(att.GetTextSize()); + SetTextFont(att.GetTextFont()); +} From d2f16d8fd111e81fbadd7be7447389b7259ca170 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 13 Mar 2026 08:00:10 +0100 Subject: [PATCH 21/37] [pad painter] use new virtualX methods for painting Remember context of selected window and use this context when performing drawing on the pad --- graf2d/gpad/inc/TPadPainter.h | 9 ++++ graf2d/gpad/src/TPadPainter.cxx | 85 +++++++++++++++++++++++---------- 2 files changed, 68 insertions(+), 26 deletions(-) diff --git a/graf2d/gpad/inc/TPadPainter.h b/graf2d/gpad/inc/TPadPainter.h index 24c762ed47ede..58b9c9492f83c 100644 --- a/graf2d/gpad/inc/TPadPainter.h +++ b/graf2d/gpad/inc/TPadPainter.h @@ -13,6 +13,7 @@ #define ROOT_TPadPainter #include "TVirtualPadPainter.h" +#include "GuiTypes.h" /* TVirtualPadPainter is an attempt to abstract @@ -24,6 +25,8 @@ or gl pad painter. class TVirtualPad; class TPadPainter : public TVirtualPadPainter { + WinContext_t fWinContext; + public: TPadPainter(); //Final overriders for TVirtualPadPainter pure virtual functions. @@ -71,6 +74,12 @@ class TPadPainter : public TVirtualPadPainter { void SetMarkerStyle(Style_t mstyle) override; void SetMarkerSize(Size_t msize) override; + //Overall attributes + void SetAttFill(const TAttFill &att) override; + void SetAttLine(const TAttLine &att) override; + void SetAttMarker(const TAttMarker &att) override; + void SetAttText(const TAttText &att) override; + //2. "Off-screen management" part. Int_t CreateDrawable(UInt_t w, UInt_t h) override; void ClearDrawable() override; diff --git a/graf2d/gpad/src/TPadPainter.cxx b/graf2d/gpad/src/TPadPainter.cxx index 41dd510269633..e5c89ccaac2bc 100644 --- a/graf2d/gpad/src/TPadPainter.cxx +++ b/graf2d/gpad/src/TPadPainter.cxx @@ -47,13 +47,13 @@ void ConvertPointsAndMergePassX(TVirtualPad *pad, unsigned nPoints, const T *x, void ConvertPointsAndMergeInplacePassY(std::vector &dst); template -void DrawFillAreaAux(TVirtualPad *pad, Int_t nPoints, const T *xs, const T *ys); +void DrawFillAreaAux(TVirtualPad *pad, WinContext_t cont, Int_t nPoints, const T *xs, const T *ys); template -void DrawPolyLineAux(TVirtualPad *pad, unsigned nPoints, const T *xs, const T *ys); +void DrawPolyLineAux(TVirtualPad *pad, WinContext_t cont, unsigned nPoints, const T *xs, const T *ys); template -void DrawPolyMarkerAux(TVirtualPad *pad, unsigned nPoints, const T *xs, const T *ys); +void DrawPolyMarkerAux(TVirtualPad *pad, WinContext_t cont, unsigned nPoints, const T *xs, const T *ys); } @@ -404,6 +404,7 @@ void TPadPainter::DestroyDrawable(Int_t device) { gVirtualX->SelectWindow(device); gVirtualX->ClosePixmap(); + fWinContext = (WinContext_t) 0; } @@ -413,6 +414,7 @@ void TPadPainter::DestroyDrawable(Int_t device) void TPadPainter::SelectDrawable(Int_t device) { gVirtualX->SelectWindow(device); + fWinContext = gVirtualX->GetWindowContext(device); } //////////////////////////////////////////////////////////////////////////////// @@ -423,6 +425,37 @@ void TPadPainter::DrawPixels(const unsigned char * /*pixelData*/, UInt_t /*width { } +//////////////////////////////////////////////////////////////////////////////// +/// Set fill attributes + +void TPadPainter::SetAttFill(const TAttFill &att) +{ + gVirtualX->SetAttFill(fWinContext, att); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set line attributes + +void TPadPainter::SetAttLine(const TAttLine &att) +{ + gVirtualX->SetAttLine(fWinContext, att); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set marker attributes + +void TPadPainter::SetAttMarker(const TAttMarker &att) +{ + gVirtualX->SetAttMarker(fWinContext, att); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Set text attributes + +void TPadPainter::SetAttText(const TAttText &att) +{ + gVirtualX->SetAttText(fWinContext, att); +} //////////////////////////////////////////////////////////////////////////////// /// Paint a simple line. @@ -435,7 +468,7 @@ void TPadPainter::DrawLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2) const Int_t px2 = gPad->XtoPixel(x2); const Int_t py1 = gPad->YtoPixel(y1); const Int_t py2 = gPad->YtoPixel(y2); - gVirtualX->DrawLine(px1, py1, px2, py2); + gVirtualX->DrawLineW(fWinContext, px1, py1, px2, py2); } @@ -450,7 +483,7 @@ void TPadPainter::DrawLineNDC(Double_t u1, Double_t v1, Double_t u2, Double_t v2 const Int_t py1 = gPad->VtoPixel(v1); const Int_t px2 = gPad->UtoPixel(u2); const Int_t py2 = gPad->VtoPixel(v2); - gVirtualX->DrawLine(px1, py1, px2, py2); + gVirtualX->DrawLineW(fWinContext, px1, py1, px2, py2); } @@ -472,7 +505,7 @@ void TPadPainter::DrawBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, EB if (TMath::Abs(py1 - py2) < 1) py1 = py2 + 1; - gVirtualX->DrawBox(px1, py1, px2, py2, (TVirtualX::EBoxMode)mode); + gVirtualX->DrawBoxW(fWinContext, px1, py1, px2, py2, (TVirtualX::EBoxMode)mode); } //////////////////////////////////////////////////////////////////////////////// @@ -485,7 +518,7 @@ void TPadPainter::DrawFillArea(Int_t nPoints, const Double_t *xs, const Double_t return; } - DrawFillAreaAux(gPad, nPoints, xs, ys); + DrawFillAreaAux(gPad, fWinContext, nPoints, xs, ys); } @@ -499,7 +532,7 @@ void TPadPainter::DrawFillArea(Int_t nPoints, const Float_t *xs, const Float_t * return; } - DrawFillAreaAux(gPad, nPoints, xs, ys); + DrawFillAreaAux(gPad, fWinContext, nPoints, xs, ys); } //////////////////////////////////////////////////////////////////////////////// @@ -514,7 +547,7 @@ void TPadPainter::DrawPolyLine(Int_t n, const Double_t *xs, const Double_t *ys) return; } - DrawPolyLineAux(gPad, n, xs, ys); + DrawPolyLineAux(gPad, fWinContext, n, xs, ys); } @@ -530,7 +563,7 @@ void TPadPainter::DrawPolyLine(Int_t n, const Float_t *xs, const Float_t *ys) return; } - DrawPolyLineAux(gPad, n, xs, ys); + DrawPolyLineAux(gPad, fWinContext, n, xs, ys); } @@ -553,7 +586,7 @@ void TPadPainter::DrawPolyLineNDC(Int_t n, const Double_t *u, const Double_t *v) xy[i].fY = (SCoord_t)gPad->VtoPixel(v[i]); } - gVirtualX->DrawPolyLine(n, &xy[0]); + gVirtualX->DrawPolyLineW(fWinContext, n, &xy[0]); } //////////////////////////////////////////////////////////////////////////////// @@ -584,7 +617,7 @@ void TPadPainter::DrawSegments(Int_t n, Double_t *x, Double_t *y) } if (cnt > 1) - gVirtualX->DrawLinesSegments(cnt/2, &xy[0]); + gVirtualX->DrawLinesSegmentsW(fWinContext, cnt/2, &xy[0]); } //////////////////////////////////////////////////////////////////////////////// @@ -615,7 +648,7 @@ void TPadPainter::DrawSegmentsNDC(Int_t n, Double_t *u, Double_t *v) } if (cnt > 1) - gVirtualX->DrawLinesSegments(cnt/2, &xy[0]); + gVirtualX->DrawLinesSegmentsW(fWinContext, cnt/2, &xy[0]); } @@ -630,7 +663,7 @@ void TPadPainter::DrawPolyMarker(Int_t n, const Double_t *x, const Double_t *y) return; } - DrawPolyMarkerAux(gPad, n, x, y); + DrawPolyMarkerAux(gPad, fWinContext, n, x, y); } @@ -644,7 +677,7 @@ void TPadPainter::DrawPolyMarker(Int_t n, const Float_t *x, const Float_t *y) return; } - DrawPolyMarkerAux(gPad, n, x, y); + DrawPolyMarkerAux(gPad, fWinContext, n, x, y); } @@ -657,7 +690,7 @@ void TPadPainter::DrawText(Double_t x, Double_t y, const char *text, ETextMode m const Int_t py = gPad->YtoPixel(y); const Double_t angle = GetTextAngle(); const Double_t mgn = GetTextMagnitude(); - gVirtualX->DrawText(px, py, angle, mgn, text, (TVirtualX::ETextMode)mode); + gVirtualX->DrawTextW(fWinContext, px, py, angle, mgn, text, (TVirtualX::ETextMode)mode); } @@ -670,7 +703,7 @@ void TPadPainter::DrawText(Double_t x, Double_t y, const wchar_t *text, ETextMod const Int_t py = gPad->YtoPixel(y); const Double_t angle = GetTextAngle(); const Double_t mgn = GetTextMagnitude(); - gVirtualX->DrawText(px, py, angle, mgn, text, (TVirtualX::ETextMode)mode); + gVirtualX->DrawTextW(fWinContext, px, py, angle, mgn, text, (TVirtualX::ETextMode)mode); } @@ -683,7 +716,7 @@ void TPadPainter::DrawTextNDC(Double_t u, Double_t v, const char *text, ETextMod const Int_t py = gPad->VtoPixel(v); const Double_t angle = GetTextAngle(); const Double_t mgn = GetTextMagnitude(); - gVirtualX->DrawText(px, py, angle, mgn, text, (TVirtualX::ETextMode)mode); + gVirtualX->DrawTextW(fWinContext, px, py, angle, mgn, text, (TVirtualX::ETextMode)mode); } @@ -759,7 +792,7 @@ void TPadPainter::DrawTextNDC(Double_t u, Double_t v, const wchar_t *text, EText const Int_t py = gPad->VtoPixel(v); const Double_t angle = GetTextAngle(); const Double_t mgn = GetTextMagnitude(); - gVirtualX->DrawText(px, py, angle, mgn, text, (TVirtualX::ETextMode)mode); + gVirtualX->DrawTextW(fWinContext, px, py, angle, mgn, text, (TVirtualX::ETextMode)mode); } //Aux. private functions. @@ -962,7 +995,7 @@ void ConvertPointsAndMerge(TVirtualPad *pad, unsigned threshold, unsigned nPoint //////////////////////////////////////////////////////////////////////////////// template -void DrawFillAreaAux(TVirtualPad *pad, Int_t nPoints, const T *xs, const T *ys) +void DrawFillAreaAux(TVirtualPad *pad, WinContext_t cont, Int_t nPoints, const T *xs, const T *ys) { std::vector xy; @@ -985,15 +1018,15 @@ void DrawFillAreaAux(TVirtualPad *pad, Int_t nPoints, const T *xs, const T *ys) xy.push_back(xy.front()); if (xy.size() > 2) - gVirtualX->DrawFillArea(xy.size(), &xy[0]); + gVirtualX->DrawFillAreaW(cont, xy.size(), &xy[0]); } //////////////////////////////////////////////////////////////////////////////// template -void DrawPolyLineAux(TVirtualPad *pad, unsigned nPoints, const T *xs, const T *ys) +void DrawPolyLineAux(TVirtualPad *pad, WinContext_t cont, unsigned nPoints, const T *xs, const T *ys) { - std::vector xy; + std::vector xy; const Int_t threshold = Int_t(TMath::Min(pad->GetWw() * pad->GetAbsWNDC(), pad->GetWh() * pad->GetAbsHNDC())) * 2; @@ -1009,14 +1042,14 @@ void DrawPolyLineAux(TVirtualPad *pad, unsigned nPoints, const T *xs, const T *y ConvertPointsAndMerge(pad, threshold, nPoints, xs, ys, xy); if (xy.size() > 1) - gVirtualX->DrawPolyLine(xy.size(), &xy[0]); + gVirtualX->DrawPolyLineW(cont, xy.size(), &xy[0]); } //////////////////////////////////////////////////////////////////////////////// template -void DrawPolyMarkerAux(TVirtualPad *pad, unsigned nPoints, const T *xs, const T *ys) +void DrawPolyMarkerAux(TVirtualPad *pad, WinContext_t cont, unsigned nPoints, const T *xs, const T *ys) { std::vector xy(nPoints); @@ -1025,7 +1058,7 @@ void DrawPolyMarkerAux(TVirtualPad *pad, unsigned nPoints, const T *xs, const T xy[i].fY = (SCoord_t)pad->YtoPixel(ys[i]); } - gVirtualX->DrawPolyMarker(nPoints, &xy[0]); + gVirtualX->DrawPolyMarkerW(cont, nPoints, &xy[0]); } } From 06b0ab5bd232c9d72e4d07ea44b1f209902de58e Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 13 Mar 2026 08:58:52 +0100 Subject: [PATCH 22/37] [tgx11ttf] implement new text drawing methods with TTF --- graf2d/x11/inc/TGX11.h | 2 +- graf2d/x11/src/TGX11.cxx | 17 +++++++++++++++++ graf2d/x11ttf/inc/TGX11TTF.h | 5 +++-- graf2d/x11ttf/src/TGX11TTF.cxx | 16 ++++++++-------- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/graf2d/x11/inc/TGX11.h b/graf2d/x11/inc/TGX11.h index 3fd5db95d9a97..66165e86f7693 100644 --- a/graf2d/x11/inc/TGX11.h +++ b/graf2d/x11/inc/TGX11.h @@ -215,7 +215,7 @@ class TGX11 : public TVirtualX { void DrawLinesSegments(Int_t n, TPoint *xy) override; void DrawPolyMarker(Int_t n, TPoint *xy) override; void DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn, const char *text, ETextMode mode) override; - void DrawText(Int_t, Int_t, Float_t, Float_t, const wchar_t *, ETextMode) override {} + void DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn, const wchar_t *text, ETextMode mode) override; //---- Methods used for new graphics ----- WinContext_t GetWindowContext(Int_t wid) override; diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index 6dfea9fb578d4..bacdf1c3d04a8 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -848,6 +848,23 @@ void TGX11::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn, DrawTextW((WinContext_t) gCws, x, y, angle, mgn, text, mode); } +//////////////////////////////////////////////////////////////////////////////// +/// Draw a text string using current font. +/// +/// \param [in] mode : drawing mode +/// - mode=0 : the background is not drawn (kClear) +/// - mode=1 : the background is drawn (kOpaque) +/// \param [in] x,y : text position +/// \param [in] angle : text angle +/// \param [in] mgn : magnification factor +/// \param [in] text : text string + +void TGX11::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn, + const wchar_t *text, ETextMode mode) +{ + DrawTextW((WinContext_t) gCws, x, y, angle, mgn, text, mode); +} + //////////////////////////////////////////////////////////////////////////////// /// Draw a text string using current font on specified window. /// diff --git a/graf2d/x11ttf/inc/TGX11TTF.h b/graf2d/x11ttf/inc/TGX11TTF.h index fe9bafcc766d2..d6909d3dd47e5 100644 --- a/graf2d/x11ttf/inc/TGX11TTF.h +++ b/graf2d/x11ttf/inc/TGX11TTF.h @@ -58,9 +58,10 @@ class TGX11TTF : public TGX11 { ~TGX11TTF() override { } Bool_t Init(void *display) override; - void DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn, + + void DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Float_t mgn, const char *text, ETextMode mode) override; - void DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn, + void DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Float_t mgn, const wchar_t *text, ETextMode mode) override; using TGX11::SetTextFont; diff --git a/graf2d/x11ttf/src/TGX11TTF.cxx b/graf2d/x11ttf/src/TGX11TTF.cxx index 4e78d86abbf6d..8850640929ec5 100644 --- a/graf2d/x11ttf/src/TGX11TTF.cxx +++ b/graf2d/x11ttf/src/TGX11TTF.cxx @@ -360,13 +360,13 @@ void TGX11TTF::DrawImage(FT_Bitmap *source, ULong_t fore, ULong_t back, //////////////////////////////////////////////////////////////////////////////// /// Draw text using TrueType fonts. If TrueType fonts are not available the -/// text is drawn with TGX11::DrawText. +/// text is drawn with TGX11::DrawTextW. -void TGX11TTF::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn, - const char *text, ETextMode mode) +void TGX11TTF::DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Float_t mgn, + const char *text, ETextMode mode) { if (!fHasTTFonts) { - TGX11::DrawText(x, y, angle, mgn, text, mode); + TGX11::DrawTextW(wctxt, x, y, angle, mgn, text, mode); } else { if (!TTF::fgInit) TTF::Init(); TTF::SetRotationMatrix(angle); @@ -379,13 +379,13 @@ void TGX11TTF::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn, //////////////////////////////////////////////////////////////////////////////// /// Draw text using TrueType fonts. If TrueType fonts are not available the -/// text is drawn with TGX11::DrawText. +/// text is drawn with TGX11::DrawTextW. -void TGX11TTF::DrawText(Int_t x, Int_t y, Float_t angle, Float_t mgn, - const wchar_t *text, ETextMode mode) +void TGX11TTF::DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Float_t mgn, + const wchar_t *text, ETextMode mode) { if (!fHasTTFonts) { - TGX11::DrawText(x, y, angle, mgn, text, mode); + TGX11::DrawTextW(wctxt, x, y, angle, mgn, text, mode); } else { if (!TTF::fgInit) TTF::Init(); TTF::SetRotationMatrix(angle); From d75e2ee1606c584d82edf88b1ff2b1330f649a0b Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 13 Mar 2026 09:34:21 +0100 Subject: [PATCH 23/37] [tgx11] use context for TTF text drawing Provide protected methods to return window, GC and textAlign for selected window context. And use context in TTF rendering methods. So now TGX11TTF also correctly implementes API, but not yet thread-safe because of TTF global states. --- graf2d/x11/inc/TGX11.h | 6 +++- graf2d/x11/src/TGX11.cxx | 41 ++++++++++++++++++++++- graf2d/x11ttf/inc/TGX11TTF.h | 8 ++--- graf2d/x11ttf/src/TGX11TTF.cxx | 59 +++++++++++++++++++--------------- 4 files changed, 82 insertions(+), 32 deletions(-) diff --git a/graf2d/x11/inc/TGX11.h b/graf2d/x11/inc/TGX11.h index 66165e86f7693..50696bff38d08 100644 --- a/graf2d/x11/inc/TGX11.h +++ b/graf2d/x11/inc/TGX11.h @@ -112,7 +112,7 @@ class TGX11 : public TVirtualX { Int_t fScreenNumber; ///< Screen number Int_t fTextAlignH; ///< Text Alignment Horizontal Int_t fTextAlignV; ///< Text Alignment Vertical - Int_t fTextAlign; ///< Text alignment (set in SetTextAlign) + Int_t fTextAlign; ///< Text alignment (set in SetTextAlign) !!! conflict with TAttText Float_t fCharacterUpX; ///< Character Up vector along X Float_t fCharacterUpY; ///< Character Up vector along Y Float_t fTextMagnitude; ///< Text Magnitude @@ -130,6 +130,10 @@ class TGX11 : public TVirtualX { Bool_t AllocColor(Colormap cmap, RXColor *color); void QueryColors(Colormap cmap, RXColor *colors, Int_t ncolors); void *GetGC(Int_t which) const; + Window_t GetWindow(WinContext_t wctxt) const; + void *GetGCW(WinContext_t wctxt, Int_t which) const; + Int_t GetTextAlignW(WinContext_t wctxt) const; + XColor_t &GetColor(Int_t cid); TGX11(TGX11 &&org); diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index bacdf1c3d04a8..228a1cc161b1e 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -1048,7 +1048,7 @@ XColor_t &TGX11::GetColor(Int_t cid) } //////////////////////////////////////////////////////////////////////////////// -/// Return current window pointer. Protected method used by TGX11TTF. +/// Return current window pointer. Window_t TGX11::GetCurrentWindow() const { @@ -1072,6 +1072,45 @@ void *TGX11::GetGC(Int_t which) const return &gCws->fGClist[which]; } +//////////////////////////////////////////////////////////////////////////////// +/// Return X11 window for specified window context. +/// Protected method used by TGX11TTF. + +Window_t TGX11::GetWindow(WinContext_t wctxt) const +{ + auto ctxt = (XWindow_t *) wctxt; + return (Window_t) (ctxt ? ctxt->fDrawing : 0); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Return X11 Graphics Context for specified window context. +/// Protected method used by TGX11TTF. + +void *TGX11::GetGCW(WinContext_t wctxt, Int_t which) const +{ + auto ctxt = (XWindow_t *) wctxt; + if (!ctxt) { + Error("GetGC", "No window context specified"); + return nullptr; + } + + if (which >= kMAXGC || which < 0) { + Error("GetGC", "trying to get illegal GC (which = %d)", which); + return nullptr; + } + return &ctxt->fGClist[which]; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Return text align value for specified window context. +/// Protected method used by TGX11TTF. + +Int_t TGX11::GetTextAlignW(WinContext_t wctxt) const +{ + auto ctxt = (XWindow_t *) wctxt; + return ctxt ? ctxt->textAlign : 0; +} + //////////////////////////////////////////////////////////////////////////////// /// Query the double buffer value for the window wid. diff --git a/graf2d/x11ttf/inc/TGX11TTF.h b/graf2d/x11ttf/inc/TGX11TTF.h index d6909d3dd47e5..b440f322b12e9 100644 --- a/graf2d/x11ttf/inc/TGX11TTF.h +++ b/graf2d/x11ttf/inc/TGX11TTF.h @@ -46,12 +46,12 @@ class TGX11TTF : public TGX11 { TXftFontHash *fXftFontHash; ///< hash table for Xft fonts #endif - void Align(void); + void Align(Int_t value); void DrawImage(FT_Bitmap *source, ULong_t fore, ULong_t back, RXImage *xim, Int_t bx, Int_t by); - Bool_t IsVisible(Int_t x, Int_t y, UInt_t w, UInt_t h); - RXImage *GetBackground(Int_t x, Int_t y, UInt_t w, UInt_t h); - void RenderString(Int_t x, Int_t y, ETextMode mode); + Bool_t IsVisible(WinContext_t wctxt, Int_t x, Int_t y, UInt_t w, UInt_t h); + RXImage *GetBackground(WinContext_t wctxt, Int_t x, Int_t y, UInt_t w, UInt_t h); + void RenderString(WinContext_t wctxt, Int_t x, Int_t y, ETextMode mode); public: TGX11TTF(TGX11 &&org); diff --git a/graf2d/x11ttf/src/TGX11TTF.cxx b/graf2d/x11ttf/src/TGX11TTF.cxx index 8850640929ec5..7d68be43deb0d 100644 --- a/graf2d/x11ttf/src/TGX11TTF.cxx +++ b/graf2d/x11ttf/src/TGX11TTF.cxx @@ -208,9 +208,9 @@ Bool_t TGX11TTF::Init(void *display) /// then the rotation is applied on the alignment variables. /// SetRotation and LayoutGlyphs should have been called before. -void TGX11TTF::Align(void) +void TGX11TTF::Align(Int_t value) { - EAlign align = (EAlign) fTextAlign; + EAlign align = (EAlign) value; // vertical alignment if (align == kTLeft || align == kTCenter || align == kTRight) { @@ -372,8 +372,8 @@ void TGX11TTF::DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Fl TTF::SetRotationMatrix(angle); TTF::PrepareString(text); TTF::LayoutGlyphs(); - Align(); - RenderString(x, y, mode); + Align(GetTextAlignW(wctxt)); + RenderString(wctxt, x, y, mode); } } @@ -391,21 +391,21 @@ void TGX11TTF::DrawTextW(WinContext_t wctxt, Int_t x, Int_t y, Float_t angle, Fl TTF::SetRotationMatrix(angle); TTF::PrepareString(text); TTF::LayoutGlyphs(); - Align(); - RenderString(x, y, mode); + Align(GetTextAlignW(wctxt)); + RenderString(wctxt, x, y, mode); } } //////////////////////////////////////////////////////////////////////////////// /// Get the background of the current window in an XImage. -RXImage *TGX11TTF::GetBackground(Int_t x, Int_t y, UInt_t w, UInt_t h) +RXImage *TGX11TTF::GetBackground(WinContext_t wctxt, Int_t x, Int_t y, UInt_t w, UInt_t h) { - Window_t cws = GetCurrentWindow(); + Window_t cws = GetWindow(wctxt); UInt_t width; UInt_t height; Int_t xy; - gVirtualX->GetWindowSize(cws, xy, xy, width, height); + GetWindowSize(cws, xy, xy, width, height); if (x < 0) { w += x; @@ -419,32 +419,37 @@ RXImage *TGX11TTF::GetBackground(Int_t x, Int_t y, UInt_t w, UInt_t h) if (x+w > width) w = width - x; if (y+h > height) h = height - y; - return (RXImage*)XGetImage((Display*)fDisplay, cws, x, y, w, h, AllPlanes, ZPixmap); + return (RXImage *)XGetImage((Display*)fDisplay, cws, x, y, w, h, AllPlanes, ZPixmap); } //////////////////////////////////////////////////////////////////////////////// /// Test if there is really something to render. -Bool_t TGX11TTF::IsVisible(Int_t x, Int_t y, UInt_t w, UInt_t h) +Bool_t TGX11TTF::IsVisible(WinContext_t wctxt, Int_t x, Int_t y, UInt_t w, UInt_t h) { - Window_t cws = GetCurrentWindow(); + Window_t cws = GetWindow(wctxt); UInt_t width; UInt_t height; Int_t xy; - gVirtualX->GetWindowSize(cws, xy, xy, width, height); + GetWindowSize(cws, xy, xy, width, height); // If w or h is 0, very likely the string is only blank characters - if ((int)w == 0 || (int)h == 0) return kFALSE; + if ((int)w == 0 || (int)h == 0) + return kFALSE; // If string falls outside window, there is probably no need to draw it. - if (x + (int)w <= 0 || x >= (int)width) return kFALSE; - if (y + (int)h <= 0 || y >= (int)height) return kFALSE; + if (x + (int)w <= 0 || x >= (int)width) + return kFALSE; + if (y + (int)h <= 0 || y >= (int)height) + return kFALSE; // If w or h are much larger than the window size, there is probably no need // to draw it. Moreover a to large text size may produce a Seg Fault in // malloc in RenderString. - if (w > 10*width) return kFALSE; - if (h > 10*height) return kFALSE; + if (w > 10*width) + return kFALSE; + if (h > 10*height) + return kFALSE; return kTRUE; } @@ -453,7 +458,7 @@ Bool_t TGX11TTF::IsVisible(Int_t x, Int_t y, UInt_t w, UInt_t h) /// Perform the string rendering in the pad. /// LayoutGlyphs should have been called before. -void TGX11TTF::RenderString(Int_t x, Int_t y, ETextMode mode) +void TGX11TTF::RenderString(WinContext_t wctxt, Int_t x, Int_t y, ETextMode mode) { TTF::TTGlyph* glyph = TTF::fgGlyphs; @@ -465,7 +470,8 @@ void TGX11TTF::RenderString(Int_t x, Int_t y, ETextMode mode) Int_t x1 = x-Xoff-fAlign.x; Int_t y1 = y+Yoff+fAlign.y-h; - if (!IsVisible(x1, y1, w, h)) return; + if (!IsVisible(wctxt, x1, y1, w, h)) + return; // create the XImage that will contain the text UInt_t depth = fDepth; @@ -481,9 +487,9 @@ void TGX11TTF::RenderString(Int_t x, Int_t y, ETextMode mode) ULong_t bg; XGCValues values; - GC *gc = (GC*)GetGC(3); + auto gc = (GC *) GetGCW(wctxt, 3); if (!gc) { - Error("DrawText", "error getting Graphics Context"); + Error("RenderString", "error getting Graphics Context"); return; } XGetGCValues((Display*)fDisplay, *gc, GCForeground | GCBackground, &values); @@ -491,7 +497,7 @@ void TGX11TTF::RenderString(Int_t x, Int_t y, ETextMode mode) // get the background if (mode == kClear) { // if mode == kClear we need to get an image of the background - XImage *bim = GetBackground(x1, y1, w, h); + XImage *bim = GetBackground(wctxt, x1, y1, w, h); if (!bim) { Error("DrawText", "error getting background image"); return; @@ -533,9 +539,10 @@ void TGX11TTF::RenderString(Int_t x, Int_t y, ETextMode mode) } // put the Ximage on the screen - Window_t cws = GetCurrentWindow(); - gc = (GC*)GetGC(6); - if (gc) XPutImage((Display*)fDisplay, cws, *gc, xim, 0, 0, x1, y1, w, h); + Window_t cws = GetWindow(wctxt); + gc = (GC *) GetGCW(wctxt, 6); + if (gc) + XPutImage((Display*)fDisplay, cws, *gc, xim, 0, 0, x1, y1, w, h); XDestroyImage(xim); } From b0bf5d363474997493b286c077b6f9f7ec585089 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 13 Mar 2026 10:20:28 +0100 Subject: [PATCH 24/37] [padpainter] use new pad painter methods to set attributes Instead set individiual line or fill attributes use new methods with TAtt... object as instance. In TPadPainter it is redirected to selected window context So even if there are several canvases displayed - attributes will be modified in the correct window context. --- core/base/src/TAttFill.cxx | 6 ++---- core/base/src/TAttLine.cxx | 18 ++++++++++++++---- core/base/src/TAttMarker.cxx | 8 ++------ core/base/src/TAttText.cxx | 17 +++++++---------- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/core/base/src/TAttFill.cxx b/core/base/src/TAttFill.cxx index c639697e0e9eb..63ad01200416b 100644 --- a/core/base/src/TAttFill.cxx +++ b/core/base/src/TAttFill.cxx @@ -224,10 +224,8 @@ void TAttFill::Modify() void TAttFill::ModifyOn(TVirtualPad *pad) { auto pp = pad ? pad->GetPainter() : nullptr; - if (!pp) - return; - pp->SetFillColor(fFillColor); - pp->SetFillStyle(fFillStyle); + if (pp) + pp->SetAttFill(*this); } //////////////////////////////////////////////////////////////////////////////// diff --git a/core/base/src/TAttLine.cxx b/core/base/src/TAttLine.cxx index 23dae3e5c3386..bc7cd57fafaf0 100644 --- a/core/base/src/TAttLine.cxx +++ b/core/base/src/TAttLine.cxx @@ -256,11 +256,21 @@ void TAttLine::ModifyOn(TVirtualPad *pad) auto pp = pad ? pad->GetPainter() : nullptr; if (!pp) return; - pp->SetLineColor(fLineColor); - pp->SetLineStyle((fLineStyle > 0 && fLineStyle < 30) ? fLineStyle : 1); - pp->SetLineWidth(std::abs(fLineWidth % 100)); -} + Bool_t normal_style = (fLineStyle > 0) && (fLineStyle < 30); + Bool_t normal_width = (fLineWidth >= 0) && (fLineWidth < 100); + + if (normal_style && normal_width) + pp->SetAttLine(*this); + else { + TAttLine att1(*this); + if (!normal_style) + att1.SetLineStyle(1); + if (!normal_width) + att1.SetLineWidth(std::abs(fLineWidth % 100)); + pp->SetAttLine(att1); + } +} //////////////////////////////////////////////////////////////////////////////// /// Reset this line attributes to default values. diff --git a/core/base/src/TAttMarker.cxx b/core/base/src/TAttMarker.cxx index da84a7266dc22..66af8d9945685 100644 --- a/core/base/src/TAttMarker.cxx +++ b/core/base/src/TAttMarker.cxx @@ -330,12 +330,8 @@ void TAttMarker::Modify() void TAttMarker::ModifyOn(TVirtualPad *pad) { auto pp = pad ? pad->GetPainter() : nullptr; - if (!pp) - return; - - pp->SetMarkerColor(fMarkerColor); - pp->SetMarkerSize (fMarkerSize); - pp->SetMarkerStyle(fMarkerStyle); + if (pp) + pp->SetAttMarker(*this); } diff --git a/core/base/src/TAttText.cxx b/core/base/src/TAttText.cxx index 2aee8a5a5cd78..352654c70aac0 100644 --- a/core/base/src/TAttText.cxx +++ b/core/base/src/TAttText.cxx @@ -329,7 +329,6 @@ void TAttText::Modify() ModifyOn(gPad); } - //////////////////////////////////////////////////////////////////////////////// /// Change current text attributes if necessary on specified pad. @@ -339,6 +338,7 @@ void TAttText::ModifyOn(TVirtualPad *pad) if (!pp) return; + Float_t tsize0 = fTextSize; Float_t tsize = fTextSize; // there was difference in text size handling, keep it in one place @@ -362,15 +362,12 @@ void TAttText::ModifyOn(TVirtualPad *pad) } } } - pp->SetTextAngle(fTextAngle); - if (pp->GetTextFont() != fTextFont) { - pp->SetTextFont(fTextFont); - pp->SetTextSize(tsize); - } else if (pp->GetTextSize() != tsize) { - pp->SetTextSize(tsize); - } - pp->SetTextAlign(fTextAlign); - pp->SetTextColor(fTextColor); + + fTextSize = tsize; + + pp->SetAttText(*this); + + fTextSize = tsize0; } From 0716980b0b1936c7494782dc36d03c377db65f63 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 13 Mar 2026 11:24:36 +0100 Subject: [PATCH 25/37] [tgx11] implement several attributes getters While some objects painters analyze attributes like gVirtualX->GetLineWidth(), provide such getters. But only for transition phase - later one can dismiss methods again --- graf2d/x11/inc/TGX11.h | 3 +++ graf2d/x11/src/TGX11.cxx | 27 +++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/graf2d/x11/inc/TGX11.h b/graf2d/x11/inc/TGX11.h index 50696bff38d08..3123605593344 100644 --- a/graf2d/x11/inc/TGX11.h +++ b/graf2d/x11/inc/TGX11.h @@ -196,10 +196,13 @@ class TGX11 : public TVirtualX { //---- Methods used for old graphics ----- void SetFillColor(Color_t cindex) override; void SetFillStyle(Style_t style) override; + Style_t GetFillStyle() const override; void SetLineColor(Color_t cindex) override; void SetLineType(Int_t n, Int_t *dash) override; void SetLineStyle(Style_t linestyle) override; + Style_t GetLineStyle() const override; void SetLineWidth(Width_t width) override; + Width_t GetLineWidth() const override; void SetMarkerColor(Color_t cindex) override; void SetMarkerSize(Float_t markersize) override; void SetMarkerStyle(Style_t markerstyle) override; diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index 228a1cc161b1e..65f5999e9c3a7 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -2401,6 +2401,15 @@ void TGX11::SetFillStyle(Style_t fstyle) */ } +//////////////////////////////////////////////////////////////////////////////// +/// Return current fill style +/// FIXME: Only as temporary solution while some code analyze current fill style + +Style_t TGX11::GetFillStyle() const +{ + return gCws ? gCws->fAttFill.GetFillStyle() : TAttFill::GetFillStyle(); +} + //////////////////////////////////////////////////////////////////////////////// /// Set fill area style index. @@ -2559,6 +2568,15 @@ void TGX11::SetLineStyle(Style_t lstyle) */ } +//////////////////////////////////////////////////////////////////////////////// +/// Return current line style +/// FIXME: Only as temporary solution while some code analyze current line style + +Style_t TGX11::GetLineStyle() const +{ + return gCws ? gCws->fAttLine.GetLineStyle() : TAttLine::GetLineStyle(); +} + //////////////////////////////////////////////////////////////////////////////// /// Set line width. /// @@ -2587,6 +2605,15 @@ void TGX11::SetLineWidth(Width_t width) */ } +//////////////////////////////////////////////////////////////////////////////// +/// Return current line width +/// FIXME: Only as temporary solution while some code analyze current line wide + +Width_t TGX11::GetLineWidth() const +{ + return gCws ? gCws->fAttLine.GetLineWidth() : TAttLine::GetLineWidth(); +} + //////////////////////////////////////////////////////////////////////////////// /// Set color index for markers. From d84aa7cb2cf180cfd02e066bf9980640c1088217 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 13 Mar 2026 12:39:54 +0100 Subject: [PATCH 26/37] [pad painter] remember some attributes used in drawing line width and fill style used in drawing. While attributes set anyway via pad painter interface, just remember them to avoid need provide getters from TVirtualX --- graf2d/gpad/inc/TPadPainter.h | 2 ++ graf2d/gpad/src/TPadPainter.cxx | 36 +++++++++++++++++++++------------ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/graf2d/gpad/inc/TPadPainter.h b/graf2d/gpad/inc/TPadPainter.h index 58b9c9492f83c..01465e2c9a1db 100644 --- a/graf2d/gpad/inc/TPadPainter.h +++ b/graf2d/gpad/inc/TPadPainter.h @@ -26,6 +26,8 @@ class TVirtualPad; class TPadPainter : public TVirtualPadPainter { WinContext_t fWinContext; + Int_t fSetLineWidth = 0; ///< remember set width to optimize some painting + Style_t fSetFillStyle = 0; ///< remember set fill style to optimize painting public: TPadPainter(); diff --git a/graf2d/gpad/src/TPadPainter.cxx b/graf2d/gpad/src/TPadPainter.cxx index e5c89ccaac2bc..59eab6f395dbe 100644 --- a/graf2d/gpad/src/TPadPainter.cxx +++ b/graf2d/gpad/src/TPadPainter.cxx @@ -47,7 +47,7 @@ void ConvertPointsAndMergePassX(TVirtualPad *pad, unsigned nPoints, const T *x, void ConvertPointsAndMergeInplacePassY(std::vector &dst); template -void DrawFillAreaAux(TVirtualPad *pad, WinContext_t cont, Int_t nPoints, const T *xs, const T *ys); +void DrawFillAreaAux(TVirtualPad *pad, WinContext_t cont, Int_t nPoints, const T *xs, const T *ys, Bool_t close_path); template void DrawPolyLineAux(TVirtualPad *pad, WinContext_t cont, unsigned nPoints, const T *xs, const T *ys); @@ -132,6 +132,7 @@ void TPadPainter::SetLineStyle(Style_t lstyle) void TPadPainter::SetLineWidth(Width_t lwidth) { + fSetLineWidth = lwidth; gVirtualX->SetLineWidth(lwidth); } @@ -178,6 +179,7 @@ void TPadPainter::SetFillColor(Color_t fcolor) void TPadPainter::SetFillStyle(Style_t fstyle) { + fSetFillStyle = fstyle; gVirtualX->SetFillStyle(fstyle); } @@ -430,6 +432,7 @@ void TPadPainter::DrawPixels(const unsigned char * /*pixelData*/, UInt_t /*width void TPadPainter::SetAttFill(const TAttFill &att) { + fSetFillStyle = att.GetFillStyle(); gVirtualX->SetAttFill(fWinContext, att); } @@ -438,6 +441,7 @@ void TPadPainter::SetAttFill(const TAttFill &att) void TPadPainter::SetAttLine(const TAttLine &att) { + fSetLineWidth = att.GetLineWidth(); gVirtualX->SetAttLine(fWinContext, att); } @@ -462,7 +466,8 @@ void TPadPainter::SetAttText(const TAttText &att) void TPadPainter::DrawLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2) { - if (GetLineWidth()<=0) return; + if (fSetLineWidth <= 0) + return; const Int_t px1 = gPad->XtoPixel(x1); const Int_t px2 = gPad->XtoPixel(x2); @@ -477,7 +482,8 @@ void TPadPainter::DrawLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2) void TPadPainter::DrawLineNDC(Double_t u1, Double_t v1, Double_t u2, Double_t v2) { - if (GetLineWidth()<=0) return; + if (fSetLineWidth <= 0) + return; const Int_t px1 = gPad->UtoPixel(u1); const Int_t py1 = gPad->VtoPixel(v1); @@ -492,7 +498,8 @@ void TPadPainter::DrawLineNDC(Double_t u1, Double_t v1, Double_t u2, Double_t v2 void TPadPainter::DrawBox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, EBoxMode mode) { - if (GetLineWidth()<=0 && mode == TVirtualPadPainter::kHollow) return; + if (fSetLineWidth <= 0 && mode == TVirtualPadPainter::kHollow) + return; Int_t px1 = gPad->XtoPixel(x1); Int_t px2 = gPad->XtoPixel(x2); @@ -518,7 +525,7 @@ void TPadPainter::DrawFillArea(Int_t nPoints, const Double_t *xs, const Double_t return; } - DrawFillAreaAux(gPad, fWinContext, nPoints, xs, ys); + DrawFillAreaAux(gPad, fWinContext, nPoints, xs, ys, fSetFillStyle == 0); } @@ -532,7 +539,7 @@ void TPadPainter::DrawFillArea(Int_t nPoints, const Float_t *xs, const Float_t * return; } - DrawFillAreaAux(gPad, fWinContext, nPoints, xs, ys); + DrawFillAreaAux(gPad, fWinContext, nPoints, xs, ys, fSetFillStyle == 0); } //////////////////////////////////////////////////////////////////////////////// @@ -540,7 +547,8 @@ void TPadPainter::DrawFillArea(Int_t nPoints, const Float_t *xs, const Float_t * void TPadPainter::DrawPolyLine(Int_t n, const Double_t *xs, const Double_t *ys) { - if (GetLineWidth()<=0) return; + if (fSetLineWidth <= 0) + return; if (n < 2) { ::Error("TPadPainter::DrawPolyLine", "invalid number of points"); @@ -556,7 +564,8 @@ void TPadPainter::DrawPolyLine(Int_t n, const Double_t *xs, const Double_t *ys) void TPadPainter::DrawPolyLine(Int_t n, const Float_t *xs, const Float_t *ys) { - if (GetLineWidth()<=0) return; + if (fSetLineWidth <= 0) + return; if (n < 2) { ::Error("TPadPainter::DrawPolyLine", "invalid number of points"); @@ -572,7 +581,8 @@ void TPadPainter::DrawPolyLine(Int_t n, const Float_t *xs, const Float_t *ys) void TPadPainter::DrawPolyLineNDC(Int_t n, const Double_t *u, const Double_t *v) { - if (GetLineWidth()<=0) return; + if (fSetLineWidth <= 0) + return; if (n < 2) { ::Error("TPadPainter::DrawPolyLineNDC", "invalid number of points %d", n); @@ -594,7 +604,7 @@ void TPadPainter::DrawPolyLineNDC(Int_t n, const Double_t *u, const Double_t *v) void TPadPainter::DrawSegments(Int_t n, Double_t *x, Double_t *y) { - if (GetLineWidth() <= 0) + if (fSetLineWidth <= 0) return; if (n < 1) { @@ -625,7 +635,7 @@ void TPadPainter::DrawSegments(Int_t n, Double_t *x, Double_t *y) void TPadPainter::DrawSegmentsNDC(Int_t n, Double_t *u, Double_t *v) { - if (GetLineWidth() <= 0) + if (fSetLineWidth <= 0) return; if (n < 1) { @@ -995,7 +1005,7 @@ void ConvertPointsAndMerge(TVirtualPad *pad, unsigned threshold, unsigned nPoint //////////////////////////////////////////////////////////////////////////////// template -void DrawFillAreaAux(TVirtualPad *pad, WinContext_t cont, Int_t nPoints, const T *xs, const T *ys) +void DrawFillAreaAux(TVirtualPad *pad, WinContext_t cont, Int_t nPoints, const T *xs, const T *ys, Bool_t close_path) { std::vector xy; @@ -1014,7 +1024,7 @@ void DrawFillAreaAux(TVirtualPad *pad, WinContext_t cont, Int_t nPoints, const T ConvertPointsAndMerge(pad, threshold, nPoints, xs, ys, xy); //We close the 'polygon' and it'll be rendered as a polyline by gVirtualX. - if (!gVirtualX->GetFillStyle()) + if (close_path) xy.push_back(xy.front()); if (xy.size() > 2) From e9c0a768233abc1bbf055eeddea5682c1546c233 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Fri, 13 Mar 2026 12:40:36 +0100 Subject: [PATCH 27/37] [x11] rename method to SetDrawModeW To avoid complication with derived classes --- core/base/inc/TVirtualX.h | 2 +- core/base/src/TVirtualX.cxx | 2 +- graf2d/x11/inc/TGX11.h | 2 +- graf2d/x11/src/TGX11.cxx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/base/inc/TVirtualX.h b/core/base/inc/TVirtualX.h index 76f84f4b3da24..c59de994b8bd8 100644 --- a/core/base/inc/TVirtualX.h +++ b/core/base/inc/TVirtualX.h @@ -108,7 +108,7 @@ class TVirtualX : public TNamed, public TAttLine, public TAttFill, public TAttTe virtual void SetAttLine(WinContext_t wctxt, const TAttLine &att); virtual void SetAttMarker(WinContext_t wctxt, const TAttMarker &att); virtual void SetAttText(WinContext_t wctxt, const TAttText &att); - virtual void SetDrawMode(WinContext_t wctxt, EDrawMode mode); + virtual void SetDrawModeW(WinContext_t wctxt, EDrawMode mode); virtual void DrawBoxW(WinContext_t wctxt, Int_t x1, Int_t y1, Int_t x2, Int_t y2, EBoxMode mode); virtual void DrawFillAreaW(WinContext_t wctxt, Int_t n, TPoint *xy); diff --git a/core/base/src/TVirtualX.cxx b/core/base/src/TVirtualX.cxx index d9c412dba2980..1b9cbe1d8f912 100644 --- a/core/base/src/TVirtualX.cxx +++ b/core/base/src/TVirtualX.cxx @@ -431,7 +431,7 @@ void TVirtualX::SetAttText(WinContext_t /* wctxt */, const TAttText &att) //////////////////////////////////////////////////////////////////////////////// /// Set window draw mode -void TVirtualX::SetDrawMode(WinContext_t /* wctxt */, EDrawMode mode) +void TVirtualX::SetDrawModeW(WinContext_t /* wctxt */, EDrawMode mode) { SetDrawMode(mode); } diff --git a/graf2d/x11/inc/TGX11.h b/graf2d/x11/inc/TGX11.h index 3123605593344..6285101f43f12 100644 --- a/graf2d/x11/inc/TGX11.h +++ b/graf2d/x11/inc/TGX11.h @@ -230,7 +230,7 @@ class TGX11 : public TVirtualX { void SetAttLine(WinContext_t wctxt, const TAttLine &att) override; void SetAttMarker(WinContext_t wctxt, const TAttMarker &att) override; void SetAttText(WinContext_t wctxt, const TAttText &att) override; - void SetDrawMode(WinContext_t wctxt, EDrawMode mode) override; + void SetDrawModeW(WinContext_t wctxt, EDrawMode mode) override; void DrawBoxW(WinContext_t wctxt, Int_t x1, Int_t y1, Int_t x2, Int_t y2, EBoxMode mode) override; void DrawFillAreaW(WinContext_t wctxt, Int_t n, TPoint *xy) override; diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index 65f5999e9c3a7..2dca7717ad833 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -4624,7 +4624,7 @@ void TGX11::SetAttText(WinContext_t wctxt, const TAttText &att) } -void TGX11::SetDrawMode(WinContext_t wctxt, EDrawMode mode) +void TGX11::SetDrawModeW(WinContext_t wctxt, EDrawMode mode) { auto ctxt = (XWindow_t *) wctxt; if (!ctxt) From 2946f76e4e547826c15c3c8d92dffca9fa04dbc6 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 17 Mar 2026 08:36:31 +0100 Subject: [PATCH 28/37] [pad painter] provide direct access to PS pointer For some special applications like TASImage provide access to PS instance from pad painter. So one do not need to duplicate interface several times. --- core/base/inc/TVirtualPadPainter.h | 2 ++ graf2d/gpad/inc/TPadPainterPS.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/core/base/inc/TVirtualPadPainter.h b/core/base/inc/TVirtualPadPainter.h index 93e507397b609..dcfb518b3d12b 100644 --- a/core/base/inc/TVirtualPadPainter.h +++ b/core/base/inc/TVirtualPadPainter.h @@ -15,6 +15,7 @@ #include "Rtypes.h" class TVirtualPad; +class TVirtualPS; class TAttFill; class TAttLine; class TAttMarker; @@ -136,6 +137,7 @@ class TVirtualPadPainter { virtual Bool_t IsNative() const { return kFALSE; } virtual Bool_t IsCocoa() const { return kFALSE; } + virtual TVirtualPS *GetPS() const { return nullptr; } static TVirtualPadPainter *PadPainter(Option_t *opt = ""); diff --git a/graf2d/gpad/inc/TPadPainterPS.h b/graf2d/gpad/inc/TPadPainterPS.h index 1a463af1ff214..9a37ec658d9ab 100644 --- a/graf2d/gpad/inc/TPadPainterPS.h +++ b/graf2d/gpad/inc/TPadPainterPS.h @@ -121,6 +121,9 @@ class TPadPainterPS : public TVirtualPadPainter { void OnPad(TVirtualPad *pad) override { fPad = pad; } + TVirtualPS *GetPS() const override { return fPS; } + + private: //Let's make this clear: TPadPainterPS(const TPadPainterPS &) = delete; From 1ced44e4824a06c1730e4b7059ba36b1c73b831b Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 17 Mar 2026 08:38:31 +0100 Subject: [PATCH 29/37] [pad painter] use PS directly in ASImage --- graf2d/asimage/src/TASImage.cxx | 53 +++++++++++++++++---------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/graf2d/asimage/src/TASImage.cxx b/graf2d/asimage/src/TASImage.cxx index 6ea60a788019f..b35bcb14f81c1 100644 --- a/graf2d/asimage/src/TASImage.cxx +++ b/graf2d/asimage/src/TASImage.cxx @@ -1534,7 +1534,9 @@ void TASImage::Paint(Option_t *option) int tox = expand ? 0 : int(gPad->UtoPixel(1.) * gPad->GetLeftMargin()); int toy = expand ? 0 : int(gPad->VtoPixel(0.) * gPad->GetTopMargin()); - if (!gROOT->IsBatch()) { + auto ps = gPad->GetPainter()->GetPS(); + + if (!ps) { Window_t wid = (Window_t)gVirtualX->GetWindowID(gPad->GetPixmapID()); Image2Drawable(fScaledImage ? fScaledImage->fImage : fImage, wid, tox, toy); @@ -1559,15 +1561,13 @@ void TASImage::Paint(Option_t *option) pal_Xpos, gPad->AbsPixeltoY(pal_Ay + 1), min, max, ndiv, "+L"); } - } - - // loop over pixmap and draw image to PostScript - if (gVirtualPS) { + } else { + // loop over pixmap and draw image to PostScript Bool_t paint_as_png = kFALSE; - if (gVirtualPS->InheritsFrom("TImageDump")) { // PostScript is asimage - TImage *dump = (TImage *)gVirtualPS->GetStream(); + if (ps->InheritsFrom("TImageDump")) { // PostScript is asimage + TImage *dump = (TImage *)ps->GetStream(); if (!dump) return; dump->Merge(fScaledImage ? fScaledImage : this, "alphablend", gPad->XtoAbsPixel(0), gPad->YtoAbsPixel(1)); @@ -1589,15 +1589,15 @@ void TASImage::Paint(Option_t *option) min, max, ndiv, "+L"); } return; - } else if (gVirtualPS->InheritsFrom("TPDF")) { + } else if (ps->InheritsFrom("TPDF")) { Warning("Paint", "PDF not implemented yet"); return; - } else if (gVirtualPS->InheritsFrom("TSVG")) { + } else if (ps->InheritsFrom("TSVG")) { paint_as_png = kTRUE; } - Double_t dx = gPad->GetX2()-gPad->GetX1(); - Double_t dy = gPad->GetY2()-gPad->GetY1(); + Double_t dx = gPad->GetX2() - gPad->GetX1(); + Double_t dy = gPad->GetY2() - gPad->GetY1(); Double_t x1, x2, y1, y2; if (expand) { @@ -1613,10 +1613,10 @@ void TASImage::Paint(Option_t *option) } // get special color cell to be reused during image printing - gVirtualPS->SetFillColor(TColor::GetColor((Float_t) 1., (Float_t) 1., (Float_t) 1.)); - gVirtualPS->SetFillStyle(1001); + ps->SetFillColor(TColor::GetColor((Float_t) 1., (Float_t) 1., (Float_t) 1.)); + ps->SetFillStyle(1001); - gVirtualPS->CellArrayBegin(image->width, image->height, x1, x2, y1, y2); + ps->CellArrayBegin(image->width, image->height, x1, x2, y1, y2); if (paint_as_png) { char *buffer = nullptr; @@ -1628,7 +1628,7 @@ void TASImage::Paint(Option_t *option) if (!params.png.compression) params.png.compression = -1; if (ASImage2PNGBuff(image, (CARD8 **)&buffer, &size, ¶ms)) { - gVirtualPS->CellArrayPng(buffer, size); + ps->CellArrayPng(buffer, size); free(buffer); } } else { @@ -1638,13 +1638,13 @@ void TASImage::Paint(Option_t *option) for (Int_t yt = 0; yt < (Int_t)image->height; yt++) { imdec->decode_image_scanline(imdec); for (Int_t xt = 0; xt < (Int_t)image->width; xt++) - gVirtualPS->CellArrayFill(imdec->buffer.red[xt], - imdec->buffer.green[xt], - imdec->buffer.blue[xt]); + ps->CellArrayFill(imdec->buffer.red[xt], + imdec->buffer.green[xt], + imdec->buffer.blue[xt]); } stop_image_decoding(&imdec); } - gVirtualPS->CellArrayEnd(); + ps->CellArrayEnd(); // print the color bar if (grad_im) { @@ -1654,8 +1654,8 @@ void TASImage::Paint(Option_t *option) x2 = x1 + xconv; y2 = gPad->AbsPixeltoY(pal_Ay); y1 = y2 - yconv; - gVirtualPS->CellArrayBegin(grad_im->width, grad_im->height, - x1, x2, y1, y2); + ps->CellArrayBegin(grad_im->width, grad_im->height, + x1, x2, y1, y2); if (paint_as_png) { char *buffer = nullptr; @@ -1668,7 +1668,7 @@ void TASImage::Paint(Option_t *option) params.png.compression = -1; if (ASImage2PNGBuff(grad_im, (CARD8 **)&buffer, &size, ¶ms)) { - gVirtualPS->CellArrayPng(buffer, size); + ps->CellArrayPng(buffer, size); free(buffer); } } else { @@ -1678,13 +1678,13 @@ void TASImage::Paint(Option_t *option) for (Int_t yt = 0; yt < (Int_t)grad_im->height; yt++) { imdec->decode_image_scanline(imdec); for (Int_t xt = 0; xt < (Int_t)grad_im->width; xt++) - gVirtualPS->CellArrayFill(imdec->buffer.red[xt], - imdec->buffer.green[xt], - imdec->buffer.blue[xt]); + ps->CellArrayFill(imdec->buffer.red[xt], + imdec->buffer.green[xt], + imdec->buffer.blue[xt]); } stop_image_decoding(&imdec); } - gVirtualPS->CellArrayEnd(); + ps->CellArrayEnd(); // values of palette TGaxis axis; @@ -1693,6 +1693,7 @@ void TASImage::Paint(Option_t *option) double max = fMaxValue; axis.SetLineColor(1); // draw black ticks Double_t pal_Xpos = gPad->AbsPixeltoX(pal_Ax + pal_w); + // TODO: provide PaintAxisOn method axis.PaintAxis(pal_Xpos, gPad->AbsPixeltoY(pal_Ay + pal_h), pal_Xpos, gPad->AbsPixeltoY(pal_Ay + 1), min, max, ndiv, "+L"); From 93a9d53f7da9cf23650130f51f1a5d3b6dcdd94a Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 17 Mar 2026 08:44:11 +0100 Subject: [PATCH 30/37] [pad painter] use in TArrow Instead of gVirtualX or gVirtualPS use pad painter instance --- graf2d/graf/src/TArrow.cxx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/graf2d/graf/src/TArrow.cxx b/graf2d/graf/src/TArrow.cxx index 1138b1d35d5b7..b9f2ff414943f 100644 --- a/graf2d/graf/src/TArrow.cxx +++ b/graf2d/graf/src/TArrow.cxx @@ -13,8 +13,7 @@ #include "TMath.h" #include "TArrow.h" #include "TVirtualPad.h" -#include "TVirtualPS.h" -#include "TVirtualX.h" +#include "TVirtualPadPainter.h" Float_t TArrow::fgDefaultAngle = 60; Float_t TArrow::fgDefaultArrowSize = 0.05; @@ -296,8 +295,7 @@ void TArrow::PaintArrow(Double_t x1, Double_t y1, Double_t x2, Double_t y2, y2ar[i] = (1/ry)*(y2ar[i]-y1ndc)+ry1; } if (opt.Contains("|>")) { - if (gVirtualX) gVirtualX->SetLineStyle(1); - if (gVirtualPS) gVirtualPS->SetLineStyle(1); + gPad->GetPainter()->SetLineStyle(1); if (GetFillColor()) { gPad->PaintFillArea(3,x2ar,y2ar); gPad->PaintPolyLine(4,x2ar,y2ar); @@ -326,8 +324,7 @@ void TArrow::PaintArrow(Double_t x1, Double_t y1, Double_t x2, Double_t y2, y1ar[i] = (1/ry)*(y1ar[i]-y1ndc)+ry1; } if (opt.Contains("<|")) { - if (gVirtualX) gVirtualX->SetLineStyle(1); - if (gVirtualPS) gVirtualPS->SetLineStyle(1); + gPad->GetPainter()->SetLineStyle(1); if (GetFillColor()) { gPad->PaintFillArea(3,x1ar,y1ar); gPad->PaintPolyLine(4,x1ar,y1ar); From a29c3616da1be5c10945c7b17e61301db92c1c5e Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 17 Mar 2026 09:41:00 +0100 Subject: [PATCH 31/37] [pad painter] use in TLatex and TMathText Use pad painter for exclusive text drawing on screen or on PS device. In rare cases provide special handling of PS output (like tilde). --- graf2d/graf/src/TLatex.cxx | 223 ++++++++++++++++------------------ graf2d/graf/src/TMathText.cxx | 15 +-- 2 files changed, 106 insertions(+), 132 deletions(-) diff --git a/graf2d/graf/src/TLatex.cxx b/graf2d/graf/src/TLatex.cxx index 5156438c6ae61..a7c9a691adb5c 100644 --- a/graf2d/graf/src/TLatex.cxx +++ b/graf2d/graf/src/TLatex.cxx @@ -15,8 +15,8 @@ #include "TMathText.h" #include "TMath.h" #include "TVirtualPad.h" +#include "TVirtualPadPainter.h" #include "TVirtualPS.h" -#include "TVirtualX.h" #include "snprintf.h" const Double_t kPI = TMath::Pi(); @@ -1357,13 +1357,13 @@ TLatex::TLatexFormSize TLatex::Analyse(Double_t x, Double_t y, const TextSpec_t result = fs1+fs2; } - else if (opSpec>-1) { + else if (opSpec > -1) { TextSpec_t newSpec = spec; newSpec.fFont = fItalic ? 152 : 122; char letter = '\243' + opSpec; if(opSpec == 75 || opSpec == 76) { newSpec.fFont = GetTextFont(); - if (gVirtualX->InheritsFrom("TGCocoa")) { + if (gPad->GetPainter()->IsCocoa()) { if (opSpec == 75) letter = '\201'; // AA Angstroem if (opSpec == 76) letter = '\214'; // aa Angstroem } else { @@ -1491,25 +1491,26 @@ TLatex::TLatexFormSize TLatex::Analyse(Double_t x, Double_t y, const TextSpec_t Double_t x2 = x+fs1.Width()/2, y2 = y -fs1.Over(); // tilde must be drawn separately on screen and on PostScript // because an adjustment is required along Y for PostScript. - TVirtualPS *saveps = gVirtualPS; - if (gVirtualPS) gVirtualPS = nullptr; - Double_t y22 = y2; - if (gVirtualX->InheritsFrom("TGCocoa")) y2 -= 4.7*sub; + Double_t xx, yy; - Rotate(gPad, spec.fAngle, x2, y2, xx, yy); - TText tilde; - tilde.SetTextFont(fTextFont); - tilde.SetTextColor(spec.fColor); - tilde.SetTextSize(0.9*spec.fSize); - tilde.SetTextAlign(22); - tilde.SetTextAngle(fTextAngle); - tilde.PaintText(xx,yy,"~"); - if (saveps) { - gVirtualPS = saveps; - if (!strstr(gVirtualPS->GetTitle(),"IMG")) y22 -= 4*sub; - Rotate(gPad, spec.fAngle, x2, y22, xx, yy); - gVirtualPS->SetTextAlign(22); - gVirtualPS->Text(xx, yy, "~"); + if (auto ps = gPad->GetPainter()->GetPS()) { + if (!strstr(ps->GetTitle(), "IMG")) + y2 -= 4*sub; + Rotate(gPad, spec.fAngle, x2, y2, xx, yy); + ps->SetTextAlign(22); + ps->Text(xx, yy, "~"); + } else { + if (gPad->GetPainter()->IsCocoa()) + y2 -= 4.7*sub; + Rotate(gPad, spec.fAngle, x2, y2, xx, yy); + // TODO: use pad painter SetAttText and DrawText directly + TText tilde; + tilde.SetTextFont(fTextFont); + tilde.SetTextColor(spec.fColor); + tilde.SetTextSize(0.9*spec.fSize); + tilde.SetTextAlign(22); + tilde.SetTextAngle(fTextAngle); + tilde.PaintText(xx,yy,"~"); } break; } @@ -2150,88 +2151,76 @@ void TLatex::PaintLatex(Double_t x, Double_t y, Double_t angle, Double_t size, c TAttText::Modify(); // Change text attributes only if necessary. - TVirtualPS *saveps = gVirtualPS; - - if (gVirtualPS) { - if (gVirtualPS->InheritsFrom("TTeXDump")) { - gVirtualPS->SetTextAngle(angle); - TString t(text1); - if (t.Index("#")>=0 || t.Index("^")>=0 || t.Index("\\")>=0) { - t.ReplaceAll("#LT","\\langle"); - t.ReplaceAll("#GT","\\rangle"); - t.ReplaceAll("#club","\\clubsuit"); - t.ReplaceAll("#spade","\\spadesuit"); - t.ReplaceAll("#heart","\\heartsuit"); - t.ReplaceAll("#diamond","\\diamondsuit"); - t.ReplaceAll("#voidn","\\wp"); - t.ReplaceAll("#voidb","f"); - t.ReplaceAll("#ocopyright","\\copyright"); - t.ReplaceAll("#trademark","TM"); - t.ReplaceAll("#void3","TM"); - t.ReplaceAll("#oright","R"); - t.ReplaceAll("#void1","R"); - t.ReplaceAll("#3dots","\\ldots"); - t.ReplaceAll("#lbar","\\mid"); - t.ReplaceAll("#bar","\\wwbar"); - t.ReplaceAll("#void8","\\mid"); - t.ReplaceAll("#divide","\\div"); - t.ReplaceAll("#Jgothic","\\Im"); - t.ReplaceAll("#Rgothic","\\Re"); - t.ReplaceAll("#doublequote","\""); - t.ReplaceAll("#plus","+"); - t.ReplaceAll("#minus","-"); - t.ReplaceAll("#/","/"); - t.ReplaceAll("#upoint","."); - t.ReplaceAll("#aa","\\mbox{\\aa}"); - t.ReplaceAll("#AA","\\mbox{\\AA}"); - - t.ReplaceAll("#omicron","o"); - t.ReplaceAll("#Alpha","A"); - t.ReplaceAll("#Beta","B"); - t.ReplaceAll("#Epsilon","E"); - t.ReplaceAll("#Zeta","Z"); - t.ReplaceAll("#Eta","H"); - t.ReplaceAll("#Iota","I"); - t.ReplaceAll("#Kappa","K"); - t.ReplaceAll("#Mu","M"); - t.ReplaceAll("#Nu","N"); - t.ReplaceAll("#Omicron","O"); - t.ReplaceAll("#Rho","P"); - t.ReplaceAll("#Tau","T"); - t.ReplaceAll("#Chi","X"); - t.ReplaceAll("#varomega","\\varpi"); - - t.ReplaceAll("#varUpsilon","?"); - t.ReplaceAll("#corner","?"); - t.ReplaceAll("#ltbar","?"); - t.ReplaceAll("#bottombar","?"); - t.ReplaceAll("#notsubset","?"); - t.ReplaceAll("#arcbottom","?"); - t.ReplaceAll("#cbar","?"); - t.ReplaceAll("#arctop","?"); - t.ReplaceAll("#topbar","?"); - t.ReplaceAll("#arcbar","?"); - t.ReplaceAll("#downleftarrow","?"); - t.ReplaceAll("#splitline","\\genfrac{}{}{0pt}{}"); - - t.ReplaceAll("#","\\"); - t.ReplaceAll("%","\\%"); - } - gVirtualPS->Text(x,y,t.Data()); - } else { - Bool_t saveb = gPad->IsBatch(); - gPad->SetBatch(kTRUE); - if (!PaintLatex1( x, y, angle, size, text1)) { - if (saveps) gVirtualPS = saveps; - return; - } - gPad->SetBatch(saveb); - } - gVirtualPS = nullptr; + auto ps = gPad->GetPainter()->GetPS(); + + if (ps && ps->InheritsFrom("TTeXDump")) { + TString t(text1); + if (t.Index("#")>=0 || t.Index("^")>=0 || t.Index("\\")>=0) { + t.ReplaceAll("#LT","\\langle"); + t.ReplaceAll("#GT","\\rangle"); + t.ReplaceAll("#club","\\clubsuit"); + t.ReplaceAll("#spade","\\spadesuit"); + t.ReplaceAll("#heart","\\heartsuit"); + t.ReplaceAll("#diamond","\\diamondsuit"); + t.ReplaceAll("#voidn","\\wp"); + t.ReplaceAll("#voidb","f"); + t.ReplaceAll("#ocopyright","\\copyright"); + t.ReplaceAll("#trademark","TM"); + t.ReplaceAll("#void3","TM"); + t.ReplaceAll("#oright","R"); + t.ReplaceAll("#void1","R"); + t.ReplaceAll("#3dots","\\ldots"); + t.ReplaceAll("#lbar","\\mid"); + t.ReplaceAll("#bar","\\wwbar"); + t.ReplaceAll("#void8","\\mid"); + t.ReplaceAll("#divide","\\div"); + t.ReplaceAll("#Jgothic","\\Im"); + t.ReplaceAll("#Rgothic","\\Re"); + t.ReplaceAll("#doublequote","\""); + t.ReplaceAll("#plus","+"); + t.ReplaceAll("#minus","-"); + t.ReplaceAll("#/","/"); + t.ReplaceAll("#upoint","."); + t.ReplaceAll("#aa","\\mbox{\\aa}"); + t.ReplaceAll("#AA","\\mbox{\\AA}"); + + t.ReplaceAll("#omicron","o"); + t.ReplaceAll("#Alpha","A"); + t.ReplaceAll("#Beta","B"); + t.ReplaceAll("#Epsilon","E"); + t.ReplaceAll("#Zeta","Z"); + t.ReplaceAll("#Eta","H"); + t.ReplaceAll("#Iota","I"); + t.ReplaceAll("#Kappa","K"); + t.ReplaceAll("#Mu","M"); + t.ReplaceAll("#Nu","N"); + t.ReplaceAll("#Omicron","O"); + t.ReplaceAll("#Rho","P"); + t.ReplaceAll("#Tau","T"); + t.ReplaceAll("#Chi","X"); + t.ReplaceAll("#varomega","\\varpi"); + + t.ReplaceAll("#varUpsilon","?"); + t.ReplaceAll("#corner","?"); + t.ReplaceAll("#ltbar","?"); + t.ReplaceAll("#bottombar","?"); + t.ReplaceAll("#notsubset","?"); + t.ReplaceAll("#arcbottom","?"); + t.ReplaceAll("#cbar","?"); + t.ReplaceAll("#arctop","?"); + t.ReplaceAll("#topbar","?"); + t.ReplaceAll("#arcbar","?"); + t.ReplaceAll("#downleftarrow","?"); + t.ReplaceAll("#splitline","\\genfrac{}{}{0pt}{}"); + + t.ReplaceAll("#","\\"); + t.ReplaceAll("%","\\%"); + } + ps->SetTextAngle(angle); + ps->Text(x, y, t.Data()); + } else { + PaintLatex1(x, y, angle, size, text1); } - - if (!gPad->IsBatch()) PaintLatex1( x, y, angle, size, text1); - if (saveps) gVirtualPS = saveps; } //////////////////////////////////////////////////////////////////////////////// @@ -2255,30 +2244,23 @@ Int_t TLatex::PaintLatex1(Double_t x, Double_t y, Double_t angle, Double_t size, // Do not use Latex if font is low precision. if (fTextFont % 10 < 2) { - if (gVirtualX) gVirtualX->SetTextAngle(angle); - if (gVirtualPS) gVirtualPS->SetTextAngle(angle); - gPad->PaintText(x,y,text1); + gPad->GetPainter()->SetTextAngle(angle); + gPad->PaintText(x, y, text1); return 1; } - Bool_t saveb = gPad->IsBatch(); // Paint the text using TMathText if contains a "\" if (strstr(text1,"\\")) { - TMathText tm; - tm.SetTextAlign(GetTextAlign()); - tm.SetTextFont(GetTextFont()); - tm.SetTextColor(GetTextColor()); - tm.PaintMathText(x, y, angle, size, text1); - // If PDF, paint using TLatex - if (gVirtualPS) { - if (gVirtualPS->InheritsFrom("TPDF") || - gVirtualPS->InheritsFrom("TSVG")) { - newText.ReplaceAll("\\","#"); - gPad->SetBatch(kTRUE); - } else { - return 1; - } + auto ps = gPad->GetPainter()->GetPS(); + // If PDF or SVG, paint using TLatex + if (ps && (ps->InheritsFrom("TPDF") || ps->InheritsFrom("TSVG"))) { + newText.ReplaceAll("\\","#"); } else { + TMathText tm; + tm.SetTextAlign(GetTextAlign()); + tm.SetTextFont(GetTextFont()); + tm.SetTextColor(GetTextColor()); + tm.PaintMathText(x, y, angle, size, text1); return 1; } } @@ -2334,7 +2316,6 @@ Int_t TLatex::PaintLatex1(Double_t x, Double_t y, Double_t angle, Double_t size, Analyse(x,y,newSpec,text,length); } - gPad->SetBatch(saveb); SetTextSize(saveSize); SetTextAngle(angle); SetTextFont(saveFont); diff --git a/graf2d/graf/src/TMathText.cxx b/graf2d/graf/src/TMathText.cxx index e907f7eb511ff..db37252c02cbc 100644 --- a/graf2d/graf/src/TMathText.cxx +++ b/graf2d/graf/src/TMathText.cxx @@ -18,8 +18,8 @@ #include "TMathText.h" #include "TMath.h" #include "TVirtualPad.h" +#include "TVirtualPadPainter.h" #include "TVirtualPS.h" -#include "TVirtualX.h" #include "TText.h" #include "../../../graf2d/mathtext/inc/mathtext.h" @@ -583,20 +583,13 @@ void TMathText::PaintMathText(Double_t x, Double_t y, Double_t angle, Short_t saveAlign = fTextAlign; TAttText::Modify(); - if (gVirtualPS) { // Initialise TMathTextRenderer - if (gPad->IsBatch()) { - if (gVirtualPS->InheritsFrom("TImageDump")) gPad->PaintText(0, 0, ""); - } + if (auto ps = gPad->GetPainter()->GetPS()) { // Initialise TMathTextRenderer + if (ps->InheritsFrom("TImageDump")) gPad->PaintText(0, 0, ""); } // Do not use Latex if font is low precision. if (fTextFont % 10 < 2) { - if (gVirtualX) { - gVirtualX->SetTextAngle(angle); - } - if (gVirtualPS) { - gVirtualPS->SetTextAngle(angle); - } + gPad->GetPainter()->SetTextAngle(angle); gPad->PaintText(x, y, text1); return; } From ccabda1d3a3d4e71c353e0c91ea776a4820263e4 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 17 Mar 2026 10:22:39 +0100 Subject: [PATCH 32/37] [ps] let create ps pad painter in non batch mode --- graf2d/gpad/src/TCanvas.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graf2d/gpad/src/TCanvas.cxx b/graf2d/gpad/src/TCanvas.cxx index 2164222d104f9..3f4896031cfd8 100644 --- a/graf2d/gpad/src/TCanvas.cxx +++ b/graf2d/gpad/src/TCanvas.cxx @@ -2630,7 +2630,7 @@ Bool_t TCanvas::EnsurePSPainter(Bool_t create, TVirtualPadPainter *&oldp) return kFALSE; } - if (!gVirtualPS || !IsBatch()) + if (!gVirtualPS /* || !IsBatch() */) return kFALSE; From 0d9081e6c29335b1e7d8c2aee3c75c0b807894cf Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 17 Mar 2026 11:11:01 +0100 Subject: [PATCH 33/37] [gl painter] now text align is identical on both platforms --- graf3d/gl/src/TGLFontManager.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graf3d/gl/src/TGLFontManager.cxx b/graf3d/gl/src/TGLFontManager.cxx index 58ea1188d5936..a5a708b861462 100644 --- a/graf3d/gl/src/TGLFontManager.cxx +++ b/graf3d/gl/src/TGLFontManager.cxx @@ -200,7 +200,7 @@ void TGLFont::RenderHelper(const Char *txt, Double_t x, Double_t y, Double_t ang //later gVirtualX->GetTextAling() will give you 7. Brilliant! //But with Cocoa you'll have 11. As it should be, of course. - if (gVirtualX->InheritsFrom("TGCocoa")) { + if (gVirtualX->InheritsFrom("TGCocoa") || true) { const UInt_t hAlign = UInt_t(align / 10); switch (hAlign) { case 1: From 058361f27f34fe01e619084392df4f541fb07f46 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 17 Mar 2026 14:51:50 +0100 Subject: [PATCH 34/37] [tgx11] correctly implement fallback methods for attr One cannot use TGX11 itself while one access attributes via getter methods which already redefined in TGX11. So make copy of stored attributes --- graf2d/x11/src/TGX11.cxx | 61 ++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/graf2d/x11/src/TGX11.cxx b/graf2d/x11/src/TGX11.cxx index 2dca7717ad833..235913943469f 100644 --- a/graf2d/x11/src/TGX11.cxx +++ b/graf2d/x11/src/TGX11.cxx @@ -2366,7 +2366,10 @@ void TGX11::SetFillColor(Color_t cindex) { TAttFill::SetFillColor(cindex); - SetAttFill((WinContext_t) gCws, *this); + TAttFill arg(gCws->fAttFill); + arg.SetFillColor(cindex); + + SetAttFill((WinContext_t) gCws, arg); /* if (!gStyle->GetFillColor() && cindex > 1) cindex = 0; @@ -2391,7 +2394,10 @@ void TGX11::SetFillStyle(Style_t fstyle) { TAttFill::SetFillStyle(fstyle); - SetAttFill((WinContext_t) gCws, *this); + TAttFill arg(gCws->fAttFill); + arg.SetFillStyle(fstyle); + + SetAttFill((WinContext_t) gCws, arg); /* if (fFillStyle == fstyle) return; fFillStyle = fstyle; @@ -2483,7 +2489,10 @@ void TGX11::SetLineColor(Color_t cindex) TAttLine::SetLineColor(cindex); - SetAttLine((WinContext_t) gCws, *this); + TAttLine arg(gCws->fAttLine); + arg.SetLineColor(cindex); + + SetAttLine((WinContext_t) gCws, arg); //SetColor(gGCline, Int_t(cindex)); //SetColor(gGCdash, Int_t(cindex)); @@ -2532,7 +2541,10 @@ void TGX11::SetLineStyle(Style_t lstyle) { TAttLine::SetLineStyle(lstyle); - SetAttLine((WinContext_t) gCws, *this); + TAttLine arg(gCws->fAttLine); + arg.SetLineStyle(lstyle); + + SetAttLine((WinContext_t) gCws, arg); /* static Int_t dashed[2] = {3,3}; @@ -2586,7 +2598,10 @@ void TGX11::SetLineWidth(Width_t width) { TAttLine::SetLineWidth(width); - SetAttLine((WinContext_t) gCws, *this); + TAttLine arg(gCws->fAttLine); + arg.SetLineWidth(width); + + SetAttLine((WinContext_t) gCws, arg); /* @@ -2623,7 +2638,10 @@ void TGX11::SetMarkerColor(Color_t cindex) TAttMarker::SetMarkerColor(cindex); - SetAttMarker((WinContext_t) gCws, *this); + TAttMarker arg(gCws->fAttMarker); + arg.SetMarkerColor(cindex); + + SetAttMarker((WinContext_t) gCws, arg); } //////////////////////////////////////////////////////////////////////////////// @@ -2635,7 +2653,10 @@ void TGX11::SetMarkerSize(Float_t msize) { TAttMarker::SetMarkerSize(msize); - SetAttMarker((WinContext_t) gCws, *this); + TAttMarker arg(gCws->fAttMarker); + arg.SetMarkerSize(msize); + + SetAttMarker((WinContext_t) gCws, arg); } //////////////////////////////////////////////////////////////////////////////// @@ -2674,7 +2695,10 @@ void TGX11::SetMarkerStyle(Style_t markerstyle) { TAttMarker::SetMarkerStyle(markerstyle); - SetAttMarker((WinContext_t) gCws, *this); + TAttMarker arg(gCws->fAttMarker); + arg.SetMarkerStyle(markerstyle); + + SetAttMarker((WinContext_t) gCws, arg); /* if (fMarkerStyle == markerstyle) return; @@ -3361,7 +3385,10 @@ void TGX11::SetTextAlign(Short_t talign) TAttText::SetTextAlign(talign); - SetAttText((WinContext_t) gCws, *this); + TAttText arg(gCws->fAttText); + arg.SetTextAlign(talign); + + SetAttText((WinContext_t) gCws, arg); // FIXME: member fTextAlign conflicts with TAttText::fTextAlign fTextAlign = gCws->textAlign; @@ -3375,7 +3402,11 @@ void TGX11::SetTextColor(Color_t cindex) if (cindex < 0) return; TAttText::SetTextColor(cindex); - SetAttText((WinContext_t) gCws, *this); + + TAttText arg(gCws->fAttText); + arg.SetTextColor(cindex); + + SetAttText((WinContext_t) gCws, arg); /* SetColor(gGCtext, Int_t(cindex)); @@ -3447,7 +3478,10 @@ void TGX11::SetTextFont(Font_t fontnumber) { TAttText::SetTextFont(fontnumber); - SetAttText((WinContext_t) gCws, *this); + TAttText arg(gCws->fAttText); + arg.SetTextFont(fontnumber); + + SetAttText((WinContext_t) gCws, arg); } //////////////////////////////////////////////////////////////////////////////// @@ -3457,7 +3491,10 @@ void TGX11::SetTextSize(Float_t textsize) { TAttText::SetTextSize(textsize); - SetAttText((WinContext_t) gCws, *this); + TAttText arg(gCws->fAttText); + arg.SetTextSize(textsize); + + SetAttText((WinContext_t) gCws, arg); } //////////////////////////////////////////////////////////////////////////////// From e0db29aa83708a65e23ad8b11cd9781dd739d10e Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 17 Mar 2026 15:34:11 +0100 Subject: [PATCH 35/37] [pad painter] use for TWbox painting Replace usage of gVirtualX --- graf2d/graf/src/TWbox.cxx | 135 ++++++++++++++++++++++---------------- 1 file changed, 77 insertions(+), 58 deletions(-) diff --git a/graf2d/graf/src/TWbox.cxx b/graf2d/graf/src/TWbox.cxx index a4be334f69f5f..d52fa03d9fb09 100644 --- a/graf2d/graf/src/TWbox.cxx +++ b/graf2d/graf/src/TWbox.cxx @@ -14,9 +14,9 @@ #include "Strlen.h" #include "TWbox.h" #include "TColor.h" +#include "TStyle.h" #include "TVirtualPad.h" -#include "TVirtualX.h" -#include "TPoint.h" +#include "TVirtualPadPainter.h" /** \class TWbox @@ -135,69 +135,88 @@ void TWbox::PaintWbox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, void TWbox::PaintFrame(Double_t x1, Double_t y1,Double_t x2, Double_t y2, Color_t color, Short_t bordersize, Short_t bordermode, - Bool_t tops) + Bool_t /* tops */) { - if (!gPad) return; - if (bordermode == 0) return; - if (bordersize <= 0) bordersize = 2; + if (bordermode == 0) + return; + if (bordersize <= 0) + bordersize = 2; + + auto pp = gPad->GetPainter(); + if (!pp) + return; + + Double_t ww = gPad->GetWw(), wh = gPad->GetWh(); + + if (pp->GetPS()) { + // SL: need to calculate page size to get real coordiantes for border + // TODO: Code can be removed if border not need to be exact pixel size + Float_t xsize = 20, ysize = 26; + gStyle->GetPaperSize(xsize, ysize); + Double_t ratio = wh/ww; + if (xsize * ratio > ysize) + xsize = ysize/ratio; + else + ysize = xsize*ratio; + ww = 72 / 2.54 * xsize; + wh = 72 / 2.54 * ysize; + } + + const Double_t realBsX = bordersize / (gPad->GetAbsWNDC() * ww) * (gPad->GetX2() - gPad->GetX1()); + const Double_t realBsY = bordersize / (gPad->GetAbsHNDC() * wh) * (gPad->GetY2() - gPad->GetY1()); + + // GetColorDark() and GetColorBright() use GetFillColor() + Color_t oldfillcolor = GetFillColor(); + Color_t light = !color ? 0 : TColor::GetColorBright(color); + Color_t dark = !color ? 0 : TColor::GetColorDark(color); - Short_t pxl,pyl,pxt,pyt,px1,py1,px2,py2; Double_t xl, xt, yl, yt; // Compute real left bottom & top right of the box in pixels - px1 = gPad->XtoPixel(x1); py1 = gPad->YtoPixel(y1); - px2 = gPad->XtoPixel(x2); py2 = gPad->YtoPixel(y2); - if (px1 < px2) {pxl = px1; pxt = px2; xl = x1; xt = x2; } - else {pxl = px2; pxt = px1; xl = x2; xt = x1;} - if (py1 > py2) {pyl = py1; pyt = py2; yl = y1; yt = y2;} - else {pyl = py2; pyt = py1; yl = y2; yt = y1;} - - if (!gPad->IsBatch()) { - TPoint frame[7]; - - // GetDarkColor() and GetLightColor() use GetFillColor() - Color_t oldcolor = GetFillColor(); - SetFillColor(color); - TAttFill::Modify(); - - // Draw top&left part of the box - frame[0].fX = pxl; frame[0].fY = pyl; - frame[1].fX = pxl + bordersize; frame[1].fY = pyl - bordersize; - frame[2].fX = frame[1].fX; frame[2].fY = pyt + bordersize; - frame[3].fX = pxt - bordersize; frame[3].fY = frame[2].fY; - frame[4].fX = pxt; frame[4].fY = pyt; - frame[5].fX = pxl; frame[5].fY = pyt; - frame[6].fX = pxl; frame[6].fY = pyl; - - if (bordermode == -1) gVirtualX->SetFillColor(GetDarkColor()); - else gVirtualX->SetFillColor(GetLightColor()); - gVirtualX->DrawFillArea(7, frame); - - // Draw bottom&right part of the box - frame[0].fX = pxl; frame[0].fY = pyl; - frame[1].fX = pxl + bordersize; frame[1].fY = pyl - bordersize; - frame[2].fX = pxt - bordersize; frame[2].fY = frame[1].fY; - frame[3].fX = frame[2].fX; frame[3].fY = pyt + bordersize; - frame[4].fX = pxt; frame[4].fY = pyt; - frame[5].fX = pxt; frame[5].fY = pyl; - frame[6].fX = pxl; frame[6].fY = pyl; - - if (bordermode == -1) gVirtualX->SetFillColor(TColor::GetColorBright(GetFillColor())); - else gVirtualX->SetFillColor(TColor::GetColorDark(GetFillColor())); - gVirtualX->DrawFillArea(7, frame); - - gVirtualX->SetFillColor(-1); - SetFillColor(oldcolor); + if (gPad->XtoPixel(x1) < gPad->XtoPixel(x2)) { + xl = x1; + xt = x2; + } else { + xl = x2; + xt = x1; + } + if (gPad->YtoPixel(y1) > gPad->YtoPixel(y2)) { + yl = y1; + yt = y2; + } else { + yl = y2; + yt = y1; } - if (!tops) return; - - // same for PostScript - // Double_t dx = (xt - xl) *Double_t(bordersize)/Double_t(pxt - pxl); - // Int_t border = gVirtualPS->XtoPS(xt) - gVirtualPS->XtoPS(xt-dx); - - gPad->PaintBorderPS(xl, yl, xt, yt, bordermode, bordersize, - GetDarkColor(), GetLightColor()); + Double_t frameXs[7] = {}, frameYs[7] = {}; + + // Draw top&left part of the box + frameXs[0] = xl; frameYs[0] = yl; + frameXs[1] = xl + realBsX; frameYs[1] = yl + realBsY; + frameXs[2] = frameXs[1]; frameYs[2] = yt - realBsY; + frameXs[3] = xt - realBsX; frameYs[3] = frameYs[2]; + frameXs[4] = xt; frameYs[4] = yt; + frameXs[5] = xl; frameYs[5] = yt; + frameXs[6] = xl; frameYs[6] = yl; + + SetFillColor(bordermode == -1 ? dark : light); + pp->SetAttFill(*this); + pp->DrawFillArea(7, frameXs, frameYs); + + // Draw bottom&right part of the box + frameXs[0] = xl; frameYs[0] = yl; + frameXs[1] = xl + realBsX; frameYs[1] = yl + realBsY; + frameXs[2] = xt - realBsX; frameYs[2] = frameYs[1]; + frameXs[3] = frameXs[2]; frameYs[3] = yt - realBsY; + frameXs[4] = xt; frameYs[4] = yt; + frameXs[5] = xt; frameYs[5] = yl; + frameXs[6] = xl; frameYs[6] = yl; + + SetFillColor(bordermode == -1 ? light : dark); + pp->SetAttFill(*this); + pp->DrawFillArea(7, frameXs, frameYs); + + SetFillColor(oldfillcolor); } //////////////////////////////////////////////////////////////////////////////// From e50a949dc45e2c7254ac301d43d0a12d7f349811 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Tue, 17 Mar 2026 16:02:40 +0100 Subject: [PATCH 36/37] [pad painter] use TWbox methods to paint pad border While both TPad and TWbox uses same code, put it together in TWbox::PaintBorderOn method. So fully avoid usage of PaintBorderPS method, can be removed in the future --- graf2d/gpad/src/TPad.cxx | 98 ++++----------------------------------- graf2d/graf/inc/TWbox.h | 3 ++ graf2d/graf/src/TWbox.cxx | 47 +++++++++++++++---- 3 files changed, 50 insertions(+), 98 deletions(-) diff --git a/graf2d/gpad/src/TPad.cxx b/graf2d/gpad/src/TPad.cxx index ca927656b89a6..3badc5ba720d6 100644 --- a/graf2d/gpad/src/TPad.cxx +++ b/graf2d/gpad/src/TPad.cxx @@ -46,6 +46,7 @@ #include "TMethod.h" #include "TDataType.h" #include "TFrame.h" +#include "TWbox.h" #include "TExec.h" #include "TDatime.h" #include "TColor.h" @@ -3828,99 +3829,20 @@ void TPad::PaintBorder(Color_t color, Bool_t /* tops */) if (IsTransparent()) return; - // then paint 3d frame (depending on bordermode) - // Paint a 3D frame around the pad. - if (fBorderMode == 0) return; - Int_t bordersize = fBorderSize; - if (bordersize <= 0) - bordersize = 2; - - Double_t ww = GetWw(), wh = GetWh(); - - if (!pp->IsNative()) { - // SL: need to calculate page size to get real coordiantes for border - // TODO: Code can be removed if border not need to be exact pixel size - Float_t xsize = 20, ysize = 26; - gStyle->GetPaperSize(xsize, ysize); - Double_t ratio = wh/ww; - if (xsize * ratio > ysize) - xsize = ysize/ratio; - else - ysize = xsize*ratio; - ww = 72 / 2.54 * xsize; - wh = 72 / 2.54 * ysize; - } - - const Double_t realBsX = bordersize / (GetAbsWNDC() * ww) * (fX2 - fX1); - const Double_t realBsY = bordersize / (GetAbsHNDC() * wh) * (fY2 - fY1); + // then paint 3d frame (depending on bordermode) + // Paint a 3D frame around the pad. - // GetColorDark() and GetColorBright() use GetFillColor() - Color_t oldfillcolor = pp->GetFillColor(); - Color_t light = !color ? 0 : TColor::GetColorBright(color); - Color_t dark = !color ? 0 : TColor::GetColorDark(color); - - Double_t xl, xt, yl, yt; - - // Compute real left bottom & top right of the box in pixels - if (XtoPixel(fX1) < XtoPixel(fX2)) { - xl = fX1; - xt = fX2; - } else { - xl = fX2; - xt = fX1; - } - if (YtoPixel(fY1) > YtoPixel(fY2)) { - yl = fY1; - yt = fY2; - } else { - yl = fY2; - yt = fY1; - } - - Double_t frameXs[7] = {}, frameYs[7] = {}; - - // Draw top&left part of the box - frameXs[0] = xl; frameYs[0] = yl; - frameXs[1] = xl + realBsX; frameYs[1] = yl + realBsY; - frameXs[2] = frameXs[1]; frameYs[2] = yt - realBsY; - frameXs[3] = xt - realBsX; frameYs[3] = frameYs[2]; - frameXs[4] = xt; frameYs[4] = yt; - frameXs[5] = xl; frameYs[5] = yt; - frameXs[6] = xl; frameYs[6] = yl; - - pp->SetFillColor(fBorderMode == -1 ? dark : light); - pp->DrawFillArea(7, frameXs, frameYs); - - // Draw bottom&right part of the box - frameXs[0] = xl; frameYs[0] = yl; - frameXs[1] = xl + realBsX; frameYs[1] = yl + realBsY; - frameXs[2] = xt - realBsX; frameYs[2] = frameYs[1]; - frameXs[3] = frameXs[2]; frameYs[3] = yt - realBsY; - frameXs[4] = xt; frameYs[4] = yt; - frameXs[5] = xt; frameYs[5] = yl; - frameXs[6] = xl; frameYs[6] = yl; - - pp->SetFillColor(fBorderMode == -1 ? light : dark); - pp->DrawFillArea(7, frameXs, frameYs); - - // If this pad is a button, highlight it - if (InheritsFrom(TButton::Class()) && fBorderMode == -1) { - if (TestBit(kFraming)) { // bit set in TButton::SetFraming - Color_t oldlinecolor = pp->GetLineColor(); - pp->SetLineColor(GetFillColor() != 2 ? 2 : 4); - pp->DrawBox(xl + realBsX, yl + realBsY, xt - realBsX, yt - realBsY, TVirtualPadPainter::kHollow); - pp->SetLineColor(oldlinecolor); - } - } - pp->SetFillColor(oldfillcolor); - - // No need to use PaintBorderPS, it is already performed via pad painter done! + TWbox box; + box.SetFillColor(color); + box.SetFillStyle(GetFillStyle()); + TAttLine::Copy(box); - //if (tops) - // PaintBorderPS(xl, yl, xt, yt, fBorderMode, bordersize, dark, light); + box.PaintBorderOn(this, fX1, fY1, fX2, fY2, + fBorderSize, fBorderMode, + InheritsFrom(TButton::Class()) && fBorderMode == -1 && TestBit(kFraming)); } //////////////////////////////////////////////////////////////////////////////// diff --git a/graf2d/graf/inc/TWbox.h b/graf2d/graf/inc/TWbox.h index 1890643c8178f..c194f3eb36e93 100644 --- a/graf2d/graf/inc/TWbox.h +++ b/graf2d/graf/inc/TWbox.h @@ -42,6 +42,9 @@ class TWbox : public TBox { Int_t GetDarkColor() const {return TColor::GetColorDark(GetFillColor());} Int_t GetLightColor() const {return TColor::GetColorBright(GetFillColor());} void Paint(Option_t *option="") override; + void PaintBorderOn(TVirtualPad *pad, + Double_t x1, Double_t y1,Double_t x2 ,Double_t y2, + Short_t bordersize, Short_t bordermode, Bool_t with_selection = kFALSE); virtual void PaintFrame(Double_t x1, Double_t y1,Double_t x2 ,Double_t y2, Color_t color, Short_t bordersize, Short_t bordermode, Bool_t tops); diff --git a/graf2d/graf/src/TWbox.cxx b/graf2d/graf/src/TWbox.cxx index d52fa03d9fb09..a2fb8b9bd8619 100644 --- a/graf2d/graf/src/TWbox.cxx +++ b/graf2d/graf/src/TWbox.cxx @@ -136,17 +136,36 @@ void TWbox::PaintWbox(Double_t x1, Double_t y1, Double_t x2, Double_t y2, void TWbox::PaintFrame(Double_t x1, Double_t y1,Double_t x2, Double_t y2, Color_t color, Short_t bordersize, Short_t bordermode, Bool_t /* tops */) +{ + if (bordermode == 0) + return; + + auto oldcolor = GetFillColor(); + SetFillColor(color); + + PaintBorderOn(gPad, x1, y1, x2, y2, bordersize, bordermode); + + SetFillColor(oldcolor); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Paint a 3D border around a box. +/// Used also by the pad painter + +void TWbox::PaintBorderOn(TVirtualPad *pad, + Double_t x1, Double_t y1,Double_t x2 ,Double_t y2, + Short_t bordersize, Short_t bordermode, Bool_t with_selection) { if (bordermode == 0) return; if (bordersize <= 0) bordersize = 2; - auto pp = gPad->GetPainter(); + auto pp = pad->GetPainter(); if (!pp) return; - Double_t ww = gPad->GetWw(), wh = gPad->GetWh(); + Double_t ww = pad->GetWw(), wh = pad->GetWh(); if (pp->GetPS()) { // SL: need to calculate page size to get real coordiantes for border @@ -162,25 +181,25 @@ void TWbox::PaintFrame(Double_t x1, Double_t y1,Double_t x2, Double_t y2, wh = 72 / 2.54 * ysize; } - const Double_t realBsX = bordersize / (gPad->GetAbsWNDC() * ww) * (gPad->GetX2() - gPad->GetX1()); - const Double_t realBsY = bordersize / (gPad->GetAbsHNDC() * wh) * (gPad->GetY2() - gPad->GetY1()); + const Double_t realBsX = bordersize / (pad->GetAbsWNDC() * ww) * (pad->GetX2() - pad->GetX1()); + const Double_t realBsY = bordersize / (pad->GetAbsHNDC() * wh) * (pad->GetY2() - pad->GetY1()); // GetColorDark() and GetColorBright() use GetFillColor() - Color_t oldfillcolor = GetFillColor(); - Color_t light = !color ? 0 : TColor::GetColorBright(color); - Color_t dark = !color ? 0 : TColor::GetColorDark(color); + Color_t fillcolor = GetFillColor(); + Color_t light = !fillcolor ? 0 : GetLightColor(); + Color_t dark = !fillcolor ? 0 : GetDarkColor(); Double_t xl, xt, yl, yt; // Compute real left bottom & top right of the box in pixels - if (gPad->XtoPixel(x1) < gPad->XtoPixel(x2)) { + if (pad->XtoPixel(x1) < pad->XtoPixel(x2)) { xl = x1; xt = x2; } else { xl = x2; xt = x1; } - if (gPad->YtoPixel(y1) > gPad->YtoPixel(y2)) { + if (pad->YtoPixel(y1) > pad->YtoPixel(y2)) { yl = y1; yt = y2; } else { @@ -216,7 +235,15 @@ void TWbox::PaintFrame(Double_t x1, Double_t y1,Double_t x2, Double_t y2, pp->SetAttFill(*this); pp->DrawFillArea(7, frameXs, frameYs); - SetFillColor(oldfillcolor); + SetFillColor(fillcolor); + + if (with_selection) { + Color_t oldlinecolor = GetLineColor(); + SetLineColor(GetFillColor() != 2 ? 2 : 4); + pp->SetAttLine(*this); + pp->DrawBox(xl + realBsX, yl + realBsY, xt - realBsX, yt - realBsY, TVirtualPadPainter::kHollow); + SetLineColor(oldlinecolor); + } } //////////////////////////////////////////////////////////////////////////////// From 71398df1dcb206f9aa90475149bdb393c5193e91 Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Wed, 18 Mar 2026 16:49:15 +0100 Subject: [PATCH 37/37] [stressGraphics] adjust ref files for quarks tests Now border decorations of the sub-pad drawn slightly different using TWbox method. So ref file size is slightly changed --- test/stressGraphics.ref | 2 +- test/stressGraphics_builtinzlib.ref | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/stressGraphics.ref b/test/stressGraphics.ref index eec9f7d64dc73..6b74f24324e41 100644 --- a/test/stressGraphics.ref +++ b/test/stressGraphics.ref @@ -71,7 +71,7 @@ annotation3d 547845 3000 193367 3000 32383 12000 58073 20000 547493 3000 tgraph2d3 15025 3000 29289 500 42525 11300 33336 3900 14787 4000 ntuple1 254604 5000 383258 7000 55666 30400 46534 6500 259594 7000 - quarks 5045 150 14075 200 33239 600 25303 500 5076 150 + quarks 4846 150 14075 200 33239 600 25303 500 4877 150 timage 1435879 150000 12837 100 26170 100 365000 15000 1085792 250000 zoomtf1 5884 500 16577 200 40706 14000 30026 4000 5884 500 zoomfit 5723 700 15720 200 32236 11000 16916 3200 5670 800 diff --git a/test/stressGraphics_builtinzlib.ref b/test/stressGraphics_builtinzlib.ref index e0eac7809ed28..8cabb76b1ab5f 100644 --- a/test/stressGraphics_builtinzlib.ref +++ b/test/stressGraphics_builtinzlib.ref @@ -71,7 +71,7 @@ annotation3d 547845 3000 193367 3000 32383 12000 58073 20000 547493 3000 tgraph2d3 16675 3000 29481 500 40536 11300 33519 3900 16452 4000 ntuple1 256544 5000 381654 7000 54446 30400 45002 6500 261593 7000 - quarks 5045 150 14074 100 32913 600 25421 600 5076 150 + quarks 4846 150 14074 100 32913 600 25421 600 4877 150 timage 1442666 150000 12840 100 26100 100 374206 15000 1102279 250000 zoomtf1 6130 500 16468 200 49750 14000 29288 4000 6050 500 zoomfit 6200 700 15646 200 31219 11000 18280 3200 6113 800