diff --git a/include/nana/config.hpp b/include/nana/config.hpp index 52ec94c6..696492de 100644 --- a/include/nana/config.hpp +++ b/include/nana/config.hpp @@ -50,27 +50,31 @@ // Windows: #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) - #define NANA_WINDOWS + #define NANA_WINDOWS - // end Windows + // MINGW ... + #if defined(__MINGW32__) || defined(__MINGW64__) || defined(MINGW) + #define NANA_MINGW + #endif // MINGW + + // end Windows - // MacOS: who define APPLE ?? - //#define APPLE - #elif defined(APPLE) - #define NANA_MACOS - #define NANA_X11 + // MacOS: who define APPLE ?? + //#define APPLE + #elif defined(APPLE) + #define NANA_MACOS + #define NANA_X11 // how to add this: include_directories(/opt/X11/include/) - // end MacOS + // end MacOS - // Linux: (not sure about __GNU__ ??) - #elif (defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && !defined(_CRAYC) - #define NANA_LINUX - #define NANA_X11 - // end Linux - - #else - #error( "Only Windows and Unix are supported now (Mac OS is experimental)"); + // Linux: (not sure about __GNU__ ??) + #elif (defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && !defined(_CRAYC) + #define NANA_LINUX + #define NANA_X11 + // end Linux + #else + # static_assert(false, "Only Windows and Unix are supported now (Mac OS is experimental)"); #endif // Select platform #if defined(NANA_LINUX) || defined(NANA_MACOS) @@ -95,19 +99,35 @@ // google: That's a known issue, tracked by an active bug (DevDiv#1060849). We were able to update the STL's headers in response to char16_t/char32_t, but we still need to update the separately compiled sources. #define STD_CODECVT_NOT_SUPPORTED #endif // _MSC_VER == 1900 -#endif // _MSVC -#if defined(__clang__) +#elif defined(__clang__) //Clang + + #include //Introduces some implement-specific flags of ISO C++ Library + #if defined(__GLIBCPP__) || defined(__GLIBCXX__) + // is a known issue on libstdc++, it works on libc++ + #define STD_CODECVT_NOT_SUPPORTED + #endif + #elif defined(__GNUC__) //GCC - // MINGW ... - #if defined(__MINGW32__) || defined(__MINGW64__) || defined(MINGW) - #define NANA_MINGW - #endif // MINGW + #include //Introduces some implement-specific flags of ISO C++ Library + #if defined(__GLIBCPP__) || defined(__GLIBCXX__) + // is a known issue on libstdc++, it works on libc++ + #define STD_CODECVT_NOT_SUPPORTED + + //It's a known issue of libstdc++ on MinGW + //introduce to_string/to_wstring workarounds for disabled capacity of stdlib + #ifdef _GLIBCXX_HAVE_BROKEN_VSWPRINTF + #if (__GNUC__ < 5) + # define STD_TO_STRING_NOT_SUPPORTED + #endif + + #define STD_TO_WSTRING_NOT_SUPPORTED + #endif + #endif - // support for GCC 4.8.1 will be discontinued. Please use v5 or newer. #if (__GNUC__ == 4) - #if ((__GNUC_MINOR__ < 8) || (__GNUC_MINOR__ == 8 && __GNUC_PATCHLEVEL__ <= 1)) + #if ((__GNUC_MINOR__ < 8) || (__GNUC_MINOR__ == 8 && __GNUC_PATCHLEVEL__ < 1)) #define STD_THREAD_NOT_SUPPORTED //boost.thread is preferred @@ -124,20 +144,23 @@ #endif #if defined(NANA_MINGW) - //It's a known issue under MinGW + //It's a knonwn issue under MinGW #define STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED #endif - #if ((__GNUC_MINOR__ < 8) || defined(NANA_MINGW)) - #define STD_TO_STRING_NOT_SUPPORTED + #if (__GNUC_MINOR__ < 8) + //introduce to_string/to_wstring workaround for lack of stdlib definitions + #ifndef STD_TO_STRING_NOT_SUPPORTED + # define STD_TO_STRING_NOT_SUPPORTED + #endif + + #ifndef STD_TO_WSTRING_NOT_SUPPORTED + # define STD_TO_WSTRING_NOT_SUPPORTED + #endif #endif #endif #endif -// is a known issue on libstdc++, it works on libc++ -#if defined(__GLIBCPP__) || defined( __GLIBCXX__ ) - #define STD_CODECVT_NOT_SUPPORTED -#endif // __GLIBCPP__ or __GLIBCXX__ // End compilers ... diff --git a/include/nana/deploy.hpp b/include/nana/deploy.hpp index 2b8f7e13..a4414ac9 100644 --- a/include/nana/deploy.hpp +++ b/include/nana/deploy.hpp @@ -1,10 +1,10 @@ /* * The Deploy Implementation * Nana C++ Library(http://www.nanapro.org) - * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * @file: nana/deploy.hpp @@ -75,7 +75,12 @@ namespace std std::string to_string(long long); std::string to_string(unsigned long long); std::string to_string(float); - +} +#endif + +#ifdef STD_TO_WSTRING_NOT_SUPPORTED +namespace std +{ std::wstring to_wstring(long double); std::wstring to_wstring(double); std::wstring to_wstring(unsigned); diff --git a/include/nana/gui/detail/native_window_interface.hpp b/include/nana/gui/detail/native_window_interface.hpp index 5db4a645..6a88c0a7 100644 --- a/include/nana/gui/detail/native_window_interface.hpp +++ b/include/nana/gui/detail/native_window_interface.hpp @@ -70,10 +70,12 @@ namespace detail static void capture_window(native_window_type, bool); static nana::point cursor_position(); static native_window_type get_owner_window(native_window_type); + static native_window_type parent_window(native_window_type); + static native_window_type parent_window(native_window_type child, native_window_type new_parent, bool returns_previous); //For Caret - static void caret_create(native_window_type, const ::nana::size&); + static void caret_create(native_window_type, const ::nana::size&); static void caret_destroy(native_window_type); - static void caret_pos(native_window_type, const ::nana::point&); + static void caret_pos(native_window_type, const ::nana::point&); static void caret_visible(native_window_type, bool); static void set_focus(native_window_type); diff --git a/source/deploy.cpp b/source/deploy.cpp index ce92982a..0f751352 100644 --- a/source/deploy.cpp +++ b/source/deploy.cpp @@ -298,6 +298,7 @@ namespace std #endif //STD_NUMERIC_CONVERSIONS_NOT_SUPPORTED #ifdef STD_TO_STRING_NOT_SUPPORTED +#include namespace std { std::string to_string(double v) @@ -362,7 +363,13 @@ namespace std ss << v; return ss.str(); } +} +#endif // STD_TO_STRING_NOT_SUPPORTED +#ifdef STD_TO_WSTRING_NOT_SUPPORTED +#include +namespace std +{ std::wstring to_wstring(double v) { std::wstringstream ss; diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index 202a76d3..786a5df2 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -281,7 +281,8 @@ namespace nana{ attr_mask, &win_attr); if(handle) { - if(owner) + //make owner if it is a popup window + if((!nested) && owner) restrict::spec.make_owner(owner, reinterpret_cast(handle)); XTextProperty name; @@ -417,8 +418,6 @@ namespace nana{ if(handle) { - restrict::spec.make_owner(parent, reinterpret_cast(handle)); - XTextProperty name; char text[] = "Nana Child Window"; char * str = text; @@ -786,21 +785,30 @@ namespace nana{ #if defined(NANA_WINDOWS) ::RECT r; ::GetWindowRect(reinterpret_cast(wd), & r); - HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER); - if(owner) + HWND coord_wd = ::GetWindow(reinterpret_cast(wd), GW_OWNER); + + if (!coord_wd) + coord_wd = ::GetParent(reinterpret_cast(wd)); + + if (coord_wd) { ::POINT pos = {r.left, r.top}; - ::ScreenToClient(owner, &pos); + ::ScreenToClient(coord_wd, &pos); return nana::point(pos.x, pos.y); } return nana::point(r.left, r.top); #elif defined(NANA_X11) int x, y; nana::detail::platform_scope_guard psg; - Window root = reinterpret_cast(restrict::spec.get_owner(wd)); - if(root == 0) root = restrict::spec.root_window(); + Window coord_wd = reinterpret_cast(restrict::spec.get_owner(wd)); + if(!coord_wd) + { + coord_wd = reinterpret_cast(parent_window(wd)); + if(!coord_wd) + coord_wd = restrict::spec.root_window(); + } Window child; - if(True == ::XTranslateCoordinates(restrict::spec.open_display(), reinterpret_cast(wd), root, 0, 0, &x, &y, &child)) + if(True == ::XTranslateCoordinates(restrict::spec.open_display(), reinterpret_cast(wd), coord_wd, 0, 0, &x, &y, &child)) return nana::point(x, y); return nana::point(0, 0); #endif @@ -1202,6 +1210,54 @@ namespace nana{ #endif } + native_window_type native_interface::parent_window(native_window_type wd) + { +#ifdef NANA_WINDOWS + return reinterpret_cast(::GetParent(reinterpret_cast(wd))); +#elif defined(NANA_X11) + Window root; + Window parent; + Window * children; + unsigned size; + + platform_scope_guard lock; + + if(0 != ::XQueryTree(restrict::spec.open_display(), reinterpret_cast(wd), + &root, &parent, &children, &size)) + { + ::XFree(children); + return reinterpret_cast(parent); + } + return nullptr; +#endif + } + + native_window_type native_interface::parent_window(native_window_type child, native_window_type new_parent, bool returns_previous) + { +#ifdef NANA_WINDOWS + auto prev = ::SetParent(reinterpret_cast(child), reinterpret_cast(new_parent)); + + if (prev) + ::PostMessage(prev, WM_CHANGEUISTATE, UIS_INITIALIZE, NULL); + + ::SetWindowPos(reinterpret_cast(child), NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); + + return reinterpret_cast(returns_previous ? prev : nullptr); +#elif defined(NANA_X11) + native_window_type prev = nullptr; + + platform_scope_guard lock; + + if(returns_previous) + prev = parent_window(child); + + ::XReparentWindow(restrict::spec.open_display(), + reinterpret_cast(child), reinterpret_cast(new_parent), + 0, 0); + return prev; +#endif + } + void native_interface::caret_create(native_window_type wd, const ::nana::size& caret_sz) { #if defined(NANA_WINDOWS) diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index 9f0e779e..f44be0a6 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -140,7 +140,7 @@ namespace nana for (++i; i < end; ++i) { core_window_t* cover = *i; - if (cover->visible && (nullptr == cover->effect.bground)) + if ((category::flags::root != cover->other.category) && cover->visible && (nullptr == cover->effect.bground)) { if (overlap(vis_rect, rectangle{ cover->pos_root, cover->dimension }, block.r)) { @@ -271,9 +271,15 @@ namespace nana for (auto child : wd->children) { //it will not past children if no drawer and visible is false. - if ((false == child->visible) || ((child->other.category != category::lite_widget_tag::value) && child->drawer.graphics.empty())) + if ((false == child->visible) || ((category::flags::lite_widget != child->other.category) && child->drawer.graphics.empty())) continue; + if (category::flags::root == child->other.category) + { + paint(child, is_child_refreshed, is_child_refreshed); + continue; + } + if (nullptr == child->effect.bground) { if (overlap(nana::rectangle{ child->pos_root, child->dimension }, parent_rect, rect)) diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 909cf193..4aa19757 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -291,6 +291,14 @@ namespace detail if (result.native_handle) { core_window_t* wd = new core_window_t(owner, widget_notifier_interface::get_notifier(wdg), (category::root_tag**)nullptr); + if (nested) + { + wd->owner = nullptr; + wd->parent = owner; + wd->index = static_cast(owner->children.size()); + owner->children.push_back(wd); + } + wd->flags.take_active = !app.no_activate; wd->title = native_interface::window_caption(result.native_handle); @@ -542,10 +550,10 @@ namespace detail std::lock_guard lock(mutex_); if (impl_->wd_register.available(wd)) { - if(wd->other.category != category::root_tag::value) + if (category::flags::root != wd->other.category) { //Move child widgets - if(x != wd->pos_owner.x || y != wd->pos_owner.y) + if (x != wd->pos_owner.x || y != wd->pos_owner.y) { point delta{ x - wd->pos_owner.x, y - wd->pos_owner.y }; @@ -562,8 +570,20 @@ namespace detail return true; } } - else if(false == passive) + else if (!passive) + { + //Check if this root is a nested + if (wd->parent && (category::flags::root != wd->parent->other.category)) + { + //The parent of the window is not a root, the position should + //be transformed to a position based on its parent. + + x += wd->parent->pos_root.x; + y += wd->parent->pos_root.y; + } + native_interface::move_window(wd->root, x, y); + } } return false; @@ -602,22 +622,36 @@ namespace detail } else { + ::nana::rectangle root_r = r; + //Move event should not get called here, + //because the window is a root, the event will get called by system event handler. + + //Check if this root is a nested + if (wd->parent && (category::flags::root != wd->parent->other.category)) + { + //The parent of the window is not a root, the position should + //be transformed to a position based on its parent. + + root_r.x += wd->parent->pos_root.x; + root_r.y += wd->parent->pos_root.y; + } + if(size_changed) { - wd->dimension.width = r.width; - wd->dimension.height = r.height; + wd->dimension.width = root_r.width; + wd->dimension.height = root_r.height; wd->drawer.graphics.make(wd->dimension); wd->root_graph->make(wd->dimension); - native_interface::move_window(wd->root, r); + native_interface::move_window(wd->root, root_r); arg_resized arg; arg.window_handle = reinterpret_cast(wd); - arg.width = r.width; - arg.height = r.height; + arg.width = root_r.width; + arg.height = root_r.height; brock.emit(event_code::resized, wd, arg, true, brock.get_thread_context()); } else - native_interface::move_window(wd->root, r.x, r.y); + native_interface::move_window(wd->root, root_r.x, root_r.y); } return (moved || size_changed); @@ -919,34 +953,37 @@ namespace detail arg.receiver = wd->root; brock.emit(event_code::focus, prev_focus, arg, true, brock.get_thread_context()); } + + //Check the prev_focus again, because it may be closed in focus event + if (!impl_->wd_register.available(prev_focus)) + prev_focus = nullptr; } else if(wd->root == native_interface::get_focus_window()) - wd = nullptr; //no new focus_window + return prev_focus; //no new focus_window - if(wd) - { - if(wd->together.caret) - wd->together.caret->set_active(true); - arg.window_handle = reinterpret_cast(wd); - arg.getting = true; - arg.receiver = wd->root; - brock.emit(event_code::focus, wd, arg, true, brock.get_thread_context()); + if(wd->together.caret) + wd->together.caret->set_active(true); - if (!root_has_been_focused) - native_interface::set_focus(root_wd->root); + arg.window_handle = reinterpret_cast(wd); + arg.getting = true; + arg.receiver = wd->root; + brock.emit(event_code::focus, wd, arg, true, brock.get_thread_context()); - //A fix by Katsuhisa Yuasa - //The menubar token window will be redirected to the prev focus window when the new - //focus window is a menubar. - //The focus window will be restore to the prev focus which losts the focus becuase of - //memberbar. - if (wd == wd->root_widget->other.attribute.root->menubar) - wd = prev_focus; + if (!root_has_been_focused) + native_interface::set_focus(root_wd->root); + + //A fix by Katsuhisa Yuasa + //The menubar token window will be redirected to the prev focus window when the new + //focus window is a menubar. + //The focus window will be restore to the prev focus which losts the focus becuase of + //memberbar. + if (prev_focus && (wd == wd->root_widget->other.attribute.root->menubar)) + wd = prev_focus; + + if (wd != wd->root_widget->other.attribute.root->menubar) + brock.set_menubar_taken(wd); - if (wd != wd->root_widget->other.attribute.root->menubar) - brock.set_menubar_taken(wd); - } return prev_focus; } @@ -1301,7 +1338,9 @@ namespace detail void window_manager::_m_disengage(core_window_t* wd, core_window_t* for_new) { auto * const wdpa = wd->parent; - bool established = (for_new && wdpa != for_new); + + + bool established = (for_new && (wdpa != for_new)); decltype(for_new->root_widget->other.attribute.root) pa_root_attr = nullptr; if (established) @@ -1443,14 +1482,26 @@ namespace detail std::function set_pos_root; set_pos_root = [&set_pos_root](core_window_t* wd, const nana::point& delta_pos) { - wd->pos_root -= delta_pos; for (auto child : wd->children) { - child->root = wd->root; - child->root_graph = wd->root_graph; - child->root_widget = wd->root_widget; - set_pos_root(child, delta_pos); + if (category::flags::root == child->other.category) + { + auto pos = native_interface::window_position(child->root); + native_interface::parent_window(child->root, wd->root, false); + + pos -= delta_pos; + native_interface::move_window(child->root, pos.x, pos.y); + } + else + { + child->root = wd->root; + child->root_graph = wd->root_graph; + child->root_widget = wd->root_widget; + set_pos_root(child, delta_pos); + } } + + wd->pos_root -= delta_pos; }; set_pos_root(wd, delta_pos); @@ -1481,8 +1532,30 @@ namespace detail brock.emit(event_code::destroy, wd, arg, true, brock.get_thread_context()); //Delete the children widgets. - for (auto i = wd->children.rbegin(), end = wd->children.rend(); i != end; ++i) - _m_destroy(*i); + for (auto i = wd->children.rbegin(), end = wd->children.rend(); i != end;) + { + auto child = *i; + + if (category::flags::root == child->other.category) + { + //closing a child root window erases itself from wd->children, + //to make sure the iterator is valid, it must be reloaded. + + auto offset = std::distance(wd->children.rbegin(), i); + + //!!! + //a potential issue is that if the calling thread is not same with child's thread, + //the child root window may not be erased from wd->children now. + native_interface::close_window(child->root); + + i = wd->children.rbegin(); + std::advance(i, offset); + end = wd->children.rend(); + continue; + } + _m_destroy(child); + ++i; + } wd->children.clear(); @@ -1508,7 +1581,7 @@ namespace detail void window_manager::_m_move_core(core_window_t* wd, const point& delta) { - if(wd->other.category != category::root_tag::value) //A root widget always starts at (0, 0) and its childs are not to be changed + if(category::flags::root != wd->other.category) //A root widget always starts at (0, 0) and its childs are not to be changed { wd->pos_root += delta; if (category::flags::frame != wd->other.category) @@ -1525,6 +1598,11 @@ namespace detail for (auto child : wd->children) _m_move_core(child, delta); } + else + { + auto pos = native_interface::window_position(wd->root) + delta; + native_interface::move_window(wd->root, pos.x, pos.y); + } } //_m_find diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index fdd4522c..2d731b77 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -542,8 +542,8 @@ namespace API { auto iwd = reinterpret_cast(wd); internal_scope_guard lock; - if(restrict::wd_manager().available(iwd)) - return reinterpret_cast(iwd->other.category == category::flags::root ? iwd->owner : iwd->parent); + if (restrict::wd_manager().available(iwd)) + return reinterpret_cast(iwd->parent); return nullptr; } diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index fd206764..3e1159a5 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -526,17 +526,16 @@ namespace nana auto index = state_.active; for (auto & m : menu_->items) { + if (0 == index--) + break; + if (m.flags.splitter) { pos.y += 2; continue; } - if (0 == index) - break; - pos.y += _m_item_height() + 1; - --index; } tmstamp = state_.active_timestamp;