improve dnd interfaces
This commit is contained in:
parent
01ed1d13e9
commit
ce1b143b59
@ -22,6 +22,14 @@
|
||||
|
||||
namespace nana
|
||||
{
|
||||
/// Drag and drop actions
|
||||
enum class dnd_action
|
||||
{
|
||||
copy, ///< Copy the data to target.
|
||||
move, ///< Move the data to target.
|
||||
link ///< Create a link from source data to target.
|
||||
};
|
||||
|
||||
class simple_dragdrop
|
||||
{
|
||||
struct implementation;
|
||||
@ -67,7 +75,12 @@ namespace nana
|
||||
data(const data&) = delete;
|
||||
data& operator=(const data&) = delete;
|
||||
public:
|
||||
data();
|
||||
/// Constructor
|
||||
/**
|
||||
* Constructs a data object used for drag and drop
|
||||
* @param requested_action Indicates how the data to be transferred.
|
||||
*/
|
||||
data(dnd_action requested_action = dnd_action::copy);
|
||||
data(data&&);
|
||||
~data();
|
||||
|
||||
@ -81,9 +94,29 @@ namespace nana
|
||||
dragdrop(window source);
|
||||
~dragdrop();
|
||||
|
||||
/// Condition of dragging
|
||||
/***
|
||||
* The preciate function is called when press mouse button on the source window, it returns true to indicate the start of dragging. If the predicate is not set, it always start to drag.
|
||||
* @param predicate_fn A predicate function to be set.
|
||||
*/
|
||||
void condition(std::function<bool()> predicate_fn);
|
||||
|
||||
/// Transferred data
|
||||
/**
|
||||
* Set a data generator. When drag begins, it is called to generate a data object for transferring.
|
||||
* @param generator It returns the data for transferring.
|
||||
*/
|
||||
void prepare_data(std::function<data()> generator);
|
||||
void drop_finished(std::function<void(bool)> finish_fn);
|
||||
|
||||
/// Drop handler
|
||||
/**
|
||||
* The drop handler is called when the drop operation is completed. There are 3 parameters for the handler
|
||||
* dropped Indicates whether the data is accepted by a target window.
|
||||
* executed_action Indicates the action returned by target window. Ignore if dropped is false.
|
||||
* data_transferred The data object which is generated by the generator.
|
||||
* @param finish_fn The drop handling function.
|
||||
*/
|
||||
void drop_finished(std::function<void(bool dropped, dnd_action executed_action, data& data_transferred)> finish_fn);
|
||||
private:
|
||||
implementation* const impl_;
|
||||
};
|
||||
|
@ -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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user