fix caret color issue for X

This commit is contained in:
Jinhao 2016-07-09 15:47:51 +08:00
parent 6ee314a9ea
commit ffdfb46eae
2 changed files with 70 additions and 73 deletions

View File

@ -175,7 +175,8 @@ namespace detail
Atom xdnd_finished; Atom xdnd_finished;
}; };
struct caret_tag; //A forward declaration of caret data
struct caret_rep;
class timer_runner; class timer_runner;
@ -243,9 +244,7 @@ namespace detail
void caret_close(native_window_type); void caret_close(native_window_type);
void caret_pos(native_window_type, const ::nana::point&); void caret_pos(native_window_type, const ::nana::point&);
void caret_visible(native_window_type, bool); void caret_visible(native_window_type, bool);
void caret_flash(caret_tag&);
bool caret_update(native_window_type, nana::paint::graphics& root_graph, bool is_erase_caret_from_root_graph); bool caret_update(native_window_type, nana::paint::graphics& root_graph, bool is_erase_caret_from_root_graph);
static bool caret_reinstate(caret_tag&);
void set_error_handler(); void set_error_handler();
int rev_error_handler(); int rev_error_handler();
@ -287,7 +286,7 @@ namespace detail
{ {
volatile bool exit_thread; volatile bool exit_thread;
std::unique_ptr<std::thread> thr; std::unique_ptr<std::thread> thr;
std::map<native_window_type, caret_tag*> carets; std::map<native_window_type, caret_rep*> carets;
}caret_holder_; }caret_holder_;
std::map<native_window_type, window_context_t> wincontext_; std::map<native_window_type, window_context_t> wincontext_;

View File

