1 Return-Path: a-higuti@math.sci.hokudai.ac.jp
2 Delivery-Date: Thu Sep 23 14:52:43 1999
3 Return-Path: <a-higuti@math.sci.hokudai.ac.jp>
4 Received: from localhost (IDENT:otaylor@localhost [127.0.0.1])
5 by fresnel.labs.redhat.com (8.9.3/8.9.3) with ESMTP id OAA00891
6 for <otaylor@localhost>; Thu, 23 Sep 1999 14:52:41 -0400
7 Received: from lacrosse.redhat.com
8 by localhost with POP3 (fetchmail-5.0.0)
9 for otaylor@localhost (single-drop); Thu, 23 Sep 1999 14:52:42 -0400 (EDT)
10 Received: from mail.redhat.com (mail.redhat.com [199.183.24.239])
11 by lacrosse.corp.redhat.com (8.9.3/8.9.3) with ESMTP id OAA19205
12 for <otaylor@lacrosse.redhat.com>; Thu, 23 Sep 1999 14:01:27 -0400
13 Received: from math.sci.hokudai.ac.jp (seki.math.sci.hokudai.ac.jp [133.50.152.8])
14 by mail.redhat.com (8.8.7/8.8.7) with ESMTP id OAA13383
15 for <otaylor@redhat.com>; Thu, 23 Sep 1999 14:01:49 -0400
16 Received: from heathcliff (a-higuti@hilbert.math.sci.hokudai.ac.jp [133.50.152.11])
17 by math.sci.hokudai.ac.jp (8.8.8/3.6W01/06/98) with SMTP id DAA23889
18 for <otaylor@redhat.com>; Fri, 24 Sep 1999 03:01:10 +0900 (JST)
19 Date: Fri, 24 Sep 1999 03:01:10 +0900 (JST)
20 Message-Id: <199909231801.DAA23889@math.sci.hokudai.ac.jp>
21 From: a-higuti@math.sci.hokudai.ac.jp (Akira Higuchi)
22 To: otaylor@redhat.com
23 Subject: Adding more gdk_isw* macros
25 Content-Type: text/plain; charset=US-ASCII
28 Xref: fresnel.labs.redhat.com prog-gtk:648
32 I'm working on adding CJK support to gnome apps, and I need your advice.
34 As you know, gtk+-1.2 has some support for CJK. It's sufficient for most
35 gnome apps to be internationalized, but some problems remain. The most
36 problem is that there is no way of doing word wrapping for CJK strings.
38 For example, gtk-xmhtml shows Japanese text very uglily, because Japanese
39 sentences are recognized as very long words. (a Japanese sentence
40 contain any spaces in most cases.) The same problem is in gtk+ itself, too;
41 Word wrapping in GtkLabel and GtkText doesn't work correctly for CJK text,
42 because of the same reason as above.
44 In order to fix it, we need more gdk_isw* functions than we already have
45 in gdki18n.h. (I regret I didn't add them before gtk+-1.2 was released.)
46 I attach herewith a patch which fixes it, but I think it's not acceptable
47 to adding a new macro to a stable version of gtk+. (is it?)
49 The question I want to ask you is: what's the best way of fixing the
50 problem without adding these macros to gdki18n.h? A solution is to add
51 these macros to each *.c files (in GtkLabel, GtkText, and gtkxmhtml etc.)
52 rather than gtki18n.h, but it's very ugly I think.
54 Please don't say "wait until gscript is completed" ;-( I don't want to
55 wait for a long time. (Please let me know if I can help you with gscript
56 BTW. I've not hacked gscript yet, because it seems to be too early to be
57 hacked by other than you.)
61 ---------------- x8 ---------------- x8 ---------------- x8 ----------------
62 diff -ur gtk+-1.2.5-pre2/gdk/gdki18n.h gtk+-1.2.5-pre2.new/gdk/gdki18n.h
63 --- gtk+-1.2.5-pre2/gdk/gdki18n.h Wed Jun 9 21:07:51 1999
64 +++ gtk+-1.2.5-pre2.new/gdk/gdki18n.h Thu Sep 23 14:59:38 1999
66 # define gdk_iswspace(c) ((wchar_t)(c) <= 0xFF && isspace(c))
69 +/* The following 9 macros are added in gtk+ 1.2.X. Don't use them without
70 + * checking GTK_CHECK_VERSION. For example,
71 + * #if GTK_CHECK_VERSION (1,2,X)
72 + * ... code which uses gdk_iswalpha(), gdk_iswcntrl(), etc. ...
75 +#if !defined(G_HAVE_BROKEN_WCTYPE) && (defined(G_HAVE_WCTYPE_H) || defined(G_HAVE_WCHAR_H)) && !defined(X_LOCALE)
76 +# define gdk_iswalpha(c) iswalpha(c)
77 +# define gdk_iswcntrl(c) iswcntrl(c)
78 +# define gdk_iswdigit(c) iswdigit(c)
79 +# define gdk_iswlower(c) iswlower(c)
80 +# define gdk_iswgraph(c) iswgraph(c)
81 +# define gdk_iswprint(c) iswprint(c)
82 +# define gdk_iswpunct(c) iswpunct(c)
83 +# define gdk_iswupper(c) iswupper(c)
84 +# define gdk_iswxdigit(c) iswxdigit(c)
86 +# define gdk_iswalpha(c) ((wchar_t)(c) <= 0xFF && isalpha(c))
87 +# define gdk_iswcntrl(c) ((wchar_t)(c) <= 0xFF && iscntrl(c))
88 +# define gdk_iswdigit(c) ((wchar_t)(c) <= 0xFF && isdigit(c))
89 +# define gdk_iswlower(c) ((wchar_t)(c) <= 0xFF && islower(c))
90 +# define gdk_iswgraph(c) ((wchar_t)(c) > 0xFF || isgraph(c))
91 +# define gdk_iswprint(c) ((wchar_t)(c) > 0xFF || isprint(c))
92 +# define gdk_iswpunct(c) ((wchar_t)(c) <= 0xFF && ispunct(c))
93 +# define gdk_iswupper(c) ((wchar_t)(c) <= 0xFF && isupper(c))
94 +# define gdk_iswxdigit(c) ((wchar_t)(c) <= 0xFF && isxdigit(c))
97 #endif /* __GDK_I18N_H__ */
98 diff -ur gtk+-1.2.5-pre2/gtk/gtkentry.c gtk+-1.2.5-pre2.new/gtk/gtkentry.c
99 --- gtk+-1.2.5-pre2/gtk/gtkentry.c Wed Aug 18 14:23:53 1999
100 +++ gtk+-1.2.5-pre2.new/gtk/gtkentry.c Thu Sep 23 00:22:21 1999
101 @@ -1943,11 +1943,21 @@
102 gtk_move_backward_word (GTK_ENTRY (editable));
106 +alnum_or_ideogram (GtkEntry *entry, guint index)
109 + ch = entry->text[index];
110 + if (entry->use_wchar)
111 + return !(gdk_iswpunct (ch) || gdk_iswcntrl (ch) || gdk_iswspace (ch));
113 + return !(ispunct (ch) || iscntrl (ch) || isspace (ch));
117 gtk_move_forward_word (GtkEntry *entry)
119 GtkEditable *editable;
123 editable = GTK_EDITABLE (entry);
124 @@ -1961,21 +1971,12 @@
126 if (entry->text && (editable->current_pos < entry->text_length))
128 - text = entry->text;
129 - i = editable->current_pos;
131 - if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
132 - for (; i < entry->text_length; i++)
134 - if ((entry->use_wchar) ? gdk_iswalnum (text[i]) : isalnum (text[i]))
138 + for (i = editable->current_pos; i < entry->text_length; i++)
139 + if (alnum_or_ideogram (entry, i))
141 for (; i < entry->text_length; i++)
143 - if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
146 + if (!alnum_or_ideogram (entry, i))
149 editable->current_pos = i;
151 @@ -1985,7 +1986,6 @@
152 gtk_move_backward_word (GtkEntry *entry)
154 GtkEditable *editable;
158 editable = GTK_EDITABLE (entry);
159 @@ -1999,26 +1999,19 @@
161 if (entry->text && editable->current_pos > 0)
163 - text = entry->text;
164 - i = editable->current_pos - 1;
165 - if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
166 - for (; i >= 0; i--)
167 + for (i = editable->current_pos - 1; i >= 0; i--)
168 + if (alnum_or_ideogram (entry, i))
170 + for (; i >= 0; i--)
171 + if (!alnum_or_ideogram (entry, i))
173 - if ((entry->use_wchar) ? gdk_iswalnum (text[i]) : isalnum (text[i]))
178 - for (; i >= 0; i--)
180 - if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
192 editable->current_pos = i;
195 diff -ur gtk+-1.2.5-pre2/gtk/gtklabel.c gtk+-1.2.5-pre2.new/gtk/gtklabel.c
196 --- gtk+-1.2.5-pre2/gtk/gtklabel.c Wed Jun 9 20:40:13 1999
197 +++ gtk+-1.2.5-pre2.new/gtk/gtklabel.c Thu Sep 23 11:29:25 1999
201 GtkLabelULine *uline;
202 + gboolean paragraph_break;
205 struct _GtkLabelULine
207 word->beginning = NULL;
210 + word->paragraph_break = FALSE;
215 if (str == label->label_wc || str[-1] == '\n')
217 /* Paragraph break */
218 + word->paragraph_break = TRUE;
221 max_line_width = MAX (line_width, max_line_width);
224 word = gtk_label_word_alloc ();
226 + word->paragraph_break = TRUE;
228 word->beginning = str;
231 return MAX (line_width, max_line_width);
235 +is_ideogram (GdkWChar wc)
237 + return !(gdk_iswalnum (wc) || gdk_iswspace (wc) ||
238 + gdk_iswpunct (wc) || gdk_iswcntrl (wc));
241 /* this needs to handle white space better. */
243 gtk_label_split_text_wrapped (GtkLabel *label)
245 if (str == label->label_wc || str[-1] == '\n')
247 /* Paragraph break */
248 + word->paragraph_break = TRUE;
251 max_line_width = MAX (line_width, max_line_width);
252 @@ -546,24 +558,30 @@
254 word->space = space_width * nspaces;
257 + else if (gdk_iswspace (str[-1]))
259 /* Regular inter-word space */
260 word->space = space_width;
267 word->beginning = str;
270 while (*p && !gdk_iswspace (*p))
272 + if (word->length > 0 && (is_ideogram (p[-1]) || is_ideogram (*p)))
277 word->width = gdk_text_width_wc (GTK_WIDGET (label)->style->font, str, word->length);
281 + if (*str && gdk_iswspace (*str))
284 line_width += word->space + word->width;
287 for (word = label->words; word; word = word->next)
289 - if (word->space == 0
290 + if (word->paragraph_break
292 && (line_width >= min_width
293 || line_width + word->width + word->space > max_width)))
295 GtkLabelWord *word, *line, *next_line;
298 - gint x, y, space, extra_width, add_space, baseline_skip;
299 + gint x, y, space, num_words, extra_width, add_space, baseline_skip;
300 + gboolean deliver_equivalently;
302 g_return_if_fail (label->wrap);
304 @@ -724,20 +743,24 @@
306 baseline_skip = (GTK_WIDGET (label)->style->font->ascent +
307 GTK_WIDGET (label)->style->font->descent + 1);
308 + deliver_equivalently = FALSE;
310 for (line = label->words; line != 0; line = next_line)
313 + space = num_words = 0;
314 extra_width = max_line_width - line->width;
316 for (next_line = line->next; next_line; next_line = next_line->next)
318 - if (next_line->space == 0)
319 + if (next_line->paragraph_break)
320 break; /* New paragraph */
321 if (next_line->space + next_line->width > extra_width)
323 + if (next_line->space == 0)
324 + deliver_equivalently = TRUE; /* An ideogram is found. */
325 extra_width -= next_line->space + next_line->width;
326 space += next_line->space;
331 @@ -747,14 +770,18 @@
333 for (word = line->next; word != next_line; word = word->next)
335 - if (next_line && next_line->space)
336 + if (next_line && !next_line->paragraph_break &&
337 + label->jtype == GTK_JUSTIFY_FILL &&
338 + (deliver_equivalently ? num_words : space) > 0)
340 - /* Not last line of paragraph --- fill line if needed */
341 - if (label->jtype == GTK_JUSTIFY_FILL) {
342 + /* Not last line of paragraph --- fill line */
343 + if (deliver_equivalently)
344 + add_space = (extra_width + num_words / 2) / num_words;
346 add_space = (extra_width * word->space + space / 2) / space;
347 - extra_width -= add_space;
348 - space -= word->space;
350 + extra_width -= add_space;
351 + space -= word->space;
355 word->x = x + word->space + add_space;
358 for (word = label->words; word; word = word->next)
360 - gchar save = word->beginning[word->length];
361 + GdkWChar save = word->beginning[word->length];
362 word->beginning[word->length] = '\0';
363 gtk_label_paint_word (label, x, y, word, &event->area);
364 word->beginning[word->length] = save;
365 diff -ur gtk+-1.2.5-pre2/gtk/gtktext.c gtk+-1.2.5-pre2.new/gtk/gtktext.c
366 --- gtk+-1.2.5-pre2/gtk/gtktext.c Sat Sep 4 08:50:38 1999
367 +++ gtk+-1.2.5-pre2.new/gtk/gtktext.c Thu Sep 23 00:21:40 1999
375 + CHAR_CLASS_IDEOGRAM,
376 + CHAR_CLASS_OTHERS /* punct, cntrl */
379 typedef struct _TextProperty TextProperty;
380 typedef struct _TabStopMark TabStopMark;
381 typedef struct _PrevTabCont PrevTabCont;
383 const GtkPropertyMark *mark,
384 const PrevTabCont *tab_cont,
385 PrevTabCont *next_cont);
386 +static void find_word_wrap_position (GtkText* text, LineParams *lp);
387 +static CharClass char_class (GtkText* text, guint index);
388 static void recompute_geometry (GtkText* text);
389 static void insert_expose (GtkText* text, guint old_pixels, gint nchars, guint new_line_count);
390 static void delete_expose (GtkText* text,
391 @@ -4084,27 +4093,21 @@
393 undraw_cursor (text, FALSE);
395 - if (text->use_wchar)
396 + while (!LAST_INDEX (text, text->cursor_mark))
398 - while (!LAST_INDEX (text, text->cursor_mark) &&
399 - !gdk_iswalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index)))
400 - advance_mark (&text->cursor_mark);
402 - while (!LAST_INDEX (text, text->cursor_mark) &&
403 - gdk_iswalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index)))
404 - advance_mark (&text->cursor_mark);
405 + CharClass cc = char_class (text, text->cursor_mark.index);
406 + if (cc == CHAR_CLASS_ALNUM || cc == CHAR_CLASS_IDEOGRAM)
408 + advance_mark (&text->cursor_mark);
411 + while (!LAST_INDEX (text, text->cursor_mark))
413 - while (!LAST_INDEX (text, text->cursor_mark) &&
414 - !isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index)))
415 - advance_mark (&text->cursor_mark);
417 - while (!LAST_INDEX (text, text->cursor_mark) &&
418 - isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index)))
419 - advance_mark (&text->cursor_mark);
420 + CharClass cc = char_class (text, text->cursor_mark.index);
421 + if (cc != CHAR_CLASS_ALNUM && cc != CHAR_CLASS_IDEOGRAM)
423 + advance_mark (&text->cursor_mark);
427 find_cursor (text, TRUE);
428 draw_cursor (text, FALSE);
430 @@ -4116,25 +4119,19 @@
432 undraw_cursor (text, FALSE);
434 - if (text->use_wchar)
435 + while (text->cursor_mark.index > 0)
437 - while ((text->cursor_mark.index > 0) &&
438 - !gdk_iswalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
439 - decrement_mark (&text->cursor_mark);
441 - while ((text->cursor_mark.index > 0) &&
442 - gdk_iswalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
443 - decrement_mark (&text->cursor_mark);
444 + CharClass cc = char_class (text, text->cursor_mark.index - 1);
445 + if (cc == CHAR_CLASS_ALNUM || cc == CHAR_CLASS_IDEOGRAM)
447 + decrement_mark (&text->cursor_mark);
450 + while (text->cursor_mark.index > 0)
452 - while ((text->cursor_mark.index > 0) &&
453 - !isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
454 - decrement_mark (&text->cursor_mark);
456 - while ((text->cursor_mark.index > 0) &&
457 - isalnum (GTK_TEXT_INDEX(text, text->cursor_mark.index-1)))
458 - decrement_mark (&text->cursor_mark);
459 + CharClass cc = char_class (text, text->cursor_mark.index - 1);
460 + if (cc != CHAR_CLASS_ALNUM && cc != CHAR_CLASS_IDEOGRAM)
462 + decrement_mark (&text->cursor_mark);
465 find_cursor (text, TRUE);
466 @@ -4755,27 +4752,8 @@
467 GtkPropertyMark saved_mark = lp.end;
468 guint saved_characters = lp.displayable_chars;
470 - lp.displayable_chars += 1;
472 - if (text->use_wchar)
474 - while (!gdk_iswspace (GTK_TEXT_INDEX (text, lp.end.index)) &&
475 - (lp.end.index > lp.start.index))
477 - decrement_mark (&lp.end);
478 - lp.displayable_chars -= 1;
483 - while (!isspace(GTK_TEXT_INDEX (text, lp.end.index)) &&
484 - (lp.end.index > lp.start.index))
486 - decrement_mark (&lp.end);
487 - lp.displayable_chars -= 1;
491 + find_word_wrap_position (text, &lp);
493 /* If whole line is one word, revert to char wrapping */
494 if (lp.end.index == lp.start.index)
496 @@ -4821,6 +4799,54 @@
497 lp.tab_cont_next = *next_cont;
503 +char_class (GtkText* text, guint index)
506 + wc = GTK_TEXT_INDEX (text, index);
507 + if (text->use_wchar)
509 + if (gdk_iswspace (wc))
510 + return CHAR_CLASS_SPACE;
511 + else if (gdk_iswalnum (wc))
512 + return CHAR_CLASS_ALNUM;
513 + else if (gdk_iswpunct (wc) || gdk_iswcntrl (wc))
514 + return CHAR_CLASS_OTHERS;
516 + return CHAR_CLASS_IDEOGRAM;
521 + return CHAR_CLASS_SPACE;
522 + else if (isalnum (wc))
523 + return CHAR_CLASS_ALNUM;
524 + else if (ispunct (wc) || iscntrl (wc))
525 + return CHAR_CLASS_OTHERS;
527 + return CHAR_CLASS_IDEOGRAM;
532 +find_word_wrap_position (GtkText* text, LineParams *lp)
534 + while (lp->end.index > lp->start.index &&
535 + char_class (text, lp->end.index) != CHAR_CLASS_SPACE &&
536 + char_class (text, lp->end.index) != CHAR_CLASS_IDEOGRAM &&
537 + char_class (text, lp->end.index - 1) != CHAR_CLASS_IDEOGRAM)
539 + decrement_mark (&lp->end);
540 + lp->displayable_chars -= 1;
543 + /* lp->end.index points the position to be cut just now. If it's not a
544 + * space, move it to the next display line. */
545 + if (lp->end.index > lp->start.index &&
546 + char_class (text, lp->end.index) != CHAR_CLASS_SPACE)
547 + decrement_mark (&lp->end);
551 ---------------- x8 ---------------- x8 ---------------- x8 ----------------
553 --------------------------------------
555 Dept. of Mathematics, Hokkaido Univ.
557 Email: a-higuti@math.sci.hokudai.ac.jp