From e8ae11e20872363bc4c382168e18e333c5f75043 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 10 Jun 2015 06:53:58 +0800 Subject: [PATCH] fix a refreshing issue bad refreshing when a lite_widget is destroying if the lite_widget's parent is also a type of lite_widget --- include/nana/detail/win32/platform_spec.hpp | 7 +++ include/nana/gui/detail/bedrock.hpp | 2 +- include/nana/gui/detail/drawer.hpp | 2 +- include/nana/gui/detail/effects_renderer.hpp | 41 ++++++++++++-- include/nana/gui/detail/window_manager.hpp | 4 +- source/gui/detail/drawer.cpp | 12 ++-- source/gui/detail/linux_X11/bedrock.cpp | 2 +- source/gui/detail/win32/bedrock.cpp | 17 ++++-- source/gui/detail/window_manager.cpp | 58 +++++++++----------- 9 files changed, 96 insertions(+), 49 deletions(-) diff --git a/include/nana/detail/win32/platform_spec.hpp b/include/nana/detail/win32/platform_spec.hpp index 9e735f99..39f21366 100644 --- a/include/nana/detail/win32/platform_spec.hpp +++ b/include/nana/detail/win32/platform_spec.hpp @@ -55,6 +55,13 @@ namespace detail unsigned ignore; //determinate that pos or size would be ignored. }; + struct map_thread + { + rectangle update_area; + bool ignore_update_area; + bool forced; + }; + enum { tray = 0x501, diff --git a/include/nana/gui/detail/bedrock.hpp b/include/nana/gui/detail/bedrock.hpp index 1ae2a41d..501a3c8c 100644 --- a/include/nana/gui/detail/bedrock.hpp +++ b/include/nana/gui/detail/bedrock.hpp @@ -42,7 +42,7 @@ namespace detail ~bedrock(); void pump_event(window, bool is_modal); - void map_thread_root_buffer(core_window_t*, bool forced); + void map_thread_root_buffer(core_window_t*, bool forced, const rectangle* update_area = nullptr); static int inc_window(unsigned tid = 0); thread_context* open_thread_context(unsigned tid = 0); thread_context* get_thread_context(unsigned tid = 0); diff --git a/include/nana/gui/detail/drawer.hpp b/include/nana/gui/detail/drawer.hpp index f6948a45..121c84b8 100644 --- a/include/nana/gui/detail/drawer.hpp +++ b/include/nana/gui/detail/drawer.hpp @@ -110,7 +110,7 @@ namespace nana void key_char(const arg_keyboard&); void key_release(const arg_keyboard&); void shortkey(const arg_keyboard&); - void map(window, bool forced); //Copy the root buffer to screen + void map(window, bool forced, const rectangle* update_area = nullptr); //Copy the root buffer to screen void refresh(); drawer_trigger* realizer() const; void attached(widget&, drawer_trigger&); diff --git a/include/nana/gui/detail/effects_renderer.hpp b/include/nana/gui/detail/effects_renderer.hpp index 91daf849..b9b1b785 100644 --- a/include/nana/gui/detail/effects_renderer.hpp +++ b/include/nana/gui/detail/effects_renderer.hpp @@ -13,9 +13,9 @@ namespace nana{ { edge_nimbus_renderer() = default; public: - typedef CoreWindow core_window_t; - typedef window_layout window_layer; - typedef nana::paint::graphics & graph_reference; + using core_window_t = CoreWindow; + using window_layer = window_layout; + using graph_reference = ::nana::paint::graphics&; static edge_nimbus_renderer& instance() { @@ -28,7 +28,34 @@ namespace nana{ return 2; } - bool render(core_window_t * wd, bool forced) + void erase(core_window_t* wd) + { + if (effects::edge_nimbus::none == wd->effect.edge_nimbus) + return; + + core_window_t * root_wd = wd->root_widget; + auto & nimbus = root_wd->other.attribute.root->effects_edge_nimbus; + + for (auto i = nimbus.cbegin(); i != nimbus.cend(); ++i) + { + if (i->window == wd) + { + auto pixels = weight(); + rectangle r{wd->pos_root, wd->dimension}; + r.x -= static_cast(pixels); + r.y -= static_cast(pixels); + r.width += static_cast(pixels << 1); + r.height += static_cast(pixels << 1); + + root_wd->root_graph->paste(root_wd->root, r, r.x, r.y); + + nimbus.erase(i); + break; + } + } + } + + bool render(core_window_t * wd, bool forced, const rectangle* update_area = nullptr) { bool rendered = false; core_window_t * root_wd = wd->root_widget; @@ -49,8 +76,12 @@ namespace nana{ { if(_m_edge_nimbus(focused, action.window) && window_layer::read_visual_rectangle(action.window, r)) { - if(action.window == wd) + if (action.window == wd) + { + if (update_area) + ::nana::overlap(*update_area, rectangle(r), r); rendered = true; + } //Avoiding duplicated rendering. If the window is declared to lazy refresh, it should be rendered. if ((forced && (action.window == wd)) || !action.rendered || (action.window->other.upd_state == core_window_t::update_state::refresh)) diff --git a/include/nana/gui/detail/window_manager.hpp b/include/nana/gui/detail/window_manager.hpp index 37c9c150..ba6aa451 100644 --- a/include/nana/gui/detail/window_manager.hpp +++ b/include/nana/gui/detail/window_manager.hpp @@ -150,9 +150,9 @@ namespace detail core_window_t* root(native_window_type) const; //Copy the root buffer that wnd specified into DeviceContext - void map(core_window_t*, bool forced); + void map(core_window_t*, bool forced, const rectangle* update_area = nullptr); - bool update(core_window_t*, bool redraw, bool force); + bool update(core_window_t*, bool redraw, bool force, const rectangle* update_area = nullptr); void refresh_tree(core_window_t*); bool do_lazy_refresh(core_window_t*, bool force_copy_to_screen); diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp index 3b9702a3..8c176b4b 100644 --- a/source/gui/detail/drawer.cpp +++ b/source/gui/detail/drawer.cpp @@ -240,7 +240,7 @@ namespace nana _m_emit(event_code::shortkey, arg, &drawer_trigger::shortkey); } - void drawer::map(window wd, bool forced) //Copy the root buffer to screen + void drawer::map(window wd, bool forced, const rectangle* update_area) //Copy the root buffer to screen { if(wd) { @@ -262,11 +262,15 @@ namespace nana #endif } - if (false == edge_nimbus_renderer_t::instance().render(iwd, forced)) + if (false == edge_nimbus_renderer_t::instance().render(iwd, forced, update_area)) { - nana::rectangle vr; - if(bedrock_type::window_manager_t::wndlayout_type::read_visual_rectangle(iwd, vr)) + rectangle vr; + if (bedrock_type::window_manager_t::wndlayout_type::read_visual_rectangle(iwd, vr)) + { + if (update_area) + ::nana::overlap(*update_area, rectangle(vr), vr); iwd->root_graph->paste(iwd->root, vr, vr.x, vr.y); + } } if(owns_caret) diff --git a/source/gui/detail/linux_X11/bedrock.cpp b/source/gui/detail/linux_X11/bedrock.cpp index 44ccef61..1a5a1ecc 100644 --- a/source/gui/detail/linux_X11/bedrock.cpp +++ b/source/gui/detail/linux_X11/bedrock.cpp @@ -167,7 +167,7 @@ namespace detail delete impl_; } - void bedrock::map_thread_root_buffer(core_window_t*, bool forced) + void bedrock::map_thread_root_buffer(core_window_t*, bool forced, const rectangle*) { //GUI in X11 is thread-independent, so no implementation. } diff --git a/source/gui/detail/win32/bedrock.cpp b/source/gui/detail/win32/bedrock.cpp index 4a9d0f11..1bb25cc9 100644 --- a/source/gui/detail/win32/bedrock.cpp +++ b/source/gui/detail/win32/bedrock.cpp @@ -338,9 +338,14 @@ namespace detail return bedrock_object; } - void bedrock::map_thread_root_buffer(core_window_t* wd, bool forced) + void bedrock::map_thread_root_buffer(core_window_t* wd, bool forced, const rectangle* update_area) { - ::PostMessage(reinterpret_cast(wd->root), nana::detail::messages::map_thread_root_buffer, reinterpret_cast(wd), static_cast(forced ? TRUE : FALSE)); + auto stru = reinterpret_cast(::HeapAlloc(::GetProcessHeap(), 0, sizeof(detail::messages::map_thread))); + if (stru) + { + if (FALSE == ::PostMessage(reinterpret_cast(wd->root), nana::detail::messages::map_thread_root_buffer, reinterpret_cast(wd), reinterpret_cast(stru))) + ::HeapFree(::GetProcessHeap(), 0, stru); + } } void interior_helper_for_menu(MSG& msg, native_window_type menu_window) @@ -591,8 +596,12 @@ namespace detail } return true; case nana::detail::messages::map_thread_root_buffer: - bedrock.wd_manager.map(reinterpret_cast(wParam), (TRUE == lParam)); - ::UpdateWindow(wd); + { + auto stru = reinterpret_cast(lParam); + bedrock.wd_manager.map(reinterpret_cast(wParam), stru->forced, (stru->ignore_update_area ? nullptr : &stru->update_area)); + ::UpdateWindow(wd); + ::HeapFree(::GetProcessHeap(), 0, stru); + } return true; case nana::detail::messages::remote_thread_move_window: { diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index b7719985..7f8da08b 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -372,21 +372,26 @@ namespace detail //@brief: Delete the window handle void window_manager::destroy(core_window_t* wd) { - core_window_t* parent = nullptr; + //Thread-Safe Required! + std::lock_guard lock(mutex_); + if (impl_->wd_register.available(wd) == false) return; + + rectangle update_area(wd->pos_owner, wd->dimension); + + auto parent = wd->parent; + if (parent) + utl::erase(parent->children, wd); + + _m_destroy(wd); + + while (parent && (parent->other.category == ::nana::category::flags::lite_widget)) { - //Thread-Safe Required! - std::lock_guard lock(mutex_); - if (impl_->wd_register.available(wd) == false) return; - - if (wd->parent) - { - parent = wd->parent; - utl::erase(wd->parent->children, wd); - } - - _m_destroy(wd); + update_area.x += parent->pos_owner.x; + update_area.y += parent->pos_owner.y; + parent = parent->parent; } - update(parent, false, false); + + update(parent, false, false, &update_area); } //destroy_handle @@ -672,7 +677,7 @@ namespace detail } //Copy the root buffer that wnd specified into DeviceContext - void window_manager::map(core_window_t* wd, bool forced) + void window_manager::map(core_window_t* wd, bool forced, const rectangle* update_area) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -680,12 +685,12 @@ namespace detail { //Copy the root buffer that wd specified into DeviceContext #if defined(NANA_LINUX) - wd->drawer.map(reinterpret_cast(wd), forced); + wd->drawer.map(reinterpret_cast(wd), forced, update_area); #elif defined(NANA_WINDOWS) if(nana::system::this_thread_id() == wd->thread_id) - wd->drawer.map(reinterpret_cast(wd), forced); + wd->drawer.map(reinterpret_cast(wd), forced, update_area); else - bedrock::instance().map_thread_root_buffer(wd, forced); + bedrock::instance().map_thread_root_buffer(wd, forced, update_area); #endif } } @@ -694,7 +699,7 @@ namespace detail //@brief: update is used for displaying the screen-off buffer. // Because of a good efficiency, if it is called in an event procedure and the event procedure window is the // same as update's, update would not map the screen-off buffer and just set the window for lazy refresh - bool window_manager::update(core_window_t* wd, bool redraw, bool forced) + bool window_manager::update(core_window_t* wd, bool redraw, bool forced, const rectangle* update_area) { //Thread-Safe Required! std::lock_guard lock(mutex_); @@ -705,7 +710,7 @@ namespace detail if(forced || (false == wd->belong_to_lazy())) { wndlayout_type::paint(wd, redraw, false); - this->map(wd, forced); + this->map(wd, forced, update_area); } else { @@ -1252,18 +1257,9 @@ namespace detail if (!established) { - if (effects::edge_nimbus::none != wd->effect.edge_nimbus) - { - auto & cont = root_attr->effects_edge_nimbus; - for (auto i = cont.begin(); i != cont.end(); ++i) - { - if (i->window == wd) - { - cont.erase(i); - break; - } - } - } + //remove the window from edge nimbus effect when it is destroying + using edge_nimbus = detail::edge_nimbus_renderer; + edge_nimbus::instance().erase(wd); } else if (pa_root_attr != root_attr) {