diff --git a/uppsrc/CtrlCore/Ctrl.iml b/uppsrc/CtrlCore/Ctrl.iml index 85cf0553e..143716e8d 100644 --- a/uppsrc/CtrlCore/Ctrl.iml +++ b/uppsrc/CtrlCore/Ctrl.iml @@ -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) diff --git a/uppsrc/CtrlCore/X11DnD.cpp b/uppsrc/CtrlCore/X11DnD.cpp index 35ff5adc7..57c2d5b4d 100644 --- a/uppsrc/CtrlCore/X11DnD.cpp +++ b/uppsrc/CtrlCore/X11DnD.cpp @@ -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 fmt; - const VectorMap *data; - Ptr 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; - -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 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 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 sDnDSource; - -int Ctrl::DoDragAndDrop(const char *fmts, const Image& sample, dword actions, - const VectorMap& 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 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 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 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 fmt; + const VectorMap *data; + Ptr 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; + +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 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 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 sDnDSource; + +int Ctrl::DoDragAndDrop(const char *fmts, const Image& sample, dword actions, + const VectorMap& 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 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 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 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 diff --git a/uppsrc/CtrlCore/init b/uppsrc/CtrlCore/init index cb2c82ff1..aa63470cf 100644 --- a/uppsrc/CtrlCore/init +++ b/uppsrc/CtrlCore/init @@ -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 diff --git a/uppsrc/CtrlLib/EditField.cpp b/uppsrc/CtrlLib/EditField.cpp index 5a81cfb8c..0548881be 100644 --- a/uppsrc/CtrlLib/EditField.cpp +++ b/uppsrc/CtrlLib/EditField.cpp @@ -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 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; } } diff --git a/uppsrc/CtrlLib/LineEdit.cpp b/uppsrc/CtrlLib/LineEdit.cpp index 53ed8097f..cce1e59d6 100644 --- a/uppsrc/CtrlLib/LineEdit.cpp +++ b/uppsrc/CtrlLib/LineEdit.cpp @@ -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); diff --git a/uppsrc/ide/Common/ComDlg.cpp b/uppsrc/ide/Common/ComDlg.cpp index 4c1b48487..8567fee4f 100644 --- a/uppsrc/ide/Common/ComDlg.cpp +++ b/uppsrc/ide/Common/ComDlg.cpp @@ -158,4 +158,4 @@ void ShellOpenFolder(const String& dir) #else system("xdg-open " + dir + " &"); #endif -} \ No newline at end of file +}