From 32a6d9eb56ced1803356d22329df581bda82b51c Mon Sep 17 00:00:00 2001 From: Mirek Fidler Date: Tue, 13 Jan 2026 09:46:59 +0100 Subject: [PATCH] CtrlCore: X11 Optimized clipboard handling --- .../IsClipboardText/IsClipboardText.upp | 10 +++++ benchmarks/IsClipboardText/main.cpp | 24 ++++++++++++ uppsrc/CtrlCore/DrawTextX11.cpp | 1 - uppsrc/CtrlCore/ImageX11.cpp | 1 - uppsrc/CtrlCore/X11Clip.cpp | 38 ++++++++++--------- uppsrc/CtrlCore/X11Ctrl.h | 7 +++- uppsrc/CtrlCore/X11Proc.cpp | 4 +- uppsrc/CtrlCore/X11Top.cpp | 8 ++-- 8 files changed, 66 insertions(+), 27 deletions(-) create mode 100644 benchmarks/IsClipboardText/IsClipboardText.upp create mode 100644 benchmarks/IsClipboardText/main.cpp diff --git a/benchmarks/IsClipboardText/IsClipboardText.upp b/benchmarks/IsClipboardText/IsClipboardText.upp new file mode 100644 index 000000000..8f8a0fa40 --- /dev/null +++ b/benchmarks/IsClipboardText/IsClipboardText.upp @@ -0,0 +1,10 @@ +uses + CtrlLib; + +file + main.cpp; + +mainconfig + "" = "GUI", + "" = "GUI X11"; + diff --git a/benchmarks/IsClipboardText/main.cpp b/benchmarks/IsClipboardText/main.cpp new file mode 100644 index 000000000..5c941889f --- /dev/null +++ b/benchmarks/IsClipboardText/main.cpp @@ -0,0 +1,24 @@ +#include + +using namespace Upp; + +struct MyApp : TopWindow { + void Paint(Draw& w) override { + w.DrawRect(GetSize(), White()); + for(int i = 0; i < 100; i++) { + { + RTIMING("IsClipboardAvailableText"); + IsClipboardAvailableText(); + } + { + RTIMING("IsClipboardAvailableImage"); + IsClipboardAvailableImage(); + } + } + } +}; + +GUI_APP_MAIN +{ + MyApp().Run(); +} diff --git a/uppsrc/CtrlCore/DrawTextX11.cpp b/uppsrc/CtrlCore/DrawTextX11.cpp index 56dd5c3fe..0f57a8a8f 100644 --- a/uppsrc/CtrlCore/DrawTextX11.cpp +++ b/uppsrc/CtrlCore/DrawTextX11.cpp @@ -157,7 +157,6 @@ INITBLOCK { void SystemDraw::DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx) { GuiLock __; - DTIMING("DrawText"); LLOG("DrawText " << ToUtf8(WString(text, n)) << " color:" << ink << " font:" << font); //TODO - X11 seems to crash when displaying too long strings (?) int ox = x + actual_offset.x; diff --git a/uppsrc/CtrlCore/ImageX11.cpp b/uppsrc/CtrlCore/ImageX11.cpp index d87752532..aed07bde7 100644 --- a/uppsrc/CtrlCore/ImageX11.cpp +++ b/uppsrc/CtrlCore/ImageX11.cpp @@ -152,7 +152,6 @@ static XPicture sGetSolidFill(Color c) void ImageSysData::Paint(SystemDraw& w, int x, int y, const Rect& src, Color c) { GuiLock __; - DTIMING("PAINT IMAGE"); x += w.GetOffset().x; y += w.GetOffset().y; Size sz = img.GetSize(); diff --git a/uppsrc/CtrlCore/X11Clip.cpp b/uppsrc/CtrlCore/X11Clip.cpp index 511e28e8b..1becb6058 100644 --- a/uppsrc/CtrlCore/X11Clip.cpp +++ b/uppsrc/CtrlCore/X11Clip.cpp @@ -142,6 +142,23 @@ String Ctrl::Xclipboard::Read(int fmt, int selection, int property) return Null; } +bool Ctrl::Xclipboard::IsAvailable(int fmt, bool primary) +{ + GuiLock __; + if(data.GetCount()) + return data.Find(fmt) >= 0; + String& formats = this->formats[primary]; + if(formats.IsVoid()) + formats = Read(XAtom("TARGETS"), XAtom(primary ? "PRIMARY" : "CLIPBOARD"), XAtom("CLIPDATA")); + int c = formats.GetCount() / sizeof(Atom); + const Atom *m = (Atom *) ~formats; + for(int i = 0; i < c; i++) { + if(m[i] == (dword)fmt) + return true; + } + return false; +} + Ctrl::Xclipboard& Ctrl::xclipboard() { static Xclipboard xc; @@ -200,21 +217,6 @@ WString ReadClipboardUnicodeText() return ToUtf32(ReadClipboard("UTF8_STRING")); } -bool Ctrl::Xclipboard::IsAvailable(int fmt, const char *type) -{ - GuiLock __; - if(data.GetCount()) - return data.Find(fmt) >= 0; - String formats = Read(XAtom("TARGETS"), XAtom(type), XAtom("CLIPDATA")); - int c = formats.GetCount() / sizeof(Atom); - const Atom *m = (Atom *) ~formats; - for(int i = 0; i < c; i++) { - if(m[i] == (dword)fmt) - return true; - } - return false; -} - bool Ctrl::ClipHas(int type, const char *fmt) { GuiLock __; @@ -222,11 +224,11 @@ bool Ctrl::ClipHas(int type, const char *fmt) if(strcmp(fmt, "files") == 0) fmt = "text/uri-list"; if(type == 0) - return Ctrl::xclipboard().IsAvailable(XAtom(fmt), "CLIPBOARD"); + return Ctrl::xclipboard().IsAvailable(XAtom(fmt), false); if(type == 2) { if(sel_ctrl) return sel_formats.Find(fmt) >= 0; - return Ctrl::xclipboard().IsAvailable(XAtom(fmt), "PRIMARY"); + return Ctrl::xclipboard().IsAvailable(XAtom(fmt), true); } return drop_formats.Find(fmt) >= 0; } @@ -318,7 +320,7 @@ void Append(VectorMap& data, const WString& text) // optimize bool IsClipboardAvailable(const char *fmt) { GuiLock __; - return Ctrl::xclipboard().IsAvailable(XAtom(fmt), "CLIPBOARD"); + return Ctrl::xclipboard().IsAvailable(XAtom(fmt), false); } bool IsClipboardAvailableText() diff --git a/uppsrc/CtrlCore/X11Ctrl.h b/uppsrc/CtrlCore/X11Ctrl.h index ecab0cda3..58cadb27f 100644 --- a/uppsrc/CtrlCore/X11Ctrl.h +++ b/uppsrc/CtrlCore/X11Ctrl.h @@ -69,12 +69,15 @@ public: Window win; VectorMap data; + + String formats[2]; // 0 CLIPBOARD, 1 PRIMARY String Read(int fmt, int selection, int property); void Write(int fmt, const ClipData& data); - bool IsAvailable(int fmt, const char *type); + bool IsAvailable(int fmt, bool primary); - void Clear() { data.Clear(); } + void InvalidateFormats() { formats[0] = String::GetVoid(); formats[1] = String::GetVoid(); } + void Clear() { data.Clear(); InvalidateFormats(); } void Request(XSelectionRequestEvent *se); Xclipboard(); diff --git a/uppsrc/CtrlCore/X11Proc.cpp b/uppsrc/CtrlCore/X11Proc.cpp index cd2ac409a..b549d8e5e 100644 --- a/uppsrc/CtrlCore/X11Proc.cpp +++ b/uppsrc/CtrlCore/X11Proc.cpp @@ -68,7 +68,7 @@ void Ctrl::SetLastActive(XWindow *w, Ctrl *la) void Ctrl::EventProc(XWindow& w, XEvent *event) { - GuiLock __; + GuiLock __; eventid++; Ptr _this = this; bool pressed = false; @@ -109,10 +109,12 @@ void Ctrl::EventProc(XWindow& w, XEvent *event) LTIMING("XUserInput"); switch(event->type) { case FocusIn: + xclipboard().InvalidateFormats(); if(w.xic) XSetICFocus(w.xic); break; case FocusOut: + xclipboard().InvalidateFormats(); if(w.xic) XUnsetICFocus(w.xic); break; diff --git a/uppsrc/CtrlCore/X11Top.cpp b/uppsrc/CtrlCore/X11Top.cpp index 42a45f84e..00c8f952f 100644 --- a/uppsrc/CtrlCore/X11Top.cpp +++ b/uppsrc/CtrlCore/X11Top.cpp @@ -43,24 +43,24 @@ void TopWindow::EventProc(XWindow& w, XEvent *event) if(event->xclient.message_type == XAtom("WM_PROTOCOLS")) { Atom a = event->xclient.data.l[0]; if(a == XAtom("WM_DELETE_WINDOW") && IsEnabled()) { - DLOG("DELETE_WINDOW " << Name()); + LLOG("DELETE_WINDOW " << Name()); WhenClose(); return; } if(a == XAtom("WM_TAKE_FOCUS")) { - DLOG("TAKE_FOCUS serial: " << event->xclient.serial); + LLOG("TAKE_FOCUS serial: " << event->xclient.serial); Xeventtime = event->xclient.data.l[1]; TakeFocus(); return; } if(a == XAtom("_NET_WM_PING")) { - DLOG("_NET_WM_PING"); + LLOG("_NET_WM_PING"); XEvent ev = *event; ev.xclient.window = Xroot; XSendEvent(Xdisplay, Xroot, 0, SubstructureRedirectMask|SubstructureNotifyMask, &ev); return; } - DLOG("Unknown WM_PROTOCOLS: " << XAtomName(a)); + LLOG("Unknown WM_PROTOCOLS: " << XAtomName(a)); } } else