*CtrlCore, CtrlLib: Fixed D&D in LineEdit, EditField

git-svn-id: svn://ultimatepp.org/upp/trunk@4347 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2011-12-26 16:52:23 +00:00
parent 79622a8568
commit 8d3d7c1f07
6 changed files with 473 additions and 472 deletions

View file

@ -9,44 +9,40 @@ IMAGE_ID(DndCopy98)
IMAGE_ID(DndData)
IMAGE_BEGIN_DATA
IMAGE_DATA(120,156,237,154,91,136,13,113,28,199,191,110,43,81,238,47,10,39,181,158,36,145,7,235,206,150,187,8,41,183,245,66)
IMAGE_DATA(173,7,228,65,33,183,114,217,92,138,16,121,217,164,220,10,81,10,229,65,81,188,88,121,17,187,229,36,90,75,109,203)
IMAGE_DATA(38,235,210,142,239,239,156,153,115,206,206,252,231,204,204,158,253,255,231,60,204,175,190,205,153,255,206,153,207,247,247,251)
IMAGE_DATA(95,102,246,244,71,10,41,20,132,133,120,195,178,85,109,107,172,105,190,132,237,225,42,181,213,176,7,203,9,219,195,3)
IMAGE_DATA(195,30,172,194,136,193,131,229,14,195,30,60,124,195,30,148,124,131,30,124,249,134,60,20,229,27,240,16,200,215,236,33)
IMAGE_DATA(136,233,168,153,122,69,213,81,227,117,241,225,93,143,132,219,68,189,132,158,245,209,147,175,130,47,236,11,208,243,124,112)
IMAGE_DATA(179,154,21,30,132,127,72,3,27,200,247,239,99,100,235,252,64,193,151,118,169,125,181,38,126,13,117,3,249,241,61,67)
IMAGE_DATA(225,161,176,6,238,177,169,210,34,42,21,210,131,228,181,19,93,199,86,177,26,88,116,226,175,236,245,75,109,15,97,66)
IMAGE_DATA(152,227,225,237,95,191,26,100,218,234,158,213,89,53,119,107,50,127,147,163,156,23,92,43,227,181,54,36,223,47,252,106)
IMAGE_DATA(144,105,123,154,126,154,171,119,125,67,125,230,188,135,249,64,190,63,155,220,124,40,250,93,3,95,250,100,171,205,117,214)
IMAGE_DATA(159,12,167,245,87,107,142,251,241,251,199,204,185,6,190,227,161,240,253,52,195,233,248,215,97,181,255,110,207,240,228,40)
IMAGE_DATA(231,154,248,238,240,121,98,88,198,248,33,164,147,47,243,122,169,205,240,83,148,249,31,53,82,246,189,107,139,40,202,250)
IMAGE_DATA(151,68,18,241,68,153,254,24,80,105,107,136,105,126,193,2,42,15,154,42,195,30,220,139,248,110,195,30,84,15,18,147)
IMAGE_DATA(30,252,30,102,166,60,20,123,160,154,240,16,244,80,215,237,33,204,139,133,78,15,69,249,6,60,4,242,53,123,8,98)
IMAGE_DATA(58,186,79,157,161,86,82,35,116,241,225,93,143,132,123,133,58,9,61,235,163,39,95,5,95,216,235,161,231,249,224,102)
IMAGE_DATA(221,87,120,16,254,18,13,108,32,223,191,251,144,173,243,110,5,95,218,165,246,149,154,248,83,169,109,200,143,239,148,194)
IMAGE_DATA(131,206,26,72,94,115,208,117,108,153,172,129,48,71,192,155,155,201,26,168,194,100,13,124,61,20,176,227,224,75,173,171)
IMAGE_DATA(108,110,28,239,103,142,135,184,222,79,147,72,34,137,36,244,68,153,254,24,16,27,191,224,97,27,27,63,70,15,170,127)
IMAGE_DATA(64,98,227,199,224,193,195,55,236,65,201,55,232,193,151,111,200,67,81,190,1,15,129,124,205,30,130,152,70,243,135,249)
IMAGE_DATA(245,200,147,111,28,124,23,203,164,7,21,195,52,95,217,110,184,31,202,133,239,59,22,157,99,58,157,238,114,30,116,140)
IMAGE_DATA(10,119,223,195,237,167,27,199,238,228,159,59,143,154,131,59,23,221,223,9,184,93,169,249,151,4,71,146,127,146,191,230)
IMAGE_DATA(239,4,220,174,187,249,247,216,49,42,92,131,135,36,252,162,76,127,12,72,118,6,32,217,25,16,131,7,15,223,176,7)
IMAGE_DATA(37,223,160,7,95,190,33,15,69,249,6,60,4,242,53,123,8,98,58,74,118,6,148,215,206,128,138,94,192,186,185,64)
IMAGE_DATA(227,49,160,243,60,175,59,8,252,155,0,60,71,180,237,252,14,35,202,206,128,138,65,192,233,35,64,219,101,224,215,98)
IMAGE_DATA(224,211,84,224,221,38,224,243,109,122,217,1,52,247,7,118,241,186,222,33,249,145,118,6,244,97,222,231,200,222,15,180)
IMAGE_DATA(242,243,9,182,45,160,102,245,3,78,209,79,103,43,175,63,76,95,108,155,73,245,13,225,33,210,206,0,154,104,124,2)
IMAGE_DATA(252,29,8,92,228,57,187,0,19,153,239,97,26,249,209,64,62,39,72,243,27,126,103,52,112,151,127,27,69,245,10,224)
IMAGE_DATA(71,218,25,112,154,12,230,254,141,159,215,80,147,168,45,103,129,142,183,108,103,255,191,98,194,71,175,3,127,86,3,239)
IMAGE_DATA(249,183,249,84,69,136,26,168,66,89,3,25,107,181,192,23,126,158,199,188,143,10,251,53,217,149,217,177,39,235,67,237)
IMAGE_DATA(37,224,231,6,32,205,207,171,168,193,221,228,3,249,241,153,219,25,112,138,227,156,181,110,99,82,215,88,144,246,183,121)
IMAGE_DATA(54,145,152,206,252,55,222,97,255,172,202,230,47,126,134,149,192,247,236,12,224,96,125,254,130,76,154,233,108,176,107,110)
IMAGE_DATA(115,166,83,163,232,229,158,244,255,80,224,182,221,54,180,4,190,227,33,247,126,202,193,84,189,135,99,172,133,12,118,238)
IMAGE_DATA(103,182,29,160,214,82,203,70,2,245,55,129,223,155,129,175,114,78,77,161,6,148,200,247,4,107,191,107,59,231,216,67)
IMAGE_DATA(230,207,73,219,198,197,177,241,56,208,242,136,158,104,228,43,231,226,94,94,54,155,26,131,112,235,64,212,144,123,206,28)
IMAGE_DATA(206,57,182,156,253,76,254,135,133,92,131,56,39,111,177,157,75,18,102,81,227,168,254,26,216,78,200,218,34,243,91,230)
IMAGE_DATA(152,140,243,21,212,52,106,50,178,121,235,100,59,33,107,139,204,111,153,99,50,206,101,172,73,127,235,168,121,18,73,244)
IMAGE_DATA(104,252,7,44,92,244,185,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
IMAGE_END_DATA(1184, 4)
IMAGE_DATA(120,156,237,154,73,104,20,81,20,69,111,28,18,68,193,41,110,2,106,16,146,149,136,40,89,56,196,49,160,40,138,18)
IMAGE_DATA(69,112,222,24,136,11,21,23,1,21,135,128,19,154,128,162,162,184,17,17,156,32,138,129,128,10,46,5,221,36,226,38)
IMAGE_DATA(104,4,179,48,196,40,132,160,136,35,105,239,163,171,210,157,174,95,169,174,238,252,87,189,168,7,151,174,254,93,93,231)
IMAGE_DATA(190,247,135,170,110,62,202,81,142,180,72,32,218,72,56,170,113,52,91,155,47,225,120,184,67,213,41,123,72,184,225,120)
IMAGE_DATA(104,83,246,144,72,143,8,60,36,50,67,217,131,135,175,236,193,200,87,244,224,203,87,242,48,34,95,193,67,32,223,178)
IMAGE_DATA(135,32,166,171,94,170,157,58,79,85,218,226,195,187,30,9,247,3,245,26,118,214,71,79,190,6,190,176,175,193,206,253)
IMAGE_DATA(33,147,213,107,240,32,252,83,22,216,64,170,127,159,35,89,231,54,3,95,218,165,246,53,150,248,123,168,251,72,141,239)
IMAGE_DATA(165,6,15,54,107,32,121,29,194,240,177,165,89,3,97,86,194,155,155,95,13,180,194,175,6,154,145,206,142,130,47,125)
IMAGE_DATA(82,231,112,221,245,71,59,196,67,84,207,167,113,196,17,71,28,118,162,64,255,12,168,112,52,69,155,159,118,179,149,27)
IMAGE_DATA(205,98,101,15,153,55,252,6,101,15,166,31,32,154,30,252,126,4,105,121,240,240,149,61,24,249,138,30,124,249,74,30)
IMAGE_DATA(70,228,43,120,8,228,91,246,16,196,116,213,74,93,162,54,83,165,182,248,240,174,71,194,189,77,93,132,157,245,209,147)
IMAGE_DATA(175,129,47,236,29,176,115,127,200,100,181,26,60,8,127,189,5,54,144,234,223,99,72,214,185,193,192,151,118,169,125,133)
IMAGE_DATA(37,126,21,181,31,169,241,93,110,240,96,179,6,146,215,10,12,31,91,154,53,16,102,41,188,185,105,214,192,20,154,53)
IMAGE_DATA(240,245,144,198,142,130,47,181,94,236,112,163,120,62,115,61,68,245,124,26,71,28,113,196,97,39,10,244,207,128,200,248)
IMAGE_DATA(105,55,219,200,248,17,122,48,253,0,137,140,31,129,7,15,95,217,131,145,175,232,193,151,175,228,97,68,190,130,135,64)
IMAGE_DATA(190,101,15,65,76,213,252,161,191,30,121,242,141,130,159,193,210,244,96,98,104,243,141,237,202,253,80,40,124,223,177,232)
IMAGE_DATA(190,118,119,119,15,123,31,244,26,22,158,121,141,76,63,57,188,230,146,255,208,251,176,57,100,230,98,251,59,1,151,203)
IMAGE_DATA(55,255,188,224,136,243,143,243,183,252,157,128,203,229,154,255,168,189,134,133,91,240,16,135,95,20,232,159,1,241,206,0)
IMAGE_DATA(196,59,3,34,240,224,225,43,123,48,242,21,61,248,242,149,60,140,200,87,240,16,200,183,236,33,136,233,42,222,25,80)
IMAGE_DATA(88,59,3,138,139,128,237,43,129,174,179,192,224,85,158,119,18,248,55,23,120,137,112,91,217,93,70,152,157,1,197,147)
IMAGE_DATA(128,230,211,192,192,77,224,231,58,224,83,21,240,110,55,208,211,66,47,7,129,222,18,224,48,207,27,147,37,63,212,206)
IMAGE_DATA(128,177,204,251,10,217,199,129,126,30,95,96,219,26,106,217,120,160,137,126,6,251,121,126,35,125,177,173,154,26,151,133)
IMAGE_DATA(135,80,59,3,104,162,235,5,240,119,34,112,157,239,217,5,152,199,124,27,105,228,91,7,249,156,32,189,111,249,157,153)
IMAGE_DATA(192,99,126,86,70,21,5,240,67,237,12,104,38,131,185,127,229,241,86,106,62,181,239,50,240,171,147,237,236,255,118,38)
IMAGE_DATA(124,230,30,240,103,11,240,158,159,173,166,138,179,168,129,41,140,53,144,177,86,15,124,230,241,42,230,125,70,216,111,200)
IMAGE_DATA(174,72,142,61,89,31,234,111,0,63,118,2,221,60,174,165,38,231,200,7,82,227,115,104,103,64,19,199,57,107,61,192)
IMAGE_DATA(164,238,178,32,223,59,83,108,34,177,132,249,239,122,196,254,169,77,230,47,126,166,229,193,247,236,12,224,96,125,249,138)
IMAGE_DATA(76,154,25,236,112,106,238,112,150,80,101,244,242,68,250,127,42,208,226,180,77,205,131,239,122,24,122,62,229,96,170,57)
IMAGE_DATA(194,49,214,71,6,59,183,135,109,39,168,109,212,134,25,192,173,7,192,239,189,192,23,121,79,45,164,38,228,201,247,4)
IMAGE_DATA(107,127,248,0,231,216,83,230,207,73,59,192,197,177,235,28,208,247,140,158,104,228,11,231,226,81,158,182,156,154,133,236)
IMAGE_DATA(214,129,176,33,215,172,158,206,57,182,145,253,76,254,199,181,92,131,56,39,31,178,157,75,18,150,81,115,168,18,11,108)
IMAGE_DATA(55,100,109,145,249,45,115,76,198,249,38,106,17,181,0,201,188,109,178,221,144,181,69,230,183,204,49,25,231,50,214,164)
IMAGE_DATA(191,109,212,60,142,56,70,53,254,3,214,248,59,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
IMAGE_END_DATA(1056, 4)
IMAGE_BEGIN_DATA
IMAGE_DATA(120,156,237,152,191,107,21,65,16,199,7,44,108,45,2,182,175,201,159,96,147,66,108,37,41,180,16,65,5,65,65,124)

View file

@ -1,430 +1,430 @@
#include "CtrlCore.h"
#ifdef GUI_X11
#define LLOG(x) // LOG(x)
NAMESPACE_UPP
bool Xdnd_waiting_status;
bool Xdnd_waiting_finished;
int Xdnd_status;
int Xdnd_version;
static Atom XdndEnter;
static Atom XdndPosition;
static Atom XdndLeave;
static Atom XdndDrop;
static Atom XdndStatus;
static Atom XdndFinished;
static Atom XdndActionCopy;
static Atom XdndActionMove;
void InitDndAtoms()
{
ONCELOCK {
XdndEnter = XAtom("XdndEnter");
XdndPosition = XAtom("XdndPosition");
XdndLeave = XAtom("XdndLeave");
XdndDrop = XAtom("XdndDrop");
XdndStatus = XAtom("XdndStatus");
XdndFinished = XAtom("XdndFinished");
XdndActionCopy = XAtom("XdndActionCopy");
XdndActionMove = XAtom("XdndActionMove");
}
}
XEvent ClientMsg(Window src, Atom type, int format = 32)
{
XEvent e;
Zero(e);
e.xclient.type = ClientMessage;
e.xclient.display = Xdisplay;
e.xclient.window = src;
e.xclient.message_type = type;
e.xclient.format = format;
return e;
}
struct DnDLoop : LocalLoop {
Image move, copy, reject;
Vector<Atom> fmt;
const VectorMap<String, ClipData> *data;
Ptr<Ctrl> source;
void SetFmts(Window w, Atom property);
Window src, target;
int action;
void Request(XSelectionRequestEvent *se);
void Sync();
String GetData(const String& f);
void Leave();
virtual void LeftUp(Point, dword);
virtual bool Key(dword, int);
virtual void MouseMove(Point p, dword);
virtual Image CursorImage(Point, dword);
};
Ptr<DnDLoop> dndloop;
void DnDLoop::Leave()
{
GuiLock __;
if(target) {
LLOG("Sending XdndLeave to " << target);
XEvent e = ClientMsg(target, XdndLeave);
e.xclient.data.l[0] = src;
XSendEvent(Xdisplay, target, XFalse, 0, &e);
}
}
void DnDLoop::Sync()
{
GuiLock __;
if(Xdnd_waiting_status || Xdnd_waiting_finished)
return;
bool tx = Ctrl::TrapX11Errors();
Window root;
unsigned int d1;
int x, y, d2;
Window tgt = Xroot;
int version;
for(;;) {
if(XQueryPointer(Xdisplay, tgt, &root, &tgt, &x, &y, &d2, &d2, &d1)) {
if(!tgt)
break;
Vector<int> x = GetPropertyInts(tgt, XAtom("XdndAware"));
LLOG("XdndAware " << tgt << ": " << x.GetCount());
if(x.GetCount()) {
Xdnd_version = x[0];
break;
}
}
else {
tgt = None;
break;
}
}
if(Xdnd_version < 3)
tgt = None;
if(tgt != target) {
Leave();
target = tgt;
if(target) {
LLOG("Sending XdndEnter to " << target << ", src = " << src);
XEvent e = ClientMsg(target, XdndEnter);
e.xclient.data.l[0] = src;
e.xclient.data.l[1] = (fmt.GetCount() > 3) | (version << 24);
for(int i = 0; i < min(3, fmt.GetCount()); i++)
e.xclient.data.l[i + 2] = fmt[i];
XSendEvent(Xdisplay, target, XFalse, 0, &e);
}
}
if(target) {
LLOG("Sending XdndPosition to " << target << " " << x << ", " << y);
XEvent e = ClientMsg(target, XdndPosition);
e.xclient.data.l[0] = src;
e.xclient.data.l[1] = 0;
e.xclient.data.l[2] = MAKELONG(y, x);
e.xclient.data.l[3] = Xeventtime;
int action = XdndActionCopy;
if(source && source->GetTopCtrl()->GetWindow() == target)
action = XdndActionMove;
if(GetShift())
action = XdndActionMove;
if(GetCtrl())
action = XdndActionCopy;
e.xclient.data.l[4] = action;
XSendEvent(Xdisplay, target, XFalse, 0, &e);
XFlush(Xdisplay);
Xdnd_waiting_status = true;
dword timeout = GetTickCount();
LLOG("Waiting for XdndStatus");
while(Xdnd_waiting_status && GetTickCount() - timeout < 200) {
GuiSleep(0);
ProcessEvents();
}
LLOG("Waiting status " << GetTickCount() - timeout << "ms");
if(Xdnd_waiting_status) {
LLOG("XdndStatus timeout");
Xdnd_status = DND_NONE;
Xdnd_waiting_status = false;
}
else
LLOG("XdndStatus recieved " << Xdnd_status);
}
Ctrl::UntrapX11Errors(tx);
}
void Ctrl::DropStatusEvent(XEvent *event)
{
GuiLock __;
InitDndAtoms();
if(event->type != ClientMessage)
return;
LLOG("DropStatus Client Message " << XAtomName(event->xclient.message_type));
if(event->type == ClientMessage && dndloop && event->xclient.data.l[0] == (int)dndloop->target) {
if(event->xclient.message_type == XdndStatus && Xdnd_waiting_status) {
LLOG("XdndStatus, xdnd action: " << XAtomName(event->xclient.data.l[4]));
if(Xdnd_status == DND_NONE)
Xdnd_status = (event->xclient.data.l[1] & 1) ?
event->xclient.data.l[4] == (int)XdndActionMove ? DND_MOVE : DND_COPY
: DND_NONE;
Xdnd_waiting_status = false;
}
if(event->xclient.message_type == XdndFinished && Xdnd_waiting_finished) {
LLOG("XdndFinished, xdnd action: " << XAtomName(event->xclient.data.l[2]));
if(Xdnd_version == 5)
Xdnd_status = (event->xclient.data.l[1] & 1) ?
event->xclient.data.l[2] == (int)XdndActionMove ? DND_MOVE : DND_COPY
: DND_NONE;
Xdnd_waiting_finished = false;
}
}
}
void DnDLoop::LeftUp(Point, dword)
{
GuiLock __;
LLOG("DnDLoop::LeftUp");
bool tx = TrapX11Errors();
if(target) {
LLOG("Sending XdndDrop to " << target);
XEvent e = ClientMsg(target, XdndDrop);
e.xclient.data.l[0] = src;
e.xclient.data.l[1] = 0;
e.xclient.data.l[2] = Xeventtime;
Xdnd_waiting_finished = true;
XSendEvent(Xdisplay, target, XFalse, 0, &e);
XFlush(Xdisplay);
int timeout = GetTickCount();
LLOG("Waiting for XdndFinished");
while(Xdnd_waiting_finished && GetTickCount() - timeout < 200) {
GuiSleep(0);
ProcessEvents();
}
LLOG("Waiting finished " << GetTickCount() - timeout << "ms");
if(Xdnd_waiting_status) {
LLOG("XdndFinished timeout");
Xdnd_status = DND_NONE;
Xdnd_waiting_finished = false;
}
else
LLOG("XdndFinished recieved");
}
EndLoop();
UntrapX11Errors(tx);
}
void DnDLoop::MouseMove(Point p, dword)
{
GuiLock __;
LLOG("DnDLoop::MouseMove");
Sync();
}
bool DnDLoop::Key(dword, int)
{
GuiLock __;
LLOG("DnDLoop::Key");
Sync();
return false;
}
Image DnDLoop::CursorImage(Point, dword)
{
GuiLock __;
return Xdnd_status == DND_MOVE ? move : Xdnd_status == DND_COPY ? copy : reject;
}
void DnDLoop::SetFmts(Window w, Atom property)
{
GuiLock __;
Buffer<Atom> x(fmt.GetCount());
for(int i = 0; i < fmt.GetCount(); i++) {
x[i] = fmt[i];
LLOG('\t' << XAtomName(x[i]));
}
XChangeProperty(Xdisplay, w, property, XAtom("ATOM"),
32, 0, (unsigned char*)~x,
fmt.GetCount());
}
String DnDLoop::GetData(const String& f)
{
GuiLock __;
int i = data->Find(f);
String d;
if(i >= 0)
d = (*data)[i].Render();
else
if(source)
d = source->GetDropData(f);
return d;
}
String DnDGetData(const String& f)
{
GuiLock __;
String d;
if(dndloop)
d = dndloop->GetData(f);
return d;
}
void DnDLoop::Request(XSelectionRequestEvent *se)
{
GuiLock __;
LLOG("DnDRequest " << XAtomName(se->target));
XEvent e;
e.xselection.type = SelectionNotify;
e.xselection.display = Xdisplay;
e.xselection.requestor = se->requestor;
e.xselection.selection = XAtom("XdndSelection");
e.xselection.target = se->target;
e.xselection.time = se->time;
e.xselection.property = se->property;
if(se->target == XAtom("TARGETS")) {
LLOG("DnDRequest targets:");
SetFmts(se->requestor, se->property);
}
else {
String d = GetData(XAtomName(se->target));
if(d.GetCount())
XChangeProperty(Xdisplay, se->requestor, se->property, se->target, 8, PropModeReplace,
d, d.GetCount());
else
e.xselection.property = None;
}
XSendEvent(Xdisplay, se->requestor, XFalse, 0, &e);
}
void DnDRequest(XSelectionRequestEvent *se)
{
GuiLock __;
if(dndloop) dndloop->Request(se);
}
void DnDClear() {}
void GuiPlatformAdjustDragImage(ImageBuffer& b);
Image MakeDragImage(const Image& arrow, Image sample);
Ptr<Ctrl> sDnDSource;
int Ctrl::DoDragAndDrop(const char *fmts, const Image& sample, dword actions,
const VectorMap<String, ClipData>& data)
{
GuiLock __;
InitDndAtoms();
DnDLoop d;
Xdnd_waiting_status = Xdnd_waiting_finished = false;
d.reject = actions & DND_EXACTIMAGE ? CtrlCoreImg::DndNone() : MakeDragImage(CtrlCoreImg::DndNone(), sample);
if(actions & DND_COPY)
d.copy = actions & DND_EXACTIMAGE ? sample : MakeDragImage(CtrlCoreImg::DndCopy(), sample);
if(actions & DND_MOVE)
d.move = actions & DND_EXACTIMAGE ? sample : MakeDragImage(CtrlCoreImg::DndMoveX11(), sample);
d.SetMaster(*this);
d.data = &data;
d.source = this;
dndloop = &d;
Vector<String> f = Split(fmts, ';');
for(int i = 0; i < f.GetCount(); i++)
d.fmt.Add(XAtom(f[i]));
for(int i = 0; i < data.GetCount(); i++)
d.fmt.Add(XAtom(data.GetKey(i)));
d.SetFmts(xclipboard().win, XAtom("XdndTypeList"));
XSetSelectionOwner(Xdisplay, XAtom("XdndSelection"), xclipboard().win, CurrentTime);
d.src = xclipboard().win;
d.target = None;
sDnDSource = this;
d.Run();
sDnDSource = NULL;
SyncCaret();
LLOG("DoDragAndDrop finished");
return Xdnd_status;
}
Ctrl *Ctrl::GetDragAndDropSource()
{
GuiLock __;
return sDnDSource;
}
Index<String> Ctrl::drop_formats;
int XdndAction;
Point XdndPos;
PasteClip sMakeDropClip(bool paste)
{
PasteClip d;
d.type = 1;
d.paste = paste;
d.accepted = false;
d.allowed = DND_MOVE|DND_COPY;
d.action = XdndAction;
return d;
}
void Ctrl::DnD(Window src, bool paste)
{
GuiLock __;
PasteClip d = sMakeDropClip(paste);
LLOG("Source action " << XdndAction);
DnD(XdndPos, d);
XdndAction = d.GetAction();
LLOG("Target action " << XdndAction);
XEvent e = ClientMsg(src, paste ? XdndFinished : XdndStatus);
e.xclient.data.l[0] = GetWindow();
(paste ? e.xclient.data.l[2] : e.xclient.data.l[4])
= XdndAction == DND_MOVE ? XdndActionMove : XdndActionCopy;
if(d.IsAccepted())
e.xclient.data.l[1] = 1;
LLOG("Sending status/finished to " << src << " accepted: " << d.IsAccepted());
XSendEvent(Xdisplay, src, XFalse, 0, &e);
}
void Ctrl::DropEvent(XWindow& w, XEvent *event)
{
GuiLock __;
InitDndAtoms();
if(event->type != ClientMessage)
return;
Window src = event->xclient.data.l[0];
LLOG("Client Message " << GetWindow() << " " << XAtomName(event->xclient.message_type)
<< ", src: " << src);
if(event->xclient.message_type == XdndEnter) {
LLOG("DnDEnter");
drop_formats.Clear();
if(event->xclient.data.l[1] & 1) {
Vector<int> v = GetPropertyInts(src, XAtom("XdndTypeList"), XA_ATOM);
for(int i = 0; i < v.GetCount(); i++)
drop_formats.Add(XAtomName(v[i]));
}
else
for(int i = 2; i <= 4; i++)
drop_formats.Add(XAtomName(event->xclient.data.l[i]));
}
static Point xdndpos;
if(event->xclient.message_type == XdndPosition) {
dword x = event->xclient.data.l[2];
XdndPos = Point(HIWORD(x), LOWORD(x));
LLOG("XdndPosition " << XdndPos << ", action " << XAtomName(event->xclient.data.l[4]));
XdndAction = event->xclient.data.l[4] == (int)XdndActionMove ? DND_MOVE : DND_COPY;
DnD(src, false);
}
if(event->xclient.message_type == XdndLeave)
DnDLeave();
if(event->xclient.message_type == XdndDrop && dndctrl) {
LLOG("XdndDrop to " << UPP::Name(dndctrl));
DnD(src, true);
DnDLeave();
}
}
END_UPP_NAMESPACE
#endif
#include "CtrlCore.h"
#ifdef GUI_X11
#define LLOG(x) // DLOG(x)
NAMESPACE_UPP
bool Xdnd_waiting_status;
bool Xdnd_waiting_finished;
int Xdnd_status;
int Xdnd_version;
static Atom XdndEnter;
static Atom XdndPosition;
static Atom XdndLeave;
static Atom XdndDrop;
static Atom XdndStatus;
static Atom XdndFinished;
static Atom XdndActionCopy;
static Atom XdndActionMove;
void InitDndAtoms()
{
ONCELOCK {
XdndEnter = XAtom("XdndEnter");
XdndPosition = XAtom("XdndPosition");
XdndLeave = XAtom("XdndLeave");
XdndDrop = XAtom("XdndDrop");
XdndStatus = XAtom("XdndStatus");
XdndFinished = XAtom("XdndFinished");
XdndActionCopy = XAtom("XdndActionCopy");
XdndActionMove = XAtom("XdndActionMove");
}
}
XEvent ClientMsg(Window src, Atom type, int format = 32)
{
XEvent e;
Zero(e);
e.xclient.type = ClientMessage;
e.xclient.display = Xdisplay;
e.xclient.window = src;
e.xclient.message_type = type;
e.xclient.format = format;
return e;
}
struct DnDLoop : LocalLoop {
Image move, copy, reject;
Vector<Atom> fmt;
const VectorMap<String, ClipData> *data;
Ptr<Ctrl> source;
void SetFmts(Window w, Atom property);
Window src, target;
int action;
void Request(XSelectionRequestEvent *se);
void Sync();
String GetData(const String& f);
void Leave();
virtual void LeftUp(Point, dword);
virtual bool Key(dword, int);
virtual void MouseMove(Point p, dword);
virtual Image CursorImage(Point, dword);
};
Ptr<DnDLoop> dndloop;
void DnDLoop::Leave()
{
GuiLock __;
if(target) {
LLOG("Sending XdndLeave to " << target);
XEvent e = ClientMsg(target, XdndLeave);
e.xclient.data.l[0] = src;
XSendEvent(Xdisplay, target, XFalse, 0, &e);
}
}
void DnDLoop::Sync()
{
GuiLock __;
if(Xdnd_waiting_status || Xdnd_waiting_finished)
return;
bool tx = Ctrl::TrapX11Errors();
Window root;
unsigned int d1;
int x, y, d2;
Window tgt = Xroot;
int version;
for(;;) {
if(XQueryPointer(Xdisplay, tgt, &root, &tgt, &x, &y, &d2, &d2, &d1)) {
if(!tgt)
break;
Vector<int> x = GetPropertyInts(tgt, XAtom("XdndAware"));
LLOG("XdndAware " << tgt << ": " << x.GetCount());
if(x.GetCount()) {
Xdnd_version = x[0];
break;
}
}
else {
tgt = None;
break;
}
}
if(Xdnd_version < 3)
tgt = None;
if(tgt != target) {
Leave();
target = tgt;
if(target) {
LLOG("Sending XdndEnter to " << target << ", src = " << src);
XEvent e = ClientMsg(target, XdndEnter);
e.xclient.data.l[0] = src;
e.xclient.data.l[1] = (fmt.GetCount() > 3) | (version << 24);
for(int i = 0; i < min(3, fmt.GetCount()); i++)
e.xclient.data.l[i + 2] = fmt[i];
XSendEvent(Xdisplay, target, XFalse, 0, &e);
}
}
if(target) {
LLOG("Sending XdndPosition to " << target << " " << x << ", " << y);
XEvent e = ClientMsg(target, XdndPosition);
e.xclient.data.l[0] = src;
e.xclient.data.l[1] = 0;
e.xclient.data.l[2] = MAKELONG(y, x);
e.xclient.data.l[3] = Xeventtime;
int action = XdndActionCopy;
if(source && source->GetTopCtrl()->GetWindow() == target)
action = XdndActionMove;
if(GetShift())
action = XdndActionMove;
if(GetCtrl())
action = XdndActionCopy;
e.xclient.data.l[4] = action;
XSendEvent(Xdisplay, target, XFalse, 0, &e);
XFlush(Xdisplay);
Xdnd_waiting_status = true;
dword timeout = GetTickCount();
LLOG("Waiting for XdndStatus");
Xdnd_status = DND_NONE;
while(Xdnd_waiting_status && GetTickCount() - timeout < 200) {
GuiSleep(0);
ProcessEvents();
}
LLOG("Waiting status " << GetTickCount() - timeout << "ms");
if(Xdnd_waiting_status) {
LLOG("XdndStatus timeout");
Xdnd_status = DND_NONE;
Xdnd_waiting_status = false;
}
else
LLOG("XdndStatus recieved " << Xdnd_status);
}
Ctrl::UntrapX11Errors(tx);
}
void Ctrl::DropStatusEvent(XEvent *event)
{
GuiLock __;
InitDndAtoms();
if(event->type != ClientMessage)
return;
LLOG("DropStatus Client Message " << XAtomName(event->xclient.message_type));
if(event->type == ClientMessage && dndloop && event->xclient.data.l[0] == (int)dndloop->target) {
if(event->xclient.message_type == XdndStatus && Xdnd_waiting_status) {
LLOG("XdndStatus, xdnd action: " << XAtomName(event->xclient.data.l[4]));
if(Xdnd_status == DND_NONE)
Xdnd_status = (event->xclient.data.l[1] & 1) ?
event->xclient.data.l[4] == (int)XdndActionMove ? DND_MOVE : DND_COPY
: DND_NONE;
Xdnd_waiting_status = false;
}
if(event->xclient.message_type == XdndFinished && Xdnd_waiting_finished) {
LLOG("XdndFinished, xdnd action: " << XAtomName(event->xclient.data.l[2]));
if(Xdnd_version == 5)
Xdnd_status = (event->xclient.data.l[1] & 1) ?
event->xclient.data.l[2] == (int)XdndActionMove ? DND_MOVE : DND_COPY
: DND_NONE;
Xdnd_waiting_finished = false;
}
}
}
void DnDLoop::LeftUp(Point, dword)
{
GuiLock __;
LLOG("DnDLoop::LeftUp");
bool tx = TrapX11Errors();
if(target) {
LLOG("Sending XdndDrop to " << target);
XEvent e = ClientMsg(target, XdndDrop);
e.xclient.data.l[0] = src;
e.xclient.data.l[1] = 0;
e.xclient.data.l[2] = Xeventtime;
Xdnd_waiting_finished = true;
XSendEvent(Xdisplay, target, XFalse, 0, &e);
XFlush(Xdisplay);
int timeout = GetTickCount();
LLOG("Waiting for XdndFinished");
while(Xdnd_waiting_finished && GetTickCount() - timeout < 200) {
GuiSleep(0);
ProcessEvents();
}
LLOG("Waiting finished " << GetTickCount() - timeout << "ms");
if(Xdnd_waiting_status) {
LLOG("XdndFinished timeout");
Xdnd_status = DND_NONE;
Xdnd_waiting_finished = false;
}
else
LLOG("XdndFinished recieved");
}
EndLoop();
UntrapX11Errors(tx);
}
void DnDLoop::MouseMove(Point p, dword)
{
GuiLock __;
LLOG("DnDLoop::MouseMove");
Sync();
}
bool DnDLoop::Key(dword, int)
{
GuiLock __;
LLOG("DnDLoop::Key");
Sync();
return false;
}
Image DnDLoop::CursorImage(Point, dword)
{
GuiLock __;
return Xdnd_status == DND_MOVE ? move : Xdnd_status == DND_COPY ? copy : reject;
}
void DnDLoop::SetFmts(Window w, Atom property)
{
GuiLock __;
Buffer<Atom> x(fmt.GetCount());
for(int i = 0; i < fmt.GetCount(); i++) {
x[i] = fmt[i];
LLOG('\t' << XAtomName(x[i]));
}
XChangeProperty(Xdisplay, w, property, XAtom("ATOM"),
32, 0, (unsigned char*)~x,
fmt.GetCount());
}
String DnDLoop::GetData(const String& f)
{
GuiLock __;
int i = data->Find(f);
String d;
if(i >= 0)
d = (*data)[i].Render();
else
if(source)
d = source->GetDropData(f);
return d;
}
String DnDGetData(const String& f)
{
GuiLock __;
String d;
if(dndloop)
d = dndloop->GetData(f);
return d;
}
void DnDLoop::Request(XSelectionRequestEvent *se)
{
GuiLock __;
LLOG("DnDRequest " << XAtomName(se->target));
XEvent e;
e.xselection.type = SelectionNotify;
e.xselection.display = Xdisplay;
e.xselection.requestor = se->requestor;
e.xselection.selection = XAtom("XdndSelection");
e.xselection.target = se->target;
e.xselection.time = se->time;
e.xselection.property = se->property;
if(se->target == XAtom("TARGETS")) {
LLOG("DnDRequest targets:");
SetFmts(se->requestor, se->property);
}
else {
String d = GetData(XAtomName(se->target));
if(d.GetCount())
XChangeProperty(Xdisplay, se->requestor, se->property, se->target, 8, PropModeReplace,
d, d.GetCount());
else
e.xselection.property = None;
}
XSendEvent(Xdisplay, se->requestor, XFalse, 0, &e);
}
void DnDRequest(XSelectionRequestEvent *se)
{
GuiLock __;
if(dndloop) dndloop->Request(se);
}
void DnDClear() {}
void GuiPlatformAdjustDragImage(ImageBuffer& b);
Image MakeDragImage(const Image& arrow, Image sample);
Ptr<Ctrl> sDnDSource;
int Ctrl::DoDragAndDrop(const char *fmts, const Image& sample, dword actions,
const VectorMap<String, ClipData>& data)
{
GuiLock __;
InitDndAtoms();
DnDLoop d;
Xdnd_waiting_status = Xdnd_waiting_finished = false;
d.reject = actions & DND_EXACTIMAGE ? CtrlCoreImg::DndNone() : MakeDragImage(CtrlCoreImg::DndNone(), sample);
if(actions & DND_COPY)
d.copy = actions & DND_EXACTIMAGE ? sample : MakeDragImage(CtrlCoreImg::DndCopy(), sample);
if(actions & DND_MOVE)
d.move = actions & DND_EXACTIMAGE ? sample : MakeDragImage(CtrlCoreImg::DndMoveX11(), sample);
d.SetMaster(*this);
d.data = &data;
d.source = this;
dndloop = &d;
Vector<String> f = Split(fmts, ';');
for(int i = 0; i < f.GetCount(); i++)
d.fmt.Add(XAtom(f[i]));
for(int i = 0; i < data.GetCount(); i++)
d.fmt.Add(XAtom(data.GetKey(i)));
d.SetFmts(xclipboard().win, XAtom("XdndTypeList"));
XSetSelectionOwner(Xdisplay, XAtom("XdndSelection"), xclipboard().win, CurrentTime);
d.src = xclipboard().win;
d.target = None;
sDnDSource = this;
d.Run();
sDnDSource = NULL;
SyncCaret();
LLOG("DoDragAndDrop finished");
return Xdnd_status;
}
Ctrl *Ctrl::GetDragAndDropSource()
{
GuiLock __;
return sDnDSource;
}
Index<String> Ctrl::drop_formats;
int XdndAction;
Point XdndPos;
PasteClip sMakeDropClip(bool paste)
{
PasteClip d;
d.type = 1;
d.paste = paste;
d.accepted = false;
d.allowed = DND_MOVE|DND_COPY;
d.action = XdndAction;
return d;
}
void Ctrl::DnD(Window src, bool paste)
{
GuiLock __;
PasteClip d = sMakeDropClip(paste);
LLOG("Source action " << XdndAction);
DnD(XdndPos, d);
XdndAction = d.GetAction();
LLOG("Target action " << XdndAction);
XEvent e = ClientMsg(src, paste ? XdndFinished : XdndStatus);
e.xclient.data.l[0] = GetWindow();
e.xclient.data.l[paste ? 2 : 4] = XdndAction == DND_MOVE ? XdndActionMove : XdndActionCopy;
if(d.IsAccepted())
e.xclient.data.l[1] = 1;
LLOG("Sending status/finished to " << src << " accepted: " << d.IsAccepted());
XSendEvent(Xdisplay, src, XFalse, 0, &e);
}
void Ctrl::DropEvent(XWindow& w, XEvent *event)
{
GuiLock __;
InitDndAtoms();
if(event->type != ClientMessage)
return;
Window src = event->xclient.data.l[0];
LLOG("Client Message " << GetWindow() << " " << XAtomName(event->xclient.message_type)
<< ", src: " << src);
if(event->xclient.message_type == XdndEnter) {
LLOG("DnDEnter");
drop_formats.Clear();
if(event->xclient.data.l[1] & 1) {
Vector<int> v = GetPropertyInts(src, XAtom("XdndTypeList"), XA_ATOM);
for(int i = 0; i < v.GetCount(); i++)
drop_formats.Add(XAtomName(v[i]));
}
else
for(int i = 2; i <= 4; i++)
drop_formats.Add(XAtomName(event->xclient.data.l[i]));
}
static Point xdndpos;
if(event->xclient.message_type == XdndPosition) {
dword x = event->xclient.data.l[2];
XdndPos = Point(HIWORD(x), LOWORD(x));
LLOG("XdndPosition " << XdndPos << ", action " << XAtomName(event->xclient.data.l[4]));
XdndAction = event->xclient.data.l[4] == (int)XdndActionMove ? DND_MOVE : DND_COPY;
DnD(src, false);
}
if(event->xclient.message_type == XdndLeave)
DnDLeave();
if(event->xclient.message_type == XdndDrop && dndctrl) {
LLOG("XdndDrop to " << UPP::Name(dndctrl));
DnD(src, true);
DnDLeave();
}
}
END_UPP_NAMESPACE
#endif

View file

@ -3,7 +3,7 @@
#include "Draw/init"
#include "plugin\bmp/init"
#include "RichText/init"
#define BLITZ_INDEX__ F6A8B66C284D5064504C666248075C21A
#define BLITZ_INDEX__ F656a4ea94e4f808b1ec63034b0e6c5ac
#include "CtrlCore.icpp"
#undef BLITZ_INDEX__
#endif

View file

@ -668,6 +668,7 @@ void EditField::DragAndDrop(Point p, PasteClip& d)
if(AcceptText(d)) {
SaveUndo();
int sell, selh;
WString txt = GetWString(d);
if(GetSelection(sell, selh)) {
if(c >= sell && c < selh) {
RemoveSelection();
@ -683,7 +684,7 @@ void EditField::DragAndDrop(Point p, PasteClip& d)
d.SetAction(DND_COPY);
}
}
int count = Insert(c, GetWString(d));
int count = Insert(c, txt);
SetFocus();
SetSelection(c, c + count);
Action();
@ -744,6 +745,8 @@ void EditField::LeftDrag(Point p, dword flags)
iw.Alpha().DrawText(0, 0, sel, StdFont(), White);
VectorMap<String, ClipData> data;
Append(data, sel);
bool oks = keep_selection;
keep_selection = true;
if(DoDragAndDrop(data, iw) == DND_MOVE) {
CancelSelection();
SaveUndo();
@ -752,6 +755,7 @@ void EditField::LeftDrag(Point p, dword flags)
Finish();
Action();
}
keep_selection = oks;
}
}

View file

@ -782,6 +782,7 @@ void LineEdit::DragAndDrop(Point p, PasteClip& d)
NextUndo();
int a = sb.y;
int sell, selh;
WString text = GetWString(d);
if(GetSelection(sell, selh)) {
if(c >= sell && c < selh) {
RemoveSelection();
@ -797,7 +798,7 @@ void LineEdit::DragAndDrop(Point p, PasteClip& d)
d.SetAction(DND_COPY);
}
}
int count = Insert(c, GetWString(d));
int count = Insert(c, text);
sb.y = a;
SetFocus();
SetSelection(c, c + count);

View file

@ -158,4 +158,4 @@ void ShellOpenFolder(const String& dir)
#else
system("xdg-open " + dir + " &");
#endif
}
}