From 0f66b0cb26468cfd8510744724b8c5d56044564a Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 11 Sep 2019 00:10:11 +0800 Subject: [PATCH] improve wait of x11 event to avoid blocking --- source/gui/detail/bedrock_posix.cpp | 6 + source/gui/detail/inner_fwd_implement.hpp | 13 ++ source/gui/detail/native_window_interface.cpp | 117 +++++++++++++++--- 3 files changed, 117 insertions(+), 19 deletions(-) diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index b3ed3fb4..23f55fa8 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -622,6 +622,7 @@ namespace detail } break; case ConfigureNotify: + ++(root_runtime->x11msg.config); if(msgwnd->dimension.width != static_cast(xevent.xconfigure.width) || msgwnd->dimension.height != static_cast(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; diff --git a/source/gui/detail/inner_fwd_implement.hpp b/source/gui/detail/inner_fwd_implement.hpp index af246905..a46d51eb 100644 --- a/source/gui/detail/inner_fwd_implement.hpp +++ b/source/gui/detail/inner_fwd_implement.hpp @@ -21,6 +21,10 @@ #include +#ifdef NANA_X11 +# include +#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 config{ 0 }; + std::atomic map{ 0 }; + std::atomic unmap{ 0 }; + }x11msg; +#endif private: root_misc(const root_misc&) = delete; root_misc& operator=(const root_misc&) = delete; diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index 54404ceb..3804b7e6 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -17,14 +17,15 @@ #include #if defined(NANA_WINDOWS) - #if defined(STD_THREAD_NOT_SUPPORTED) - #include - #else - #include - #endif - #include +# if defined(STD_THREAD_NOT_SUPPORTED) +# include +# else +# include +# endif +# include #elif defined(NANA_X11) - #include +# include +# 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(arg)); + auto p = reinterpret_cast(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(arg)); + { + auto p = reinterpret_cast(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(arg)); + { + auto p = reinterpret_cast(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(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(&wd)); + ::XPeekIfEvent(restrict::spec.open_display(), &dummy, pred_fn, reinterpret_cast(&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(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(wd), x11_wait::map); + x11_wait_for(reinterpret_cast(wd), x11_wait::map, cmp_value); Window grab = restrict::spec.grab(0); if(grab == reinterpret_cast(wd)) @@ -776,10 +842,12 @@ namespace nana{ } else { + std::size_t cmp_value = misc->x11msg.unmap; ::XUnmapWindow(disp, reinterpret_cast(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(wd), x11_wait::unmap); + x11_wait_for(reinterpret_cast(wd), x11_wait::unmap, cmp_value); } } static_cast(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(wd)); + std::size_t cmp_value = misc->x11msg.config; + ::XMoveWindow(disp, reinterpret_cast(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(wd), x11_wait::configure); + + x11_wait_for(reinterpret_cast(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(wd)); + std::size_t cmp_value = misc->x11msg.config; + ::XMoveResizeWindow(disp, reinterpret_cast(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(wd), x11_wait::configure); + x11_wait_for(reinterpret_cast(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(wd), &hints); } + + auto misc = bedrock::instance().wd_manager().root_runtime(reinterpret_cast(wd)); + std::size_t cmp_value = misc->x11msg.config; + ::XResizeWindow(disp, reinterpret_cast(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(wd), x11_wait::configure); + x11_wait_for(reinterpret_cast(wd), x11_wait::configure, cmp_value); return true; #endif }