improve wait of x11 event to avoid blocking

This commit is contained in:
Jinhao 2019-09-11 00:10:11 +08:00
parent 02676e9c75
commit 0f66b0cb26
3 changed files with 117 additions and 19 deletions

View File

@ -622,6 +622,7 @@ namespace detail
}
break;
case ConfigureNotify:
++(root_runtime->x11msg.config);
if(msgwnd->dimension.width != static_cast<unsigned>(xevent.xconfigure.width) || msgwnd->dimension.height != static_cast<unsigned>(xevent.xconfigure.height))
{
auto & cf = xevent.xconfigure;
@ -890,7 +891,12 @@ namespace detail
case MapNotify:
case UnmapNotify:
if(xevent.type == MapNotify)
{
++(root_runtime->x11msg.map);
x11_apply_exposed_position(native_window);
}
else
++(root_runtime->x11msg.unmap);
brock.event_expose(msgwnd, (xevent.type == MapNotify));
context.platform.motion_window = nullptr;

View File

@ -21,6 +21,10 @@
#include <map>
#ifdef NANA_X11
# include <atomic>
#endif
namespace nana{
namespace detail
{
@ -75,6 +79,15 @@ namespace nana{
root_misc(root_misc&&);
root_misc(basic_window * wd, unsigned width, unsigned height);
~root_misc();
#ifdef NANA_X11
struct x11msg_confirm
{
std::atomic<std::size_t> config{ 0 };
std::atomic<std::size_t> map{ 0 };
std::atomic<std::size_t> unmap{ 0 };
}x11msg;
#endif
private:
root_misc(const root_misc&) = delete;
root_misc& operator=(const root_misc&) = delete;

View File

@ -25,6 +25,7 @@
# include <map>
#elif defined(NANA_X11)
# include <nana/system/platform.hpp>
# include "inner_fwd_implement.hpp"
#endif
#include "../../paint/image_accessor.hpp"
@ -203,26 +204,87 @@ namespace nana{
namespace x11_wait
{
struct param
{
Window handle;
root_misc * misc;
std::size_t comp_value;
};
static Bool configure(Display *disp, XEvent *evt, char *arg)
{
return disp && evt && arg && (evt->type == ConfigureNotify) && (evt->xconfigure.window == *reinterpret_cast<Window*>(arg));
auto p = reinterpret_cast<param*>(arg);
if(p)
{
if(p->misc->x11msg.config != p->comp_value)
return true;
if(disp && evt && (evt->type == ConfigureNotify))
{
if(evt->xconfigure.window == p->handle)
return true;
}
}
return false;
}
static Bool map(Display *disp, XEvent *evt, char *arg)
{
return disp && evt && arg && (evt->type == MapNotify) && (evt->xmap.window == *reinterpret_cast<Window*>(arg));
auto p = reinterpret_cast<param*>(arg);
if(p)
{
if(p->misc->x11msg.map != p->comp_value)
return true;
if(disp && evt && (evt->type == MapNotify))
{
if(evt->xmap.window == p->handle)
return true;
}
}
return false;
}
static Bool unmap(Display *disp, XEvent *evt, char *arg)
{
return disp && evt && arg && (evt->type == MapNotify) && (evt->xunmap.window == *reinterpret_cast<Window*>(arg));
auto p = reinterpret_cast<param*>(arg);
if(p)
{
if(p->misc->x11msg.unmap != p->comp_value)
return true;
if(disp && evt && (evt->type == UnmapNotify))
{
if(evt->xunmap.window == p->handle)
return true;
}
}
return false;
}
}
static void x11_wait_for(Window wd, Bool(*pred_fn)(Display*, XEvent*, char*))
static void x11_wait_for(Window wd, Bool(*pred_fn)(Display*, XEvent*, char*), std::size_t comp_value)
{
auto misc = bedrock::instance().wd_manager().root_runtime(reinterpret_cast<native_window_type>(wd));
x11_wait::param p;
p.handle = wd;
p.misc = misc;
if(pred_fn == &x11_wait::configure)
p.comp_value = misc->x11msg.config;
else if(pred_fn == &x11_wait::map)
p.comp_value = misc->x11msg.map;
else if(pred_fn == &x11_wait::unmap)
p.comp_value = misc->x11msg.unmap;
//Checks whether the msg is received.
if(p.comp_value != comp_value)
return;
p.comp_value = comp_value;
XEvent dummy;
::XPeekIfEvent(restrict::spec.open_display(), &dummy, pred_fn, reinterpret_cast<XPointer>(&wd));
::XPeekIfEvent(restrict::spec.open_display(), &dummy, pred_fn, reinterpret_cast<XPointer>(&p));
}
#endif
@ -762,13 +824,17 @@ namespace nana{
if(show == is_window_visible(wd))
return;
auto misc = bedrock::instance().wd_manager().root_runtime(wd);
if(show)
{
std::size_t cmp_value = misc->x11msg.map;
::XMapWindow(disp, reinterpret_cast<Window>(wd));
//Wait for the mapping notify to update the local attribute of visibility so that
//the followed window_visible() call can return the updated visibility value.
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::map);
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::map, cmp_value);
Window grab = restrict::spec.grab(0);
if(grab == reinterpret_cast<Window>(wd))
@ -776,10 +842,12 @@ namespace nana{
}
else
{
std::size_t cmp_value = misc->x11msg.unmap;
::XUnmapWindow(disp, reinterpret_cast<Window>(wd));
//Wait for the mapping notify to update the local attribute of visibility so that
//the followed window_visible() call can return the updated visibility value.
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::unmap);
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::unmap, cmp_value);
}
}
static_cast<void>(active); //eliminate unused parameter compiler warning.
@ -1023,11 +1091,15 @@ namespace nana{
y += origin_y;
}
auto misc = bedrock::instance().wd_manager().root_runtime(reinterpret_cast<native_window_type>(wd));
std::size_t cmp_value = misc->x11msg.config;
::XMoveWindow(disp, reinterpret_cast<Window>(wd), x, y);
//Wait for the configuration notify to update the local attribute of position so that
//the followed window_position() call can return the updated position value.
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure);
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure, cmp_value);
#endif
}
@ -1113,6 +1185,9 @@ namespace nana{
y += origin_y;
}
auto misc = bedrock::instance().wd_manager().root_runtime(reinterpret_cast<native_window_type>(wd));
std::size_t cmp_value = misc->x11msg.config;
::XMoveResizeWindow(disp, reinterpret_cast<Window>(wd), x, y, r.width, r.height);
//Wait for the configuration notify to update the local attribute of position so that
@ -1120,7 +1195,7 @@ namespace nana{
//It seems that XMoveResizeWindow doesn't need x11_wait_for. But x11_wait_for is still called
//to make sure the local attribute is updated.
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure);
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure, cmp_value);
return true;
#endif
@ -1287,11 +1362,15 @@ namespace nana{
hints.min_height = hints.max_height = sz.height;
::XSetWMNormalHints(disp, reinterpret_cast<Window>(wd), &hints);
}
auto misc = bedrock::instance().wd_manager().root_runtime(reinterpret_cast<native_window_type>(wd));
std::size_t cmp_value = misc->x11msg.config;
::XResizeWindow(disp, reinterpret_cast<Window>(wd), sz.width, sz.height);
//It seems that XResizeWindow doesn't need x11_wait_for. But x11_wait_for is still called
//to make sure the local attribute is updated.
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure);
x11_wait_for(reinterpret_cast<Window>(wd), x11_wait::configure, cmp_value);
return true;
#endif
}