summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSadrul Habib Chowdhury <sadrul@pidgin.im>2007-05-11 21:08:47 +0000
committerSadrul Habib Chowdhury <sadrul@pidgin.im>2007-05-11 21:08:47 +0000
commit3ba74ee35f84706b0e86e1a26c7123c10ac7381a (patch)
tree4d6713d056edcdb64cd691980f83421f86508997
parentf3bd729b9acf325c1d00f96eaccc9a379a09a57f (diff)
downloadpidgin-3ba74ee35f84706b0e86e1a26c7123c10ac7381a.tar.gz
A workaround for an ncurses bug about multi-cell characters and panels.
(article.gmane.org/gmane.comp.lib.ncurses.bugs/2751)
-rw-r--r--finch/libgnt/gntwm.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/finch/libgnt/gntwm.c b/finch/libgnt/gntwm.c
index 6889c39954..69e3327525 100644
--- a/finch/libgnt/gntwm.c
+++ b/finch/libgnt/gntwm.c
@@ -48,6 +48,10 @@ static void gnt_wm_give_focus(GntWM *wm, GntWidget *widget);
static void update_window_in_list(GntWM *wm, GntWidget *wid);
static void shift_window(GntWM *wm, GntWidget *widget, int dir);
+#ifndef NO_WIDECHAR
+static int widestringwidth(wchar_t *wide);
+#endif
+
static gboolean write_already(gpointer data);
static int write_timeout;
static time_t last_active_time;
@@ -136,6 +140,65 @@ copy_win(GntWidget *widget, GntNode *node)
copywin(src, dst, node->scroll, 0, 0, 0, getmaxy(dst) - 1, getmaxx(dst) - 1, 0);
}
+/**
+ * The following is a workaround for a bug in most versions of ncursesw.
+ * Read about it in: http://article.gmane.org/gmane.comp.lib.ncurses.bugs/2751
+ *
+ * In short, if a panel hides one cell of a multi-cell character, then the rest
+ * of the characters in that line get screwed. The workaround here is to erase
+ * any such character preemptively.
+ *
+ * Caveat: If a wide character is erased, and the panel above it is moved enough
+ * to expose the entire character, it is not always redrawn.
+ */
+static void
+work_around_for_ncurses_bug()
+{
+#ifndef NO_WIDECHAR
+ PANEL *panel = NULL;
+ while ((panel = panel_below(panel)) != NULL) {
+ int sx, ex, sy, ey, w, y;
+ cchar_t ch;
+ PANEL *below = panel;
+
+ sx = panel->win->_begx;
+ ex = panel->win->_maxx + sx;
+ sy = panel->win->_begy;
+ ey = panel->win->_maxy + sy;
+
+ while ((below = panel_below(below)) != NULL) {
+ if (sy > below->win->_begy + below->win->_maxy ||
+ ey < below->win->_begy)
+ continue;
+ if (sx > below->win->_begx + below->win->_maxx ||
+ ex < below->win->_begx)
+ continue;
+ for (y = MAX(sy, below->win->_begy); y <= MIN(ey, below->win->_begy + below->win->_maxy); y++) {
+ if (mvwin_wch(below->win, y - below->win->_begy, sx - 1 - below->win->_begx, &ch) != OK)
+ goto right;
+ w = widestringwidth(ch.chars);
+ if (w > 1 && (ch.attr & 1)) {
+ ch.chars[0] = ' ';
+ ch.attr &= ~ A_CHARTEXT;
+ mvwadd_wch(below->win, y - below->win->_begy, sx - 1 - below->win->_begx, &ch);
+ touchline(below->win, y - below->win->_begy, 1);
+ }
+right:
+ if (mvwin_wch(below->win, y - below->win->_begy, ex + 1 - below->win->_begx, &ch) != OK)
+ continue;
+ w = widestringwidth(ch.chars);
+ if (w > 1 && !(ch.attr & 1)) {
+ ch.chars[0] = ' ';
+ ch.attr &= ~ A_CHARTEXT;
+ mvwadd_wch(below->win, y - below->win->_begy, ex + 1 - below->win->_begx, &ch);
+ touchline(below->win, y - below->win->_begy, 1);
+ }
+ }
+ }
+ }
+#endif
+}
+
static gboolean
update_screen(GntWM *wm)
{
@@ -148,6 +211,7 @@ update_screen(GntWM *wm)
top = top->submenu;
}
}
+ work_around_for_ncurses_bug();
update_panels();
doupdate();
return TRUE;