fix transparent window bugs

This commit is contained in:
Jinhao 2016-10-14 07:19:56 +08:00
parent 7c36c27d46
commit 092ae97c66
10 changed files with 64 additions and 70 deletions

View File

@ -85,7 +85,7 @@ namespace detail
enum class update_state
{
none, lazy, refresh
none, lazy, refreshed, request_refresh
};
struct edge_nimbus_action

View File

@ -86,7 +86,7 @@ namespace nana{
}
//Avoiding duplicated rendering. If the window is declared to lazy refresh, it should be rendered.
if ((forced && (action.window == wd)) || (focused == action.window) || !action.rendered || (action.window->other.upd_state == core_window_t::update_state::refresh))
if ((forced && (action.window == wd)) || (focused == action.window) || !action.rendered || (action.window->other.upd_state == core_window_t::update_state::refreshed))
{
rd_set.emplace_back(r, action.window);
action.rendered = true;

View File

@ -1,6 +1,6 @@
/*
* Window Layout Implementation
* Copyright(C) 2003-2013 Jinhao(cnjinhao@hotmail.com)
* Copyright(C) 2003-2016 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
@ -42,10 +42,16 @@ namespace detail
core_window_t * window;
rectangle r;
};
public:
static void paint(core_window_t*, bool is_redraw, bool is_child_refreshed);
static bool maproot(core_window_t*, bool have_refreshed, bool is_child_refreshed);
enum class paint_operation {
none,
have_refreshed,
try_refresh
};
public:
static void paint(core_window_t*, paint_operation, bool request_refresh_children);
static bool maproot(core_window_t*, bool have_refreshed, bool request_refresh_children);
static void paste_children_to_graphics(core_window_t*, nana::paint::graphics& graph);
@ -68,13 +74,12 @@ namespace detail
//_m_paste_children
//@brief:paste children window to the root graphics directly. just paste the visual rectangle
static void _m_paste_children(core_window_t*, bool is_child_refreshed, bool have_refreshed, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos);
static void _m_paste_children(core_window_t*, bool have_refreshed, bool request_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos);
static void _m_paint_glass_window(core_window_t*, bool is_redraw, bool is_child_refreshed, bool called_by_notify, bool notify_other);
//_m_notify_glasses
//@brief: Notify the glass windows that are overlapped with the specified vis_rect
static void _m_notify_glasses(core_window_t* const sigwd, const nana::rectangle& r_visual);
//Notify the windows which have brground to update their background buffer.
static void _m_notify_glasses(core_window_t* const sigwd);
private:
struct data_section
{

View File

@ -124,7 +124,7 @@ namespace detail
bool update(core_window_t*, bool redraw, bool force, const rectangle* update_area = nullptr);
void refresh_tree(core_window_t*);
bool do_lazy_refresh(core_window_t*, bool force_copy_to_screen, bool refresh_tree = false);
void do_lazy_refresh(core_window_t*, bool force_copy_to_screen, bool refresh_tree = false);
bool get_graphics(core_window_t*, nana::paint::graphics&);
bool get_visual_rectangle(core_window_t*, nana::rectangle&);

View File

@ -323,7 +323,7 @@ namespace nana
{
for (auto wd = this; wd; wd = wd->parent)
{
if (basic_window::update_state::refresh == wd->other.upd_state)
if (basic_window::update_state::refreshed == wd->other.upd_state)
return true;
}
return false;

View File

@ -1203,17 +1203,7 @@ namespace detail
{
thread_context* thrd = get_thread_context(0);
if(thrd && thrd->event_window)
{
//the state none should be tested, becuase in an event, there would be draw after an update,
//if the none is not tested, the draw after update will not be refreshed.
switch(thrd->event_window->other.upd_state)
{
case core_window_t::update_state::none:
case core_window_t::update_state::lazy:
thrd->event_window->other.upd_state = core_window_t::update_state::refresh;
default: break;
}
}
}
//Dynamically set a cursor for a window

View File

@ -1691,17 +1691,7 @@ namespace detail
{
auto* thrd = get_thread_context(0);
if (thrd && thrd->event_window)
{
//the state none should be tested, becuase in an event, there would be draw after an update,
//if the none is not tested, the draw after update will not be refreshed.
switch (thrd->event_window->other.upd_state)
{
case core_window_t::update_state::none:
case core_window_t::update_state::lazy:
thrd->event_window->other.upd_state = core_window_t::update_state::refresh;
default: break;
}
}
thrd->event_window->other.upd_state = core_window_t::update_state::refreshed;
}
//Dynamically set a cursor for a window

View File

@ -391,7 +391,7 @@ namespace nana
bool drawer::_m_lazy_decleared() const
{
return (basic_window::update_state::refresh == data_impl_->window_handle->other.upd_state);
return (basic_window::update_state::refreshed == data_impl_->window_handle->other.upd_state);
}
drawer::method_state& drawer::_m_mth_state(int pos)

View File

@ -22,26 +22,26 @@ namespace nana
namespace detail
{
//class window_layout
void window_layout::paint(core_window_t* wd, bool is_redraw, bool is_child_refreshed)
void window_layout::paint(core_window_t* wd, paint_operation operation, bool req_refresh_children)
{
if (is_redraw && wd->flags.refreshing)
if (wd->flags.refreshing && (paint_operation::try_refresh == operation))
return;
if (nullptr == wd->effect.bground)
{
if (is_redraw && (!wd->drawer.graphics.empty()))
if ((paint_operation::try_refresh == operation) && (!wd->drawer.graphics.empty()))
{
wd->flags.refreshing = true;
wd->drawer.refresh();
wd->flags.refreshing = false;
}
maproot(wd, is_redraw, is_child_refreshed);
maproot(wd, (paint_operation::none != operation), req_refresh_children);
}
else
_m_paint_glass_window(wd, is_redraw, is_child_refreshed, false, true);
_m_paint_glass_window(wd, (paint_operation::try_refresh == operation), req_refresh_children, false, true);
}
bool window_layout::maproot(core_window_t* wd, bool have_refreshed, bool is_child_refreshed)
bool window_layout::maproot(core_window_t* wd, bool have_refreshed, bool req_refresh_children)
{
auto check_opaque = wd->seek_non_lite_widget_ancestor();
if (check_opaque && check_opaque->flags.refreshing)
@ -56,7 +56,7 @@ namespace nana
if (category::flags::lite_widget != wd->other.category)
graph.bitblt(vr, wd->drawer.graphics, nana::point(vr.x - wd->pos_root.x, vr.y - wd->pos_root.y));
_m_paste_children(wd, is_child_refreshed, have_refreshed, vr, graph, nana::point());
_m_paste_children(wd, have_refreshed, req_refresh_children, vr, graph, nana::point());
if (wd->parent)
{
@ -81,11 +81,11 @@ namespace nana
graph.bitblt(el.r, (el.window->drawer.graphics), p_src);
}
_m_paste_children(el.window, is_child_refreshed, false, el.r, graph, nana::point{});
_m_paste_children(el.window, false, req_refresh_children, el.r, graph, nana::point{});
}
}
}
_m_notify_glasses(wd, vr);
_m_notify_glasses(wd);
return true;
}
return false;
@ -255,8 +255,8 @@ namespace nana
if (category::flags::lite_widget != child->other.category)
glass_buffer.bitblt(nana::rectangle{ ovlp.x - wd->pos_owner.x, ovlp.y - wd->pos_owner.y, ovlp.width, ovlp.height }, child->drawer.graphics, {ovlp.position() - child->pos_owner});
ovlp.x += wd->pos_root.x;
ovlp.y += wd->pos_root.y;
ovlp.x += wd->parent->pos_root.x;
ovlp.y += wd->parent->pos_root.y;
_m_paste_children(child, false, false, ovlp, glass_buffer, rpos);
}
}
@ -267,7 +267,7 @@ namespace nana
//_m_paste_children
//@brief:paste children window to the root graphics directly. just paste the visual rectangle
void window_layout::_m_paste_children(core_window_t* wd, bool is_child_refreshed, bool have_refreshed, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos)
void window_layout::_m_paste_children(core_window_t* wd, bool have_refreshed, bool req_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos)
{
nana::rectangle rect;
for (auto child : wd->children)
@ -278,7 +278,7 @@ namespace nana
if (category::flags::root == child->other.category)
{
paint(child, is_child_refreshed, is_child_refreshed);
paint(child, (req_refresh_children ? paint_operation::try_refresh : paint_operation::none), req_refresh_children);
continue;
}
@ -289,7 +289,7 @@ namespace nana
bool have_child_refreshed = false;
if (category::flags::lite_widget != child->other.category)
{
if (is_child_refreshed && (false == child->flags.refreshing))
if (req_refresh_children && (false == child->flags.refreshing))
{
have_child_refreshed = true;
child->flags.refreshing = true;
@ -300,13 +300,13 @@ namespace nana
graph.bitblt(nana::rectangle(rect.x - graph_rpos.x, rect.y - graph_rpos.y, rect.width, rect.height),
child->drawer.graphics, nana::point(rect.x - child->pos_root.x, rect.y - child->pos_root.y));
}
_m_paste_children(child, is_child_refreshed, have_child_refreshed, rect, graph, graph_rpos);
_m_paste_children(child, req_refresh_children, have_child_refreshed, rect, graph, graph_rpos);
}
}
else
{
//If have_refreshed, the glass should be notified.
_m_paint_glass_window(child, false, is_child_refreshed, have_refreshed, false);
//Update the glass window's background if the parent have_refreshed.
_m_paint_glass_window(child, have_refreshed, req_refresh_children, true, false);
}
}
}
@ -353,16 +353,14 @@ namespace nana
}
if (notify_other)
_m_notify_glasses(wd, vr);
_m_notify_glasses(wd);
}
}
//_m_notify_glasses
//@brief: Notify the glass windows that are overlapped with the specified vis_rect
void window_layout::_m_notify_glasses(core_window_t* const sigwd, const nana::rectangle& /*r_visual*/)
/// Notify the glass windows that are overlapped with the specified visual rectangle.
/// If a child window of sigwd is a glass window, it doesn't to be notified.
void window_layout::_m_notify_glasses(core_window_t* const sigwd)
{
typedef category::flags cat_flags;
nana::rectangle r_of_sigwd(sigwd->pos_root, sigwd->dimension);
for (auto wd : data_sect.effects_bground_windows)
{
@ -377,6 +375,8 @@ namespace nana
}
else if (sigwd != wd->parent)
{
using cat_flags = category::flags;
if (wd->parent && (cat_flags::lite_widget == wd->parent->other.category))
{
//Test if sigwd is an ancestor of the glass window, and there are lite widgets

View File

@ -759,6 +759,10 @@ namespace detail
arg.window_handle = reinterpret_cast<window>(wd);
arg.x = x;
arg.y = y;
if (wd->effect.bground)
wd->other.upd_state = basic_window::update_state::request_refresh;
brock.emit(event_code::move, wd, arg, true, brock.get_thread_context());
return true;
}
@ -803,6 +807,9 @@ namespace detail
_m_move_core(wd, delta);
moved = true;
if ((!size_changed) && wd->effect.bground)
wd->other.upd_state = basic_window::update_state::request_refresh;
arg_move arg;
arg.window_handle = reinterpret_cast<window>(wd);
arg.x = r.x;
@ -989,26 +996,28 @@ namespace detail
if (wd->displayed())
{
using paint_operation = window_layer::paint_operation;
if(forced || (false == wd->belong_to_lazy()))
{
if (!wd->flags.refreshing)
{
window_layer::paint(wd, redraw, false);
window_layer::paint(wd, (redraw ? paint_operation::try_refresh : paint_operation::none), false);
this->map(wd, forced, update_area);
return true;
}
else if (forced)
{
window_layer::paint(wd, false, false);
window_layer::paint(wd, paint_operation::none, false);
this->map(wd, true, update_area);
return true;
}
}
else if (redraw)
window_layer::paint(wd, true, false);
window_layer::paint(wd, paint_operation::try_refresh, false);
if (wd->other.upd_state == core_window_t::update_state::lazy)
wd->other.upd_state = core_window_t::update_state::refresh;
wd->other.upd_state = core_window_t::update_state::refreshed;
}
return true;
}
@ -1020,28 +1029,28 @@ namespace detail
//It's not worthy to redraw if visible is false
if (impl_->wd_register.available(wd) && wd->displayed())
window_layer::paint(wd, true, true);
window_layer::paint(wd, window_layer::paint_operation::try_refresh, true);
}
//do_lazy_refresh
//@brief: defined a behavior of flush the screen
//@return: it returns true if the wnd is available
bool window_manager::do_lazy_refresh(core_window_t* wd, bool force_copy_to_screen, bool refresh_tree)
void window_manager::do_lazy_refresh(core_window_t* wd, bool force_copy_to_screen, bool refresh_tree)
{
//Thread-Safe Required!
std::lock_guard<mutex_type> lock(mutex_);
if (false == impl_->wd_register.available(wd))
return false;
return;
//It's not worthy to redraw if visible is false
if(wd->visible && (!wd->is_draw_through()))
{
using paint_operation = window_layer::paint_operation;
if (wd->visible_parents())
{
if ((wd->other.upd_state == core_window_t::update_state::refresh) || force_copy_to_screen)
if ((wd->other.upd_state == core_window_t::update_state::refreshed) || (wd->other.upd_state == core_window_t::update_state::request_refresh) || force_copy_to_screen)
{
window_layer::paint(wd, false, refresh_tree);
window_layer::paint(wd, (wd->other.upd_state == core_window_t::update_state::request_refresh ? paint_operation::try_refresh : paint_operation::have_refreshed), refresh_tree);
this->map(wd, force_copy_to_screen);
}
else if (effects::edge_nimbus::none != wd->effect.edge_nimbus)
@ -1053,10 +1062,10 @@ namespace detail
}
}
else
window_layer::paint(wd, true, refresh_tree); //only refreshing if it has an invisible parent
window_layer::paint(wd, paint_operation::try_refresh, refresh_tree); //only refreshing if it has an invisible parent
}
wd->other.upd_state = core_window_t::update_state::none;
return true;
return;
}
//get_graphics