From 3f5d2fa0c54b38ee2ca73d335c82e49224d876de Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 27 Jan 2017 01:50:09 +0800 Subject: [PATCH 01/21] fix a deadlock the deadlock occurs between internal_scope_guard and the mutex of handle_manager --- source/gui/detail/window_manager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index e301ca5e..f5f56e71 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -1,7 +1,7 @@ /* * Window Manager Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -1386,6 +1386,7 @@ namespace detail void window_manager::remove_trash_handle(unsigned tid) { + internal_scope_guard lock; impl_->wd_register.delete_trash(tid); } From f11c54e513d30413ceb0fbf048d805df365d1794 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 30 Jan 2017 18:12:50 +0800 Subject: [PATCH 02/21] fix position issue on Linux --- source/gui/detail/native_window_interface.cpp | 37 +++++++++++++------ source/gui/msgbox.cpp | 2 +- source/gui/widgets/menu.cpp | 9 ++++- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index 0657dd14..bdf75823 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -1,7 +1,7 @@ /* * Platform Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -197,6 +197,13 @@ namespace nana{ return rectangle{ primary_monitor_size() }; } +#ifdef NANA_X11 + //The XMoveWindow and XMoveResizeWindow don't take effect if the specified window is + //unmapped, and the members x and y of XSetSizeHints is obsoluted. So the position that + //set to a unmapped windows should be kept and use the position when the window is mapped. + std::map exposed_positions; //locked by platform_scope_guard +#endif + //platform-dependent native_interface::window_result native_interface::create_window(native_window_type owner, bool nested, const rectangle& r, const appearance& app) { @@ -289,6 +296,7 @@ namespace nana{ { win_attr.save_under = True; attr_mask |= CWSaveUnder; + parent = restrict::spec.root_window(); calc_screen_point(owner, pos); } @@ -303,7 +311,12 @@ namespace nana{ { //make owner if it is a popup window if((!nested) && owner) + { restrict::spec.make_owner(owner, reinterpret_cast(handle)); + exposed_positions[handle] = pos; + } + + XChangeWindowAttributes(disp, handle, attr_mask, &win_attr); XTextProperty name; char text[] = "Nana Window"; @@ -655,6 +668,14 @@ namespace nana{ if(show) { ::XMapWindow(disp, reinterpret_cast(wd)); + + auto i = exposed_positions.find(reinterpret_cast(wd)); + if(i != exposed_positions.end()) + { + ::XMoveWindow(disp, reinterpret_cast(wd), i->second.x, i->second.y); + exposed_positions.erase(i); + } + Window grab = restrict::spec.grab(0); if(grab == reinterpret_cast(wd)) capture_window(wd, true); @@ -882,13 +903,7 @@ namespace nana{ XWindowAttributes attr; ::XGetWindowAttributes(disp, reinterpret_cast(wd), &attr); if(attr.map_state == IsUnmapped) - { - XSizeHints hints; - hints.flags = USPosition; - hints.x = x; - hints.y = y; - ::XSetWMNormalHints(disp, reinterpret_cast(wd), &hints); - } + exposed_positions[reinterpret_cast(wd)] = ::nana::point{x, y}; ::XMoveWindow(disp, reinterpret_cast(wd), x, y); #endif @@ -959,11 +974,11 @@ namespace nana{ ::XGetWindowAttributes(disp, reinterpret_cast(wd), &attr); if(attr.map_state == IsUnmapped) { - hints.flags |= (USPosition | USSize); - hints.x = x; - hints.y = y; + hints.flags |= USSize; hints.width = r.width; hints.height = r.height; + + exposed_positions[reinterpret_cast(wd)] = point{x, y}; } if(hints.flags) diff --git a/source/gui/msgbox.cpp b/source/gui/msgbox.cpp index 6b3b9510..6560fe93 100644 --- a/source/gui/msgbox.cpp +++ b/source/gui/msgbox.cpp @@ -618,7 +618,7 @@ namespace nana place_.field_display(img_fields[i], false); } - size({desc_extent.width, height }); + move(API::make_center(this->owner(), desc_extent.width, height)); caption(title); } diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 02ba5649..0d8b68f6 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -1141,7 +1141,14 @@ namespace nana throw std::out_of_range("menu: a new item inserted to an invalid position"); std::unique_ptr item{ new item_type{ std::move(text_utf8), handler } }; - impl_->mbuilder.data().items.emplace(impl_->mbuilder.data().items.cbegin() + pos, item.get()); + + items.emplace( +#ifdef _MSC_VER + items.cbegin() + pos, +#else + items.begin() + pos, +#endif + item.get()); return item_proxy{ pos, *item.release() }; } From f1a746ad4aaf801e3d02fdb48cfe3af63f17522a Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 2 Feb 2017 01:19:23 +0800 Subject: [PATCH 03/21] fix an issue of visibility state of nested_form --- source/gui/detail/window_manager.cpp | 33 +++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index f5f56e71..7ba67d3e 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -685,6 +685,30 @@ namespace detail } } + void sync_child_root_display(window_manager::core_window_t* wd) + { + for (auto & child : wd->children) + { + if (category::flags::root != child->other.category) + { + sync_child_root_display(child); + continue; + } + + auto const vs_parents = child->visible_parents(); + + if (vs_parents != child->visible) + { + native_interface::show_window(child->root, vs_parents, false); + } + else + { + if (child->visible != native_interface::is_window_visible(child->root)) + native_interface::show_window(child->root, child->visible, false); + } + } + } + //show //@brief: show or hide a window bool window_manager::show(core_window_t* wd, bool visible) @@ -719,8 +743,15 @@ namespace detail if(category::flags::root != wd->other.category) bedrock::instance().event_expose(wd, visible); - if(nv) + if (nv) + { + if (visible && !wd->visible_parents()) + return true; + native_interface::show_window(nv, visible, wd->flags.take_active); + } + + sync_child_root_display(wd); } return true; } From ef8b66341a0ac9832dabcf49b373844732917ddf Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 2 Feb 2017 17:53:47 +0800 Subject: [PATCH 04/21] fix issue that cursor of place splitter the cursor doesn't change when it leaves place splitter for a nested_form --- include/nana/gui/detail/basic_window.hpp | 5 +---- source/gui/detail/bedrock_windows.cpp | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/include/nana/gui/detail/basic_window.hpp b/include/nana/gui/detail/basic_window.hpp index a21ef4ad..34cbd72f 100644 --- a/include/nana/gui/detail/basic_window.hpp +++ b/include/nana/gui/detail/basic_window.hpp @@ -1,7 +1,7 @@ /** * A Basic Window Widget Definition * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -220,9 +220,6 @@ namespace detail basic_window* focus{nullptr}; basic_window* menubar{nullptr}; bool ime_enabled{false}; -#if defined(NANA_WINDOWS) - cursor running_cursor{ nana::cursor::arrow }; -#endif cursor state_cursor{nana::cursor::arrow}; basic_window* state_cursor_window{ nullptr }; diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index 11ef721a..95624980 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -1,7 +1,7 @@ /** * A Bedrock Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -784,7 +784,7 @@ namespace detail static auto& brock = bedrock::instance(); static restrict::TRACKMOUSEEVENT track = {sizeof track, 0x00000002}; - auto native_window = reinterpret_cast(root_window); + auto const native_window = reinterpret_cast(root_window); auto & wd_manager = brock.wd_manager(); auto* root_runtime = wd_manager.root_runtime(native_window); @@ -1720,9 +1720,16 @@ namespace detail thrd->cursor.handle = ::LoadCursor(nullptr, translate(cur)); } - if (wd->root_widget->other.attribute.root->running_cursor != cur) + auto this_cur = reinterpret_cast( +#ifdef _WIN64 + ::GetClassLongPtr(reinterpret_cast(wd->root), GCLP_HCURSOR) +#else + ::GetClassLong(reinterpret_cast(wd->root), GCL_HCURSOR) +#endif + ); + + if(this_cur != thrd->cursor.handle) { - wd->root_widget->other.attribute.root->running_cursor = cur; #ifdef _WIN64 ::SetClassLongPtr(reinterpret_cast(wd->root), GCLP_HCURSOR, reinterpret_cast(thrd->cursor.handle)); @@ -1731,6 +1738,7 @@ namespace detail static_cast(reinterpret_cast(thrd->cursor.handle))); #endif } + if (cursor::arrow == thrd->cursor.predef_cursor) { thrd->cursor.window = nullptr; @@ -1804,10 +1812,7 @@ namespace detail undefine_state_cursor(wd, thrd); if(wd == thrd->cursor.window) - { set_cursor(wd, cursor::arrow, thrd); - wd->root_widget->other.attribute.root->running_cursor = cursor::arrow; - } break; default: break; From 168842e2cfc7e05f2268aad61a29e948933934f9 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 7 Feb 2017 05:35:30 +0800 Subject: [PATCH 05/21] fix escape of menu --- source/gui/widgets/menu.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 0d8b68f6..47c16bf0 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -991,6 +991,12 @@ namespace nana case keyboard::enter: this->pick(); break; + case keyboard::escape: + //Leave sub menu. But if the sub menu doesn't exist, + //close the menu. + if (!this->submenu(false)) + close(); + break; default: if (2 != send_shortkey(arg.key)) { From 7a32fa27673b9601bbd0db5fc7c1be978653db12 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 7 Feb 2017 06:36:19 +0800 Subject: [PATCH 06/21] fix issue that scroll returns bad value because range > peak --- include/nana/gui/widgets/scroll.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/nana/gui/widgets/scroll.hpp b/include/nana/gui/widgets/scroll.hpp index dbbb6452..c4e39981 100644 --- a/include/nana/gui/widgets/scroll.hpp +++ b/include/nana/gui/widgets/scroll.hpp @@ -122,7 +122,9 @@ namespace nana void value(size_type s) { - if (s + metrics_.range > metrics_.peak) + if (metrics_.range > metrics_.peak) + s = 0; + else if (s + metrics_.range > metrics_.peak) s = metrics_.peak - metrics_.range; if (graph_ && (metrics_.value != s)) From 4e42c1881562d91a9fe6e400ad706084f6d48a96 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 10 Feb 2017 08:09:08 +0800 Subject: [PATCH 07/21] implement key_press support for menu in Linux --- source/detail/platform_spec_posix.cpp | 16 +++++++---- source/detail/x11/msg_dispatcher.hpp | 6 ++-- source/gui/detail/bedrock_posix.cpp | 12 ++++---- source/gui/detail/bedrock_windows.cpp | 40 +++++++++++++-------------- source/gui/widgets/menu.cpp | 2 +- source/system/dataexch.cpp | 1 + 6 files changed, 42 insertions(+), 35 deletions(-) diff --git a/source/detail/platform_spec_posix.cpp b/source/detail/platform_spec_posix.cpp index 7dd11333..cce9028f 100644 --- a/source/detail/platform_spec_posix.cpp +++ b/source/detail/platform_spec_posix.cpp @@ -1,7 +1,7 @@ /* * Platform Specification Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Nana Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -1163,8 +1163,16 @@ namespace detail // 2 = msg_dispatcher should ignore the msg, because the XEvent is processed by _m_msg_filter int platform_spec::_m_msg_filter(XEvent& evt, msg_packet_tag& msg) { + auto & bedrock = detail::bedrock::instance(); + platform_spec & self = instance(); - if(SelectionNotify == evt.type) + if(KeyPress == evt.type || KeyRelease == evt.type) + { + auto menu_wd = bedrock.get_menu(reinterpret_cast(evt.xkey.window), true); + if(menu_wd) + evt.xkey.window = reinterpret_cast(menu_wd); + } + else if(SelectionNotify == evt.type) { if(evt.xselection.property) { @@ -1197,7 +1205,6 @@ namespace detail } } - self.selection_.items.erase(self.selection_.items.begin()); std::lock_guardcond_mutex)> lock(im->cond_mutex); @@ -1373,9 +1380,8 @@ namespace detail { Window child; ::XTranslateCoordinates(self.display_, self.root_window(), evt.xclient.window, x, y, &self.xdnd_.pos.x, &self.xdnd_.pos.y, &child); - typedef detail::bedrock bedrock; - auto wd = bedrock::instance().wd_manager().find_window(reinterpret_cast(evt.xclient.window), self.xdnd_.pos.x, self.xdnd_.pos.y); + auto wd = bedrock.wd_manager().find_window(reinterpret_cast(evt.xclient.window), self.xdnd_.pos.x, self.xdnd_.pos.y); if(wd && wd->flags.dropable) { accepted = true; diff --git a/source/detail/x11/msg_dispatcher.hpp b/source/detail/x11/msg_dispatcher.hpp index 77f43a18..b6fddcce 100644 --- a/source/detail/x11/msg_dispatcher.hpp +++ b/source/detail/x11/msg_dispatcher.hpp @@ -1,6 +1,6 @@ /* * Message Dispatcher Implementation - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -51,7 +51,7 @@ namespace detail typedef std::list msg_queue_type; msg_dispatcher(Display* disp) - : display_(disp), is_work_(false) + : display_(disp) { proc_.event_proc = 0; proc_.timer_proc = 0; @@ -338,7 +338,7 @@ namespace detail private: Display * display_; - volatile bool is_work_; + volatile bool is_work_{ false }; std::unique_ptr thrd_; struct table_tag diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 5a3a4abe..4282402d 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -1147,7 +1147,7 @@ namespace detail } } - void bedrock::pump_event(window modal_window, bool /*is_modal*/) + void bedrock::pump_event(window condition_wd, bool is_modal) { thread_context * context = open_thread_context(); if(0 == context->window_count) @@ -1162,11 +1162,11 @@ namespace detail auto & lock = wd_manager().internal_lock(); lock.revert(); - native_window_type owner_native = 0; + native_window_type owner_native{}; core_window_t * owner = 0; - if(modal_window) + if(condition_wd && is_modal) { - native_window_type modal = reinterpret_cast(modal_window)->root; + native_window_type modal = reinterpret_cast(condition_wd)->root; owner_native = native_interface::get_owner_window(modal); if(owner_native) { @@ -1177,7 +1177,7 @@ namespace detail } } - nana::detail::platform_spec::instance().msg_dispatch(modal_window ? reinterpret_cast(modal_window)->root : 0); + nana::detail::platform_spec::instance().msg_dispatch(condition_wd ? reinterpret_cast(condition_wd)->root : 0); if(owner_native) { @@ -1190,7 +1190,7 @@ namespace detail if(0 == --(context->event_pump_ref_count)) { - if(0 == modal_window || 0 == context->window_count) + if(0 == condition_wd || 0 == context->window_count) remove_thread_context(); } diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index 95624980..80a8fd12 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -345,7 +345,7 @@ namespace detail } } - void bedrock::pump_event(window modal_window, bool is_modal) + void bedrock::pump_event(window condition_wd, bool is_modal) { const unsigned tid = ::GetCurrentThreadId(); auto context = this->open_thread_context(tid); @@ -365,9 +365,9 @@ namespace detail try { MSG msg; - if(modal_window) + if (condition_wd) { - HWND native_handle = reinterpret_cast(reinterpret_cast(modal_window)->root); + HWND native_handle = reinterpret_cast(reinterpret_cast(condition_wd)->root); if (is_modal) { HWND owner = ::GetWindow(native_handle, GW_OWNER); @@ -437,27 +437,27 @@ namespace detail } catch(std::exception& e) { - (msgbox(modal_window, "An uncaptured std::exception during message pumping: ").icon(msgbox::icon_information) - <<"\n in form: "<< API::window_caption(modal_window) - <<"\n exception : "<< e.what() - ).show(); + (msgbox(condition_wd, "An uncaptured std::exception during message pumping: ").icon(msgbox::icon_information) + << "\n in form: " << API::window_caption(condition_wd) + <<"\n exception : "<< e.what() + ).show(); - internal_scope_guard lock; - _m_except_handler(); + internal_scope_guard lock; + _m_except_handler(); - intr_locker.forward(); - if (0 == --(context->event_pump_ref_count)) - { - if ((nullptr == modal_window) || (0 == context->window_count)) - remove_thread_context(); - } - throw; + intr_locker.forward(); + if (0 == --(context->event_pump_ref_count)) + { + if ((nullptr == condition_wd) || (0 == context->window_count)) + remove_thread_context(); + } + throw; } catch(...) { - (msgbox(modal_window, "An exception during message pumping!").icon(msgbox::icon_information) + (msgbox(condition_wd, "An exception during message pumping!").icon(msgbox::icon_information) <<"An uncaptured non-std exception during message pumping!" - << "\n in form: " << API::window_caption(modal_window) + << "\n in form: " << API::window_caption(condition_wd) ).show(); internal_scope_guard lock; _m_except_handler(); @@ -465,7 +465,7 @@ namespace detail intr_locker.forward(); if(0 == --(context->event_pump_ref_count)) { - if((nullptr == modal_window) || (0 == context->window_count)) + if ((nullptr == condition_wd) || (0 == context->window_count)) remove_thread_context(); } throw; @@ -474,7 +474,7 @@ namespace detail intr_locker.forward(); if(0 == --(context->event_pump_ref_count)) { - if((nullptr == modal_window) || (0 == context->window_count)) + if ((nullptr == condition_wd) || (0 == context->window_count)) remove_thread_context(); } }//end pump_event diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 47c16bf0..78f842bc 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -747,7 +747,7 @@ namespace nana //add a is_wd_parent_menu to determine whether the menu wants the focus. //if a submenu gets the focus, the program may cause a crash error when the submenu is being destroyed : base_type(wd, false, rectangle(pos, nana::size(2, 2)), appear::bald()), - want_focus_{ (!wd) || ((!is_wd_parent_menu) && (API::focus_window() != wd)) }, + want_focus_{ (!wd) || ((!is_wd_parent_menu) && (API::root(API::focus_window()) != API::root(wd))) }, event_focus_{ nullptr } { caption("nana menu window"); diff --git a/source/system/dataexch.cpp b/source/system/dataexch.cpp index 8648ed1c..e4872f93 100644 --- a/source/system/dataexch.cpp +++ b/source/system/dataexch.cpp @@ -116,6 +116,7 @@ namespace nana{ namespace system{ //#elif defined(NANA_X11) #else static_cast(g); //eliminate unused parameter compiler warning. + static_cast(owner); throw "not implemented yet."; return false; #endif From 26ec27b4c429ca9e0f30e841cbd7ccc60531d735 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 11 Feb 2017 10:44:50 +0800 Subject: [PATCH 08/21] fix issue that incorrect treebox selection --- source/gui/widgets/treebox.cpp | 53 +++++++++++++++------------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index c7aeba61..e3bc094d 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -166,7 +166,7 @@ namespace nana class trigger::item_locator { public: - typedef tree_cont_type::node_type node_type; + using node_type = tree_cont_type::node_type; item_locator(implement * impl, int item_pos, int x, int y); int operator()(node_type &node, int affect); @@ -1323,29 +1323,31 @@ namespace nana node_r.width = comp_placer->item_width(*impl_->data.graph, node_attr_); node_r.height = comp_placer->item_height(*impl_->data.graph); - if(pos_.y < item_pos_.y + static_cast(node_r.height)) + if ((pos_.y < item_pos_.y + static_cast(node_r.height)) && (pos_.y >= item_pos_.y)) { - auto logic_pos = pos_ - item_pos_; - node_ = &node; + auto const logic_pos = pos_ - item_pos_; - for(int comp = static_cast(component::begin); comp != static_cast(component::end); ++comp) + for (int comp = static_cast(component::begin); comp != static_cast(component::end); ++comp) { nana::rectangle r = node_r; - if(comp_placer->locate(static_cast(comp), node_attr_, &r)) + if (!comp_placer->locate(static_cast(comp), node_attr_, &r)) + continue; + + if (r.is_hit(logic_pos)) { - if(r.is_hit(logic_pos)) - { - what_ = static_cast(comp); - if(component::expender == what_ && (false == node_attr_.has_children)) - what_ = component::end; + node_ = &node; + what_ = static_cast(comp); + if (component::expender == what_ && (false == node_attr_.has_children)) + what_ = component::end; - if(component::text == what_) - node_text_r_ = r; + if (component::text == what_) + node_text_r_ = r; - return 0; - } + break; } } + + return 0; //Stop iterating } item_pos_.y += node_r.height; @@ -1874,22 +1876,15 @@ namespace nana if(impl_->set_expanded(node_state.event_node, !node_state.event_node->value.second.expanded)) impl_->make_adjust(node_state.event_node, 0); - has_redraw = true; - } - else if(nl.item_body()) - { - if(node_state.selected != node_state.event_node) - { - impl_->set_selected(node_state.event_node); - has_redraw = true; - } + has_redraw = true; //btw, don't select the node } } - else if(node_state.selected != node_state.event_node) - { - impl_->set_selected(node_state.event_node); - has_redraw = true; - } + } + + if ((!has_redraw) && (node_state.selected != node_state.event_node)) + { + impl_->set_selected(node_state.event_node); + has_redraw = true; } if(has_redraw) From a22954d8d880a4dec77b370ab910e625948b0781 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 12 Feb 2017 08:06:50 +0800 Subject: [PATCH 09/21] fix issue that mouse_up penetration in Linux --- source/gui/detail/bedrock_posix.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 4282402d..f47ca96a 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -611,11 +611,18 @@ namespace detail //If a root window is created during the mouse_down event, Nana.GUI will ignore the mouse_up event. if (msgwnd->root != native_interface::get_focus_window()) { - //call the drawer mouse up event for restoring the surface graphics - msgwnd->set_action(mouse_action::normal); + auto pos = native_interface::cursor_position(); + auto rootwd = native_interface::find_window(pos.x, pos.y); + native_interface::calc_window_point(rootwd, pos); + if(msgwnd != wd_manager.find_window(rootwd, pos.x, pos.y)) + { + //call the drawer mouse up event for restoring the surface graphics + msgwnd->set_action(mouse_action::normal); - draw_invoker(&drawer::mouse_up, msgwnd, arg, &context); - wd_manager.do_lazy_refresh(msgwnd, false); + arg.evt_code = event_code::mouse_up; + draw_invoker(&drawer::mouse_up, msgwnd, arg, &context); + wd_manager.do_lazy_refresh(msgwnd, false); + } } } else From eb7ae0d635b206ae15da8ed59e34246613f73ee7 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 13 Feb 2017 07:18:39 +0800 Subject: [PATCH 10/21] fix bug that treebox.clear only rm the 1st node --- include/nana/gui/widgets/categorize.hpp | 2 +- include/nana/gui/widgets/detail/tree_cont.hpp | 13 +++++++++---- include/nana/gui/widgets/treebox.hpp | 3 +++ source/gui/widgets/categorize.cpp | 4 ++-- source/gui/widgets/treebox.cpp | 4 ++-- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/include/nana/gui/widgets/categorize.hpp b/include/nana/gui/widgets/categorize.hpp index 1e64fa14..dcbdde12 100644 --- a/include/nana/gui/widgets/categorize.hpp +++ b/include/nana/gui/widgets/categorize.hpp @@ -1,7 +1,7 @@ /** * A Categorize Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at diff --git a/include/nana/gui/widgets/detail/tree_cont.hpp b/include/nana/gui/widgets/detail/tree_cont.hpp index c9684ba6..628007d5 100644 --- a/include/nana/gui/widgets/detail/tree_cont.hpp +++ b/include/nana/gui/widgets/detail/tree_cont.hpp @@ -1,6 +1,6 @@ /* * A Tree Container class implementation - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -76,12 +76,17 @@ namespace detail ~tree_cont() { - clear(); + clear(&root_); } - void clear() + void clear(node_type* node) { - remove(root_.child); + while (node->child) + { + //If there is a sibling of child, the root_.child + //will be assigned with the sibling. + remove(node->child); + } } bool verify(const node_type* node) const diff --git a/include/nana/gui/widgets/treebox.hpp b/include/nana/gui/widgets/treebox.hpp index 2f4fe7d7..60b17116 100644 --- a/include/nana/gui/widgets/treebox.hpp +++ b/include/nana/gui/widgets/treebox.hpp @@ -201,6 +201,9 @@ namespace nana /// Set the check state, and it returns itself. item_proxy& check(bool); + /// Clears the child nodes + item_proxy& clear(); + /// Return true when the node is expanded \todo change to expanded ?? bool expanded() const; diff --git a/source/gui/widgets/categorize.cpp b/source/gui/widgets/categorize.cpp index cf29e267..0ce7646c 100644 --- a/source/gui/widgets/categorize.cpp +++ b/source/gui/widgets/categorize.cpp @@ -1,7 +1,7 @@ /* * A Categorize Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -343,7 +343,7 @@ namespace nana { if(tree_.get_root()->child) { - tree_.clear(); + tree_.clear(tree_.get_root()); return true; } return false; diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index e3bc094d..fc03ddc1 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -2175,8 +2175,8 @@ namespace nana void treebox::clear() { - auto impl = get_drawer_trigger().impl(); - impl->attr.tree_cont.clear(); + auto& tree_cont = get_drawer_trigger().impl()->attr.tree_cont; + tree_cont.clear(tree_cont.get_root()); get_drawer_trigger().draw(); } From 9f366ab008b8d96183da682dbe9e886815629739 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 13 Feb 2017 07:21:10 +0800 Subject: [PATCH 11/21] new treebox::item_proxy::clear() method --- source/gui/widgets/treebox.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index fc03ddc1..c1eefb44 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -870,6 +870,16 @@ namespace nana return *this; } + item_proxy& item_proxy::clear() + { + if (node_) + { + trigger_->impl()->attr.tree_cont.clear(node_); + trigger_->draw(); + } + return *this; + } + bool item_proxy::expanded() const { return (node_ && node_->value.second.expanded); From 2829a6c2de40e06628aaaf51efc90366263a7a7e Mon Sep 17 00:00:00 2001 From: Jinhao Date: Tue, 14 Feb 2017 07:46:50 +0800 Subject: [PATCH 12/21] fix bug that spinbox always resets the caret(#185) --- include/nana/gui/widgets/spinbox.hpp | 2 +- source/gui/widgets/spinbox.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/nana/gui/widgets/spinbox.hpp b/include/nana/gui/widgets/spinbox.hpp index e090426a..5b9b5a02 100644 --- a/include/nana/gui/widgets/spinbox.hpp +++ b/include/nana/gui/widgets/spinbox.hpp @@ -1,7 +1,7 @@ /** * A Spin box widget * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at diff --git a/source/gui/widgets/spinbox.cpp b/source/gui/widgets/spinbox.cpp index 9f63baa2..ca87855a 100644 --- a/source/gui/widgets/spinbox.cpp +++ b/source/gui/widgets/spinbox.cpp @@ -1,7 +1,7 @@ /* * A Spin box widget * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -295,13 +295,13 @@ namespace nana return range_->value(); } - bool value(const ::std::string& value_str) + bool value(const ::std::string& value_str, bool reset_editor) { bool diff; if (!range_->value(value_str, diff)) return false; - if (diff) + if (diff && reset_editor) reset_text(); return true; } @@ -572,7 +572,7 @@ namespace nana { if (impl_->editor()->respond_char(arg)) { - if (!impl_->value(to_utf8(impl_->editor()->text()))) + if (!impl_->value(to_utf8(impl_->editor()->text()), false)) impl_->draw_spins(); API::dev::lazy_refresh(); @@ -657,7 +657,7 @@ namespace nana internal_scope_guard lock; if (handle()) { - if (get_drawer_trigger().impl()->value(s)) + if (get_drawer_trigger().impl()->value(s, true)) API::refresh_window(handle()); } } From 1d31809051ce6045f2918fe81fee65c1bc85f7e2 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 17 Feb 2017 07:17:47 +0800 Subject: [PATCH 13/21] improve text_editor set_accept --- include/nana/system/dataexch.hpp | 4 ++- source/gui/widgets/skeletons/text_editor.cpp | 29 +++++++++++++------- source/system/dataexch.cpp | 10 ++++++- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/include/nana/system/dataexch.hpp b/include/nana/system/dataexch.hpp index 7d9ded94..7ce6be72 100644 --- a/include/nana/system/dataexch.hpp +++ b/include/nana/system/dataexch.hpp @@ -1,6 +1,6 @@ /* * Data Exchanger Implementation - * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -38,6 +38,8 @@ namespace system{ void get(std::string& text_utf8); void get(std::wstring& text); + + std::wstring wget(); private: bool _m_set(format, const void* buf, std::size_t size, native_window_type); void* _m_get(format, size_t& size); diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 051e8d1b..11723089 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1,7 +1,7 @@ /* * A text editor implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -2344,24 +2344,29 @@ namespace nana{ namespace widgets void text_editor::paste() { - std::wstring text; - nana::system::dataexch().get(text); + auto text = system::dataexch{}.wget(); //If it is required check the acceptable - if (accepts::no_restrict != impl_->capacities.acceptive) + if ((accepts::no_restrict != impl_->capacities.acceptive) || impl_->capacities.pred_acceptive) { for (auto i = text.begin(); i != text.end(); ++i) { - if (!_m_accepts(*i)) + if (_m_accepts(*i)) + { + if (accepts::no_restrict == impl_->capacities.acceptive) + put(*i); + + continue; + } + + if (accepts::no_restrict != impl_->capacities.acceptive) { text.erase(i, text.end()); - break; + put(std::move(text)); } + break; } } - - if (!text.empty()) - put(std::move(text)); } void text_editor::enter(bool record_undo) @@ -2814,8 +2819,12 @@ namespace nana{ namespace widgets bool text_editor::_m_accepts(char_type ch) const { - if(accepts::no_restrict == impl_->capacities.acceptive) + if (accepts::no_restrict == impl_->capacities.acceptive) + { + if (impl_->capacities.pred_acceptive) + return impl_->capacities.pred_acceptive(ch); return true; + } //Checks the input whether it meets the requirement for a numeric. auto str = text(); diff --git a/source/system/dataexch.cpp b/source/system/dataexch.cpp index e4872f93..f622de63 100644 --- a/source/system/dataexch.cpp +++ b/source/system/dataexch.cpp @@ -1,6 +1,6 @@ /* * Data Exchanger Implementation - * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at @@ -183,6 +183,14 @@ namespace nana{ namespace system{ #endif } } + + std::wstring dataexch::wget() + { + std::wstring str; + this->get(str); + return str; + } + //private: bool dataexch::_m_set(format fmt, const void* buf, std::size_t size, native_window_type owner) { From f17eb8cadda8699dabd10a38961c754c839a747c Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Fri, 17 Feb 2017 21:37:51 -0800 Subject: [PATCH 14/21] Fix non-unicode char (and typo) --- include/nana/gui/programming_interface.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/nana/gui/programming_interface.hpp b/include/nana/gui/programming_interface.hpp index 06ff5716..75c3ed40 100644 --- a/include/nana/gui/programming_interface.hpp +++ b/include/nana/gui/programming_interface.hpp @@ -63,7 +63,7 @@ namespace API void affinity_execute(window window_handle, const std::function&); bool set_events(window, const std::shared_ptr&); - + template std::unique_ptr make_scheme() { @@ -157,7 +157,7 @@ namespace API }//end namespace detail void exit(); ///< close all windows in current thread - void exit_all(); ///< close all windows + void exit_all(); ///< close all windows /// @brief Searchs whether the text contains a '&' and removes the character for transforming. /// If the text contains more than one '&' charachers, the others are ignored. e.g @@ -185,7 +185,7 @@ namespace API void window_icon_default(const paint::image& small_icon, const paint::image& big_icon = {}); void window_icon(window, const paint::image& small_icon, const paint::image& big_icon = {}); - + bool empty_window(window); ///< Determines whether a window is existing. bool is_window(window); ///< Determines whether a window is existing, equal to !empty_window. bool is_destroying(window); ///< Determines whether a window is destroying @@ -288,7 +288,7 @@ namespace API * @param window_handle A handle to the window to be refreshed. */ void refresh_window(window window_handle); - void refresh_window_tree(window); ///< Refreshs the specified window and all it’s children windows, then display it immediately + void refresh_window_tree(window); ///< Refreshes the specified window and all its children windows, then display it immediately void update_window(window); ///< Copies the off-screen buffer to the screen for immediate display. void window_caption(window, const std::string& title_utf8); @@ -300,7 +300,7 @@ namespace API void activate_window(window); - /// Determines whether the specified window will get the keyboard focus when its root window gets native system focus. + /// Determines whether the specified window will get the keyboard focus when its root window gets native system focus. bool is_focus_ready(window); /// Returns the current keyboard focus window. @@ -318,7 +318,7 @@ namespace API * @param ignore_children Indicates whether to redirect the mouse input to its children if the mouse pointer is over its children. */ void set_capture(window window_handle, bool ignore_children); - + /// Disable a window to grab the mouse input. /** * @param window handle A handle to a window to release grab of mouse input. From 4cceb6deaf41d09884f720632d1206c63d57ca9f Mon Sep 17 00:00:00 2001 From: Alexander Karatarakis Date: Fri, 17 Feb 2017 21:58:03 -0800 Subject: [PATCH 15/21] Fix warning C4003: not enough actual parameters for macro This would trigger when the argument to STRING2 was a MACRO that was defined but had no value --- include/nana/verbose_preprocessor.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/nana/verbose_preprocessor.hpp b/include/nana/verbose_preprocessor.hpp index 07b306f8..4bac4862 100644 --- a/include/nana/verbose_preprocessor.hpp +++ b/include/nana/verbose_preprocessor.hpp @@ -30,9 +30,9 @@ - #define STRING2(x) #x + #define STRING2(...) #__VA_ARGS__ #define STRING(x) STRING2(x) - #define SHOW_VALUE(x) " " #x " = " STRING2(x) + #define SHOW_VALUE(x) " " #x " = " STRING2(x) #pragma message ( "\n -----> Verbose preprocessor" ) #pragma message ( SHOW_VALUE(VERBOSE_PREPROCESSOR) ) @@ -124,7 +124,7 @@ #pragma message ( SHOW_VALUE(USE_LIBJPEG_FROM_OS) ) #pragma message ( SHOW_VALUE(NANA_LIBJPEG) ) - + // #pragma message ( "\n =" STRING() ", \n =" STRING()" , \n =" STRING() ) #if defined(STOP_VERBOSE_PREPROCESSOR) From c1113cf41d7d4f331f20a67ca8e233da32c4db74 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 19 Feb 2017 13:11:13 +0800 Subject: [PATCH 16/21] fix crash that could occur when clearing treebox --- include/nana/gui/widgets/detail/tree_cont.hpp | 25 ++++ include/nana/gui/widgets/treebox.hpp | 1 - source/gui/widgets/treebox.cpp | 117 ++++++++++-------- 3 files changed, 91 insertions(+), 52 deletions(-) diff --git a/include/nana/gui/widgets/detail/tree_cont.hpp b/include/nana/gui/widgets/detail/tree_cont.hpp index 628007d5..2490ab95 100644 --- a/include/nana/gui/widgets/detail/tree_cont.hpp +++ b/include/nana/gui/widgets/detail/tree_cont.hpp @@ -58,6 +58,31 @@ namespace detail t = t_next; } } + + bool is_ancestor_of(const tree_node* child) const + { + while (child) + { + if (child->owner == this) + return true; + + child = child->owner; + } + return false; + } + + tree_node * front() const + { + if (this->owner && (this != this->owner->child)) + { + auto i = this->owner->child; + while (i->next != this) + i = i->next; + + return i; + } + return nullptr; + } }; template diff --git a/include/nana/gui/widgets/treebox.hpp b/include/nana/gui/widgets/treebox.hpp index 60b17116..0ea3f302 100644 --- a/include/nana/gui/widgets/treebox.hpp +++ b/include/nana/gui/widgets/treebox.hpp @@ -119,7 +119,6 @@ namespace nana implement * impl() const; void check(node_type*, checkstate); - bool draw(); const tree_cont_type & tree() const; tree_cont_type & tree(); diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index c1eefb44..fd38b513 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -220,7 +220,7 @@ namespace nana mutable std::map image_table; - tree_cont_type::node_type * first; + tree_cont_type::node_type * first; //The node at the top of screen int indent_pixels; int offset_x; }shape; @@ -304,19 +304,56 @@ namespace nana } } - bool draw(bool scrollbar_react) + bool clear(node_type* node) + { + if (!node) + return false; + + if (node->is_ancestor_of(shape.first)) + { + shape.first = node->front(); + if (shape.first) + shape.first = node->owner; + } + + if (node->is_ancestor_of(node_state.pointed)) + node_state.pointed = nullptr; + + if (node->is_ancestor_of(node_state.selected)) + node_state.selected = nullptr; + + if (node->is_ancestor_of(node_state.event_node)) + node_state.event_node = nullptr; + + if (node->child) + { + attr.tree_cont.clear(node); + return true; + } + return false; + } + + bool draw(bool reset_scroll, bool ignore_update = false) { if(data.graph && (false == data.stop_drawing)) { - if(scrollbar_react) + if (reset_scroll) show_scroll(); - //Draw background - data.graph->rectangle(true, data.widget_ptr->bgcolor()); + if (attr.auto_draw) + { - //Draw tree - attr.tree_cont.for_each(shape.first, Renderer(this, nana::point(static_cast(attr.tree_cont.indent_size(shape.first) * shape.indent_pixels) - shape.offset_x, 1))); - return true; + //Draw background + data.graph->rectangle(true, data.widget_ptr->bgcolor()); + + //Draw tree + attr.tree_cont.for_each(shape.first, Renderer(this, nana::point(static_cast(attr.tree_cont.indent_size(shape.first) * shape.indent_pixels) - shape.offset_x, 1))); + + if (!ignore_update) + API::update_window(data.widget_ptr->handle()); + + return true; + } } return false; } @@ -535,7 +572,7 @@ namespace nana if(value == false) { //if contracting a parent of the selected node, select the contracted node. - if(check_kinship(node, node_state.selected)) + if (node->is_ancestor_of(node_state.selected)) set_selected(node); } @@ -543,7 +580,6 @@ namespace nana if(node->child) { data.stop_drawing = true; - //attr.ext_event.expand(data.widget_ptr->handle(), item_proxy(data.trigger_ptr, node), value); item_proxy iprx(data.trigger_ptr, node); data.widget_ptr->events().expanded.emit(::nana::arg_treebox{ *data.widget_ptr, iprx, value }, data.widget_ptr->handle()); data.stop_drawing = false; @@ -866,7 +902,7 @@ namespace nana item_proxy& item_proxy::check(bool ck) { trigger_->check(node_, ck ? checkstate::checked : checkstate::unchecked); - trigger_->draw(); + trigger_->impl()->draw(false); return *this; } @@ -874,8 +910,9 @@ namespace nana { if (node_) { - trigger_->impl()->attr.tree_cont.clear(node_); - trigger_->draw(); + auto impl = trigger_->impl(); + impl->clear(node_); + impl->draw(true); } return *this; } @@ -889,10 +926,8 @@ namespace nana { auto * impl = trigger_->impl(); if(impl->set_expanded(node_, exp)) - { impl->draw(true); - API::update_window(impl->data.widget_ptr->handle()); - } + return *this; } @@ -905,10 +940,8 @@ namespace nana { auto * impl = trigger_->impl(); if(impl->set_selected(s ? node_ : nullptr)) - { impl->draw(true); - API::update_window(*impl->data.widget_ptr); - } + return *this; } @@ -1542,7 +1575,6 @@ namespace nana } impl_->draw(false); - API::update_window(impl_->data.widget_ptr->handle()); if (impl_->node_state.tooltip) { @@ -1641,16 +1673,6 @@ namespace nana } } - bool trigger::draw() - { - if (!impl_->attr.auto_draw) - return false; - - if(impl_->draw(false)) - API::update_window(impl_->data.widget_ptr->handle()); - return true; - } - auto trigger::tree() -> tree_cont_type & { return impl_->attr.tree_cont; @@ -1697,16 +1719,17 @@ namespace nana else p = impl_->attr.tree_cont.insert(node, key, treebox_node_type(std::move(title))); - if(p && impl_->attr.auto_draw && impl_->draw(true)) - API::update_window(impl_->data.widget_ptr->handle()); + if (p) + impl_->draw(true); + return p; } trigger::node_type* trigger::insert(const std::string& path, std::string&& title) { auto x = impl_->attr.tree_cont.insert(path, treebox_node_type(std::move(title))); - if(x && impl_->attr.auto_draw && impl_->draw(true)) - API::update_window(impl_->data.widget_ptr->handle()); + if (x) + impl_->draw(true); return x; } @@ -1748,28 +1771,19 @@ namespace nana void trigger::selected(node_type* node) { if(tree().verify(node) && impl_->set_selected(node)) - { - if(impl_->draw(true)) - API::update_window(impl_->data.widget_ptr->handle()); - } + impl_->draw(true); } void trigger::set_expand(node_type* node, bool exp) { if((impl_->data.widget_ptr) && impl_->set_expanded(node, exp)) - { impl_->draw(true); - API::update_window(impl_->data.widget_ptr->handle()); - } } void trigger::set_expand(const std::string& path, bool exp) { if(impl_->set_expanded(impl_->attr.tree_cont.find(path), exp)) - { impl_->draw(true); - API::update_window(impl_->data.widget_ptr->handle()); - } } node_image_tag& trigger::icon(const std::string& id) const @@ -1796,8 +1810,8 @@ namespace nana { node->value.second.img_idstr = id; auto i = impl_->shape.image_table.find(id); - if((i != impl_->shape.image_table.end()) && impl_->draw(true)) - API::update_window(impl_->data.widget_ptr->handle()); + if (i != impl_->shape.image_table.end()) + impl_->draw(true); } } @@ -1843,7 +1857,8 @@ namespace nana void trigger::refresh(graph_reference) { - impl_->draw(false); + //Don't reset the scroll and update the window + impl_->draw(false, true); } void trigger::dbl_click(graph_reference, const arg_mouse& arg) @@ -2173,7 +2188,7 @@ namespace nana if (comp_placer->enabled(component::crook) != enable) { comp_placer->enable(component::crook, enable); - get_drawer_trigger().draw(); + impl->draw(false); } return *this; } @@ -2185,9 +2200,9 @@ namespace nana void treebox::clear() { - auto& tree_cont = get_drawer_trigger().impl()->attr.tree_cont; - tree_cont.clear(tree_cont.get_root()); - get_drawer_trigger().draw(); + auto impl = get_drawer_trigger().impl(); + impl->clear(impl->attr.tree_cont.get_root()); + impl->draw(true); } treebox::node_image_type& treebox::icon(const std::string& id) const From 9fa0bc2db9fc4dd095234cc53e9b2ef27d3d0cba Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sun, 19 Feb 2017 21:09:06 +0800 Subject: [PATCH 17/21] remove some duplicated functions of treebox --- include/nana/gui/widgets/treebox.hpp | 6 -- source/gui/widgets/treebox.cpp | 95 ++++++---------------------- 2 files changed, 20 insertions(+), 81 deletions(-) diff --git a/include/nana/gui/widgets/treebox.hpp b/include/nana/gui/widgets/treebox.hpp index 0ea3f302..210ecc31 100644 --- a/include/nana/gui/widgets/treebox.hpp +++ b/include/nana/gui/widgets/treebox.hpp @@ -128,17 +128,11 @@ namespace nana void placer(::nana::pat::cloneable&&); const ::nana::pat::cloneable& placer() const; - nana::any & value(node_type*) const; node_type* insert(node_type*, const std::string& key, std::string&&); node_type* insert(const std::string& path, std::string&&); - bool verify_kinship(node_type* parent, node_type* child) const; - - void remove(node_type*); node_type * selected() const; void selected(node_type*); - void set_expand(node_type*, bool); - void set_expand(const ::std::string& path, bool); node_image_tag& icon(const ::std::string&) const; void icon_erase(const ::std::string&); diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index fd38b513..3b498ff9 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include namespace nana @@ -304,9 +303,9 @@ namespace nana } } - bool clear(node_type* node) + bool unlink(node_type* node, bool perf_clear) { - if (!node) + if (!attr.tree_cont.verify(node)) return false; if (node->is_ancestor_of(shape.first)) @@ -325,12 +324,18 @@ namespace nana if (node->is_ancestor_of(node_state.event_node)) node_state.event_node = nullptr; - if (node->child) + if (perf_clear) { - attr.tree_cont.clear(node); - return true; + if (node->child) + { + attr.tree_cont.clear(node); + return true; + } + return false; } - return false; + + attr.tree_cont.remove(node); + return true; } bool draw(bool reset_scroll, bool ignore_update = false) @@ -439,17 +444,6 @@ namespace nana return nullptr; } - static bool check_kinship(const node_type* parent, const node_type * child) - { - if((!parent) || (!child)) - return false; - - while(child && (child != parent)) - child = child->owner; - - return (nullptr != child); - } - bool make_adjust(node_type * node, int reason) { if(!node) return false; @@ -911,8 +905,8 @@ namespace nana if (node_) { auto impl = trigger_->impl(); - impl->clear(node_); - impl->draw(true); + if(impl->unlink(node_, true)) + impl->draw(true); } return *this; } @@ -1703,14 +1697,6 @@ namespace nana return impl_->data.comp_placer; } - nana::any & trigger::value(node_type* node) const - { - if(impl_->attr.tree_cont.verify(node) == false) - throw std::invalid_argument("Nana.GUI.treebox.value() invalid node"); - - return node->value.second.value; - } - trigger::node_type* trigger::insert(node_type* node, const std::string& key, std::string&& title) { node_type * p = impl_->attr.tree_cont.node(node, key); @@ -1733,36 +1719,6 @@ namespace nana return x; } - bool trigger::verify_kinship(node_type* parent, node_type* child) const - { - if(false == (parent && child)) return false; - - while(child && (child != parent)) - child = child->owner; - - return (nullptr != child); - } - - void trigger::remove(node_type* node) - { - if (!tree().verify(node)) - return; - - auto & shape = impl_->shape; - auto & node_state = impl_->node_state; - - if(verify_kinship(node, node_state.event_node)) - node_state.event_node = nullptr; - - if(verify_kinship(node, shape.first)) - shape.first = nullptr; - - if(verify_kinship(node, node_state.selected)) - node_state.selected = nullptr; - - impl_->attr.tree_cont.remove(node); - } - trigger::node_type* trigger::selected() const { return impl_->node_state.selected; @@ -1774,18 +1730,6 @@ namespace nana impl_->draw(true); } - void trigger::set_expand(node_type* node, bool exp) - { - if((impl_->data.widget_ptr) && impl_->set_expanded(node, exp)) - impl_->draw(true); - } - - void trigger::set_expand(const std::string& path, bool exp) - { - if(impl_->set_expanded(impl_->attr.tree_cont.find(path), exp)) - impl_->draw(true); - } - node_image_tag& trigger::icon(const std::string& id) const { auto i = impl_->shape.image_table.find(id); @@ -2201,8 +2145,8 @@ namespace nana void treebox::clear() { auto impl = get_drawer_trigger().impl(); - impl->clear(impl->attr.tree_cont.get_root()); - impl->draw(true); + if (impl->unlink(impl->attr.tree_cont.get_root(), true)) + impl->draw(true); } treebox::node_image_type& treebox::icon(const std::string& id) const @@ -2234,15 +2178,16 @@ namespace nana treebox::item_proxy treebox::erase(item_proxy i) { auto next = i.sibling(); - get_drawer_trigger().remove(i._m_node()); + if (get_drawer_trigger().impl()->unlink(i._m_node(), false)) + get_drawer_trigger().impl()->draw(true); return next; } void treebox::erase(const std::string& keypath) { auto i = find(keypath); - if(!i.empty()) - get_drawer_trigger().remove(i._m_node()); + if (!i.empty()) + this->erase(i); } std::string treebox::make_key_path(item_proxy i, const std::string& splitter) const From 66be23c9204c5567d1c51e6f57ba23bffa517a7c Mon Sep 17 00:00:00 2001 From: Jinhao Date: Mon, 20 Feb 2017 03:41:04 +0800 Subject: [PATCH 18/21] fix issues that occur when expands/shrinks treebox --- include/nana/gui/widgets/treebox.hpp | 5 +- source/gui/widgets/treebox.cpp | 241 +++++++++++++-------------- 2 files changed, 114 insertions(+), 132 deletions(-) diff --git a/include/nana/gui/widgets/treebox.hpp b/include/nana/gui/widgets/treebox.hpp index 210ecc31..a7e1bc77 100644 --- a/include/nana/gui/widgets/treebox.hpp +++ b/include/nana/gui/widgets/treebox.hpp @@ -37,7 +37,7 @@ namespace nana { enum class component { - begin, expender = begin, crook, icon, text, bground, end + begin, expander = begin, crook, icon, text, bground, end }; struct node_image_tag @@ -120,9 +120,6 @@ namespace nana void check(node_type*, checkstate); - const tree_cont_type & tree() const; - tree_cont_type & tree(); - void renderer(::nana::pat::cloneable&&); const ::nana::pat::cloneable& renderer() const; void placer(::nana::pat::cloneable&&); diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index 3b498ff9..350a4210 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -198,7 +198,7 @@ namespace nana template struct trigger::basic_implement { - typedef trigger::node_type node_type; + using node_type = trigger::node_type; struct rep_tag { @@ -215,7 +215,6 @@ namespace nana { nana::upoint border; nana::scroll scroll; - std::size_t prev_first_value; mutable std::map image_table; @@ -234,9 +233,9 @@ namespace nana { tooltip_window * tooltip; component comp_pointed; - tree_cont_type::node_type * pointed; - tree_cont_type::node_type * selected; - tree_cont_type::node_type * event_node; + node_type * pointed; + node_type * selected; + node_type * pressed_node; }node_state; struct track_node_tag @@ -259,7 +258,6 @@ namespace nana data.widget_ptr = nullptr; data.stop_drawing = false; - shape.prev_first_value = 0; shape.first = nullptr; shape.indent_pixels = 10; shape.offset_x = 0; @@ -270,7 +268,7 @@ namespace nana node_state.comp_pointed = component::end; node_state.pointed = nullptr; node_state.selected = nullptr; - node_state.event_node = nullptr; + node_state.pressed_node = nullptr; track_node.key_time = 0; @@ -321,9 +319,6 @@ namespace nana if (node->is_ancestor_of(node_state.selected)) node_state.selected = nullptr; - if (node->is_ancestor_of(node_state.event_node)) - node_state.event_node = nullptr; - if (perf_clear) { if (node->child) @@ -338,16 +333,15 @@ namespace nana return true; } - bool draw(bool reset_scroll, bool ignore_update = false) + bool draw(bool reset_scroll, bool ignore_update = false, bool ignore_auto_draw = false) { if(data.graph && (false == data.stop_drawing)) { if (reset_scroll) show_scroll(); - if (attr.auto_draw) + if (attr.auto_draw || ignore_auto_draw) { - //Draw background data.graph->rectangle(true, data.widget_ptr->bgcolor()); @@ -448,27 +442,41 @@ namespace nana { if(!node) return false; - auto & tree_container = attr.tree_cont; + auto & tree = attr.tree_cont; + auto const first_pos = tree.distance_if(shape.first, pred_allow_child{}); + auto const node_pos = tree.distance_if(node, pred_allow_child{}); + auto const max_allow = max_allowed(); switch(reason) { case 0: - //adjust if the node expanded and the number of its children are over the max number allowed - if(shape.first != node) + if (node->value.second.expanded) { - unsigned child_size = tree_container.child_size_if(*node, pred_allow_child()); - const std::size_t max_allow = max_allowed(); - - if(child_size < max_allow) + //adjust if the number of its children are over the max number allowed + if (shape.first != node) { - unsigned off1 = tree_container.distance_if(shape.first, pred_allow_child()); - unsigned off2 = tree_container.distance_if(node, pred_allow_child()); - const unsigned size = off2 - off1 + child_size + 1; - if(size > max_allow) - shape.first = tree_container.advance_if(shape.first, size - max_allow, pred_allow_child()); + auto child_size = tree.child_size_if(*node, pred_allow_child()); + if (child_size < max_allow) + { + auto const size = node_pos - first_pos + child_size + 1; + if (size > max_allow) + shape.first = tree.advance_if(shape.first, size - max_allow, pred_allow_child{}); + } + else + shape.first = node; + } + } + else + { + //The node is shrank + auto visual_size = visual_item_size(); + if (visual_size > max_allow) + { + if (first_pos + max_allow > visual_size) + shape.first = tree.advance_if(nullptr, visual_size - max_allow, pred_allow_child{}); } else - shape.first = node; + shape.first = nullptr; } break; case 1: @@ -476,7 +484,7 @@ namespace nana case 3: //param is the begin pos of an item in absolute. { - int beg = static_cast(tree_container.indent_size(node) * shape.indent_pixels) - shape.offset_x; + int beg = static_cast(tree.indent_size(node) * shape.indent_pixels) - shape.offset_x; int end = beg + static_cast(node_w_pixels(node)); bool take_adjust = false; @@ -499,16 +507,14 @@ namespace nana case 4: if(shape.first != node) { - unsigned off_first = tree_container.distance_if(shape.first, pred_allow_child()); - unsigned off_node = tree_container.distance_if(node, pred_allow_child()); - if(off_node < off_first) + if (node_pos < first_pos) { shape.first = node; return true; } - else if(off_node - off_first > max_allowed()) + else if (node_pos - first_pos > max_allow) { - shape.first = tree_container.advance_if(0, off_node - max_allowed() + 1, pred_allow_child()); + shape.first = tree.advance_if(nullptr, node_pos - max_allow + 1, pred_allow_child{}); return true; } } @@ -603,44 +609,24 @@ namespace nana { if(scroll.empty()) { - shape.prev_first_value = 0; scroll.create(*data.widget_ptr, nana::rectangle(data.graph->width() - 16, 0, 16, data.graph->height())); - auto fn = [this](const arg_mouse& arg){ - this->event_scrollbar(arg); - }; - auto & events = scroll.events(); - events.mouse_down(fn); - events.mouse_move(fn); - events.mouse_wheel(fn); + scroll.events().value_changed.connect_unignorable([this](const arg_scroll& arg) + { + adjust.scroll_timestamp = nana::system::timestamp(); + adjust.timer.start(); + + shape.first = attr.tree_cont.advance_if(nullptr, shape.scroll.value(), pred_allow_child{}); + draw(false, false, true); + }); } scroll.amount(visual_items); scroll.range(max_allow); } - scroll.value(attr.tree_cont.distance_if(shape.first, pred_allow_child())); - } - - void event_scrollbar(const arg_mouse& arg) - { - if((event_code::mouse_wheel == arg.evt_code) || arg.is_left_button()) - { - if(shape.prev_first_value != shape.scroll.value()) - { - shape.prev_first_value = shape.scroll.value(); - adjust.scroll_timestamp = nana::system::timestamp(); - adjust.timer.start(); - - shape.first = attr.tree_cont.advance_if(nullptr, shape.prev_first_value, pred_allow_child()); - - if(arg.window_handle == shape.scroll.handle()) - { - draw(false); - API::update_window(data.widget_ptr->handle()); - } - } - } + auto pos = attr.tree_cont.distance_if(shape.first, pred_allow_child{}); + scroll.value(pos); } std::size_t visual_item_size() const @@ -702,11 +688,10 @@ namespace nana attr.tree_cont.template for_each(shape.first, nl); bool redraw = false; - node_state.event_node = nl.node(); - - if(nl.node() && (nl.what() != component::end)) + auto const node = nl.node(); + if (node && (nl.what() != component::end)) { - if((nl.what() != node_state.comp_pointed || nl.node() != node_state.pointed)) + if ((nl.what() != node_state.comp_pointed) || (node != node_state.pointed)) { node_state.comp_pointed = nl.what(); @@ -715,12 +700,11 @@ namespace nana item_proxy iprx(data.trigger_ptr, node_state.pointed); data.widget_ptr->events().hovered.emit(::nana::arg_treebox{ *data.widget_ptr, iprx, false }, data.widget_ptr->handle()); - if (nl.node() != node_state.pointed) + if (node != node_state.pointed) close_tooltip_window(); } - - node_state.pointed = nl.node(); + node_state.pointed = node; item_proxy iprx(data.trigger_ptr, node_state.pointed); data.widget_ptr->events().hovered.emit(::nana::arg_treebox{ *data.widget_ptr, iprx, true }, data.widget_ptr->handle()); @@ -781,11 +765,11 @@ namespace nana }; auto & events = node_state.tooltip->events(); - events.mouse_leave(fn); - events.mouse_move(fn); - events.mouse_down.connect(fn); - events.mouse_up.connect(fn); - events.dbl_click.connect(fn); + events.mouse_leave.connect_unignorable(fn); + events.mouse_move.connect_unignorable(fn); + events.mouse_down.connect_unignorable(fn); + events.mouse_up.connect_unignorable(fn); + events.dbl_click.connect_unignorable(fn); } } @@ -1170,7 +1154,7 @@ namespace nana { switch(comp) { - case component_t::expender: + case component_t::expander: if(attr.has_children) { r->width = item_offset; @@ -1259,7 +1243,7 @@ namespace nana void expander(graph_reference graph, const compset_interface * compset) const override { comp_attribute_t attr; - if(compset->comp_attribute(component::expender, attr)) + if(compset->comp_attribute(component::expander, attr)) { facade arrow("solid_triangle"); arrow.direction(direction::southeast); @@ -1374,7 +1358,7 @@ namespace nana { node_ = &node; what_ = static_cast(comp); - if (component::expender == what_ && (false == node_attr_.has_children)) + if (component::expander == what_ && (false == node_attr_.has_children)) what_ = component::end; if (component::text == what_) @@ -1667,16 +1651,6 @@ namespace nana } } - auto trigger::tree() -> tree_cont_type & - { - return impl_->attr.tree_cont; - } - - auto trigger::tree() const -> tree_cont_type const & - { - return impl_->attr.tree_cont; - } - void trigger::renderer(::nana::pat::cloneable&& r) { impl_->data.renderer = std::move(r); @@ -1726,7 +1700,7 @@ namespace nana void trigger::selected(node_type* node) { - if(tree().verify(node) && impl_->set_selected(node)) + if(impl_->attr.tree_cont.verify(node) && impl_->set_selected(node)) impl_->draw(true); } @@ -1750,7 +1724,7 @@ namespace nana void trigger::node_icon(node_type* node, const std::string& id) { - if(tree().verify(node)) + if(impl_->attr.tree_cont.verify(node)) { node->value.second.img_idstr = id; auto i = impl_->shape.image_table.find(id); @@ -1768,7 +1742,7 @@ namespace nana bool trigger::rename(node_type *node, const char* key, const char* name) { - if((key || name ) && tree().verify(node)) + if((key || name ) && impl_->attr.tree_cont.verify(node)) { if(key && (key != node->value.first)) { @@ -1813,12 +1787,21 @@ namespace nana item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y); impl_->attr.tree_cont.for_each(shape.first, nl); - if(nl.node() && (nl.what() == component::text || nl.what() == component::icon)) + auto const node = nl.node(); + if (!node) + return; + + auto & node_state = impl_->node_state; + switch (nl.what()) { - impl_->node_state.event_node = nl.node(); - impl_->set_expanded(impl_->node_state.event_node, !impl_->node_state.event_node->value.second.expanded); - impl_->draw(true); + case component::icon: + case component::text: + impl_->set_expanded(node, !node->value.second.expanded); + impl_->draw(true, true, false); API::dev::lazy_refresh(); + break; + default: + break; } } @@ -1833,26 +1816,19 @@ namespace nana bool has_redraw = false; auto & node_state = impl_->node_state; - node_state.event_node = nullptr; + node_state.pressed_node = nl.node(); - if(nl.node()) + if (node_state.pressed_node && (component::expander == nl.what())) { - node_state.event_node = nl.node(); - if(nl.what() != component::end) - { - if(nl.what() == component::expender) - { - if(impl_->set_expanded(node_state.event_node, !node_state.event_node->value.second.expanded)) - impl_->make_adjust(node_state.event_node, 0); + if(impl_->set_expanded(node_state.pressed_node, !node_state.pressed_node->value.second.expanded)) + impl_->make_adjust(node_state.pressed_node, 0); - has_redraw = true; //btw, don't select the node - } - } + has_redraw = true; //btw, don't select the node } - if ((!has_redraw) && (node_state.selected != node_state.event_node)) + if ((!has_redraw) && (node_state.selected != node_state.pressed_node)) { - impl_->set_selected(node_state.event_node); + impl_->set_selected(node_state.pressed_node); has_redraw = true; } @@ -1871,25 +1847,33 @@ namespace nana item_locator nl(impl_, xpos, arg.pos.x, arg.pos.y); impl_->attr.tree_cont.for_each(shape.first, nl); + auto const pressed_node = impl_->node_state.pressed_node; + impl_->node_state.pressed_node = nullptr; + if(!nl.node()) return; - if((impl_->node_state.selected != nl.node()) && nl.item_body()) + if (pressed_node == nl.node()) { - impl_->set_selected(nl.node()); - if(impl_->make_adjust(impl_->node_state.selected, 1)) - impl_->adjust.scroll_timestamp = 1; - } - else if (nl.what() == component::crook) - { - checkstate cs = checkstate::unchecked; - if (checkstate::unchecked == nl.node()->value.second.checked) - cs = checkstate::checked; + if ((impl_->node_state.selected != nl.node()) && nl.item_body()) + { + impl_->set_selected(nl.node()); + if (impl_->make_adjust(impl_->node_state.selected, 1)) + impl_->adjust.scroll_timestamp = 1; + } + else if (nl.what() == component::crook) + { + checkstate cs = checkstate::unchecked; + if (checkstate::unchecked == nl.node()->value.second.checked) + cs = checkstate::checked; - check(nl.node(), cs); + check(nl.node(), cs); + } + else + return; //Do not refresh } else - return; //Do not refresh + return; //Don't refresh impl_->draw(true); API::dev::lazy_refresh(); @@ -1906,18 +1890,19 @@ namespace nana void trigger::mouse_wheel(graph_reference, const arg_wheel& arg) { - auto & shape = impl_->shape; - std::size_t prev = shape.prev_first_value; + auto & scroll = impl_->shape.scroll; + if (scroll.empty()) + return; - shape.scroll.make_step(!arg.upwards); + auto const value_before = scroll.value(); - impl_->event_scrollbar(arg); + scroll.make_step(!arg.upwards); - if(prev != shape.prev_first_value) + if (value_before != scroll.value()) { impl_->track_mouse(arg.pos.x, arg.pos.y); - impl_->draw(false); + impl_->draw(false, true, true); API::dev::lazy_refresh(); } } @@ -2162,7 +2147,7 @@ namespace nana auto treebox::find(const std::string& keypath) -> item_proxy { auto * trg = &get_drawer_trigger(); - return item_proxy(trg, trg->tree().find(keypath)); + return item_proxy(trg, trg->impl()->attr.tree_cont.find(keypath)); } treebox::item_proxy treebox::insert(const std::string& path_key, std::string title) @@ -2192,7 +2177,7 @@ namespace nana std::string treebox::make_key_path(item_proxy i, const std::string& splitter) const { - auto & tree = get_drawer_trigger().tree(); + auto & tree = get_drawer_trigger().impl()->attr.tree_cont; auto pnode = i._m_node(); if(tree.verify(pnode)) { From 00d2e5408f7a1ec6aa60289ec455d5738c8637b2 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 24 Feb 2017 21:16:37 +0800 Subject: [PATCH 19/21] fix issue that umake_event causes memory leak --- source/gui/detail/events_operation.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/gui/detail/events_operation.cpp b/source/gui/detail/events_operation.cpp index bcafd688..55c4234d 100644 --- a/source/gui/detail/events_operation.cpp +++ b/source/gui/detail/events_operation.cpp @@ -80,7 +80,6 @@ namespace nana internal_scope_guard lock; if (dockers_) { - for (auto i = dockers_->begin(), end = dockers_->end(); i != end; ++i) { if (reinterpret_cast(evt) == *i) @@ -92,7 +91,11 @@ namespace nana deleted_flags_ = true; } else + { + bedrock::instance().evt_operation().cancel(evt); dockers_->erase(i); + delete reinterpret_cast(evt); + } break; } } From 663c7d361f8f103183583a67bc63680c4ae42b64 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 25 Feb 2017 02:36:08 +0800 Subject: [PATCH 20/21] fix memory leak by API::umake_event --- source/gui/detail/events_operation.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/gui/detail/events_operation.cpp b/source/gui/detail/events_operation.cpp index 55c4234d..40fe338e 100644 --- a/source/gui/detail/events_operation.cpp +++ b/source/gui/detail/events_operation.cpp @@ -85,7 +85,7 @@ namespace nana if (reinterpret_cast(evt) == *i) { //Checks whether this event is working now. - if (emitting_count_ > 1) + if (emitting_count_) { static_cast(*i)->flag_deleted = true; deleted_flags_ = true; @@ -134,7 +134,11 @@ namespace nana for (auto i = evt_->dockers_->begin(); i != evt_->dockers_->end();) { if (static_cast(*i)->flag_deleted) + { + bedrock::instance().evt_operation().cancel(reinterpret_cast(*i)); + delete (*i); i = evt_->dockers_->erase(i); + } else ++i; } From cc24607a4856f51552fcb6024f370dbb9e7d7204 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 15 Mar 2017 23:43:47 +0800 Subject: [PATCH 21/21] small change --- source/gui/detail/window_manager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 7ba67d3e..affd3abd 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -1417,7 +1417,8 @@ namespace detail void window_manager::remove_trash_handle(unsigned tid) { - internal_scope_guard lock; + //Thread-Safe Required! + std::lock_guard lock(mutex_); impl_->wd_register.delete_trash(tid); }