Merge remote-tracking branch 'cnjinhao/develop-1.7' into cmake-dev
This commit is contained in:
commit
83d29f3a82
@ -20,6 +20,7 @@ matrix:
|
||||
- alsa-oss
|
||||
- libx11-dev
|
||||
- libxft-dev
|
||||
- libxcursor-dev
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
@ -36,6 +37,7 @@ matrix:
|
||||
- alsa-oss
|
||||
- libx11-dev
|
||||
- libxft-dev
|
||||
- libxcursor-dev
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise
|
||||
|
@ -1041,6 +1041,12 @@ namespace detail
|
||||
msg_dispatcher_->dispatch(reinterpret_cast<Window>(modal));
|
||||
}
|
||||
|
||||
void platform_spec::msg_dispatch(std::function<bool(const msg_packet_tag&)> msg_filter_fn)
|
||||
{
|
||||
msg_dispatcher_->dispatch(msg_filter_fn);
|
||||
|
||||
}
|
||||
|
||||
void* platform_spec::request_selection(native_window_type requestor, Atom type, size_t& size)
|
||||
{
|
||||
if(requestor)
|
||||
@ -1104,6 +1110,40 @@ namespace detail
|
||||
return graph;
|
||||
}
|
||||
|
||||
|
||||
bool platform_spec::register_dragdrop(native_window_type wd, dragdrop_interface* ddrop)
|
||||
{
|
||||
platform_scope_guard lock;
|
||||
if(0 != xdnd_.dragdrop.count(wd))
|
||||
return false;
|
||||
|
||||
int dndver = 4;
|
||||
::XChangeProperty(display_, reinterpret_cast<Window>(wd), atombase_.xdnd_aware, XA_ATOM, sizeof(int) * 8,
|
||||
PropModeReplace, reinterpret_cast<unsigned char*>(&dndver), 1);
|
||||
|
||||
auto & ref_drop = xdnd_.dragdrop[wd];
|
||||
ref_drop.dragdrop = ddrop;
|
||||
ref_drop.ref_count = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
dragdrop_interface* platform_spec::remove_dragdrop(native_window_type wd)
|
||||
{
|
||||
platform_scope_guard lock;
|
||||
auto i = xdnd_.dragdrop.find(wd);
|
||||
if(i == xdnd_.dragdrop.end())
|
||||
return nullptr;
|
||||
|
||||
auto ddrop = i->second;
|
||||
if(ddrop.ref_count <= 1)
|
||||
{
|
||||
xdnd_.dragdrop.erase(i);
|
||||
return ddrop.dragdrop;
|
||||
}
|
||||
--ddrop.ref_count;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//_m_msg_filter
|
||||
//@return: _m_msg_filter returns three states
|
||||
// 0 = msg_dispatcher dispatches the XEvent
|
||||
@ -1163,7 +1203,7 @@ namespace detail
|
||||
else if(evt.xselection.property == self.atombase_.xdnd_selection)
|
||||
{
|
||||
bool accepted = false;
|
||||
msg.kind = msg.kind_mouse_drop;
|
||||
msg.kind = msg_packet_tag::pkt_family::mouse_drop;
|
||||
msg.u.mouse_drop.window = 0;
|
||||
if(bytes_left > 0 && type == self.xdnd_.good_type)
|
||||
{
|
||||
|
@ -143,7 +143,7 @@ namespace detail
|
||||
{
|
||||
//Make a cleanup msg packet to infor the dispatcher the window is closed.
|
||||
msg_packet_tag msg;
|
||||
msg.kind = msg.kind_cleanup;
|
||||
msg.kind = msg_packet_tag::pkt_family::cleanup;
|
||||
msg.u.packet_window = wd;
|
||||
thr->msg_queue.push_back(msg);
|
||||
}
|
||||
@ -171,6 +171,30 @@ namespace detail
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename MsgFilter>
|
||||
void dispatch(MsgFilter msg_filter_fn)
|
||||
{
|
||||
auto tid = nana::system::this_thread_id();
|
||||
msg_packet_tag msg;
|
||||
int qstate;
|
||||
|
||||
//Test whether the thread is registered for window, and retrieve the queue state for event
|
||||
while((qstate = _m_read_queue(tid, msg, 0)))
|
||||
{
|
||||
//the queue is empty
|
||||
if(-1 == qstate)
|
||||
{
|
||||
if(false == _m_wait_for_queue(tid))
|
||||
proc_.timer_proc(tid);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(msg_filter_fn(msg))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
void _m_msg_driver()
|
||||
{
|
||||
@ -220,7 +244,7 @@ namespace detail
|
||||
switch(proc_.filter_proc(event, msg_pack))
|
||||
{
|
||||
case 0:
|
||||
msg_pack.kind = msg_pack.kind_xevent;
|
||||
msg_pack.kind = msg_packet_tag::pkt_family::xevent;
|
||||
msg_pack.u.xevent = event;
|
||||
_m_msg_dispatch(msg_pack);
|
||||
break;
|
||||
@ -246,9 +270,9 @@ namespace detail
|
||||
{
|
||||
switch(pack.kind)
|
||||
{
|
||||
case msg_packet_tag::kind_xevent:
|
||||
case msg_packet_tag::pkt_family::xevent:
|
||||
return _m_event_window(pack.u.xevent);
|
||||
case msg_packet_tag::kind_mouse_drop:
|
||||
case msg_packet_tag::pkt_family::mouse_drop:
|
||||
return pack.u.mouse_drop.window;
|
||||
default:
|
||||
break;
|
||||
@ -294,7 +318,7 @@ namespace detail
|
||||
//Check whether the event dispatcher is used for the modal window
|
||||
//and when the modal window is closing, the event dispatcher would
|
||||
//stop event pumping.
|
||||
if((modal == msg.u.packet_window) && (msg.kind == msg.kind_cleanup))
|
||||
if((modal == msg.u.packet_window) && (msg.kind == msg_packet_tag::pkt_family::cleanup))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
|
@ -10,8 +10,8 @@ namespace detail
|
||||
{
|
||||
struct msg_packet_tag
|
||||
{
|
||||
enum kind_t{kind_xevent, kind_mouse_drop, kind_cleanup};
|
||||
kind_t kind;
|
||||
enum class pkt_family{xevent, mouse_drop, cleanup};
|
||||
pkt_family kind;
|
||||
union
|
||||
{
|
||||
XEvent xevent;
|
||||
|
@ -36,6 +36,7 @@
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include "msg_packet.hpp"
|
||||
#include "../platform_abstraction_types.hpp"
|
||||
|
||||
@ -176,6 +177,12 @@ namespace detail
|
||||
~platform_scope_guard();
|
||||
};
|
||||
|
||||
class dragdrop_interface
|
||||
{
|
||||
public:
|
||||
virtual ~dragdrop_interface() = default;
|
||||
};
|
||||
|
||||
class platform_spec
|
||||
{
|
||||
typedef platform_spec self_type;
|
||||
@ -246,6 +253,7 @@ namespace detail
|
||||
void msg_insert(native_window_type);
|
||||
void msg_set(timer_proc_type, event_proc_type);
|
||||
void msg_dispatch(native_window_type modal);
|
||||
void msg_dispatch(std::function<bool(const msg_packet_tag&)>);
|
||||
|
||||
//X Selections
|
||||
void* request_selection(native_window_type requester, Atom type, size_t & bufsize);
|
||||
@ -255,6 +263,9 @@ namespace detail
|
||||
//@biref: The image object should be kept for a long time till the window is closed,
|
||||
// the image object is release in remove() method.
|
||||
const nana::paint::graphics& keep_window_icon(native_window_type, const nana::paint::image&);
|
||||
|
||||
bool register_dragdrop(native_window_type, dragdrop_interface*);
|
||||
dragdrop_interface* remove_dragdrop(native_window_type);
|
||||
private:
|
||||
static int _m_msg_filter(XEvent&, msg_packet_tag&);
|
||||
void _m_caret_routine();
|
||||
@ -311,6 +322,14 @@ namespace detail
|
||||
int timestamp;
|
||||
Window wd_src;
|
||||
nana::point pos;
|
||||
|
||||
struct refcount_dragdrop
|
||||
{
|
||||
dragdrop_interface* dragdrop{nullptr};
|
||||
std::size_t ref_count{0};
|
||||
};
|
||||
|
||||
std::map<native_window_type, refcount_dragdrop> dragdrop;
|
||||
}xdnd_;
|
||||
|
||||
msg_dispatcher * msg_dispatcher_;
|
||||
|
@ -418,10 +418,10 @@ namespace detail
|
||||
{
|
||||
switch(msg.kind)
|
||||
{
|
||||
case nana::detail::msg_packet_tag::kind_xevent:
|
||||
case nana::detail::msg_packet_tag::pkt_family::xevent:
|
||||
window_proc_for_xevent(display, msg.u.xevent);
|
||||
break;
|
||||
case nana::detail::msg_packet_tag::kind_mouse_drop:
|
||||
case nana::detail::msg_packet_tag::pkt_family::mouse_drop:
|
||||
window_proc_for_packet(display, msg);
|
||||
break;
|
||||
default: break;
|
||||
@ -441,7 +441,7 @@ namespace detail
|
||||
|
||||
switch(msg.kind)
|
||||
{
|
||||
case nana::detail::msg_packet_tag::kind_mouse_drop:
|
||||
case nana::detail::msg_packet_tag::pkt_family::mouse_drop:
|
||||
msgwd = brock.wd_manager().find_window(native_window, {msg.u.mouse_drop.x, msg.u.mouse_drop.y});
|
||||
if(msgwd)
|
||||
{
|
||||
|
@ -10,6 +10,7 @@
|
||||
* @file: nana/gui/dragdrop.cpp
|
||||
* @author: Jinhao(cnjinhao@hotmail.com)
|
||||
*/
|
||||
|
||||
#include <nana/gui/dragdrop.hpp>
|
||||
#include <nana/gui/programming_interface.hpp>
|
||||
|
||||
@ -24,6 +25,11 @@
|
||||
# include <oleidl.h>
|
||||
# include <comdef.h>
|
||||
# include <Shlobj.h>
|
||||
#elif defined(NANA_X11)
|
||||
# include "../detail/posix/platform_spec.hpp"
|
||||
# include <nana/gui/detail/native_window_interface.hpp>
|
||||
# include <X11/Xcursor/Xcursor.h>
|
||||
# include <fstream>
|
||||
#endif
|
||||
|
||||
namespace nana
|
||||
@ -367,6 +373,60 @@ namespace nana
|
||||
private:
|
||||
std::vector<medium> mediums_;
|
||||
};
|
||||
#elif defined(NANA_X11)
|
||||
class x11_dragdrop: public detail::dragdrop_interface
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
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_;
|
||||
};
|
||||
#endif
|
||||
|
||||
class dragdrop_service
|
||||
@ -385,6 +445,7 @@ namespace nana
|
||||
if (nullptr == native_wd)
|
||||
return;
|
||||
|
||||
#ifdef NANA_WINDOWS
|
||||
if(table_.empty())
|
||||
::OleInitialize(nullptr);
|
||||
|
||||
@ -403,22 +464,33 @@ namespace nana
|
||||
drop_target = i->second;
|
||||
drop_target->AddRef();
|
||||
}
|
||||
#elif defined(NANA_X11)
|
||||
auto ddrop = new x11_dragdrop;
|
||||
if(!_m_spec().register_dragdrop(native_wd, ddrop))
|
||||
delete ddrop;
|
||||
#endif
|
||||
}
|
||||
|
||||
void remove(window wd)
|
||||
{
|
||||
#ifdef NANA_WINDOWS
|
||||
auto i = table_.find(API::root(wd));
|
||||
if (i != table_.end())
|
||||
{
|
||||
if (0 == i->second->Release())
|
||||
table_.erase(i);
|
||||
}
|
||||
|
||||
#elif defined(NANA_X11)
|
||||
auto ddrop = _m_spec().remove_dragdrop(API::root(wd));
|
||||
delete ddrop;
|
||||
#endif
|
||||
drop_assoc_.erase(wd);
|
||||
|
||||
}
|
||||
|
||||
bool dragdrop(window drag_wd)
|
||||
{
|
||||
#ifdef NANA_WINDOWS
|
||||
auto i = table_.find(API::root(drag_wd));
|
||||
if (table_.end() == i)
|
||||
return false;
|
||||
@ -438,19 +510,158 @@ namespace nana
|
||||
auto status = ::DoDragDrop(drop_dat, drop_src, DROPEFFECT_COPY, &eff);
|
||||
|
||||
i->second->set_source(nullptr);
|
||||
|
||||
return true;
|
||||
#elif defined(NANA_X11)
|
||||
auto const native_wd = reinterpret_cast<Window>(API::root(drag_wd));
|
||||
|
||||
{
|
||||
detail::platform_scope_guard lock;
|
||||
::XSetSelectionOwner(_m_spec().open_display(), _m_spec().atombase().xdnd_selection, native_wd, CurrentTime);
|
||||
}
|
||||
|
||||
|
||||
hovered_.window_handle = nullptr;
|
||||
hovered_.native_wd = 0;
|
||||
window target_wd = 0;
|
||||
auto& atombase = _m_spec().atombase();
|
||||
//while(true)
|
||||
{
|
||||
|
||||
_m_spec().msg_dispatch([this, drag_wd, native_wd, &target_wd, &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();
|
||||
if (MotionNotify == msg_pkt.u.xevent.type)
|
||||
{
|
||||
auto pos = API::cursor_position();
|
||||
auto native_cur_wd = reinterpret_cast<Window>(detail::native_interface::find_window(pos.x, pos.y));
|
||||
|
||||
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_wd, atombase.xdnd_enter, atombase.text_uri_list, XA_STRING);
|
||||
hovered_.native_wd = native_cur_wd;
|
||||
}
|
||||
|
||||
auto cur_wd = API::find_window(API::cursor_position());
|
||||
|
||||
if(hovered_.window_handle != cur_wd)
|
||||
{
|
||||
_m_free_cursor();
|
||||
|
||||
hovered_.window_handle = cur_wd;
|
||||
|
||||
if((drag_wd == cur_wd) || drop_assoc_.has(drag_wd, cur_wd))
|
||||
hovered_.cursor = ::XcursorFilenameLoadCursor(disp, icons_.cursor("dnd-move").c_str());
|
||||
else
|
||||
hovered_.cursor = ::XcursorFilenameLoadCursor(disp, icons_.cursor("dnd-none").c_str());
|
||||
::XDefineCursor(disp, native_cur_wd, hovered_.cursor);
|
||||
}
|
||||
}
|
||||
else if(msg_pkt.u.xevent.type == ButtonRelease)
|
||||
{
|
||||
target_wd = API::find_window(API::cursor_position());
|
||||
::XUndefineCursor(disp, hovered_.native_wd);
|
||||
_m_free_cursor();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
return (nullptr != target_wd);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
drop_association& drop_assoc()
|
||||
{
|
||||
return drop_assoc_;
|
||||
}
|
||||
#ifdef NANA_X11
|
||||
private:
|
||||
static nana::detail::platform_spec & _m_spec()
|
||||
{
|
||||
return nana::detail::platform_spec::instance();
|
||||
}
|
||||
|
||||
//dndversion<<24, fl_XdndURIList, XA_STRING, 0
|
||||
static void _m_client_msg(Window wd_target, Window wd_src, Atom xdnd_atom, Atom data, Atom data_type)
|
||||
{
|
||||
auto const display = _m_spec().open_display();
|
||||
XEvent evt;
|
||||
::memset(&evt, 0, sizeof evt);
|
||||
evt.xany.type = ClientMessage;
|
||||
evt.xany.display = display;
|
||||
evt.xclient.window = wd_target;
|
||||
evt.xclient.message_type = xdnd_atom;
|
||||
evt.xclient.format = 32;
|
||||
|
||||
//Target window
|
||||
evt.xclient.data.l[0] = wd_src;
|
||||
//Accept set
|
||||
evt.xclient.data.l[1] = 1;
|
||||
evt.xclient.data.l[2] = data;
|
||||
evt.xclient.data.l[3] = data_type;
|
||||
evt.xclient.data.l[4] = 0;
|
||||
|
||||
::XSendEvent(display, wd_target, True, NoEventMask, &evt);
|
||||
|
||||
}
|
||||
|
||||
static int _m_xdnd_aware(Window wd)
|
||||
{
|
||||
Atom actual; int format; unsigned long count, remaining;
|
||||
unsigned char *data = 0;
|
||||
XGetWindowProperty(_m_spec().open_display(), wd, _m_spec().atombase().xdnd_aware,
|
||||
0, 4, False, XA_ATOM, &actual, &format, &count, &remaining, &data);
|
||||
|
||||
int version = 0;
|
||||
if ((actual == XA_ATOM) && (format==32) && count && data)
|
||||
version = int(*(Atom*)data);
|
||||
|
||||
if (data)
|
||||
::XFree(data);
|
||||
return version;
|
||||
}
|
||||
|
||||
void _m_free_cursor()
|
||||
{
|
||||
if(hovered_.cursor)
|
||||
{
|
||||
::XFreeCursor(_m_spec().open_display(), hovered_.cursor);
|
||||
hovered_.cursor = 0;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
std::map<native_window_type, win32com_drop_target*> table_;
|
||||
drop_association drop_assoc_;
|
||||
#ifdef NANA_WINDOWS
|
||||
std::map<native_window_type, win32com_drop_target*> table_;
|
||||
#elif defined (NANA_X11)
|
||||
shared_icons icons_;
|
||||
struct hovered_status
|
||||
{
|
||||
Window native_wd{0};
|
||||
window window_handle{nullptr};
|
||||
|
||||
unsigned shape{0};
|
||||
Cursor cursor{0};
|
||||
}hovered_;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct simple_dragdrop::implementation
|
||||
{
|
||||
window window_handle;
|
||||
@ -459,7 +670,7 @@ namespace nana
|
||||
|
||||
bool dragging{ false };
|
||||
|
||||
#if 0
|
||||
#ifdef NANA_X11
|
||||
bool cancel()
|
||||
{
|
||||
if (!dragging)
|
||||
@ -499,11 +710,15 @@ namespace nana
|
||||
|
||||
auto & events = API::events<>(drag_wd);
|
||||
|
||||
#ifdef NANA_WINDOWS
|
||||
#if 1 //#ifdef NANA_WINDOWS
|
||||
events.mouse_down.connect_unignorable([this](const arg_mouse& arg){
|
||||
if (arg.is_left_button() && API::is_window(impl_->window_handle))
|
||||
{
|
||||
impl_->dragging = ((!impl_->predicate) || impl_->predicate());
|
||||
|
||||
using basic_window = ::nana::detail::basic_window;
|
||||
auto real_wd = reinterpret_cast<::nana::detail::basic_window*>(impl_->window_handle);
|
||||
real_wd->other.dnd_state = dragdrop_status::ready;
|
||||
}
|
||||
});
|
||||
|
||||
@ -528,11 +743,11 @@ namespace nana
|
||||
i->second();
|
||||
}
|
||||
});
|
||||
#else
|
||||
#elif 1
|
||||
events.mouse_down.connect_unignorable([drag_wd](const arg_mouse& arg){
|
||||
if (arg.is_left_button() && API::is_window(drag_wd))
|
||||
{
|
||||
API::set_capture(drag_wd, true);
|
||||
//API::set_capture(drag_wd, true);
|
||||
|
||||
using basic_window = ::nana::detail::basic_window;
|
||||
auto real_wd = reinterpret_cast<::nana::detail::basic_window*>(drag_wd);
|
||||
@ -566,7 +781,7 @@ namespace nana
|
||||
}
|
||||
}
|
||||
|
||||
API::release_capture(impl_->window_handle);
|
||||
//API::release_capture(impl_->window_handle);
|
||||
}
|
||||
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user