@ -140,26 +140,69 @@ namespace detail
//end class charset_conv //end class charset_conv
#endif #endif
struct caret_tag //Caret implementation
struct caret_rep
{ {
native_window_type window; native_window_type window;
bool has_input_method_focus; bool has_input_method_focus{ false };
bool visible; bool visible{ false };
nana::point pos; nana::point pos;
nana::size size; nana::size size;
nana::rectangle rev; nana::rectangle rev;
nana::paint::graphics graph;
nana::paint::graphics rev_graph; nana::paint::graphics rev_graph;
XIM input_method; XIM input_method{ 0 };
XIC input_context; XIC input_context{ 0 };
XFontSet input_font; XFontSet input_font{ 0 };
XRectangle input_spot; XRectangle input_spot;
XRectangle input_status_area; XRectangle input_status_area;
long input_context_event_mask; long input_context_event_mask{ 0 };
caret_tag(native_window_type wd) caret_rep(native_window_type wd)
: window(wd), has_input_method_focus(false), visible(false), input_method(0), input_context(0), input_font(0), input_context_event_mask(0) : window{ wd }
{} {}
//Copy the reversed graphics to the window
bool reinstate()
{
if(rev.width && rev.height)
{
rev_graph.paste(window, rev, 0, 0);
//Drop the reversed graphics in order to draw the
//caret in the next flash.
rev.width = rev.height = 0;
return true;
}
return false;
}
void twinkle()
{
if(!visible)
return;
if(!reinstate())
{
rev_graph.bitblt(rectangle{size}, window, pos);
rev.width = size.width;
rev.height = size.height;
rev.x = pos.x;
rev.y = pos.y;
paint::pixel_buffer pxbuf;
pxbuf.open(rev_graph.handle());
auto pxsize = pxbuf.size();
for(int y = 0; y < static_cast<int>(pxsize.height); ++y)
for(int x = 0; x < static_cast<int>(pxsize.width); ++x)
{
auto px = pxbuf.at({x, y});
px->element.red = ~px->element.red;
px->element.green = ~px->element.green;
px->element.blue = ~px->element.blue;
}
pxbuf.paste(window, {rev.x, rev.y});
}
}
}; };
class timer_runner class timer_runner
@ -734,12 +777,12 @@ namespace detail
{ {
bool is_start_routine = false; bool is_start_routine = false;
platform_scope_guard psg; platform_scope_guard psg;
caret_tag * & addr = caret_holder_.carets[wd]; auto & addr = caret_holder_.carets[wd];
if(0 == addr) if(nullptr == addr)
{ {
::XSetLocaleModifiers(""); ::XSetLocaleModifiers("");
addr = new caret_tag(wd); addr = new caret_rep(wd);
is_start_routine = (caret_holder_.carets.size() == 1); is_start_routine = (caret_holder_.carets.size() == 1);
addr->input_method = ::XOpenIM(display_, 0, 0, 0); addr->input_method = ::XOpenIM(display_, 0, 0, 0);
if(addr->input_method) if(addr->input_method)
@ -815,10 +858,7 @@ namespace detail
} }
addr->visible = false; addr->visible = false;
addr->graph.make(caret_sz);
addr->graph.rectangle(true, colors::black);
addr->rev_graph.make(caret_sz); addr->rev_graph.make(caret_sz);
addr->size = caret_sz; addr->size = caret_sz;
if(addr->input_context && (false == addr->has_input_method_focus)) if(addr->input_context && (false == addr->has_input_method_focus))
@ -844,7 +884,7 @@ namespace detail
auto i = caret_holder_.carets.find(wd); auto i = caret_holder_.carets.find(wd);
if(i != caret_holder_.carets.end()) if(i != caret_holder_.carets.end())
{ {
caret_tag * addr = i->second; auto addr = i->second;
if(addr->input_context) if(addr->input_context)
{ {
if(addr->has_input_method_focus) if(addr->has_input_method_focus)
@ -901,9 +941,8 @@ namespace detail
auto i = caret_holder_.carets.find(wd); auto i = caret_holder_.carets.find(wd);
if(i != caret_holder_.carets.end()) if(i != caret_holder_.carets.end())
{ {
caret_tag & crt = *i->second; i->second->reinstate();
caret_reinstate(crt); i->second->pos = pos;
crt.pos = pos;
} }
} }
@ -913,12 +952,12 @@ namespace detail
auto i = caret_holder_.carets.find(wd); auto i = caret_holder_.carets.find(wd);
if(i != caret_holder_.carets.end()) if(i != caret_holder_.carets.end())
{ {
caret_tag& crt = *i->second; auto & crt = *i->second;
if(crt.visible != vis) if(crt.visible != vis)
{ {
if(vis == false) if(vis == false)
{ {
caret_reinstate(crt); crt.reinstate();
if(crt.input_context && crt.has_input_method_focus) if(crt.input_context && crt.has_input_method_focus)
{ {
::XUnsetICFocus(crt.input_context); ::XUnsetICFocus(crt.input_context);
@ -938,60 +977,19 @@ namespace detail
} }
} }
void platform_spec::caret_flash(caret_tag & crt) bool platform_spec::caret_update(native_window_type wd, nana::paint::graphics& /*root_graph*/, bool after_mapping)
{
if(crt.visible && (false == caret_reinstate(crt)))
{
crt.rev_graph.bitblt(rectangle{crt.size}, crt.window, crt.pos);
crt.rev.width = crt.size.width;
crt.rev.height = crt.size.height;
crt.rev.x = crt.pos.x;
crt.rev.y = crt.pos.y;
crt.graph.paste(crt.window, crt.rev, 0, 0);
}
}
bool platform_spec::caret_update(native_window_type wd, nana::paint::graphics& root_graph, bool is_erase_caret_from_root_graph)
{ {
platform_scope_guard psg; platform_scope_guard psg;
auto i = caret_holder_.carets.find(wd); auto i = caret_holder_.carets.find(wd);
if(i != caret_holder_.carets.end()) if(i != caret_holder_.carets.end())
{ {
caret_tag & crt = *i->second; auto & crt = *i->second;
if(is_erase_caret_from_root_graph) if(!after_mapping)
{ {
root_graph.bitblt(crt.rev, crt.rev_graph); return crt.reinstate();
} }
else else
{ crt.twinkle();
bool owns_caret = false;
nana::paint::graphics * crt_graph;
if(crt.rev.width && crt.rev.height)
{
crt.rev_graph.bitblt(rectangle{crt.size}, root_graph, crt.pos);
crt_graph = &crt.graph;
owns_caret = true;
}
else
crt_graph = &crt.rev_graph;
root_graph.bitblt(crt.rev, *crt_graph);
return owns_caret;
}
}
return false;
}
//Copy the reversed graphics to the window
bool platform_spec::caret_reinstate(caret_tag& crt)
{
if(crt.rev.width && crt.rev.height)
{
crt.rev_graph.paste(crt.window, crt.rev, 0, 0);
//Drop the reversed graphics in order to draw the
//caret in the next flash.
crt.rev.width = crt.rev.height = 0;
return true;
} }
return false; return false;
} }
@ -1021,7 +1019,7 @@ namespace detail
if(xlib_locker_.try_lock()) if(xlib_locker_.try_lock())
{ {
for(auto i : caret_holder_.carets) for(auto i : caret_holder_.carets)
caret_flash(*(i.second)); i.second->twinkle();
xlib_locker_.unlock(); xlib_locker_.unlock();
} }