Merge remote-tracking branch 'cnjinhao/develop-1.7' into cmake-dev

This commit is contained in:
qPCR4vir 2018-10-23 19:07:14 +02:00
commit 83d29f3a82
7 changed files with 318 additions and 18 deletions

View File

@ -20,6 +20,7 @@ matrix:
- alsa-oss - alsa-oss
- libx11-dev - libx11-dev
- libxft-dev - libxft-dev
- libxcursor-dev
sources: sources:
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
@ -36,6 +37,7 @@ matrix:
- alsa-oss - alsa-oss
- libx11-dev - libx11-dev
- libxft-dev - libxft-dev
- libxcursor-dev
sources: sources:
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
- llvm-toolchain-precise - llvm-toolchain-precise

View File

@ -1041,6 +1041,12 @@ namespace detail
msg_dispatcher_->dispatch(reinterpret_cast<Window>(modal)); 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) void* platform_spec::request_selection(native_window_type requestor, Atom type, size_t& size)
{ {
if(requestor) if(requestor)
@ -1104,6 +1110,40 @@ namespace detail
return graph; 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 //_m_msg_filter
//@return: _m_msg_filter returns three states //@return: _m_msg_filter returns three states
// 0 = msg_dispatcher dispatches the XEvent // 0 = msg_dispatcher dispatches the XEvent
@ -1163,7 +1203,7 @@ namespace detail
else if(evt.xselection.property == self.atombase_.xdnd_selection) else if(evt.xselection.property == self.atombase_.xdnd_selection)
{ {
bool accepted = false; bool accepted = false;
msg.kind = msg.kind_mouse_drop; msg.kind = msg_packet_tag::pkt_family::mouse_drop;
msg.u.mouse_drop.window = 0; msg.u.mouse_drop.window = 0;
if(bytes_left > 0 && type == self.xdnd_.good_type) if(bytes_left > 0 && type == self.xdnd_.good_type)
{ {

View File

@ -143,7 +143,7 @@ namespace detail
{ {
//Make a cleanup msg packet to infor the dispatcher the window is closed. //Make a cleanup msg packet to infor the dispatcher the window is closed.
msg_packet_tag msg; msg_packet_tag msg;
msg.kind = msg.kind_cleanup; msg.kind = msg_packet_tag::pkt_family::cleanup;
msg.u.packet_window = wd; msg.u.packet_window = wd;
thr->msg_queue.push_back(msg); 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: private:
void _m_msg_driver() void _m_msg_driver()
{ {
@ -220,7 +244,7 @@ namespace detail
switch(proc_.filter_proc(event, msg_pack)) switch(proc_.filter_proc(event, msg_pack))
{ {
case 0: case 0:
msg_pack.kind = msg_pack.kind_xevent; msg_pack.kind = msg_packet_tag::pkt_family::xevent;
msg_pack.u.xevent = event; msg_pack.u.xevent = event;
_m_msg_dispatch(msg_pack); _m_msg_dispatch(msg_pack);
break; break;
@ -246,9 +270,9 @@ namespace detail
{ {
switch(pack.kind) switch(pack.kind)
{ {
case msg_packet_tag::kind_xevent: case msg_packet_tag::pkt_family::xevent:
return _m_event_window(pack.u.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; return pack.u.mouse_drop.window;
default: default:
break; break;
@ -294,7 +318,7 @@ namespace detail
//Check whether the event dispatcher is used for the modal window //Check whether the event dispatcher is used for the modal window
//and when the modal window is closing, the event dispatcher would //and when the modal window is closing, the event dispatcher would
//stop event pumping. //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 0;
return 1; return 1;

View File

@ -10,8 +10,8 @@ namespace detail
{ {
struct msg_packet_tag struct msg_packet_tag
{ {
enum kind_t{kind_xevent, kind_mouse_drop, kind_cleanup}; enum class pkt_family{xevent, mouse_drop, cleanup};
kind_t kind; pkt_family kind;
union union
{ {
XEvent xevent; XEvent xevent;

View File

@ -36,6 +36,7 @@
#include <vector> #include <vector>
#include <map> #include <map>
#include <functional>
#include "msg_packet.hpp" #include "msg_packet.hpp"
#include "../platform_abstraction_types.hpp" #include "../platform_abstraction_types.hpp"
@ -176,6 +177,12 @@ namespace detail
~platform_scope_guard(); ~platform_scope_guard();
}; };
class dragdrop_interface
{
public:
virtual ~dragdrop_interface() = default;
};
class platform_spec class platform_spec
{ {
typedef platform_spec self_type; typedef platform_spec self_type;
@ -246,6 +253,7 @@ namespace detail
void msg_insert(native_window_type); void msg_insert(native_window_type);
void msg_set(timer_proc_type, event_proc_type); void msg_set(timer_proc_type, event_proc_type);
void msg_dispatch(native_window_type modal); void msg_dispatch(native_window_type modal);
void msg_dispatch(std::function<bool(const msg_packet_tag&)>);
//X Selections //X Selections
void* request_selection(native_window_type requester, Atom type, size_t & bufsize); 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, //@biref: The image object should be kept for a long time till the window is closed,
// the image object is release in remove() method. // the image object is release in remove() method.
const nana::paint::graphics& keep_window_icon(native_window_type, const nana::paint::image&); 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: private:
static int _m_msg_filter(XEvent&, msg_packet_tag&); static int _m_msg_filter(XEvent&, msg_packet_tag&);
void _m_caret_routine(); void _m_caret_routine();
@ -311,6 +322,14 @@ namespace detail
int timestamp; int timestamp;
Window wd_src; Window wd_src;
nana::point pos; 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_; }xdnd_;
msg_dispatcher * msg_dispatcher_; msg_dispatcher * msg_dispatcher_;

View File

@ -418,10 +418,10 @@ namespace detail
{ {
switch(msg.kind) 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); window_proc_for_xevent(display, msg.u.xevent);
break; 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); window_proc_for_packet(display, msg);
break; break;
default: break; default: break;
@ -441,7 +441,7 @@ namespace detail
switch(msg.kind) 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}); msgwd = brock.wd_manager().find_window(native_window, {msg.u.mouse_drop.x, msg.u.mouse_drop.y});
if(msgwd) if(msgwd)
{ {

View File

@ -10,6 +10,7 @@
* @file: nana/gui/dragdrop.cpp * @file: nana/gui/dragdrop.cpp
* @author: Jinhao(cnjinhao@hotmail.com) * @author: Jinhao(cnjinhao@hotmail.com)
*/ */
#include <nana/gui/dragdrop.hpp> #include <nana/gui/dragdrop.hpp>
#include <nana/gui/programming_interface.hpp> #include <nana/gui/programming_interface.hpp>
@ -24,6 +25,11 @@
# include <oleidl.h> # include <oleidl.h>
# include <comdef.h> # include <comdef.h>
# include <Shlobj.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 #endif
namespace nana namespace nana
@ -367,6 +373,60 @@ namespace nana
private: private:
std::vector<medium> mediums_; 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 #endif
class dragdrop_service class dragdrop_service
@ -385,6 +445,7 @@ namespace nana
if (nullptr == native_wd) if (nullptr == native_wd)
return; return;
#ifdef NANA_WINDOWS
if(table_.empty()) if(table_.empty())
::OleInitialize(nullptr); ::OleInitialize(nullptr);
@ -403,22 +464,33 @@ namespace nana
drop_target = i->second; drop_target = i->second;
drop_target->AddRef(); 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) void remove(window wd)
{ {
#ifdef NANA_WINDOWS
auto i = table_.find(API::root(wd)); auto i = table_.find(API::root(wd));
if (i != table_.end()) if (i != table_.end())
{ {
if (0 == i->second->Release()) if (0 == i->second->Release())
table_.erase(i); table_.erase(i);
} }
#elif defined(NANA_X11)
auto ddrop = _m_spec().remove_dragdrop(API::root(wd));
delete ddrop;
#endif
drop_assoc_.erase(wd); drop_assoc_.erase(wd);
} }
bool dragdrop(window drag_wd) bool dragdrop(window drag_wd)
{ {
#ifdef NANA_WINDOWS
auto i = table_.find(API::root(drag_wd)); auto i = table_.find(API::root(drag_wd));
if (table_.end() == i) if (table_.end() == i)
return false; return false;
@ -438,19 +510,158 @@ namespace nana
auto status = ::DoDragDrop(drop_dat, drop_src, DROPEFFECT_COPY, &eff); auto status = ::DoDragDrop(drop_dat, drop_src, DROPEFFECT_COPY, &eff);
i->second->set_source(nullptr); i->second->set_source(nullptr);
return true; 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() drop_association& drop_assoc()
{ {
return 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: private:
std::map<native_window_type, win32com_drop_target*> table_;
drop_association drop_assoc_; 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 struct simple_dragdrop::implementation
{ {
window window_handle; window window_handle;
@ -459,7 +670,7 @@ namespace nana
bool dragging{ false }; bool dragging{ false };
#if 0 #ifdef NANA_X11
bool cancel() bool cancel()
{ {
if (!dragging) if (!dragging)
@ -499,11 +710,15 @@ namespace nana
auto & events = API::events<>(drag_wd); auto & events = API::events<>(drag_wd);
#ifdef NANA_WINDOWS #if 1 //#ifdef NANA_WINDOWS
events.mouse_down.connect_unignorable([this](const arg_mouse& arg){ events.mouse_down.connect_unignorable([this](const arg_mouse& arg){
if (arg.is_left_button() && API::is_window(impl_->window_handle)) if (arg.is_left_button() && API::is_window(impl_->window_handle))
{ {
impl_->dragging = ((!impl_->predicate) || impl_->predicate()); 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(); i->second();
} }
}); });
#else #elif 1
events.mouse_down.connect_unignorable([drag_wd](const arg_mouse& arg){ events.mouse_down.connect_unignorable([drag_wd](const arg_mouse& arg){
if (arg.is_left_button() && API::is_window(drag_wd)) 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; using basic_window = ::nana::detail::basic_window;
auto real_wd = reinterpret_cast<::nana::detail::basic_window*>(drag_wd); 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);
} }
}); });