diff --git a/include/nana/gui/detail/native_window_interface.hpp b/include/nana/gui/detail/native_window_interface.hpp index c80d51f1..25b2fc7f 100644 --- a/include/nana/gui/detail/native_window_interface.hpp +++ b/include/nana/gui/detail/native_window_interface.hpp @@ -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 @@ -66,11 +66,11 @@ namespace detail static nana::point window_position(native_window_type); static void move_window(native_window_type, int x, int y); - static void move_window(native_window_type, const rectangle&); + static bool move_window(native_window_type, const rectangle&); static void bring_top(native_window_type, bool activated); static void set_window_z_order(native_window_type, native_window_type wd_after, z_order_action action_if_no_wd_after); - static void window_size(native_window_type, const size&); + static bool window_size(native_window_type, const size&); static void get_window_rect(native_window_type, rectangle&); static void window_caption(native_window_type, const native_string_type&); static native_string_type window_caption(native_window_type); diff --git a/include/nana/paint/graphics.hpp b/include/nana/paint/graphics.hpp index 8843a03f..7d6d6df8 100644 --- a/include/nana/paint/graphics.hpp +++ b/include/nana/paint/graphics.hpp @@ -91,6 +91,8 @@ namespace nana const void* pixmap() const; const void* context() const; + void swap(graphics& other); + /// Creates a graphics/drawable resource /** * @param sz The dimension of the graphics to be requested. If sz is empty, it performs as release(). diff --git a/source/detail/mswin/platform_spec.hpp b/source/detail/mswin/platform_spec.hpp index 30bc8b84..5eb6df45 100644 --- a/source/detail/mswin/platform_spec.hpp +++ b/source/detail/mswin/platform_spec.hpp @@ -47,16 +47,6 @@ namespace detail bool visible; }; - struct move_window - { - enum { Pos = 1, Size = 2}; - int x; - int y; - unsigned width; - unsigned height; - unsigned ignore; //determinate that pos or size would be ignored. - }; - struct map_thread { rectangle update_area; @@ -77,7 +67,6 @@ namespace detail async_set_focus, remote_flush_surface, remote_thread_destroy_window, - remote_thread_move_window, operate_caret, //wParam: 1=Destroy, 2=SetPos remote_thread_set_window_pos, remote_thread_set_window_text, diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 4e7c8a07..94dd0562 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -250,17 +250,24 @@ namespace detail _m_emit_core(evt_code, wd, false, arg, bForce__EmitInternal); - //A child of wd may not be drawn if it was out of wd's range before wd resized, - //so refresh all children of wd when a resized occurs. - if(ask_update || (event_code::resized == evt_code)) + bool good_wd = false; + if(wd_manager().available(wd)) { - wd_manager().do_lazy_refresh(wd, false, (event_code::resized == evt_code)); + //A child of wd may not be drawn if it was out of wd's range before wd resized, + //so refresh all children of wd when a resized occurs. + if(ask_update || (event_code::resized == evt_code) || (update_state::refreshed == wd->other.upd_state)) + { + wd_manager().do_lazy_refresh(wd, false, (event_code::resized == evt_code)); + } + else + wd->other.upd_state = update_state::none; + + good_wd = true; } - else if(wd_manager().available(wd)) - wd->other.upd_state = core_window_t::update_state::none; + if(thrd) thrd->event_window = prev_wd; - return true; + return good_wd; } void assign_arg(arg_mouse& arg, basic_window* wd, unsigned msg, const XEvent& evt) diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index 67f40ffe..2d75e7d4 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -601,40 +601,6 @@ namespace detail ::HeapFree(::GetProcessHeap(), 0, stru); } return true; - case nana::detail::messages::remote_thread_move_window: - { - auto * mw = reinterpret_cast(wParam); - - ::RECT r; - ::GetWindowRect(wd, &r); - if(mw->ignore & mw->Pos) - { - mw->x = r.left; - mw->y = r.top; - } - else - { - HWND owner = ::GetWindow(wd, GW_OWNER); - if(owner) - { - ::RECT owr; - ::GetWindowRect(owner, &owr); - ::POINT pos = {owr.left, owr.top}; - ::ScreenToClient(owner, &pos); - mw->x += (owr.left - pos.x); - mw->y += (owr.top - pos.y); - } - } - - if(mw->ignore & mw->Size) - { - mw->width = r.right - r.left; - mw->height = r.bottom - r.top; - } - ::MoveWindow(wd, mw->x, mw->y, mw->width, mw->height, true); - delete mw; - } - return true; case nana::detail::messages::remote_thread_set_window_pos: ::SetWindowPos(wd, reinterpret_cast(wParam), 0, 0, 0, 0, static_cast(lParam)); return true; @@ -1652,18 +1618,21 @@ namespace detail _m_event_filter(evt_code, wd, thrd); } - if (wd->other.upd_state == core_window_t::update_state::none) - wd->other.upd_state = core_window_t::update_state::lazy; + using update_state = basic_window::update_state; + + if (update_state::none == wd->other.upd_state) + wd->other.upd_state = update_state::lazy; _m_emit_core(evt_code, wd, false, arg, bForce__EmitInternal); bool good_wd = false; if (wd_manager().available(wd)) { - if (ask_update) + //Ignore ask_update if update state is refreshed. + if (ask_update || (update_state::refreshed == wd->other.upd_state)) wd_manager().do_lazy_refresh(wd, false); else - wd->other.upd_state = basic_window::update_state::none; + wd->other.upd_state = update_state::none; good_wd = true; } diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index 821296c1..a054dba7 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -863,30 +863,27 @@ namespace nana{ void native_interface::move_window(native_window_type wd, int x, int y) { #if defined(NANA_WINDOWS) - if(::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId()) + ::RECT r; + ::GetWindowRect(reinterpret_cast(wd), &r); + HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER); + if(owner) { - nana::detail::messages::move_window * mw = new nana::detail::messages::move_window; - mw->x = x; - mw->y = y; - mw->ignore = mw->Size; - ::PostMessage(reinterpret_cast(wd), nana::detail::messages::remote_thread_move_window, reinterpret_cast(mw), 0); + ::RECT owner_rect; + ::GetWindowRect(owner, &owner_rect); + ::POINT pos = {owner_rect.left, owner_rect.top}; + ::ScreenToClient(owner, &pos); + x += (owner_rect.left - pos.x); + y += (owner_rect.top - pos.y); } - else + + + if (::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId()) { - ::RECT r; - ::GetWindowRect(reinterpret_cast(wd), &r); - HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER); - if(owner) - { - ::RECT owner_rect; - ::GetWindowRect(owner, &owner_rect); - ::POINT pos = {owner_rect.left, owner_rect.top}; - ::ScreenToClient(owner, &pos); - x += (owner_rect.left - pos.x); - y += (owner_rect.top - pos.y); - } + nana::internal_revert_guard irg; ::MoveWindow(reinterpret_cast(wd), x, y, r.right - r.left, r.bottom - r.top, true); } + else + ::MoveWindow(reinterpret_cast(wd), x, y, r.right - r.left, r.bottom - r.top, true); #elif defined(NANA_X11) Display * disp = restrict::spec.open_display(); @@ -908,41 +905,36 @@ namespace nana{ #endif } - void native_interface::move_window(native_window_type wd, const rectangle& r) + bool native_interface::move_window(native_window_type wd, const rectangle& r) { #if defined(NANA_WINDOWS) - if(::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId()) + + int x = r.x; + int y = r.y; + HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER); + if(owner) { - auto * mw = new nana::detail::messages::move_window; - mw->x = r.x; - mw->y = r.y; - mw->width = r.width; - mw->height = r.height; - mw->ignore = 0; - ::PostMessage(reinterpret_cast(wd), nana::detail::messages::remote_thread_move_window, reinterpret_cast(mw), 0); + ::RECT owner_rect; + ::GetWindowRect(owner, &owner_rect); + ::POINT pos = {owner_rect.left, owner_rect.top}; + ::ScreenToClient(owner, &pos); + x += (owner_rect.left - pos.x); + y += (owner_rect.top - pos.y); } - else - { - int x = r.x; - int y = r.y; - HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER); - if(owner) - { - ::RECT owner_rect; - ::GetWindowRect(owner, &owner_rect); - ::POINT pos = {owner_rect.left, owner_rect.top}; - ::ScreenToClient(owner, &pos); - x += (owner_rect.left - pos.x); - y += (owner_rect.top - pos.y); - } - RECT client, wd_area; - ::GetClientRect(reinterpret_cast(wd), &client); - ::GetWindowRect(reinterpret_cast(wd), &wd_area); - unsigned ext_w = (wd_area.right - wd_area.left) - client.right; - unsigned ext_h = (wd_area.bottom - wd_area.top) - client.bottom; - ::MoveWindow(reinterpret_cast(wd), x, y, r.width + ext_w, r.height + ext_h, true); + RECT client, wd_area; + ::GetClientRect(reinterpret_cast(wd), &client); + ::GetWindowRect(reinterpret_cast(wd), &wd_area); + unsigned ext_w = (wd_area.right - wd_area.left) - client.right; + unsigned ext_h = (wd_area.bottom - wd_area.top) - client.bottom; + + if (::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId()) + { + nana::internal_revert_guard irg; + return (FALSE != ::MoveWindow(reinterpret_cast(wd), x, y, r.width + ext_w, r.height + ext_h, true)); } + + return (FALSE != ::MoveWindow(reinterpret_cast(wd), x, y, r.width + ext_w, r.height + ext_h, true)); #elif defined(NANA_X11) Display * disp = restrict::spec.open_display(); long supplied; @@ -984,6 +976,7 @@ namespace nana{ ::XSetWMNormalHints(disp, reinterpret_cast(wd), &hints); ::XMoveResizeWindow(disp, reinterpret_cast(wd), x, y, r.width, r.height); + return true; #endif } @@ -1062,32 +1055,28 @@ namespace nana{ #endif } - void native_interface::window_size(native_window_type wd, const size& sz) + bool native_interface::window_size(native_window_type wd, const size& sz) { #if defined(NANA_WINDOWS) - if(::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId()) + ::RECT r; + ::GetWindowRect(reinterpret_cast(wd), &r); + HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER); + HWND parent = ::GetParent(reinterpret_cast(wd)); + if(parent && (parent != owner)) { - auto * mw = new nana::detail::messages::move_window; - mw->width = sz.width; - mw->height = sz.height; - mw->ignore = mw->Pos; - ::PostMessage(reinterpret_cast(wd), nana::detail::messages::remote_thread_move_window, reinterpret_cast(mw), 0); + ::POINT pos = {r.left, r.top}; + ::ScreenToClient(parent, &pos); + r.left = pos.x; + r.top = pos.y; } - else + + if (::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId()) { - ::RECT r; - ::GetWindowRect(reinterpret_cast(wd), &r); - HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER); - HWND parent = ::GetParent(reinterpret_cast(wd)); - if(parent && (parent != owner)) - { - ::POINT pos = {r.left, r.top}; - ::ScreenToClient(parent, &pos); - r.left = pos.x; - r.top = pos.y; - } - ::MoveWindow(reinterpret_cast(wd), r.left, r.top, static_cast(sz.width), static_cast(sz.height), true); + nana::internal_revert_guard irg; + return (FALSE != ::MoveWindow(reinterpret_cast(wd), r.left, r.top, static_cast(sz.width), static_cast(sz.height), true)); } + + return (FALSE != ::MoveWindow(reinterpret_cast(wd), r.left, r.top, static_cast(sz.width), static_cast(sz.height), true)); #elif defined(NANA_X11) auto disp = restrict::spec.open_display(); nana::detail::platform_scope_guard psg; @@ -1104,6 +1093,7 @@ namespace nana{ ::XSetWMNormalHints(disp, reinterpret_cast(wd), &hints); } ::XResizeWindow(disp, reinterpret_cast(wd), sz.width, sz.height); + return true; #endif } diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index 701eb530..e948aeec 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -953,24 +953,45 @@ namespace detail if (wd->dimension == sz) return false; + //Before resiz the window, creates the new graphics + paint::graphics graph; + paint::graphics root_graph; + if (category::flags::lite_widget != wd->other.category) + { + //If allocation fails, here throws std::bad_alloc. + graph.make(sz); + if (category::flags::root == wd->other.category) + root_graph.make(sz); + } + + auto pre_sz = wd->dimension; + wd->dimension = sz; if(category::flags::lite_widget != wd->other.category) { bool graph_state = wd->drawer.graphics.empty(); - wd->drawer.graphics.make(sz); + wd->drawer.graphics.swap(graph); //It shall make a typeface_changed() call when the graphics state is changing. - //Because when a widget is created with zero-size, it may get some wrong result in typeface_changed() call + //Because when a widget is created with zero-size, it may get some wrong results in typeface_changed() call //due to the invaliable graphics object. if(graph_state != wd->drawer.graphics.empty()) wd->drawer.typeface_changed(); if(category::flags::root == wd->other.category) { - wd->root_graph->make(sz); + //wd->root_graph->make(sz); + wd->root_graph->swap(root_graph); if(false == passive) - native_interface::window_size(wd->root, sz + nana::size(wd->extra_width, wd->extra_height)); + if (!native_interface::window_size(wd->root, sz + nana::size(wd->extra_width, wd->extra_height))) + { + wd->dimension = pre_sz; + wd->drawer.graphics.swap(graph); + wd->root_graph->swap(root_graph); + wd->drawer.typeface_changed(); + return false; + } } #ifndef WIDGET_FRAME_DEPRECATED else if(category::flags::frame == wd->other.category) diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index 6ced8b96..a048423c 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -291,6 +291,12 @@ namespace paint return (impl_->handle ? impl_->handle->context : nullptr); } + void graphics::swap(graphics& other) + { + if (context() != other.context()) + impl_.swap(other.impl_); + } + void graphics::make(const ::nana::size& sz) { if (impl_->handle == nullptr || impl_->size != sz)