+2005-03-18 Dani Carbonell <bocata@panete.net>
+
+ * src/client.c
+ * src/dialogs.c
+ * src/fields.c
+ * src/misc.c
+ * src/misc.h
+ * src/partyline.c
+ * src/tetrinet.c
+ * src/winlist.c: Applied patch from Vidar Holen, which implements
+ proper UTF-8 support. Just convert all incoming data to UTF-8, and
+ avoid any other conversion. Rocks!
+
2005-03-05 Abel Cheung <maddog@linuxhall.org>
* configure.in: Added "tr" "vi" to ALL_LINGUAS.
printf ("< %s\n", buf);
#endif
- *str = g_strdup (buf);
+ /** Convert all incoming data to utf-8 (or fall back to locale, and then
+ * iso8859-1. - vidar */
+ *str = ensure_utf8 (buf);
return 0;
}
void teamdialog_button (GtkWidget *button, gint response, gpointer data)
{
GtkEntry *entry = GTK_ENTRY (gnome_entry_gtk_entry (GNOME_ENTRY (data)));
- gchar *aux;
-
button = button; /* so we get no unused parameter warning */
-
+
switch (response)
{
case GTK_RESPONSE_OK :
{
- aux = g_locale_from_utf8 (gtk_entry_get_text (entry), -1, NULL, NULL, NULL);
gconf_client_set_string (gconf_client, "/apps/gtetrinet/player/team",
gtk_entry_get_text (entry), NULL);
- tetrinet_changeteam (aux);
- g_free (aux);
+ tetrinet_changeteam (gtk_entry_get_text(entry));
}; break;
}
-
+
teamdialog_destroy ();
}
void teamdialog_new (void)
{
GtkWidget *hbox, *widget, *entry;
- gchar *team_utf8 = g_locale_to_utf8 (team, -1, NULL, NULL, NULL);
+ gchar *team_utf8 = team;
if (team_dialog != NULL)
{
gtk_window_present (GTK_WINDOW (team_dialog));
return;
}
-
+
team_dialog = gtk_dialog_new_with_buttons (_("Change team"),
GTK_WINDOW (app),
GTK_DIALOG_NO_SEPARATOR,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
gtk_window_set_skip_taskbar_hint (GTK_WINDOW (team_dialog), TRUE);
- gtk_dialog_set_default_response (GTK_DIALOG (team_dialog), GTK_RESPONSE_OK);
+ gtk_dialog_set_default_response (GTK_DIALOG (team_dialog), GTK_RESPONSE_OK);
gtk_window_set_position (GTK_WINDOW (team_dialog), GTK_WIN_POS_MOUSE);
gtk_window_set_resizable (GTK_WINDOW (team_dialog), FALSE);
team_utf8);
g_object_set (G_OBJECT (gnome_entry_gtk_entry (GNOME_ENTRY (entry))),
"activates_default", TRUE, NULL);
- g_free (team_utf8);
gtk_box_pack_start_defaults (GTK_BOX (hbox), entry);
gtk_container_set_border_width (GTK_CONTAINER (hbox), GNOME_PAD_SMALL);
gtk_box_pack_end_defaults (GTK_BOX (GTK_DIALOG (team_dialog)->vbox), hbox);
-
+
/* pass the entry in the data pointer */
g_signal_connect (G_OBJECT(team_dialog), "response",
GTK_SIGNAL_FUNC(teamdialog_button), (gpointer)entry);
void connectdialog_button (GtkDialog *dialog, gint button)
{
- gchar *team_utf8, *nick, *nick1; /* intermediate buffer for recoding purposes */
+ gchar *nick; /* intermediate buffer for recoding purposes */
const gchar *server1;
GtkWidget *dialog_error;
gtk_widget_destroy (dialog_error);
return;
}
-
+
spectating = GTK_TOGGLE_BUTTON(spectatorcheck)->active ? TRUE : FALSE;
if (spectating)
{
}
}
- team_utf8 = g_locale_from_utf8 (gtk_entry_get_text (GTK_ENTRY(gnome_entry_gtk_entry(GNOME_ENTRY(teamnameentry)))),
- -1, NULL, NULL, NULL);
-
- GTET_O_STRCPY (team, team_utf8);
+ GTET_O_STRCPY (team, gtk_entry_get_text(GTK_ENTRY(gnome_entry_gtk_entry(GNOME_ENTRY(teamnameentry)))));
nick = g_strdup (gtk_entry_get_text (GTK_ENTRY (gnome_entry_gtk_entry (GNOME_ENTRY (nicknameentry)))));
g_strstrip (nick); /* we remove leading and trailing whitespaces */
if (g_utf8_strlen (nick, -1) > 0)
{
- nick1 = g_locale_from_utf8 (nick, -1, NULL, NULL, NULL);
- client_init (server1, nick1);
- g_free (nick1);
+ client_init (server1, nick);
}
else
{
gconf_client_set_string (gconf_client, "/apps/gtetrinet/player/team",
gtk_entry_get_text (GTK_ENTRY(gnome_entry_gtk_entry(GNOME_ENTRY(teamnameentry)))),
NULL);
- g_free (team_utf8);
+
g_free (nick);
break;
case GTK_RESPONSE_CANCEL:
void connectdialog_new (void)
{
GtkWidget *widget, *table1, *table2, *frame;
- gchar *aux;
/* check if dialog is already displayed */
if (connecting)
{
gtk_label_set_mnemonic_widget (GTK_LABEL (widget), nicknameentry);
g_object_set(G_OBJECT(gnome_entry_gtk_entry(GNOME_ENTRY(nicknameentry))),
"activates_default", TRUE, NULL);
- aux = g_locale_to_utf8 (nick, -1, NULL, NULL, NULL);
gtk_entry_set_text (GTK_ENTRY(gnome_entry_gtk_entry(GNOME_ENTRY(nicknameentry))),
- aux);
- g_free (aux);
+ nick);
+ /* g_free (aux);*/
gtk_widget_show (nicknameentry);
gtk_table_attach (GTK_TABLE(table2), nicknameentry, 1, 2, 0, 1,
GTK_FILL | GTK_EXPAND, 0, 0, 0);
gtk_label_set_mnemonic_widget (GTK_LABEL (teamnamelabel), teamnameentry);
g_object_set(G_OBJECT(gnome_entry_gtk_entry(GNOME_ENTRY(teamnameentry))),
"activates_default", TRUE, NULL);
- aux = g_locale_to_utf8 (team, -1, NULL, NULL, NULL);
gtk_entry_set_text (GTK_ENTRY(gnome_entry_gtk_entry(GNOME_ENTRY(teamnameentry))),
- aux);
- g_free (aux);
+ team);
+ /*g_free (aux);*/
gtk_widget_show (teamnameentry);
gtk_table_attach (GTK_TABLE(table2), teamnameentry, 1, 2, 1, 2,
GTK_FILL | GTK_EXPAND, 0, 0, 0);
void fields_setlabel (int field, char *name, char *team, int num)
{
char buf[11];
- gchar *name_utf8, *team_utf8;
g_snprintf (buf, sizeof(buf), "%d", num);
gtk_label_set_text (GTK_LABEL(fieldlabels[field][5]), "");
}
else {
- name_utf8 = g_locale_to_utf8 (nocolor (name), -1, NULL, NULL, NULL);
gtk_widget_show (fieldlabels[field][0]);
gtk_widget_show (fieldlabels[field][1]);
gtk_widget_show (fieldlabels[field][2]);
gtk_widget_hide (fieldlabels[field][3]);
gtk_label_set_text (GTK_LABEL(fieldlabels[field][0]), buf);
- gtk_label_set_text (GTK_LABEL(fieldlabels[field][2]), name_utf8);
+ gtk_label_set_text (GTK_LABEL(fieldlabels[field][2]), name);
gtk_label_set_text (GTK_LABEL(fieldlabels[field][3]), "");
if (team == NULL || team[0] == 0) {
gtk_widget_hide (fieldlabels[field][4]);
gtk_label_set_text (GTK_LABEL(fieldlabels[field][5]), "");
}
else {
- team_utf8 = g_locale_to_utf8 (nocolor (team), -1, NULL, NULL, NULL);
gtk_widget_show (fieldlabels[field][4]);
gtk_widget_show (fieldlabels[field][5]);
- gtk_label_set_text (GTK_LABEL(fieldlabels[field][5]), team_utf8);
- g_free (team_utf8);
+ gtk_label_set_text (GTK_LABEL(fieldlabels[field][5]), team);
}
- g_free (name_utf8);
}
}
void gmsginput_activate (void)
{
- gchar *locale_s, buf[256];
+ gchar buf[512]; /* Increased from 256 to ease up for utf-8 sequences. - vidar */
const gchar *s;
-
+
if (gmsgstate == 0)
{
fields_gmsginputclear ();
if (strncmp("/me ", s, 4) == 0) {
/* post /me thingy */
g_snprintf (buf, sizeof(buf), "* %s %s", nick, s+4);
- locale_s = g_locale_from_utf8 (buf, -1, NULL, NULL, NULL);
- /* FIXME : if there is an error while converting from UTF8 to current locale, we ignore the message */
- if (locale_s == NULL) return;
- client_outmessage (OUT_GMSG, locale_s);
- g_free (locale_s);
+ client_outmessage (OUT_GMSG,buf);
}
else {
/* post message */
g_snprintf (buf, sizeof(buf), "<%s> %s", nick, s);
- locale_s = g_locale_from_utf8 (buf, -1, NULL, NULL, NULL);
- /* FIXME : if there is an error while converting from UTF8 to current locale, we ignore the message */
- if (locale_s == NULL) return;
- client_outmessage (OUT_GMSG, locale_s);
- g_free (locale_s);
+ client_outmessage (OUT_GMSG, buf);
}
}
fields_gmsginputclear ();
void leftlabel_set (GtkWidget *align, char *str)
{
- gchar *aux;
-
- aux = g_locale_to_utf8 (str, -1, NULL, NULL, NULL);
- gtk_label_set_text (GTK_LABEL(GTK_BIN(align)->child), aux);
- g_free (aux);
+ gtk_label_set_text (GTK_LABEL(GTK_BIN(align)->child), str);
}
/* returns a random number in the range 0 to n-1 --
GtkTextTag *t_c;
} gtet_text_tags[] =
{
+ /* Code + 0xE000 */
{{0, 0, 0, 0}, NULL}, /* ^A black */
{{0, 0, 0, 0}, NULL}, /* ^B black */
{{0, 0x0000, 0xFFFF, 0xFFFF}, NULL}, /* ^C cyan */
tag_table = gtk_text_buffer_get_tag_table(buffer);
}
-void textbox_addtext (GtkTextView *textbox, const unsigned char *text)
+void textbox_addtext (GtkTextView *textbox, const unsigned char *str)
{
+ /* At this point, str should be valid utf-8 except for some 0xFF-bytes for
+ * formatting. */
+
GtkTextTag *color, *lastcolor;
- int i;
/* int bottom; */
- char last = 0;
+ gunichar last = 0;
+ gunichar tmp;
gboolean attr_bold = FALSE;
gboolean attr_italic = FALSE;
gboolean attr_underline = FALSE;
/* GtkAdjustment *textboxadj = GTK_TEXT_VIEW(textbox)->vadjustment; */
GtkTextIter iter;
-
+ guchar* p;
+ guchar* text=g_strdup(str);
+
+
/* is the scroll bar at the bottom ?? */
/* if ((textboxadj->value+10)>(textboxadj->upper-textboxadj->lower-textboxadj->page_size))
bottom = TRUE;
if (gtk_text_buffer_get_char_count (textbox->buffer)) /* not first line */
gtk_text_buffer_insert (textbox->buffer, &iter, "\n", 1);
-
- for (i = 0; text[i]; i ++) {
- if (text[i] == TETRI_TB_RESET) {
+
+ /* For-loop with utf-8 support. - vidar*/
+ for(p=text; p[0]; p=g_utf8_next_char(p)) {
+ tmp=p[0]; /* Only for checking color codes now.*/
+
+ if (tmp == TETRI_TB_RESET) {
lastcolor = color = gtet_text_tags[0].t_c;
attr_bold = FALSE;
attr_italic = FALSE;
attr_underline = FALSE;
}
- else if (text[i] <= TETRI_TB_END_OFFSET) {
+ else if (tmp <= TETRI_TB_END_OFFSET) {
g_assert(TETRI_TB_END_OFFSET < 32); /* ASCII space */
g_assert(TETRI_TB_C_END_OFFSET <= TETRI_TB_END_OFFSET);
- switch (text[i]) {
+ switch (tmp) {
case TETRI_TB_BOLD: attr_bold = !attr_bold; break;
case TETRI_TB_ITALIC: attr_italic = !attr_italic; break;
case TETRI_TB_UNDERLINE: attr_underline = !attr_underline; break;
default: /* it is a color... */
- if (text[i] > TETRI_TB_C_END_OFFSET) break;
- if (text[i] == last) {
+ if (tmp > TETRI_TB_C_END_OFFSET) break;
+ if (tmp == last) {
/* restore previous color */
color = lastcolor;
last = 0;
}
/* save color */
lastcolor = color;
- last = text[i];
+ last = tmp;
/* get new color */
- color = gtet_text_tags[text[i] - TETRI_TB_C_BEG_OFFSET].t_c;
+ color = gtet_text_tags[tmp - TETRI_TB_C_BEG_OFFSET].t_c;
}
}
else
{
- gchar *out = g_locale_to_utf8 (&text[i], 1, NULL, NULL, NULL);
- if (out)
- {
+ tmp=g_utf8_get_char(p); /* It's not a color code, so get the entire char. */
+ /* gchar *out = g_locale_to_utf8 (&text[i], 1, NULL, NULL, NULL); */
+ gchar out[7]; /* max utf-8 length plus \0 */
+ out[g_unichar_to_utf8(tmp,out)]='\0'; /* convert and terminate */
+ g_assert(g_utf8_validate(out,-1,NULL));
+
if (0)
{ /* do nothing */ ; }
else if (attr_bold && attr_italic && attr_underline)
else
gtk_text_buffer_insert (textbox->buffer, &iter, out, -1);
- }
-
- g_free(out);
}
next:
/* scroll to bottom */
/* gtk_text_thaw (textbox); */
/* if (bottom) adjust_bottom (textboxadj); */
+
+ g_free(text);
}
/* have to use an idle handler for the adjustment ... or the TextView goes
return ret->str;
}
+
+/* Check if string is utf-8. If it isn't, convert from locale or iso8859-1. */
+gchar* ensure_utf8(const char* str) {
+ gchar* text;
+
+ if(g_utf8_validate(str,-1,NULL)) {
+ /* The string is valid utf-8, copy it. */
+ text=g_strdup(str);
+ } else {
+ /* The string isn't valid utf-8, try locale. */
+ text=g_locale_to_utf8(str,-1,NULL,NULL,NULL);
+ if(!text) { /* The locale didn't work. Use ISO8859-1. */
+ text=g_convert(str,-1,"UTF-8","ISO8859-1",NULL,NULL,NULL);
+ }
+ }
+ /* Any random byte sequence is valid iso8859-1, so this won't happen.*/
+ g_assert(text!=NULL && g_utf8_validate(text,-1,NULL));
+ return text;
+}
+
+
extern void adjust_bottom_text_view (GtkTextView *);
extern char *nocolor (char *str);
+/* Function to validate a char*, and if it's not utf-8, try the locale
+ * or iso8859-1. The returned gchar* must be freed. */
+gchar* ensure_utf8(const char* str);
+
/* Better versions of the std. string functions */
#define GTET_STRCPY(x, y, sz) G_STMT_START { \
size_t gtet_strcpy_x_sz = (sz); \
} G_STMT_END
/* textbox codes ... */
-#define TETRI_TB_RESET 0xFF
+
+/* UTF-8 won't use 0xFF, so this is ok. - vidar
+ */
+#define TETRI_TB_RESET 0xFF
#define TETRI_TB_BOLD 2
#define TETRI_TB_ITALIC 22
if (nick)
{
- nick_utf8 = g_locale_to_utf8 (nocolor (nick), -1, NULL, NULL, NULL);
- gtk_label_set_text (GTK_LABEL(namelabel), nick_utf8);
- g_free (nick_utf8);
+ gtk_label_set_text (GTK_LABEL(namelabel), nick);
}
else gtk_label_set_text (GTK_LABEL(namelabel), "");
if (team)
{
- team_utf8 = g_locale_to_utf8 (nocolor (team), -1, NULL, NULL, NULL);
- gtk_label_set_text (GTK_LABEL(teamlabel), team_utf8);
- g_free (team_utf8);
+ gtk_label_set_text (GTK_LABEL(teamlabel), team);
}
else gtk_label_set_text (GTK_LABEL(teamlabel), "");
}
char buf0[16], buf1[128], buf2[128];
GtkListStore *playerlist_model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (playerlist)));
GtkTreeIter iter;
- gchar *aux1, *aux2; /* for recoding purposes */
-
+
/* update the playerlist so that it contains only the given names */
gtk_list_store_clear (playerlist_model);
g_snprintf (buf0, sizeof(buf0), "%d", numbers[i]);
GTET_O_STRCPY (buf1, nocolor(names[i]));
GTET_O_STRCPY (buf2, nocolor(teams[i]));
- /* we only need to recode buf1 and buf2, buf0 is just a character */
- aux1 = g_locale_to_utf8 (buf1, -1, NULL, NULL, NULL);
- aux2 = g_locale_to_utf8 (buf2, -1, NULL, NULL, NULL);
+
gtk_list_store_append (playerlist_model, &iter);
gtk_list_store_set (playerlist_model, &iter,
- 0, buf0, 1, aux1, 2, aux2, -1);
- g_free (aux1);
- g_free (aux2);
+ 0, buf0, 1, buf1, 2, buf2, -1);
}
buf0[0] = buf1[0] = buf2[0] = 0;
GTET_O_STRCPY (buf0, "S");
GTET_O_STRCPY (buf1, nocolor(specs[i]));
GTET_O_STRCPY (buf2, "");
- /* we only need to recode buf1 and buf2, buf0 is just a character */
- aux1 = g_locale_to_utf8 (buf1, -1, NULL, NULL, NULL);
- aux2 = g_locale_to_utf8 (buf2, -1, NULL, NULL, NULL);
gtk_list_store_append (playerlist_model, &iter);
gtk_list_store_set (playerlist_model, &iter,
0, buf0, 1, buf1, 2, buf2, -1);
- g_free (aux1);
- g_free (aux2);
}
}
void textentry (GtkWidget *widget)
{
const char *text;
- gchar *iso_text;
text = gtk_entry_get_text (GTK_ENTRY(widget));
if (strlen(text) == 0) return;
stop_list(); /* Parsing can't be perfect,
so make sure they can do it by hand... */
- /* convert from UTF-8 to the current locale, will work with ISO8859-1 locales */
- iso_text = g_locale_from_utf8 (text, -1, NULL, NULL, NULL);
-
- /* FIXME : if there is an error while converting from UTF8 to current locale, we ignore the message */
- if (iso_text == NULL)
- return;
-
// Show the command if it's a /msg
if (g_str_has_prefix (text, "/msg"))
partyline_text (text);
- tetrinet_playerline (iso_text);
- GTET_O_STRCPY (plhistory[plh_end], iso_text);
+ tetrinet_playerline (text);
+ GTET_O_STRCPY (plhistory[plh_end], text);
gtk_entry_set_text (GTK_ENTRY(widget), "");
plh_end ++;
if (plh_end == plh_start) plh_start ++;
if (plh_start == PLHSIZE) plh_start = 0;
plh_cur = plh_end;
- plhistory[plh_cur][0] = 0;
-
- g_free (iso_text);
+
}
static gboolean is_nick (GtkTreeModel *model,
gtk_tree_model_get (model, iter, 1, &nick, -1);
down = g_utf8_strdown (nick, -1);
path = path;
-
+
if (g_str_has_prefix (down, data))
{
aux = g_strconcat (nick, ": ", NULL);
gtk_entry_set_text (GTK_ENTRY (entrybox), aux);
gtk_editable_set_position (GTK_EDITABLE (entrybox), -1);
-
+
g_free (aux);
g_free (nick);
g_free (down);
{
GtkListStore *playerlist_model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (playerlist)));
gchar *text;
-
+
text = g_utf8_strdown (gtk_entry_get_text (GTK_ENTRY (entrybox)), -1);
if (text == NULL) return;
if (keyval == GDK_Up || keyval == GDK_Down) {
if (plh_cur == plh_end) {
- text = g_locale_from_utf8 (gtk_entry_get_text (GTK_ENTRY(widget)), -1, NULL, NULL, NULL);
- if (text != NULL)
- {
- GTET_O_STRCPY (plhistory[plh_end], text);
- g_free (text);
- }
+ GTET_O_STRCPY (plhistory[plh_end], gtk_entry_get_text(GTK_ENTRY(widget)));
}
switch (keyval) {
case GDK_Up:
if (plh_cur == PLHSIZE) plh_cur = 0;
break;
}
- text = g_locale_to_utf8 (plhistory[plh_cur], -1, NULL, NULL, NULL);
+ text = plhistory[plh_cur];
gtk_entry_set_text (GTK_ENTRY(widget), text);
gtk_editable_set_position (GTK_EDITABLE (widget), -1);
- g_free (text);
#ifdef DEBUG
printf ("history: %d %d %d %s\n", plh_start, plh_end, plh_cur,
plhistory[plh_cur]);
max = scan->value.v_int;
while ((g_scanner_get_next_token (scan) != G_TOKEN_COMMENT_SINGLE) && !g_scanner_eof (scan));
- utf8 = g_locale_to_utf8 (scan->value.v_comment, -1, NULL, NULL, NULL);
+ /* This will be utf-8 since it's converted in client_readmsg, but just in
+ * case the parsing code splits up a char sequence.. - vidar
+ */
+ utf8 = ensure_utf8(scan->value.v_comment);
name = g_strconcat ("#", utf8, NULL);
g_snprintf (final, 1024, "%d/%d", actual, max);
else
{
while ((g_scanner_get_next_token (scan) != G_TOKEN_COMMENT_SINGLE) && !g_scanner_eof (scan));
- utf8 = g_locale_to_utf8 (scan->value.v_comment, -1, NULL, NULL, NULL);
+ utf8 = ensure_utf8(scan->value.v_comment);
name = g_strconcat ("#", utf8, NULL);
-
+
while ((g_scanner_get_next_token (scan) != G_TOKEN_IDENTIFIER) && !g_scanner_eof (scan));
players = g_strdup (scan->value.v_identifier);
}
else
g_snprintf (final, 1024, "UNK");
-
+
g_scanner_get_next_token (scan); /* dump the ')' */
-
+
if (g_scanner_get_next_token (scan) == G_TOKEN_LEFT_CURLY)
{
g_scanner_get_next_token (scan);
while ((g_scanner_get_next_token (scan) != G_TOKEN_RIGHT_PAREN) && !g_scanner_eof (scan));
if (line[scan->position] != 0)
- desc = g_strstrip (g_locale_to_utf8 (&line[scan->position], -1, NULL, NULL, NULL));
+ desc = g_strstrip (ensure_utf8 (&line[scan->position]));
else
desc = g_strdup ("");
}
int x, y, i, d = 0; /* d is the number of differences */
char buf[1024], *p;
- char diff_buf[15][(FIELDWIDTH + 1)* FIELDHEIGHT * 2] = {0};
+ char diff_buf[15][(FIELDWIDTH + 1)* FIELDHEIGHT * 2] = {{0}};
int row_count[15] = {1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1};
GtkListStore *winlist_model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (winlist)));
GtkTreeIter iter;
char buf[16], *item[2];
- gchar *name_utf8;
GdkPixbuf *pixbuf;
if (team) pixbuf = team_icon;
else pixbuf = alone_icon;
item[0] = nocolor (name);
- name_utf8 = g_locale_to_utf8 (item[0], -1, NULL, NULL, NULL);
g_snprintf (buf, sizeof(buf), "%d", score);
item[1] = buf;
gtk_list_store_append (winlist_model, &iter);
gtk_list_store_set (winlist_model, &iter,
0, pixbuf,
- 1, name_utf8,
+ 1, item[0],
2, item[1],
-1);
- g_free (name_utf8);
}
void winlist_focus (void)