📄 tooltip.cc
字号:
#include "Image.hh"#include "bbsmount.hh"#include "tooltip.hh"#include "i18n.hh"#define MAX_EXTENT max_logical_extent//#define MAX_EXTENT max_ink_extentinttimeval_subtract (const struct timeval *time1, const struct timeval *time0, struct timeval *result) { result->tv_sec = time1->tv_sec - time0->tv_sec; result->tv_usec = time1->tv_usec - time0->tv_usec; if (result->tv_usec < 0) { result->tv_sec -= 1 - result->tv_usec / 1000000; result->tv_usec = 1000000 - (-result->tv_usec) % 1000000; } return (result->tv_sec < 0 || (result->tv_sec == 0 && result->tv_usec < 0));}#ifdef DELAYED_TOOLTIPSvoid *waiter_thread_helper_function(void *waiter_object) { Waiter *waiter = (Waiter *)waiter_object; waiter->waiter_loop(); return NULL;}Waiter::Waiter() { int result; end = fire = false; wait_secs = 0; wait_from.tv_sec = 0; wait_from.tv_usec = 0; func = NULL; param = NULL; result = sem_init(&run_waiter, 0, 0); if (result != 0) { perror("bbsmount: Can't initialize semaphore!"); exit(EXIT_FAILURE); } result = pthread_create(&wait_thread, NULL, waiter_thread_helper_function, (void *)this); if (result != 0) { perror("bbsmount: Can't create thread!"); exit(EXIT_FAILURE); }}Waiter::~Waiter() { int result; fire = false; end = true; sem_post(&run_waiter); result = pthread_join(wait_thread, NULL); if (result != 0) { perror("bbsmount: Can't join thread!"); exit(EXIT_FAILURE); } sem_destroy(&run_waiter);}voidWaiter::waiter_loop(void) { struct timeval current_time, difference, wait_to; struct timespec sleep_time; while (true) { if (end) pthread_exit(NULL); if (fire) { if (gettimeofday(¤t_time, NULL) != 0) { perror("bbsmount: Can't get current time!"); return; } wait_to.tv_sec = wait_from.tv_sec + wait_secs; wait_to.tv_usec = wait_from.tv_usec; if (timeval_subtract(&wait_to, ¤t_time, &difference)) { fire = false; ((*param).*func)(); } else { sleep_time.tv_sec = difference.tv_sec; sleep_time.tv_nsec = difference.tv_usec * 1000; nanosleep(&sleep_time, NULL); } } else sem_wait(&run_waiter); }}voidWaiter::wait(const int _secs, void (BToolTip::*_func)(), BToolTip *_param) { if (gettimeofday(&wait_from, NULL) != 0) { perror("bbsmount: Can't get current time!"); return; } wait_secs = _secs; func = _func; param = _param; fire = true; sem_post(&run_waiter);}voidWaiter::cancel(void) { fire = false;}#endif /* DELAYED_TOOLTIPS */BToolTip::BToolTip() { is_visible = is_created = false; real_x = real_y = x = y = timeout = 0; real_w = real_h = 0; direction = bottom_right; tooltip_window = None; tooltip_pixmap = None; pthread_mutex_init(&show_hide_syn, (pthread_mutexattr_t *)NULL);}BToolTip::~BToolTip() { hide(); if (tooltip_pixmap != None) AppWindow->getImageControl()->removeImage(tooltip_pixmap); if (tooltip_window != None) XDestroyWindow(AppWindow->getXDisplay(), tooltip_window); pthread_mutex_destroy(&show_hide_syn);}voidBToolTip::createToolTipWindow(const int _x, const int _y, const unsigned int _w, const unsigned int _h) { pthread_mutex_lock(&show_hide_syn); if (!is_created) { XSetWindowAttributes attrib; unsigned long mask = CWBorderPixel | CWColormap | CWSaveUnder | CWOverrideRedirect | CWEventMask; attrib.border_pixel = AppWindow->GetResources()->getTooltipBorderColor().getPixel(); attrib.colormap = AppWindow->getImageControl()->getColormap(); attrib.override_redirect = True; attrib.save_under = True; attrib.event_mask = ExposureMask; tooltip_window = XCreateWindow(AppWindow->getXDisplay(), DefaultRootWindow(AppWindow->getXDisplay()), _x, _y, _w, _h, AppWindow->GetResources()->getTooltipBorderWidth(), AppWindow->getImageControl()->getDepth(), InputOutput, AppWindow->getCurrentScreenInfo()->getVisual(), mask, &attrib); } else XMoveResizeWindow(AppWindow->getXDisplay(), tooltip_window, _x, _y, _w, _h); XMapWindow(AppWindow->getXDisplay(), tooltip_window); XRaiseWindow(AppWindow->getXDisplay(), tooltip_window); is_visible = true; if (!is_created || _w != real_w || _h != real_h) { BTexture *texture = AppWindow->GetResources()->getTooltipTexture(); if (tooltip_pixmap != None) AppWindow->getImageControl()->removeImage(tooltip_pixmap); tooltip_pixmap = AppWindow->getImageControl()->renderImage(_w, _h, texture);// if (tooltip_pixmap == ParentRelative) {// texture = &(resource.wstyle.t_focus);// geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap);// } if (!tooltip_pixmap) XSetWindowBackground(AppWindow->getXDisplay(), tooltip_window, AppWindow->GetResources()->getTooltipBorderColor().getPixel()); else XSetWindowBackgroundPixmap(AppWindow->getXDisplay(), tooltip_window, tooltip_pixmap); } real_w = _x; real_y = _y; real_w = _w; real_h = _h; is_created = true; pthread_mutex_unlock(&show_hide_syn);}voidBToolTip::setText(const string &tooltip_text) { unsigned int found, last_found = 0; current_tooltip_text.clear(); while ((found = tooltip_text.find('\n', last_found)) != string::npos) { current_tooltip_text.push_back(tooltip_text.substr(last_found, (found - last_found))); last_found = found + 1; } if (last_found < tooltip_text.length()) current_tooltip_text.push_back(tooltip_text.substr(last_found)); if (is_visible) showNow();}voidBToolTip::setTimeout(const int seconds) {#ifdef DELAYED_TOOLTIPS timeout = seconds;#else /* !DELAYED_TOOLTIPS */ timeout = 0;#endif /* !DELAYED_TOOLTIPS */}voidBToolTip::setPosition(const int _x, const int _y, const direction_type _direction) { x = _x; y = _y; direction = _direction; if (is_visible) show();}voidBToolTip::redraw(const int _x, const int _y, const unsigned int _w, const unsigned int _h) { int line = 0, y_start, y_end; vector<string>::const_iterator pointer; XGCValues values; if (!i18n.multibyte()) values.font = AppWindow->GetResources()->getTooltipFont()->fid; GC gctt = XCreateGC(AppWindow->getXDisplay(), tooltip_window, (i18n.multibyte() ? 0 : GCFont), &values); XClearArea(AppWindow->getXDisplay(), tooltip_window, _x, _y, _w, _h, False); for (pointer = current_tooltip_text.begin(); pointer != current_tooltip_text.end(); pointer++) { if (i18n.multibyte()) { y_start = AppWindow->GetResources()->getTooltipBevelWidth() - AppWindow->GetResources()->getTooltipFontSetExtents()->MAX_EXTENT.y + AppWindow->GetResources()->getTooltipFontSetExtents()->MAX_EXTENT.height * line++; y_end = y_start + AppWindow->GetResources()->getTooltipFontSetExtents()->MAX_EXTENT.height; } else { y_start = AppWindow->GetResources()->getTooltipFont()->ascent + AppWindow->GetResources()->getTooltipBevelWidth() + (AppWindow->GetResources()->getTooltipFont()->ascent + AppWindow->GetResources()->getTooltipFont()->descent) * line++; y_end = y_start + (AppWindow->GetResources()->getTooltipFont()->ascent + AppWindow->GetResources()->getTooltipFont()->descent); } if (_y >= y_end) continue; if (_y + (int)_h < y_start) break; if (i18n.multibyte()) { XmbDrawString(AppWindow->getXDisplay(), tooltip_window, AppWindow->GetResources()->getTooltipFontSet(), gctt, AppWindow->GetResources()->getTooltipBevelWidth(), y_start, pointer->c_str(), pointer->length()); } else { XDrawString(AppWindow->getXDisplay(), tooltip_window, gctt, AppWindow->GetResources()->getTooltipBevelWidth(), y_start, pointer->c_str(), pointer->length()); } } XFlush(AppWindow->getXDisplay()); XFreeGC(AppWindow->getXDisplay(), gctt);}voidBToolTip::processEvent(const XEvent &event) { if (event.type == Expose && event.xexpose.window == tooltip_window) redraw(event.xexpose.x, event.xexpose.y, event.xexpose.width, event.xexpose.height);}voidBToolTip::hide(void) {#ifdef DELAYED_TOOLTIPS waiter.cancel();#endif /* DELAYED_TOOLTIPS */ pthread_mutex_lock(&show_hide_syn); if (is_visible) { is_visible = false; XUnmapWindow(AppWindow->getXDisplay(), tooltip_window); current_tooltip_text.clear(); // destroy tooltip content real_w = real_h = 0; } pthread_mutex_unlock(&show_hide_syn);}voidBToolTip::show(void) {#ifdef DELAYED_TOOLTIPS if (timeout > 0) waiter.wait(timeout, &BToolTip::showNow, this); else#endif /* DELAYED_TOOLTIPS */ showNow();}voidBToolTip::showNow(void) { unsigned int text_width, text_height, width, height, max_width = 0; int new_x = x, new_y = y; vector<string>::const_iterator pointer; if (current_tooltip_text.empty()) return; if (i18n.multibyte()) { for (pointer = current_tooltip_text.begin(); pointer != current_tooltip_text.end(); pointer++) { text_width = XmbTextEscapement(AppWindow->GetResources()->getTooltipFontSet(), pointer->c_str(), pointer->length()); if (text_width > max_width) max_width = text_width; } } else { for (pointer = current_tooltip_text.begin(); pointer != current_tooltip_text.end(); pointer++) { text_width = XTextWidth(AppWindow->GetResources()->getTooltipFont(), pointer->c_str(), pointer->length()); if (text_width > max_width) max_width = text_width; } } text_width = max_width; if (i18n.multibyte()) text_height = AppWindow->GetResources()->getTooltipFontSetExtents()->MAX_EXTENT.height * current_tooltip_text.size(); else text_height = (AppWindow->GetResources()->getTooltipFont()->ascent + AppWindow->GetResources()->getTooltipFont()->descent) * current_tooltip_text.size(); width = text_width + 2 * (AppWindow->GetResources()->getTooltipBevelWidth() + AppWindow->GetResources()->getTooltipBorderWidth()); height = text_height + 2 * (AppWindow->GetResources()->getTooltipBevelWidth() + AppWindow->GetResources()->getTooltipBorderWidth()); switch (direction) { case top_left: new_x = x - width; if (new_x < 0) new_x = 0; new_y = y - height; if (new_y < 0) new_y = 0; break; case top_right: if (new_x + width >= AppWindow->getCurrentScreenInfo()->getWidth()) new_x = AppWindow->getCurrentScreenInfo()->getWidth() - width; new_y = y - height; if (new_y < 0) new_y = 0; break; case bottom_left: new_x = x - width; if (new_x < 0) new_x = 0; if (new_y + height >= AppWindow->getCurrentScreenInfo()->getHeight()) new_y = AppWindow->getCurrentScreenInfo()->getHeight() - height; break; case bottom_right: if (new_x + width >= AppWindow->getCurrentScreenInfo()->getWidth()) new_x = AppWindow->getCurrentScreenInfo()->getWidth() - width; if (new_y + height >= AppWindow->getCurrentScreenInfo()->getHeight()) new_y = AppWindow->getCurrentScreenInfo()->getHeight() - height; break; } createToolTipWindow(new_x, new_y, width, height); redraw(0, 0, width, height);}boolBToolTip::isShown(void) const { return is_visible;}intBToolTip::getTimeout(void) const { return timeout;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -