improve dnd interfaces
This commit is contained in:
@@ -513,6 +513,8 @@ namespace detail
|
||||
atombase_.xdnd_position = ::XInternAtom(display_, "XdndPosition", False);
|
||||
atombase_.xdnd_status = ::XInternAtom(display_, "XdndStatus", False);
|
||||
atombase_.xdnd_action_copy = ::XInternAtom(display_, "XdndActionCopy", False);
|
||||
atombase_.xdnd_action_move = ::XInternAtom(display_, "XdndActionMove", False);
|
||||
atombase_.xdnd_action_link = ::XInternAtom(display_, "XdndActionLink", False);
|
||||
atombase_.xdnd_drop = ::XInternAtom(display_, "XdndDrop", False);
|
||||
atombase_.xdnd_selection = ::XInternAtom(display_, "XdndSelection", False);
|
||||
atombase_.xdnd_typelist = ::XInternAtom(display_, "XdndTypeList", False);
|
||||
|
||||
@@ -159,6 +159,8 @@ namespace detail
|
||||
Atom xdnd_position;
|
||||
Atom xdnd_status;
|
||||
Atom xdnd_action_copy;
|
||||
Atom xdnd_action_move;
|
||||
Atom xdnd_action_link;
|
||||
Atom xdnd_drop;
|
||||
Atom xdnd_selection;
|
||||
Atom xdnd_typelist;
|
||||
|
||||
@@ -16,69 +16,26 @@
|
||||
|
||||
#include "platform_spec.hpp"
|
||||
#include <nana/filesystem/filesystem.hpp>
|
||||
#include <vector>
|
||||
|
||||
#include "theme.hpp"
|
||||
#include <X11/Xcursor/Xcursor.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
#define DEBUG_XDND_PROTOCOL
|
||||
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
#include <iostream> //debug
|
||||
#endif
|
||||
|
||||
namespace nana{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
|
||||
class shared_icons
|
||||
{
|
||||
public:
|
||||
shared_icons()
|
||||
{
|
||||
path_ = "/usr/share/icons/";
|
||||
ifs_.open(path_ + "default/index.theme");
|
||||
}
|
||||
|
||||
std::string cursor(const std::string& name)
|
||||
{
|
||||
auto theme = _m_read("Icon Theme", "Inherits");
|
||||
|
||||
return path_ + theme + "/cursors/" + name;
|
||||
}
|
||||
private:
|
||||
std::string _m_read(const std::string& category, const std::string& key)
|
||||
{
|
||||
ifs_.seekg(0, std::ios::beg);
|
||||
|
||||
bool found_cat = false;
|
||||
while(ifs_.good())
|
||||
{
|
||||
std::string text;
|
||||
std::getline(ifs_, text);
|
||||
|
||||
if(0 == text.find('['))
|
||||
{
|
||||
if(found_cat)
|
||||
break;
|
||||
|
||||
if(text.find(category + "]") != text.npos)
|
||||
{
|
||||
found_cat = true;
|
||||
}
|
||||
}
|
||||
else if(found_cat && (text.find(key + "=") == 0))
|
||||
{
|
||||
return text.substr(key.size() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
private:
|
||||
std::string path_;
|
||||
std::ifstream ifs_;
|
||||
};
|
||||
|
||||
struct xdnd_data
|
||||
{
|
||||
Atom requested_action;
|
||||
std::vector<std::filesystem::path> files;
|
||||
};
|
||||
|
||||
@@ -100,31 +57,40 @@ namespace nana{
|
||||
auto disp = spec_.open_display();
|
||||
detail::platform_scope_guard lock;
|
||||
::XSetSelectionOwner(disp, spec_.atombase().xdnd_selection, source, CurrentTime);
|
||||
std::cout<<"XSetSelectionOwner "<<source<<std::endl;
|
||||
|
||||
shared_icons icons;
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"XSetSelectionOwner "<<source<<std::endl;
|
||||
#endif
|
||||
/* //deprecated
|
||||
theme icons;
|
||||
cursor_.dnd_copy = ::XcursorFilenameLoadCursor(disp, icons.cursor("dnd-copy").c_str());
|
||||
cursor_.dnd_move = ::XcursorFilenameLoadCursor(disp, icons.cursor("dnd-move").c_str());
|
||||
cursor_.dnd_none = ::XcursorFilenameLoadCursor(disp, icons.cursor("dnd-none").c_str());
|
||||
cursor_.dnd_none = ::XcursorFilenameLoadCursor(disp, icons.cursor("dnd-none").c_str());
|
||||
*/
|
||||
cursor_.dnd_copy = ::XcursorLibraryLoadCursor(disp, "dnd-copy");
|
||||
cursor_.dnd_move = ::XcursorLibraryLoadCursor(disp, "dnd-move");
|
||||
cursor_.dnd_none = ::XcursorLibraryLoadCursor(disp, "dnd-none");
|
||||
}
|
||||
|
||||
~xdnd_protocol()
|
||||
{
|
||||
auto disp = spec_.open_display();
|
||||
::XFreeCursor(disp, cursor_.dnd_copy);
|
||||
::XFreeCursor(disp, cursor_.dnd_move);
|
||||
::XFreeCursor(disp, cursor_.dnd_none);
|
||||
}
|
||||
|
||||
void mouse_move(Window wd, const nana::point& pos)
|
||||
void mouse_move(Window wd, const nana::point& pos, Atom requested_action)
|
||||
{
|
||||
if(wd != target_)
|
||||
{
|
||||
_m_xdnd_leave();
|
||||
|
||||
if(_m_xdnd_enter(wd))
|
||||
_m_xdnd_position(pos);
|
||||
_m_xdnd_position(pos, requested_action);
|
||||
}
|
||||
else
|
||||
_m_xdnd_position(pos);
|
||||
_m_xdnd_position(pos, requested_action);
|
||||
}
|
||||
|
||||
void mouse_leave()
|
||||
@@ -132,9 +98,14 @@ namespace nana{
|
||||
_m_xdnd_leave();
|
||||
}
|
||||
|
||||
void mouse_release()
|
||||
bool mouse_release()
|
||||
{
|
||||
_m_xdnd_drop();
|
||||
return _m_xdnd_drop();
|
||||
}
|
||||
|
||||
Atom executed_action() const
|
||||
{
|
||||
return executed_action_;
|
||||
}
|
||||
|
||||
//Return true to exit xdnd_protocol event handler
|
||||
@@ -144,16 +115,18 @@ namespace nana{
|
||||
|
||||
if(atombase.xdnd_status == xclient.message_type)
|
||||
{
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"Event: XdndStatus"<<std::endl;
|
||||
|
||||
#endif
|
||||
if(xdnd_status_state::position != xstate_ && xdnd_status_state::drop != xstate_)
|
||||
return false;
|
||||
|
||||
Window target_wd = static_cast<Window>(xclient.data.l[0]);
|
||||
bool is_accepted_by_target = (xclient.data.l[1] & 1);
|
||||
|
||||
std::cout<<"XdndStatus: Accepted="<<is_accepted_by_target<<", target="<<is_accepted_by_target<<std::endl;
|
||||
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"XdndStatus: Accepted="<<is_accepted_by_target<<", target="<<target_wd<<std::endl;
|
||||
#endif
|
||||
if(xclient.data.l[1] & 0x2)
|
||||
{
|
||||
rectangle rct{
|
||||
@@ -166,21 +139,28 @@ namespace nana{
|
||||
if(!rct.empty())
|
||||
{
|
||||
mvout_table_[target_wd] = rct;
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<". rct=("<<rct.x<<","<<rct.y<<","<<rct.width<<","<<rct.height<<")";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<std::endl;
|
||||
|
||||
#endif
|
||||
_m_cursor(is_accepted_by_target);
|
||||
|
||||
|
||||
|
||||
if((!is_accepted_by_target) && (xdnd_status_state::drop == xstate_))
|
||||
{
|
||||
_m_xdnd_leave();
|
||||
return true;
|
||||
}
|
||||
|
||||
executed_action_ = xclient.data.l[4];
|
||||
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<" Assign ExecutedAction = "<<static_cast<int>(executed_action_)<<std::endl;
|
||||
#endif
|
||||
|
||||
xstate_ = xdnd_status_state::normal;
|
||||
}
|
||||
else if(atombase.xdnd_finished == xclient.message_type)
|
||||
@@ -193,8 +173,9 @@ namespace nana{
|
||||
{
|
||||
if(spec_.atombase().xdnd_selection == xselectionrequest.selection)
|
||||
{
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"Event SelectionRequest: XdndSelection"<<std::endl;
|
||||
|
||||
#endif
|
||||
::XEvent evt;
|
||||
evt.xselection.type = SelectionNotify;
|
||||
evt.xselection.display = xselectionrequest.display;
|
||||
@@ -204,6 +185,7 @@ namespace nana{
|
||||
evt.xselection.property = 0;
|
||||
evt.xselection.time = xselectionrequest.time;
|
||||
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
auto property_name = ::XGetAtomName(spec_.open_display(), xselectionrequest.property); //debug
|
||||
|
||||
std::cout<<"SelectionRequest"<<std::endl;
|
||||
@@ -213,11 +195,13 @@ namespace nana{
|
||||
std::cout<<" property ="<<xselectionrequest.property<<", name="<<property_name<<std::endl;
|
||||
std::cout<<" target ="<<xselectionrequest.target<<std::endl;
|
||||
::XFree(property_name);
|
||||
#endif
|
||||
|
||||
if(xselectionrequest.target == spec_.atombase().text_uri_list)
|
||||
{
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"SelectionRequest target = text_uri_list";
|
||||
|
||||
#endif
|
||||
if(data.files.size())
|
||||
{
|
||||
std::string uri_list;
|
||||
@@ -227,9 +211,9 @@ namespace nana{
|
||||
uri_list += file.u8string();
|
||||
uri_list += "\r\n";
|
||||
}
|
||||
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<". URIs="<<uri_list<<std::endl;
|
||||
|
||||
#endif
|
||||
::XChangeProperty (spec_.open_display(),
|
||||
xselectionrequest.requestor,
|
||||
xselectionrequest.property,
|
||||
@@ -242,9 +226,10 @@ namespace nana{
|
||||
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
else
|
||||
std::cout<<"SelectionRequest target = "<<xselectionrequest.target<<std::endl;
|
||||
|
||||
#endif
|
||||
platform_scope_guard lock;
|
||||
::XSendEvent(spec_.open_display(), xselectionrequest.requestor, False, 0, &evt);
|
||||
::XFlush(spec_.open_display());
|
||||
@@ -254,7 +239,6 @@ namespace nana{
|
||||
}
|
||||
}
|
||||
private:
|
||||
|
||||
bool _m_xdnd_enter(Window wd)
|
||||
{
|
||||
//xdnd version of the window
|
||||
@@ -263,13 +247,15 @@ namespace nana{
|
||||
return false;
|
||||
|
||||
target_ = wd;
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"Send XdndEnter, text/uri-list="<<spec_.atombase().text_uri_list<<std::endl;
|
||||
#endif
|
||||
_m_client_msg(spec_.atombase().xdnd_enter, (xdnd_ver << 24), spec_.atombase().text_uri_list, XA_STRING);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void _m_xdnd_position(const nana::point& pos)
|
||||
void _m_xdnd_position(const nana::point& pos, Atom requested_action)
|
||||
{
|
||||
if(xdnd_status_state::normal != xstate_)
|
||||
return;
|
||||
@@ -278,12 +264,13 @@ namespace nana{
|
||||
if(i != mvout_table_.end() && i->second.is_hit(pos))
|
||||
return;
|
||||
|
||||
std::cout<<"Send: XdndPosition"<<std::endl;
|
||||
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"Send: XdndPosition, RequestedAction="<<requested_action<<", XdndActionCopy="<<spec_.atombase().xdnd_action_copy<<std::endl;
|
||||
#endif
|
||||
xstate_ = xdnd_status_state::position;
|
||||
//Send XdndPosition
|
||||
long position = (pos.x << 16 | pos.y);
|
||||
_m_client_msg(spec_.atombase().xdnd_position, 0, position, CurrentTime, spec_.atombase().xdnd_action_copy);
|
||||
_m_client_msg(spec_.atombase().xdnd_position, 0, position, CurrentTime, requested_action);
|
||||
}
|
||||
|
||||
void _m_xdnd_leave()
|
||||
@@ -292,19 +279,30 @@ namespace nana{
|
||||
|
||||
if(target_)
|
||||
{
|
||||
std::cout<<"Send: XdndLeave"<<std::endl;
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"Send: XdndLeave, reset ExecutedAction"<<std::endl;
|
||||
#endif
|
||||
_m_client_msg(spec_.atombase().xdnd_leave, 0, 0, 0);
|
||||
target_ = 0;
|
||||
executed_action_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void _m_xdnd_drop()
|
||||
bool _m_xdnd_drop()
|
||||
{
|
||||
::XUndefineCursor(spec_.open_display(), source_);
|
||||
xstate_ = xdnd_status_state::drop;
|
||||
std::cout<<"Send: XdndDrop"<<std::endl;
|
||||
_m_client_msg(spec_.atombase().xdnd_drop, 0, CurrentTime, 0);
|
||||
|
||||
if(executed_action_)
|
||||
{
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"Send: XdndDrop"<<std::endl;
|
||||
#endif
|
||||
_m_client_msg(spec_.atombase().xdnd_drop, 0, CurrentTime, 0);
|
||||
}
|
||||
target_ = 0;
|
||||
|
||||
return (executed_action_ != 0);
|
||||
}
|
||||
private:
|
||||
//dndversion<<24, fl_XdndURIList, XA_STRING, 0
|
||||
@@ -343,7 +341,9 @@ namespace nana{
|
||||
if ((actual == XA_ATOM) && (format==32) && count && data)
|
||||
{
|
||||
version = int(*(Atom*)data);
|
||||
#ifdef DEBUG_XDND_PROTOCOL
|
||||
std::cout<<"Get:XdndAware version:"<<version<<std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (data)
|
||||
@@ -355,39 +355,17 @@ namespace nana{
|
||||
{
|
||||
::XDefineCursor(spec_.open_display(), source_, (accepted ? cursor_.dnd_move : cursor_.dnd_none));
|
||||
}
|
||||
|
||||
#if 0 //deprecated
|
||||
//Check if window has a property
|
||||
static bool _m_has_property(Window wd, Atom atom, unsigned char** data)
|
||||
{
|
||||
Atom type = 0;
|
||||
int f;
|
||||
unsigned long n, a;
|
||||
|
||||
unsigned char * data_back = nullptr;
|
||||
if(nullptr == data)
|
||||
data = &data_back;
|
||||
|
||||
if (::XGetWindowProperty(spec_.open_display(), wd, atom, 0, 0, False, AnyPropertyType, &type, &f,&n,&a,data) == Success)
|
||||
{
|
||||
//release the *data if failed to get the property or unspecified output buffer
|
||||
if((0 == type) || data_back)
|
||||
::XFree(*data);
|
||||
|
||||
return (0 != type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
nana::detail::platform_spec& spec_;
|
||||
Window const source_;
|
||||
Window target_{ 0 };
|
||||
Window const source_;
|
||||
Window target_{ 0 };
|
||||
Atom executed_action_{ 0 };
|
||||
xdnd_status_state xstate_{xdnd_status_state::normal};
|
||||
std::map<Window, nana::rectangle> mvout_table_;
|
||||
|
||||
struct cursor_rep
|
||||
{
|
||||
Cursor dnd_copy{ 0 };
|
||||
Cursor dnd_move{ 0 };
|
||||
Cursor dnd_none{ 0 };
|
||||
}cursor_;
|
||||
|
||||
@@ -39,17 +39,31 @@ namespace nana
|
||||
{
|
||||
struct dragdrop_data
|
||||
{
|
||||
dnd_action requested_action;
|
||||
std::vector<std::filesystem::path> files;
|
||||
};
|
||||
|
||||
#ifdef NANA_X11
|
||||
xdnd_data to_xdnd_data(const dragdrop_data& data)
|
||||
{
|
||||
xdnd_data xdata;
|
||||
xdata.files = data.files;
|
||||
return xdata;
|
||||
}
|
||||
xdnd_data to_xdnd_data() const noexcept
|
||||
{
|
||||
auto & atombase = nana::detail::platform_spec::instance().atombase();
|
||||
xdnd_data xdata;
|
||||
xdata.requested_action = atombase.xdnd_action_copy;
|
||||
|
||||
switch(requested_action)
|
||||
{
|
||||
case dnd_action::copy:
|
||||
xdata.requested_action = atombase.xdnd_action_copy; break;
|
||||
case dnd_action::move:
|
||||
xdata.requested_action = atombase.xdnd_action_move; break;
|
||||
case dnd_action::link:
|
||||
xdata.requested_action = atombase.xdnd_action_link; break;
|
||||
}
|
||||
|
||||
xdata.files = files;
|
||||
return xdata;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -744,7 +758,7 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
bool dragdrop(window drag_wd, dropdata_type* dropdata)
|
||||
bool dragdrop(window drag_wd, dropdata_type* dropdata, dnd_action* executed_action)
|
||||
{
|
||||
auto i = table_.find(API::root(drag_wd));
|
||||
if ((!dropdata) && table_.end() == i)
|
||||
@@ -764,6 +778,19 @@ namespace nana
|
||||
|
||||
delete drop_src;
|
||||
|
||||
if (executed_action)
|
||||
{
|
||||
switch (result_effect)
|
||||
{
|
||||
case DROPEFFECT_COPY:
|
||||
*executed_action = dnd_action::copy; break;
|
||||
case DROPEFFECT_MOVE:
|
||||
*executed_action = dnd_action::move; break;
|
||||
case DROPEFFECT_LINK:
|
||||
*executed_action = dnd_action::link; break;
|
||||
}
|
||||
}
|
||||
|
||||
return (DROPEFFECT_NONE != result_effect);
|
||||
#elif defined(NANA_X11)
|
||||
auto& atombase = _m_spec().atombase();
|
||||
@@ -780,12 +807,14 @@ namespace nana
|
||||
|
||||
hovered_.window_handle = nullptr;
|
||||
hovered_.native_wd = 0;
|
||||
window target_wd = 0;
|
||||
|
||||
if(executed_action)
|
||||
*executed_action = dropdata->data()->requested_action;
|
||||
|
||||
if(ddrop->simple_mode())
|
||||
{
|
||||
|
||||
_m_spec().msg_dispatch([this, ddrop, drag_wd, native_source, &target_wd, &atombase](const detail::msg_packet_tag& msg_pkt) mutable{
|
||||
_m_spec().msg_dispatch([this, ddrop, drag_wd, native_source, &atombase](const detail::msg_packet_tag& msg_pkt) mutable{
|
||||
if(detail::msg_packet_tag::pkt_family::xevent == msg_pkt.kind)
|
||||
{
|
||||
auto const disp = _m_spec().open_display();
|
||||
@@ -793,35 +822,7 @@ namespace nana
|
||||
{
|
||||
auto pos = API::cursor_position();
|
||||
auto native_cur_wd = reinterpret_cast<Window>(detail::native_interface::find_window(pos.x, pos.y));
|
||||
#if 0
|
||||
const char* icon = nullptr;
|
||||
if(hovered_.native_wd != native_cur_wd)
|
||||
{
|
||||
if(hovered_.native_wd)
|
||||
{
|
||||
_m_free_cursor();
|
||||
::XUndefineCursor(disp, hovered_.native_wd);
|
||||
}
|
||||
|
||||
_m_client_msg(native_cur_wd, native_source, 1, atombase.xdnd_enter, atombase.text_uri_list, XA_STRING);
|
||||
hovered_.native_wd = native_cur_wd;
|
||||
|
||||
if(!ddrop->simple_mode())
|
||||
icon = "dnd-move";
|
||||
}
|
||||
|
||||
if(ddrop->simple_mode())
|
||||
{
|
||||
auto cur_wd = API::find_window(API::cursor_position());
|
||||
if(hovered_.window_handle != cur_wd)
|
||||
{
|
||||
hovered_.window_handle = cur_wd;
|
||||
|
||||
icon = (((drag_wd == cur_wd) || ddrop->has(drag_wd, cur_wd)) ? "dnd-move" : "dnd-none");
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
const char* icon = nullptr;
|
||||
if(hovered_.native_wd != native_cur_wd)
|
||||
{
|
||||
@@ -835,23 +836,19 @@ namespace nana
|
||||
hovered_.native_wd = native_cur_wd;
|
||||
}
|
||||
|
||||
if(ddrop->simple_mode())
|
||||
|
||||
auto cur_wd = API::find_window(API::cursor_position());
|
||||
|
||||
std::cout<<" Hovered="<<cur_wd;
|
||||
if(hovered_.window_handle != cur_wd)
|
||||
{
|
||||
auto cur_wd = API::find_window(API::cursor_position());
|
||||
hovered_.window_handle = cur_wd;
|
||||
|
||||
std::cout<<" Hovered="<<cur_wd;
|
||||
if(hovered_.window_handle != cur_wd)
|
||||
{
|
||||
hovered_.window_handle = cur_wd;
|
||||
|
||||
icon = (((drag_wd == cur_wd) || ddrop->has(drag_wd, cur_wd)) ? "dnd-move" : "dnd-none");
|
||||
std::cout<<" ICON="<<icon;
|
||||
}
|
||||
|
||||
std::cout<<std::endl;
|
||||
icon = (((drag_wd == cur_wd) || ddrop->has(drag_wd, cur_wd)) ? "dnd-move" : "dnd-none");
|
||||
std::cout<<" ICON="<<icon;
|
||||
}
|
||||
else
|
||||
icon = "dnd-move";
|
||||
|
||||
std::cout<<std::endl;
|
||||
|
||||
if(icon)
|
||||
{
|
||||
@@ -859,11 +856,9 @@ namespace nana
|
||||
hovered_.cursor = ::XcursorFilenameLoadCursor(disp, icons_.cursor(icon).c_str());
|
||||
::XDefineCursor(disp, native_cur_wd, hovered_.cursor);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if(msg_pkt.u.xevent.type == ButtonRelease)
|
||||
{
|
||||
target_wd = API::find_window(API::cursor_position());
|
||||
::XUndefineCursor(disp, hovered_.native_wd);
|
||||
_m_free_cursor();
|
||||
API::release_capture(drag_wd);
|
||||
@@ -873,16 +868,19 @@ namespace nana
|
||||
}
|
||||
return detail::propagation_chain::stop;
|
||||
});
|
||||
|
||||
//In simple mode, it always returns true. The drag and drop is determined by class simple_dragdrop
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto data = detail::to_xdnd_data(*dropdata->data());
|
||||
auto data = dropdata->data()->to_xdnd_data();
|
||||
|
||||
API::set_capture(drag_wd, true);
|
||||
nana::detail::xdnd_protocol xdnd_proto{native_source};
|
||||
|
||||
//Not simple mode
|
||||
_m_spec().msg_dispatch([this, ddrop, &data, drag_wd, xdnd_proto, native_source, &target_wd, &atombase](const detail::msg_packet_tag& msg_pkt) mutable{
|
||||
_m_spec().msg_dispatch([this, ddrop, &data, drag_wd, &xdnd_proto, native_source, &atombase](const detail::msg_packet_tag& msg_pkt) mutable{
|
||||
if(detail::msg_packet_tag::pkt_family::xevent == msg_pkt.kind)
|
||||
{
|
||||
auto const disp = _m_spec().open_display();
|
||||
@@ -891,7 +889,7 @@ namespace nana
|
||||
auto pos = API::cursor_position();
|
||||
auto native_cur_wd = reinterpret_cast<Window>(detail::native_interface::find_window(pos.x, pos.y));
|
||||
|
||||
xdnd_proto.mouse_move(native_cur_wd, pos);
|
||||
xdnd_proto.mouse_move(native_cur_wd, pos, data.requested_action);
|
||||
}
|
||||
else if(ClientMessage == msg_pkt.u.xevent.type)
|
||||
{
|
||||
@@ -911,10 +909,12 @@ namespace nana
|
||||
std::cout<<"ButtonRelease"<<std::endl;
|
||||
API::release_capture(drag_wd);
|
||||
|
||||
xdnd_proto.mouse_release();
|
||||
std::cout<<"mouse_release"<<std::endl;
|
||||
target_wd = API::find_window(API::cursor_position());
|
||||
_m_free_cursor();
|
||||
|
||||
//Exits the msg loop if xdnd_proto doesn't send the XdndDrop because of refusal of the DND
|
||||
if(!xdnd_proto.mouse_release())
|
||||
return detail::propagation_chain::exit;
|
||||
}
|
||||
|
||||
return detail::propagation_chain::stop;
|
||||
@@ -922,9 +922,14 @@ namespace nana
|
||||
return detail::propagation_chain::pass;
|
||||
});
|
||||
|
||||
}
|
||||
if(xdnd_proto.executed_action() != 0)
|
||||
{
|
||||
if(executed_action)
|
||||
*executed_action = _m_from_xdnd_action(xdnd_proto.executed_action());
|
||||
|
||||
return (nullptr != target_wd);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
@@ -936,6 +941,19 @@ namespace nana
|
||||
return nana::detail::platform_spec::instance();
|
||||
}
|
||||
|
||||
static dnd_action _m_from_xdnd_action(Atom action) noexcept
|
||||
{
|
||||
auto & atombase = _m_spec().atombase();
|
||||
if(action == atombase.xdnd_action_copy)
|
||||
return dnd_action::copy;
|
||||
else if(action == atombase.xdnd_action_move)
|
||||
return dnd_action::move;
|
||||
else if(action == atombase.xdnd_action_link)
|
||||
return dnd_action::link;
|
||||
|
||||
return dnd_action::copy;
|
||||
}
|
||||
|
||||
//dndversion<<24, fl_XdndURIList, XA_STRING, 0
|
||||
static void _m_client_msg(Window wd_target, Window wd_src, int flag, Atom xdnd_atom, Atom data, Atom data_type)
|
||||
{
|
||||
@@ -974,7 +992,7 @@ namespace nana
|
||||
|
||||
#ifdef NANA_WINDOWS
|
||||
#elif defined (NANA_X11)
|
||||
nana::detail::shared_icons icons_;
|
||||
nana::detail::theme icons_;
|
||||
struct hovered_status
|
||||
{
|
||||
Window native_wd{0};
|
||||
@@ -1070,7 +1088,7 @@ namespace nana
|
||||
|
||||
std::unique_ptr<dragdrop_service::dropdata_type> dropdata{new dragdrop_service::dropdata_type};
|
||||
|
||||
auto has_dropped = dragdrop_service::instance().dragdrop(arg.window_handle, dropdata.get());
|
||||
auto has_dropped = dragdrop_service::instance().dragdrop(arg.window_handle, dropdata.get(), nullptr);
|
||||
|
||||
real_wd->other.dnd_state = dragdrop_status::not_ready;
|
||||
impl_->dragging = false;
|
||||
@@ -1125,7 +1143,7 @@ namespace nana
|
||||
dragdrop_session * ddrop{nullptr};
|
||||
std::function<bool()> predicate;
|
||||
std::function<data()> generator;
|
||||
std::function<void(bool)> drop_finished;
|
||||
std::function<void(bool, dnd_action, data&)> drop_finished;
|
||||
|
||||
struct event_handlers
|
||||
{
|
||||
@@ -1143,28 +1161,18 @@ namespace nana
|
||||
|
||||
void make_drop()
|
||||
{
|
||||
if (!generator)
|
||||
return;
|
||||
|
||||
auto transf_data = generator();
|
||||
dragdrop_service::dropdata_type dropdata;
|
||||
dropdata.assign(*transf_data.real_data_);
|
||||
/* //deprecated
|
||||
#ifdef NANA_WINDOWS
|
||||
drop_source drop_src{ source_handle };
|
||||
DWORD result_effect = DROPEFFECT_NONE;
|
||||
auto status = ::DoDragDrop(&dropdata, &drop_src, DROPEFFECT_COPY | DROPEFFECT_MOVE, &result_effect);
|
||||
|
||||
if (DROPEFFECT_NONE == result_effect)
|
||||
{
|
||||
}
|
||||
|
||||
if (drop_finished)
|
||||
drop_finished(DROPEFFECT_NONE != result_effect);
|
||||
#else
|
||||
#endif
|
||||
*/
|
||||
auto has_dropped = dragdrop_service::instance().dragdrop(source_handle, &dropdata);
|
||||
dnd_action executed_action;
|
||||
auto has_dropped = dragdrop_service::instance().dragdrop(source_handle, &dropdata, &executed_action);
|
||||
|
||||
if(drop_finished)
|
||||
drop_finished(has_dropped);
|
||||
drop_finished(has_dropped, executed_action, transf_data);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1240,15 +1248,16 @@ namespace nana
|
||||
impl_->generator = generator;
|
||||
}
|
||||
|
||||
void dragdrop::drop_finished(std::function<void(bool)> finish_fn)
|
||||
void dragdrop::drop_finished(std::function<void(bool, dnd_action, data&)> finish_fn)
|
||||
{
|
||||
impl_->drop_finished = finish_fn;
|
||||
}
|
||||
|
||||
|
||||
dragdrop::data::data():
|
||||
dragdrop::data::data(dnd_action requested_action):
|
||||
real_data_(new detail::dragdrop_data)
|
||||
{
|
||||
real_data_->requested_action = requested_action;
|
||||
}
|
||||
|
||||
dragdrop::data::~data()
|
||||
|
||||
Reference in New Issue
Block a user