add support XDND for X
This commit is contained in:
@@ -36,6 +36,8 @@
|
||||
|
||||
#include "posix/msg_dispatcher.hpp"
|
||||
|
||||
#include <iostream> //debug
|
||||
|
||||
namespace nana
|
||||
{
|
||||
namespace detail
|
||||
@@ -500,11 +502,11 @@ namespace detail
|
||||
atombase_.net_wm_window_type_dialog = ::XInternAtom(display_, "_NET_WM_WINDOW_TYPE_DIALOG", False);
|
||||
atombase_.motif_wm_hints = ::XInternAtom(display_, "_MOTIF_WM_HINTS", False);
|
||||
|
||||
atombase_.clipboard = ::XInternAtom(display_, "CLIPBOARD", True);
|
||||
atombase_.text = ::XInternAtom(display_, "TEXT", True);
|
||||
atombase_.text_uri_list = ::XInternAtom(display_, "text/uri-list", True);
|
||||
atombase_.utf8_string = ::XInternAtom(display_, "UTF8_STRING", True);
|
||||
atombase_.targets = ::XInternAtom(display_, "TARGETS", True);
|
||||
atombase_.clipboard = ::XInternAtom(display_, "CLIPBOARD", False);
|
||||
atombase_.text = ::XInternAtom(display_, "TEXT", False);
|
||||
atombase_.text_uri_list = ::XInternAtom(display_, "text/uri-list", False);
|
||||
atombase_.utf8_string = ::XInternAtom(display_, "UTF8_STRING", False);
|
||||
atombase_.targets = ::XInternAtom(display_, "TARGETS", False);
|
||||
|
||||
atombase_.xdnd_aware = ::XInternAtom(display_, "XdndAware", False);
|
||||
atombase_.xdnd_enter = ::XInternAtom(display_, "XdndEnter", False);
|
||||
@@ -514,6 +516,7 @@ namespace detail
|
||||
atombase_.xdnd_drop = ::XInternAtom(display_, "XdndDrop", False);
|
||||
atombase_.xdnd_selection = ::XInternAtom(display_, "XdndSelection", False);
|
||||
atombase_.xdnd_typelist = ::XInternAtom(display_, "XdndTypeList", False);
|
||||
atombase_.xdnd_leave = ::XInternAtom(display_, "XdndLeave", False);
|
||||
atombase_.xdnd_finished = ::XInternAtom(display_, "XdndFinished", False);
|
||||
|
||||
msg_dispatcher_ = new msg_dispatcher(display_);
|
||||
@@ -1041,7 +1044,7 @@ namespace detail
|
||||
msg_dispatcher_->dispatch(reinterpret_cast<Window>(modal));
|
||||
}
|
||||
|
||||
void platform_spec::msg_dispatch(std::function<bool(const msg_packet_tag&)> msg_filter_fn)
|
||||
void platform_spec::msg_dispatch(std::function<propagation_chain(const msg_packet_tag&)> msg_filter_fn)
|
||||
{
|
||||
msg_dispatcher_->dispatch(msg_filter_fn);
|
||||
|
||||
@@ -1116,15 +1119,49 @@ namespace detail
|
||||
platform_scope_guard lock;
|
||||
if(0 != xdnd_.dragdrop.count(wd))
|
||||
return false;
|
||||
|
||||
#if 0 //deprecated
|
||||
std::cout<<"ChangeProperty XdndAware"<<std::endl;
|
||||
int dndver = 4;
|
||||
::XChangeProperty(display_, reinterpret_cast<Window>(wd), atombase_.xdnd_aware, XA_ATOM, sizeof(int) * 8,
|
||||
PropModeReplace, reinterpret_cast<unsigned char*>(&dndver), 1);
|
||||
|
||||
#endif
|
||||
xdnd_.dragdrop[wd] = ddrop;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t platform_spec::dragdrop_target(native_window_type wd, bool insert, std::size_t count)
|
||||
{
|
||||
std::size_t new_val = 0;
|
||||
platform_scope_guard lock;
|
||||
if(insert)
|
||||
{
|
||||
new_val = (xdnd_.targets[wd] += count);
|
||||
if(1 == new_val)
|
||||
{
|
||||
std::cout<<"ChangeProperty XdndAware"<<std::endl;
|
||||
int dndver = 5;
|
||||
::XChangeProperty(display_, reinterpret_cast<Window>(wd), atombase_.xdnd_aware, XA_ATOM, sizeof(int) * 8,
|
||||
PropModeReplace, reinterpret_cast<unsigned char*>(&dndver), 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto i = xdnd_.targets.find(wd);
|
||||
if(i == xdnd_.targets.end())
|
||||
return 0;
|
||||
|
||||
new_val = (i->second > count ? i->second - count : 0);
|
||||
if(0 == new_val)
|
||||
{
|
||||
xdnd_.targets.erase(wd);
|
||||
::XDeleteProperty(display_, reinterpret_cast<Window>(wd), atombase_.xdnd_aware);
|
||||
}
|
||||
else
|
||||
i->second = new_val;
|
||||
}
|
||||
return new_val;
|
||||
}
|
||||
|
||||
x11_dragdrop_interface* platform_spec::remove_dragdrop(native_window_type wd)
|
||||
{
|
||||
platform_scope_guard lock;
|
||||
@@ -1196,6 +1233,7 @@ namespace detail
|
||||
}
|
||||
else if(evt.xselection.property == self.atombase_.xdnd_selection)
|
||||
{
|
||||
std::cout<<"Platform SelectionNotfy by XdndSelection, type="<<type<<", good_type="<<self.xdnd_.good_type<<", bytes_left="<<bytes_left<<std::endl;
|
||||
bool accepted = false;
|
||||
msg.kind = msg_packet_tag::pkt_family::mouse_drop;
|
||||
msg.u.mouse_drop.window = 0;
|
||||
@@ -1209,6 +1247,8 @@ namespace detail
|
||||
{
|
||||
auto files = new std::vector<std::string>;
|
||||
std::stringstream ss(reinterpret_cast<char*>(data));
|
||||
|
||||
std::cout<<" data:["<<ss.str()<<"]"<<std::endl;
|
||||
while(true)
|
||||
{
|
||||
std::string file;
|
||||
@@ -1228,6 +1268,8 @@ namespace detail
|
||||
|
||||
files->push_back(file);
|
||||
}
|
||||
|
||||
std::cout<<" file size:"<<files->size()<<std::endl;
|
||||
if(files->size())
|
||||
{
|
||||
msg.u.mouse_drop.window = evt.xselection.requestor;
|
||||
@@ -1241,9 +1283,12 @@ namespace detail
|
||||
accepted = true;
|
||||
::XFree(data);
|
||||
}
|
||||
else
|
||||
std::cout<<" invalid property"<<std::endl;
|
||||
}
|
||||
XEvent respond;
|
||||
::XEvent respond;
|
||||
::memset(respond.xclient.data.l, 0, sizeof(respond.xclient.data.l));
|
||||
respond.xany.type = ClientMessage;
|
||||
respond.xclient.display = self.display_;
|
||||
respond.xclient.window = self.xdnd_.wd_src;
|
||||
respond.xclient.message_type = self.atombase_.xdnd_finished;
|
||||
@@ -1266,6 +1311,16 @@ namespace detail
|
||||
}
|
||||
else if(SelectionRequest == evt.type)
|
||||
{
|
||||
std::cout<<"Event SelectionRequest in platform spec";
|
||||
//Skip if it is requested by XDND, it will be processed by dragdrop's xdnd_protocol
|
||||
if(self.atombase_.xdnd_selection == evt.xselectionrequest.selection)
|
||||
{
|
||||
std::cout<<", xdnd_selection"<<std::endl;
|
||||
return 0; //
|
||||
}
|
||||
|
||||
std::cout<<std::endl;
|
||||
|
||||
auto disp = evt.xselectionrequest.display;
|
||||
XEvent respond;
|
||||
|
||||
@@ -1311,6 +1366,7 @@ namespace detail
|
||||
{
|
||||
if(self.atombase_.xdnd_enter == evt.xclient.message_type)
|
||||
{
|
||||
std::cout<<"Platform: XdndEnter";
|
||||
const Atom * atoms = reinterpret_cast<const Atom*>(&(evt.xclient.data.l[2]));
|
||||
unsigned long len = 3;
|
||||
unsigned char * data = 0;
|
||||
@@ -1322,54 +1378,119 @@ namespace detail
|
||||
Atom type;
|
||||
int format;
|
||||
unsigned long bytes_left;
|
||||
::XGetWindowProperty(self.display_, self.xdnd_.wd_src, self.atombase_.xdnd_typelist, 0, 0, False,
|
||||
auto status = ::XGetWindowProperty(self.display_, self.xdnd_.wd_src, self.atombase_.xdnd_typelist, 0, 0, False,
|
||||
XA_ATOM, &type, &format, &len, &bytes_left, &data);
|
||||
|
||||
std::cout<<", XGetWindowProperty xdnd_typelist = "<<status<<" bytes_left="<<bytes_left<<std::endl;
|
||||
|
||||
if(bytes_left > 0)
|
||||
{
|
||||
::XGetWindowProperty(self.display_, self.xdnd_.wd_src, self.atombase_.xdnd_typelist,
|
||||
0, bytes_left, False, XA_ATOM,
|
||||
&type, &format, &len, &bytes_left, &data);
|
||||
|
||||
std::cout<<" format="<<format<<" len="<<len<<" bytes_left="<<bytes_left;
|
||||
auto type_name = ::XGetAtomName(self.display_, type);
|
||||
if(type_name)
|
||||
{
|
||||
std::cout<<" type="<<type_name;
|
||||
::XFree(type_name);
|
||||
}
|
||||
std::cout<<std::endl;
|
||||
|
||||
if(XA_ATOM == type && len > 0)
|
||||
atoms = reinterpret_cast<const Atom*>(data);
|
||||
}
|
||||
}
|
||||
else
|
||||
std::cout<<", less than 3 types"<<std::endl;
|
||||
|
||||
#define DEBUG_XdndDirectSave
|
||||
#ifdef DEBUG_XdndDirectSave
|
||||
Atom XdndDirectSave = 0;
|
||||
#endif
|
||||
self.xdnd_.good_type = None;
|
||||
for(unsigned long i = 0; i < len; ++i)
|
||||
{
|
||||
auto name = XGetAtomName(self.display_, atoms[i]); //debug
|
||||
if(name)
|
||||
{
|
||||
std::cout<<" Supported type: "<<name<<std::endl;
|
||||
#ifdef DEBUG_XdndDirectSave
|
||||
if(strstr(name, "XdndDirectSave"))
|
||||
XdndDirectSave = atoms[i];
|
||||
#endif
|
||||
::XFree(name);
|
||||
}
|
||||
else
|
||||
std::cout<<" Supported type: no name("<<atoms[i]<<")"<<std::endl;
|
||||
|
||||
if(atoms[i] == self.atombase_.text_uri_list)
|
||||
{
|
||||
self.xdnd_.good_type = self.atombase_.text_uri_list;
|
||||
break;
|
||||
//break;
|
||||
}
|
||||
}
|
||||
|
||||
if(data)
|
||||
::XFree(data);
|
||||
|
||||
#ifdef DEBUG_XdndDirectSave //debug
|
||||
if(XdndDirectSave)
|
||||
{
|
||||
Atom type;
|
||||
int format;
|
||||
unsigned long bytes_left;
|
||||
|
||||
auto status = ::XGetWindowProperty(self.display_, self.xdnd_.wd_src, XdndDirectSave, 0, 0, False, XA_ATOM, &type, &format, &len, &bytes_left, &data);
|
||||
auto name = XGetAtomName(self.display_, type); //debug
|
||||
if(name)
|
||||
{
|
||||
std::cout<<" XdndDirectSave text/plain Atom: "<<name<<std::endl;
|
||||
::XFree(name);
|
||||
}
|
||||
|
||||
std::cout<<", XGetWindowProperty XdndDirectSave = "<<status<<" bytes_left="<<bytes_left<<std::endl;
|
||||
|
||||
if(bytes_left > 0)
|
||||
{
|
||||
::XGetWindowProperty(self.display_, self.xdnd_.wd_src, XdndDirectSave,
|
||||
0, bytes_left, False, type,
|
||||
&type, &format, &len, &bytes_left, &data);
|
||||
|
||||
std::cout<<" XdndDirectSave Data:["<<(char*)data<<"]"<<std::endl;
|
||||
std::system("cp xds.txt /home/jinhao/xds.txt");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 2;
|
||||
}
|
||||
else if(self.atombase_.xdnd_position == evt.xclient.message_type)
|
||||
{
|
||||
std::cout<<"Platform: XdndPosition"<<std::endl;
|
||||
|
||||
Window wd_src = evt.xclient.data.l[0];
|
||||
int x = (evt.xclient.data.l[2] >> 16);
|
||||
int y = (evt.xclient.data.l[2] & 0xFFFF);
|
||||
|
||||
bool accepted = false;
|
||||
int accepted = 0; //0 means refusing, 1 means accpeting
|
||||
//We have got the type what we want.
|
||||
if(self.xdnd_.good_type != None)
|
||||
{
|
||||
Window child;
|
||||
::XTranslateCoordinates(self.display_, self.root_window(), evt.xclient.window, x, y, &self.xdnd_.pos.x, &self.xdnd_.pos.y, &child);
|
||||
|
||||
std::cout<<" find_window"<<std::endl;
|
||||
auto wd = bedrock.wd_manager().find_window(reinterpret_cast<native_window_type>(evt.xclient.window), self.xdnd_.pos);
|
||||
if(wd && wd->flags.dropable)
|
||||
{
|
||||
accepted = true;
|
||||
//Cache the time stamp in XdndPosition, and the time stamp must be passed to XConvertSelection for requesting selection
|
||||
self.xdnd_.timestamp = evt.xclient.data.l[3];
|
||||
self.xdnd_.pos = wd->pos_root;
|
||||
accepted = 1;
|
||||
}
|
||||
|
||||
std::cout<<" return,"<<wd<<std::endl;
|
||||
}
|
||||
|
||||
XEvent respond;
|
||||
@@ -1383,18 +1504,30 @@ namespace detail
|
||||
//Target window
|
||||
respond.xclient.data.l[0] = evt.xclient.window;
|
||||
//Accept set
|
||||
respond.xclient.data.l[1] = (accepted ? 1 : 0);
|
||||
respond.xclient.data.l[1] = accepted;
|
||||
respond.xclient.data.l[2] = 0;
|
||||
respond.xclient.data.l[3] = 0;
|
||||
respond.xclient.data.l[4] = self.atombase_.xdnd_action_copy;
|
||||
|
||||
std::cout<<" Target XdndStatus begin to send. Accepted"<<accepted<<std::endl;
|
||||
::XSendEvent(self.display_, wd_src, True, NoEventMask, &respond);
|
||||
std::cout<<" Target XdndStatus ed"<<std::endl;
|
||||
return 2;
|
||||
}
|
||||
else if(self.atombase_.xdnd_status == evt.xclient.message_type)
|
||||
{
|
||||
std::cout<<"Platform Recv XdndStatus"<<std::endl;
|
||||
}
|
||||
else if(self.atombase_.xdnd_drop == evt.xclient.message_type)
|
||||
{
|
||||
Window owner = ::XGetSelectionOwner(self.display_, self.atombase_.xdnd_selection);
|
||||
std::cout<<"Platform XdndDrop: XdndSelectionOwner = "<<owner<<std::endl;
|
||||
|
||||
::XConvertSelection(self.display_, self.atombase_.xdnd_selection, self.xdnd_.good_type, self.atombase_.xdnd_selection,
|
||||
evt.xclient.window, self.xdnd_.timestamp);
|
||||
|
||||
std::cout<<" XConvertSelection ed"<<std::endl;
|
||||
|
||||
//The XdndDrop should send a XdndFinished to source window.
|
||||
//This operation is implemented in SelectionNotify, because
|
||||
//XdndFinished should be sent after retrieving data.
|
||||
|
||||
Reference in New Issue
Block a user