summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSebastien Helleu <flashcode@flashtux.org>2006-05-08 13:26:08 +0000
committerSebastien Helleu <flashcode@flashtux.org>2006-05-08 13:26:08 +0000
commit93e69f5b3efec9ddc9198e7bb4d5f06af19bad28 (patch)
treea08da159aaad979702e350a5dae21c77683437a7 /src
parentbeb846884c0699220009cde0749f4e2f7590de3e (diff)
downloadweechat-93e69f5b3efec9ddc9198e7bb4d5f06af19bad28.zip
Fixed UTF-8 display bug with chars using more than one cell on screen (bug #16356)
Diffstat (limited to 'src')
-rw-r--r--src/common/utf8.c37
-rw-r--r--src/common/utf8.h1
-rw-r--r--src/gui/curses/gui-curses-chat.c40
-rw-r--r--src/gui/curses/gui-curses-input.c40
-rw-r--r--src/gui/gtk/gui-gtk-chat.c25
-rw-r--r--src/gui/gui-common.c14
-rw-r--r--src/gui/gui.h2
7 files changed, 122 insertions, 37 deletions
diff --git a/src/common/utf8.c b/src/common/utf8.c
index 4fa4ea043..633aba411 100644
--- a/src/common/utf8.c
+++ b/src/common/utf8.c
@@ -24,7 +24,10 @@
#include "config.h"
#endif
+#include <stdlib.h>
#include <string.h>
+#define __USE_XOPEN
+#include <wchar.h>
#include "weechat.h"
#include "utf8.h"
@@ -225,7 +228,7 @@ utf8_strlen (char *string)
}
/*
- * utf8_strlen: return length of an UTF-8 string, for N bytes
+ * utf8_strnlen: return length of an UTF-8 string, for N bytes
*/
int
@@ -256,6 +259,38 @@ utf8_strnlen (char *string, int bytes)
}
/*
+ * utf8_width_screen: return number of chars needed on screen to display UTF-8 string
+ */
+
+int
+utf8_width_screen (char *string)
+{
+ int length, num_char;
+ wchar_t *wstring;
+
+ if (!string)
+ return 0;
+
+ if (!local_utf8)
+ return strlen (string);
+
+ num_char = mbstowcs (NULL, string, 0) + 1;
+ wstring = (wchar_t *) malloc ((num_char + 1) * sizeof (wchar_t));
+ if (!wstring)
+ return utf8_strlen (string);
+
+ if (mbstowcs (wstring, string, num_char) == (size_t)(-1))
+ {
+ free (wstring);
+ return utf8_strlen (string);
+ }
+
+ length = wcswidth (wstring, num_char);
+ free (wstring);
+ return length;
+}
+
+/*
* utf8_add_offset: moves forward N chars in an UTF-8 string
*/
diff --git a/src/common/utf8.h b/src/common/utf8.h
index 0319ac3a6..17ae951a1 100644
--- a/src/common/utf8.h
+++ b/src/common/utf8.h
@@ -30,6 +30,7 @@ extern char *utf8_next_char (char *);
extern int utf8_char_size (char *);
extern int utf8_strlen (char *);
extern int utf8_strnlen (char *, int);
+extern int utf8_width_screen (char *);
extern char *utf8_add_offset (char *, int);
extern int utf8_real_pos (char *, int);
extern int utf8_pos (char *, int);
diff --git a/src/gui/curses/gui-curses-chat.c b/src/gui/curses/gui-curses-chat.c
index 45f73bfc8..e1d8d3e94 100644
--- a/src/gui/curses/gui-curses-chat.c
+++ b/src/gui/curses/gui-curses-chat.c
@@ -246,10 +246,14 @@ gui_chat_display_new_line (t_gui_window *window, int num_lines, int count,
*/
char *
-gui_chat_word_get_next_char (t_gui_window *window, unsigned char *string, int apply_style)
+gui_chat_word_get_next_char (t_gui_window *window, unsigned char *string,
+ int apply_style, int *width_screen)
{
- char str_fg[3], str_bg[3];
- int fg, bg, weechat_color;
+ char str_fg[3], str_bg[3], utf_char[16];
+ int fg, bg, weechat_color, char_size;
+
+ if (width_screen)
+ *width_screen = 0;
while (string[0])
{
@@ -399,7 +403,16 @@ gui_chat_word_get_next_char (t_gui_window *window, unsigned char *string, int ap
if (string[0] < 32)
string++;
else
- return utf8_next_char ((char *)string);
+ {
+ char_size = utf8_char_size ((char *) string);
+ if (width_screen)
+ {
+ memcpy (utf_char, string, char_size);
+ utf_char[char_size] = '\0';
+ *width_screen = utf8_width_screen (utf_char);
+ }
+ return (char *)string + char_size;
+ }
}
}
@@ -424,7 +437,7 @@ gui_chat_display_word_raw (t_gui_window *window, char *string)
while (string && string[0])
{
- next_char = gui_chat_word_get_next_char (window, (unsigned char *)string, 1);
+ next_char = gui_chat_word_get_next_char (window, (unsigned char *)string, 1, NULL);
if (!next_char)
return;
@@ -447,10 +460,10 @@ gui_chat_display_word_raw (t_gui_window *window, char *string)
void
gui_chat_display_word (t_gui_window *window,
- t_gui_line *line,
- char *data,
- char *end_offset,
- int num_lines, int count, int *lines_displayed, int simulate)
+ t_gui_line *line,
+ char *data,
+ char *end_offset,
+ int num_lines, int count, int *lines_displayed, int simulate)
{
char *end_line, saved_char_end, saved_char;
int pos_saved_char, chars_to_display, num_displayed;
@@ -557,7 +570,7 @@ gui_chat_get_word_info (t_gui_window *window,
leading_spaces = 1;
while (data && data[0])
{
- next_char = gui_chat_word_get_next_char (window, (unsigned char *)data, 0);
+ next_char = gui_chat_word_get_next_char (window, (unsigned char *)data, 0, NULL);
if (next_char)
{
prev_char = utf8_prev_char (data, next_char);
@@ -676,7 +689,9 @@ gui_chat_display_line (t_gui_window *window, t_gui_line *line, int count,
saved_char = ptr_data[word_start_offset];
ptr_data[word_start_offset] = '\0';
ptr_style = ptr_data;
- while ((ptr_style = gui_chat_word_get_next_char (window, (unsigned char *)ptr_style, 1)) != NULL)
+ while ((ptr_style = gui_chat_word_get_next_char (window,
+ (unsigned char *)ptr_style,
+ 1, NULL)) != NULL)
{
/* loop until no style/char available */
}
@@ -705,7 +720,8 @@ gui_chat_display_line (t_gui_window *window, t_gui_line *line, int count,
while (ptr_data && (ptr_data[0] == ' '))
{
next_char = gui_chat_word_get_next_char (window,
- (unsigned char *)ptr_data, 0);
+ (unsigned char *)ptr_data,
+ 0, NULL);
if (!next_char)
break;
prev_char = utf8_prev_char (ptr_data, next_char);
diff --git a/src/gui/curses/gui-curses-input.c b/src/gui/curses/gui-curses-input.c
index f6ed316f1..54aaa4c2b 100644
--- a/src/gui/curses/gui-curses-input.c
+++ b/src/gui/curses/gui-curses-input.c
@@ -67,14 +67,14 @@ gui_input_set_color (t_gui_window *window, int irc_color)
}
/*
- * gui_input_get_prompt_length: return input prompt length
+ * gui_input_get_prompt_length: return input prompt length (displayed on screen)
*/
int
gui_input_get_prompt_length (t_gui_window *window, char *nick)
{
- char *pos, *modes;
- int length, mode_found;
+ char *pos, saved_char, *modes;
+ int char_size, length, mode_found;
length = 0;
pos = cfg_look_input_format;
@@ -134,8 +134,12 @@ gui_input_get_prompt_length (t_gui_window *window, char *nick)
}
break;
default:
- length++;
- pos += utf8_char_size (pos);
+ char_size = utf8_char_size (pos);
+ saved_char = pos[char_size];
+ pos[char_size] = '\0';
+ length += utf8_width_screen (pos);
+ pos[char_size] = saved_char;
+ pos += char_size;
break;
}
}
@@ -144,6 +148,8 @@ gui_input_get_prompt_length (t_gui_window *window, char *nick)
/*
* gui_input_draw_prompt: display input prompt
+ * return: # chars displayed on screen (one UTF-8 char
+ * may be displayed on more than 1 char on screen)
*/
void
@@ -250,18 +256,23 @@ gui_input_draw_prompt (t_gui_window *window, char *nick)
/*
* gui_input_draw_text: display text in input buffer, according to color mask
+ * return: offset for cursor position on screen (one UTF-8
+ * char may be displayed on more than 1 char on screen)
*/
-void
+int
gui_input_draw_text (t_gui_window *window, int input_width)
{
char *ptr_start, *ptr_next, saved_char;
- int pos_mask, size, last_color, color;
+ int pos_mask, size, last_color, color, count_cursor, offset_cursor;
ptr_start = utf8_add_offset (window->buffer->input_buffer,
window->buffer->input_buffer_1st_display);
pos_mask = ptr_start - window->buffer->input_buffer;
last_color = -1;
+ count_cursor = window->buffer->input_buffer_pos -
+ window->buffer->input_buffer_1st_display;
+ offset_cursor = 0;
while ((input_width > 0) && ptr_start && ptr_start[0])
{
ptr_next = utf8_next_char (ptr_start);
@@ -283,6 +294,11 @@ gui_input_draw_text (t_gui_window *window, int input_width)
}
last_color = color;
wprintw (GUI_CURSES(window)->win_input, "%s", ptr_start);
+ if (count_cursor > 0)
+ {
+ offset_cursor += utf8_width_screen (ptr_start);
+ count_cursor--;
+ }
ptr_next[0] = saved_char;
ptr_start = ptr_next;
pos_mask += size;
@@ -291,6 +307,7 @@ gui_input_draw_text (t_gui_window *window, int input_width)
ptr_start = NULL;
input_width--;
}
+ return offset_cursor;
}
/*
@@ -303,7 +320,7 @@ gui_input_draw (t_gui_buffer *buffer, int erase)
t_gui_window *ptr_win;
char format[32];
char *ptr_nickname;
- int prompt_length, display_prompt;
+ int prompt_length, display_prompt, offset_cursor;
t_irc_dcc *dcc_selected;
if (!gui_ok)
@@ -368,13 +385,14 @@ gui_input_draw (t_gui_buffer *buffer, int erase)
gui_window_set_weechat_color (GUI_CURSES(ptr_win)->win_input, COLOR_WIN_INPUT);
snprintf (format, 32, "%%-%ds", ptr_win->win_width - prompt_length);
+ offset_cursor = 0;
if (ptr_win == gui_current_window)
- gui_input_draw_text (ptr_win, ptr_win->win_width - prompt_length);
+ offset_cursor = gui_input_draw_text (ptr_win,
+ ptr_win->win_width - prompt_length);
else
wprintw (GUI_CURSES(ptr_win)->win_input, format, "");
wclrtoeol (GUI_CURSES(ptr_win)->win_input);
- ptr_win->win_input_x = prompt_length +
- (buffer->input_buffer_pos - buffer->input_buffer_1st_display);
+ ptr_win->win_input_x = prompt_length + offset_cursor;
if (ptr_win == gui_current_window)
move (ptr_win->win_y + ptr_win->win_height - 1,
ptr_win->win_x + ptr_win->win_input_x);
diff --git a/src/gui/gtk/gui-gtk-chat.c b/src/gui/gtk/gui-gtk-chat.c
index 15ed9dc63..90624a000 100644
--- a/src/gui/gtk/gui-gtk-chat.c
+++ b/src/gui/gtk/gui-gtk-chat.c
@@ -191,10 +191,14 @@ gui_chat_draw_title (t_gui_buffer *buffer, int erase)
*/
char *
-gui_chat_word_get_next_char (t_gui_window *window, unsigned char *string, int apply_style)
+gui_chat_word_get_next_char (t_gui_window *window, unsigned char *string,
+ int apply_style, int *width_screen)
{
- char str_fg[3], str_bg[3];
- int fg, bg, weechat_color;
+ char str_fg[3], str_bg[3], utf_char[16];
+ int fg, bg, weechat_color, char_size;
+
+ if (width_screen)
+ *width_screen = 0;
while (string[0])
{
@@ -344,7 +348,16 @@ gui_chat_word_get_next_char (t_gui_window *window, unsigned char *string, int ap
if (string[0] < 32)
string++;
else
- return utf8_next_char ((char *)string);
+ {
+ char_size = utf8_char_size ((char *) string);
+ if (width_screen)
+ {
+ memcpy (utf_char, string, char_size);
+ utf_char[char_size] = '\0';
+ *width_screen = utf8_width_screen (utf_char);
+ }
+ return (char *)string + char_size;
+ }
}
}
@@ -416,7 +429,9 @@ gui_chat_get_word_info (t_gui_window *window,
leading_spaces = 1;
while (data && data[0])
{
- next_char = gui_chat_word_get_next_char (window, (unsigned char *)data, 0);
+ next_char = gui_chat_word_get_next_char (window,
+ (unsigned char *)data,
+ 0, NULL);
if (next_char)
{
prev_char = utf8_prev_char (data, next_char);
diff --git a/src/gui/gui-common.c b/src/gui/gui-common.c
index 300848222..8a4833d58 100644
--- a/src/gui/gui-common.c
+++ b/src/gui/gui-common.c
@@ -59,21 +59,21 @@ time_t gui_last_activity_time = 0; /* last activity time */
/*
- * gui_word_strlen: returns length of a word
+ * gui_word_strlen: returns number of char needed on sreen to display a word
* special chars like color, bold, .. are ignored
*/
int
gui_word_strlen (t_gui_window *window, char *string)
{
- int length;
+ int length, width_screen;
length = 0;
while (string && string[0])
{
- string = gui_chat_word_get_next_char (window, (unsigned char *)string, 0);
+ string = gui_chat_word_get_next_char (window, (unsigned char *)string, 0, &width_screen);
if (string)
- length++;
+ length += width_screen;
}
return length;
}
@@ -86,7 +86,7 @@ int
gui_word_real_pos (t_gui_window *window, char *string, int pos)
{
char *saved_pos;
- int real_pos;
+ int real_pos, width_screen;
if (pos <= 0)
return 0;
@@ -95,8 +95,8 @@ gui_word_real_pos (t_gui_window *window, char *string, int pos)
while (string && string[0] && (pos > 0))
{
saved_pos = string;
- string = gui_chat_word_get_next_char (window, (unsigned char *)string, 0);
- pos--;
+ string = gui_chat_word_get_next_char (window, (unsigned char *)string, 0, &width_screen);
+ pos -= width_screen;
if (string)
real_pos += (string - saved_pos);
}
diff --git a/src/gui/gui.h b/src/gui/gui.h
index 338066a54..7781bb38b 100644
--- a/src/gui/gui.h
+++ b/src/gui/gui.h
@@ -194,7 +194,7 @@ extern void gui_keyboard_default_bindings ();
/* chat */
extern void gui_chat_draw_title (t_gui_buffer *, int);
-extern char *gui_chat_word_get_next_char (t_gui_window *, unsigned char *, int);
+extern char *gui_chat_word_get_next_char (t_gui_window *, unsigned char *, int, int *);
extern void gui_chat_draw (t_gui_buffer *, int);
extern void gui_chat_draw_line (t_gui_buffer *, t_gui_line *);