ultimatepp/uppsrc/CtrlCore/X11Clip.cpp
cxl 3938bde101 CtrlCore: FixedDropFiles in Linux (added UrlDecode/UrlEncode)
git-svn-id: svn://ultimatepp.org/upp/trunk@7991 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2014-12-23 09:42:28 +00:00

408 lines
9.7 KiB
C++

#include "CtrlCore.h"
#ifdef GUI_X11
NAMESPACE_UPP
#define LLOG(x) // LOG(x)
Index<String> Ctrl::sel_formats;
Ptr<Ctrl> Ctrl::sel_ctrl;
void Ctrl::SetSelectionSource(const char *fmts)
{
GuiLock __;
LLOG("SetSelectionSource " << UPP::Name(this) << ": " << fmts);
sel_formats = Split(fmts, ';');
sel_ctrl = this;
XSetSelectionOwner(Xdisplay, XAtom("PRIMARY"), xclipboard().win, CurrentTime);
}
Ctrl::Xclipboard::Xclipboard()
{
GuiLock __;
XSetWindowAttributes swa;
win = XCreateWindow(Xdisplay, RootWindow(Xdisplay, Xscreenno),
0, 0, 10, 10, 0, CopyFromParent, InputOnly, CopyFromParent,
0, &swa);
XSelectInput(Xdisplay, win, PropertyChangeMask);
}
Ctrl::Xclipboard::~Xclipboard()
{
GuiLock __;
XDestroyWindow(Xdisplay, win);
}
void Ctrl::Xclipboard::Write(int fmt, const ClipData& _data)
{
GuiLock __;
LLOG("SetSelectionOwner " << XAtomName(fmt));
data.GetAdd(fmt) = _data;
XSetSelectionOwner(Xdisplay, XAtom("CLIPBOARD"), win, CurrentTime);
}
void Ctrl::Xclipboard::Request(XSelectionRequestEvent *se)
{
GuiLock __;
LLOG("Request " << XAtomName(se->target));
XEvent e;
e.xselection.type = SelectionNotify;
e.xselection.display = Xdisplay;
e.xselection.requestor = se->requestor;
e.xselection.selection = se->selection;
e.xselection.target = se->target;
e.xselection.time = se->time;
e.xselection.property = se->property;
if(se->target == XAtom("TARGETS")) {
LLOG("Request targets:");
if(se->selection == XAtom("PRIMARY")) {
Buffer<Atom> x(sel_formats.GetCount());
for(int i = 0; i < sel_formats.GetCount(); i++) {
x[i] = XAtom(sel_formats[i]);
LLOG('\t' << sel_formats[i]);
}
XChangeProperty(Xdisplay, se->requestor, se->property, XAtom("ATOM"),
32, 0, (unsigned char*)~x,
sel_formats.GetCount());
}
else {
Buffer<Atom> x(data.GetCount());
for(int i = 0; i < data.GetCount(); i++) {
x[i] = data.GetKey(i);
LLOG('\t' << XAtomName(x[i]));
}
XChangeProperty(Xdisplay, se->requestor, se->property, XAtom("ATOM"),
32, 0, (unsigned char*)~x,
data.GetCount());
}
}
else {
if(se->selection == XAtom("PRIMARY")) {
LLOG("Request PRIMARY data " << XAtomName(se->target));
String fmt = XAtomName(se->target);
int i = sel_formats.Find(fmt);
if(i >= 0 && sel_ctrl) {
String d = sel_ctrl->GetSelectionData(fmt);
XChangeProperty(Xdisplay, se->requestor, se->property, se->target, 8, PropModeReplace,
d, d.GetLength());
}
else
e.xselection.property = None;
}
else {
LLOG("Request CLIPBOARD data " << XAtomName(se->target));
int i = data.Find(se->target);
if(i >= 0) {
String d = data[i].Render();
XChangeProperty(Xdisplay, se->requestor, se->property, se->target, 8, PropModeReplace,
d, d.GetLength());
}
else
e.xselection.property = None;
}
}
XSendEvent(Xdisplay, se->requestor, XFalse, 0, &e);
}
String Ctrl::Xclipboard::Read(int fmt, int selection, int property)
{
GuiLock __;
if(data.GetCount() && (dword)selection == XAtom("CLIPBOARD")) {
int q = data.Find(fmt);
return q >= 0 ? data[q].Render() : String();
}
if(sel_ctrl && (dword)selection == XAtom("PRIMARY"))
return sel_ctrl->GetSelectionData(XAtomName(fmt));
XConvertSelection(Xdisplay, selection, fmt, property, win, CurrentTime);
XFlush(Xdisplay);
XEvent event;
for(int i = 0; i < 20; i++) {
if(XCheckTypedWindowEvent(Xdisplay, win, SelectionNotify, &event)) {
if(event.xselection.property != None) {
XSync(Xdisplay, false);
return ReadPropertyData(win, event.xselection.property);
}
return Null;
}
if(XCheckTypedWindowEvent(Xdisplay, win, SelectionRequest, &event) &&
event.xselectionrequest.owner == win)
Request(&event.xselectionrequest);
if(XCheckTypedWindowEvent(Xdisplay, win, SelectionClear, &event) &&
event.xselectionclear.window == win) {
if(event.xselectionclear.selection == XAtom("CLIPBOARD"))
Clear();
if(event.xselectionclear.selection == XAtom("PRIMARY")) {
sel_ctrl = NULL;
sel_formats.Clear();
}
}
Sleep(10);
}
return Null;
}
Ctrl::Xclipboard& Ctrl::xclipboard()
{
static Xclipboard xc;
return xc;
}
void ClearClipboard()
{
GuiLock __;
Ctrl::xclipboard().Clear();
}
void AppendClipboard(const char *format, const Value& data, String (*render)(const Value& data))
{
GuiLock __;
Vector<String> s = Split(format, ';');
for(int i = 0; i < s.GetCount(); i++)
Ctrl::xclipboard().Write(XAtom(s[i]), ClipData(data, render));
}
String sRawClipData(const Value& data);
void AppendClipboard(const char *fmt, const String& data)
{
GuiLock __;
AppendClipboard(fmt, data, sRawClipData);
}
String ReadClipboard(const char *fmt)
{
GuiLock __;
return Ctrl::xclipboard().Read(XAtom(fmt), XAtom("CLIPBOARD"), XAtom("CLIPDATA"));
}
void AppendClipboardText(const String& s)
{
GuiLock __;
AppendClipboard("STRING", s);
}
String ReadClipboardText()
{
GuiLock __;
return ReadClipboard("STRING");
}
void AppendClipboardUnicodeText(const WString& s)
{
GuiLock __;
AppendClipboard("UTF8_STRING", ToUtf8(s));
}
WString ReadClipboardUnicodeText()
{
GuiLock __;
return FromUtf8(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 __;
LLOG("ClipHas " << type << ": " << fmt);
if(strcmp(fmt, "files") == 0)
fmt = "text/uri-list";
if(type == 0)
return Ctrl::xclipboard().IsAvailable(XAtom(fmt), "CLIPBOARD");
if(type == 2) {
if(sel_ctrl)
return sel_formats.Find(fmt) >= 0;
return Ctrl::xclipboard().IsAvailable(XAtom(fmt), "PRIMARY");
}
return drop_formats.Find(fmt) >= 0;
}
String DnDGetData(const String& f);
String Ctrl::ClipGet(int type, const char *fmt)
{
GuiLock __;
LLOG("ClipGet " << type << ": " << fmt);
if(strcmp(fmt, "files") == 0)
fmt = "text/uri-list";
if(type && GetDragAndDropSource())
return DnDGetData(fmt);
return Ctrl::xclipboard().Read(
XAtom(fmt),
XAtom(type == 2 ? "PRIMARY" : type == 1 ? "XdndSelection" : "CLIPBOARD"),
type == 1 ? XA_SECONDARY : XAtom("CLIPDATA")
);
}
const char *ClipFmtsText()
{
return "STRING;UTF8_STRING;text/plain;text/unicode";
}
String GetString(PasteClip& clip)
{
GuiLock __;
if(clip.Accept("STRING") || clip.Accept("text/plain"))
return ~clip;
if(clip.Accept("UTF8_STRING"))
return FromUtf8(~clip).ToString();
if(clip.Accept("text/unicode"))
return Unicode__(~clip).ToString();
return Null;
}
WString GetWString(PasteClip& clip)
{
GuiLock __;
if(clip.Accept("UTF8_STRING"))
return FromUtf8(~clip);
if(clip.Accept("text/unicode"))
return Unicode__(~clip);
if(clip.Accept("STRING") || clip.Accept("text/plain"))
return ToUnicode(~clip, CHARSET_ISO8859_1);
return Null;
}
String GetTextClip(const WString& text, const String& fmt)
{
GuiLock __;
if(fmt == "STRING" || fmt == "text/plain")
return text.ToString();
if(fmt == "UTF8_STRING")
return ToUtf8(text);
if(fmt == "text/unicode")
return Unicode__(text);
return Null;
}
String GetTextClip(const String& text, const String& fmt)
{
GuiLock __;
if(fmt == "STRING" || fmt == "text/plain")
return text;
if(fmt == "UTF8_STRING")
return ToUtf8(text.ToWString());
if(fmt == "text/unicode")
return Unicode__(text.ToWString());
return Null;
}
bool AcceptText(PasteClip& clip)
{
GuiLock __;
return clip.Accept(ClipFmtsText());
}
void Append(VectorMap<String, ClipData>& data, const String& text) // optimize
{
GuiLock __;
data.GetAdd("STRING", text);
data.GetAdd("text/plain", text);
data.GetAdd("UTF8_STRING", ToUtf8(text.ToWString()));
data.GetAdd("text/unicode", Unicode__(text.ToWString()));
}
void Append(VectorMap<String, ClipData>& data, const WString& text) // optimize
{
GuiLock __;
data.GetAdd("STRING", text.ToString());
data.GetAdd("text/plain", text.ToString());
data.GetAdd("UTF8_STRING", ToUtf8(text));
data.GetAdd("text/unicode", Unicode__(text));
}
bool IsClipboardAvailable(const char *fmt)
{
GuiLock __;
return Ctrl::xclipboard().IsAvailable(XAtom(fmt), "CLIPBOARD");
}
bool IsClipboardAvailableText()
{
GuiLock __;
return IsClipboardAvailable("STRING") ||
IsClipboardAvailable("UTF8_STRING") ||
IsClipboardAvailable("text/plain") ||
IsClipboardAvailable("text/unicode");
}
bool AcceptFiles(PasteClip& clip)
{
GuiLock __;
return clip.Accept("text/uri-list");
}
bool IsAvailableFiles(PasteClip& clip)
{
GuiLock __;
return clip.IsAvailable("text/uri-list");
}
int JustLf(int c)
{
return (byte)c >= 32 || c == '\n' ? c : 0;
}
Vector<String> GetClipFiles(const String& data)
{
Vector<String> r;
Vector<String> f = Split(Filter(data, JustLf), '\n');
for(int i = 0; i < f.GetCount(); i++)
if(f[i].StartsWith("file://"))
r.Add(UrlDecode(f[i].Mid(7)));
return r;
}
Vector<String> GetFiles(PasteClip& clip) {
GuiLock __;
Vector<String> r;
if(clip.Accept("text/uri-list")) {
String txt = clip;
r = GetClipFiles(txt);
}
return r;
}
void AppendFiles(VectorMap<String, ClipData>& data, const Vector<String>& files)
{
GuiLock __;
if(files.GetCount() == 0)
return;
String h;
for(int i = 0; i < files.GetCount(); i++)
h << "file://" << UrlEncode(files[i]) << '\n';
data.GetAdd("text/uri-list") = h;
}
bool PasteClip::IsAvailable(const char *fmt) const
{
return Ctrl::ClipHas(type, fmt);
}
String PasteClip::Get(const char *fmt) const
{
return Ctrl::ClipGet(type, fmt);
}
void PasteClip::GuiPlatformConstruct()
{
type = 0;
}
END_UPP_NAMESPACE
#endif