1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2 
3 #include "mc_font.h"
4 
5 #include <stdio.h>
6 #include <ctype.h>
7 #include <pobl/bl_str.h> /* strdup */
8 #include <pobl/bl_mem.h> /* free */
9 #include <pobl/bl_debug.h>
10 #include <glib.h>
11 #include <c_intl.h>
12 
13 #if defined(GDK_WINDOWING_X11) && !GTK_CHECK_VERSION(2, 90, 0)
14 #include "gtkxlfdsel.c"
15 #endif
16 
17 #include "mc_combo.h"
18 #include "mc_flags.h"
19 #include "mc_radio.h"
20 #include "mc_char_encoding.h"
21 #include "mc_color.h"
22 #include "mc_unicode_areas.h"
23 
24 #if 0
25 #define __DEBUG
26 #endif
27 
28 typedef struct cs_info {
29   char *cs;
30 
31   /*
32    * Default font encoding name.
33    * This used only if xcore font is used.
34    *
35    * !! Notice !!
36    * The last element must be NULL.
37    * (Conforming to the specification of 'charsets' argument of
38    * gtk_xlfd_selection_dialog_set_filter()).
39    */
40   char *encoding_names[3];
41 
42 } cs_info_t;
43 
44 /* --- static variables --- */
45 
46 /*
47  * Combination of x_font_config.c:cs_table and x_font.c:cs_info_table
48  */
49 static cs_info_t cs_info_table[] = {
50   { "DEFAULT", { NULL, NULL, NULL, }, },
51 
52   /*
53    * UNICODE => ISO10646_UCS4_1 or U+XXXX-XXXX in get_correct_cs().
54    */
55   { "UNICODE", { "iso10646-1", NULL, NULL, }, },
56   { "UNICODE (Full Width)", { "iso10646-1", NULL, NULL, }, },
57   { "UNICODE (Emoji)", { "iso10646-1", NULL, NULL, }, },
58   { "UNICODE (Hankaku Kana)", { "iso10646-1", NULL, NULL, }, },
59   { "UNICODE (Hebrew)", { "iso10646-1", NULL, NULL, }, },
60   { "UNICODE (Arabic)", { "iso10646-1", NULL, NULL, }, },
61   { "UNICODE (Hindi)", { "iso10646-1", NULL, NULL, }, },
62   { "UNICODE (Bengali)", { "iso10646-1", NULL, NULL, }, },
63   { "UNICODE (Punjabi)", { "iso10646-1", NULL, NULL, }, },
64   { "UNICODE (Gujarati)", { "iso10646-1", NULL, NULL, }, },
65   { "UNICODE (Oriya)", { "iso10646-1", NULL, NULL, }, },
66   { "UNICODE (Tamil)", { "iso10646-1", NULL, NULL, }, },
67   { "UNICODE (Telugu)", { "iso10646-1", NULL, NULL, }, },
68   { "UNICODE (Kannada)", { "iso10646-1", NULL, NULL, }, },
69   { "UNICODE (Malayalam)", { "iso10646-1", NULL, NULL, }, },
70 
71   { "DEC_SPECIAL", { "iso8859-1", NULL, NULL, }, },
72   { "ISO8859_1", { "iso8859-1", NULL, NULL, }, },
73   { "ISO8859_2", { "iso8859-2", NULL, NULL, }, },
74   { "ISO8859_3", { "iso8859-3", NULL, NULL, }, },
75   { "ISO8859_4", { "iso8859-4", NULL, NULL, }, },
76   { "ISO8859_5", { "iso8859-5", NULL, NULL, }, },
77   { "ISO8859_6", { "iso8859-6", NULL, NULL, }, },
78   { "ISO8859_7", { "iso8859-7", NULL, NULL, }, },
79   { "ISO8859_8", { "iso8859-8", NULL, NULL, }, },
80   { "ISO8859_9", { "iso8859-9", NULL, NULL, }, },
81   { "ISO8859_10", { "iso8859-10", NULL, NULL, }, },
82   { "TIS620", { "tis620.2533-1", "tis620.2529-1", NULL, }, },
83   { "ISO8859_13", { "iso8859-13", NULL, NULL, }, },
84   { "ISO8859_14", { "iso8859-14", NULL, NULL, }, },
85   { "ISO8859_15", { "iso8859-15", NULL, NULL, }, },
86   { "ISO8859_16", { "iso8859-16", NULL, NULL, }, },
87 
88   /*
89    * XXX
90    * The encoding of TCVN font is iso8859-1, and its font family is .VnTime or
91    * .VnTimeH... How to deal with it ?
92    */
93   { "TCVN5712", { NULL, NULL, NULL, }, },
94 
95   { "ISCII_ASSAMESE", { NULL, NULL, NULL, }, },
96   { "ISCII_BENGALI", { NULL, NULL, NULL, }, },
97   { "ISCII_GUJARATI", { NULL, NULL, NULL, }, },
98   { "ISCII_HINDI", { NULL, NULL, NULL, }, },
99   { "ISCII_KANNADA", { NULL, NULL, NULL, }, },
100   { "ISCII_MALAYALAM", { NULL, NULL, NULL, }, },
101   { "ISCII_ORIYA", { NULL, NULL, NULL, }, },
102   { "ISCII_PUNJABI", { NULL, NULL, NULL, }, },
103   { "ISCII_TAMIL", { NULL, NULL, NULL, }, },
104   { "ISCII_TELUGU", { NULL, NULL, NULL, }, },
105   { "VISCII", { "viscii-1", NULL, NULL, }, },
106   { "KOI8_R", { "koi8-r", NULL, NULL, }, },
107   { "KOI8_U", { "koi8-u", NULL, NULL, }, },
108 
109 #if 0
110   /*
111    * XXX
112    * KOI8_T, GEORGIAN_PS and CP125X charset can be shown by unicode font only.
113    */
114   { "KOI8_T", { NULL, NULL, NULL, }, },
115   { "GEORGIAN_PS", { NULL, NULL, NULL, }, },
116 #endif
117 #ifdef USE_WIN32GUI
118   { "CP1250", { NULL, NULL, NULL, }, },
119   { "CP1251", { NULL, NULL, NULL, }, },
120   { "CP1252", { NULL, NULL, NULL, }, },
121   { "CP1253", { NULL, NULL, NULL, }, },
122   { "CP1254", { NULL, NULL, NULL, }, },
123   { "CP1255", { NULL, NULL, NULL, }, },
124   { "CP1256", { NULL, NULL, NULL, }, },
125   { "CP1257", { NULL, NULL, NULL, }, },
126   { "CP1258", { NULL, NULL, NULL, }, },
127   { "CP874", { NULL, NULL, NULL, }, },
128 #endif
129 
130   { "JISX0201_KATA", { "jisx0201.1976-0", NULL, NULL, }, },
131   { "JISX0201_ROMAN", { "jisx0201.1976-0", NULL, NULL, }, },
132   { "JISX0208_1978", { "jisx0208.1978-0", "jisx0208.1983-0", NULL, }, },
133   { "JISX0208_1983", { "jisx0208.1983-0", "jisx0208.1990-0", NULL, }, },
134   { "JISX0208_1990", { "jisx0208.1990-0", "jisx0208.1983-0", NULL, }, },
135   { "JISX0212_1990", { "jisx0212.1990-0", NULL, NULL, }, },
136   { "JISX0213_2000_1", { "jisx0213.2000-1", "jisx0208.1983-0", NULL, }, },
137   { "JISX0213_2000_2", { "jisx0213.2000-2", NULL, NULL, }, },
138   { "KSX1001_1997", { "ksc5601.1987-0", "ksx1001.1997-0", NULL, }, },
139 
140 #if 0
141   /*
142    * XXX
143    * UHC and JOHAB fonts are not used at the present time.
144    * see vt_vt100_parser.c:vt_parse_vt100_sequence().
145    */
146   { "UHC", { NULL, NULL, NULL, }, },
147   { "JOHAB", { "johabsh-1", /* "johabs-1" , */ "johab-1", NULL, }, },
148 #endif
149 
150   { "GB2312_80", { "gb2312.1980-0", NULL, NULL, }, },
151   { "GBK", { "gbk-0", NULL, NULL, }, },
152   { "BIG5", { "big5.eten-0", "big5.hku-0", NULL, }, },
153   { "HKSCS", { "big5hkscs-0", "big5-0", NULL, }, },
154   { "CNS11643_1992_1", { "cns11643.1992-1", "cns11643.1992.1-0", NULL, }, },
155   { "CNS11643_1992_2", { "cns11643.1992-2", "cns11643.1992.2-0", NULL, }, },
156   { "CNS11643_1992_3", { "cns11643.1992-3", "cns11643.1992.3-0", NULL, }, },
157   { "CNS11643_1992_4", { "cns11643.1992-4", "cns11643.1992.4-0", NULL, }, },
158   { "CNS11643_1992_5", { "cns11643.1992-5", "cns11643.1992.5-0", NULL, }, },
159   { "CNS11643_1992_6", { "cns11643.1992-6", "cns11643.1992.6-0", NULL, }, },
160   { "CNS11643_1992_7", { "cns11643.1992-7", "cns11643.1992.7-0", NULL, }, },
161 };
162 
163 static char *new_fontsize = NULL;
164 static char *old_fontsize = NULL;
165 static int is_fontsize_changed;
166 
167 static char *new_fontname_list[sizeof(cs_info_table) / sizeof(cs_info_table[0])];
168 static int dont_change_new_fontname_list = 0;
169 static int selected_cs = 0; /* 0 = DEFAULT */
170 static GtkWidget *fontcs_entry;
171 static GtkWidget *fontname_entry;
172 static GtkWidget *select_font_button;
173 static GtkWidget *xft_flag;
174 static GtkWidget *cairo_flag;
175 static GtkWidget *aa_flag;
176 static GtkWidget *vcol_flag;
177 static int dont_change_type_engine;
178 static GtkWidget *noconv_areas_button;
179 static char *noconv_areas;
180 
181 /* --- static functions  --- */
182 
reset_fontname_list(void)183 static void reset_fontname_list(void) {
184   int count;
185 
186   for (count = 0; count < sizeof(cs_info_table) / sizeof(cs_info_table[0]); count++) {
187     free(new_fontname_list[count]);
188     new_fontname_list[count] = NULL;
189   }
190 }
191 
192 /*
193  * If you use functions in mc_io.c, use this function instead of direct
194  * access to cs_info_t::cs.
195  */
get_correct_cs(int idx)196 static const char *get_correct_cs(int idx) {
197   const char *unicode_names[] = {
198       "ISO10646_UCS4_1", "ISO10646_UCS4_1_FULLWIDTH", "U+1F000-1F77F", /* Emoji */
199       "U+FF61-FF9F",                                                   /* Hankaku Kana */
200       "U+0590-05FF",                                                   /* Hebrew */
201       "U+0600-06FF",                                                   /* Arabic */
202       "U+0900-097F",                                                   /* Hindi */
203       "U+0980-09FF",                                                   /* Bengali */
204       "U+0A00-0A7F",                                                   /* Punjabi */
205       "U+0A80-0AFF",                                                   /* Gujarati */
206       "U+0B00-0B7F",                                                   /* Oriya */
207       "U+0B80-0BFF",                                                   /* Tamil */
208       "U+0C00-0C7F",                                                   /* Telugu */
209       "U+0C80-0CFF",                                                   /* Kannada */
210       "U+0D00-0D7F",                                                   /* Malayalam */
211   };
212 
213   if (idx < 0) {
214     return NULL;
215   } else if (1 <= idx && idx <= 15) {
216     return unicode_names[idx - 1];
217   } else if (idx < sizeof(cs_info_table) / sizeof(cs_info_table[0])) {
218     return cs_info_table[idx].cs;
219   } else {
220     return NULL;
221   }
222 }
223 
get_font_file(void)224 static char *get_font_file(void) {
225   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(xft_flag)) ||
226       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cairo_flag)) ||
227       mc_get_flag_value("use_aafont")) {
228     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(vcol_flag))) {
229       return "vaafont";
230     } else if (mc_radio_get_value(MC_RADIO_VERTICAL_MODE)) {
231       return "taafont";
232     } else {
233       return "aafont";
234     }
235   } else {
236     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(vcol_flag))) {
237       return "vfont";
238     } else if (mc_radio_get_value(MC_RADIO_VERTICAL_MODE)) {
239       return "tfont";
240     } else {
241       return "font";
242     }
243   }
244 }
245 
aa_flag_checked(GtkWidget * widget,gpointer data)246 static gint aa_flag_checked(GtkWidget *widget, gpointer data) {
247   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
248     if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(xft_flag)) &&
249         !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cairo_flag))) {
250       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(xft_flag), 1);
251 
252       reset_fontname_list();
253       gtk_entry_set_text(
254           GTK_ENTRY(fontname_entry),
255           g_locale_to_utf8(mc_get_font_name(get_font_file(), get_correct_cs(selected_cs)), -1, NULL,
256                            NULL, NULL));
257     }
258   }
259 
260   return 1;
261 }
262 
xft_flag_checked(GtkWidget * widget,gpointer data)263 static gint xft_flag_checked(GtkWidget *widget, gpointer data) {
264   if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) &&
265       !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cairo_flag))) {
266     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(aa_flag), 0);
267   } else if (!dont_change_type_engine) {
268     dont_change_type_engine = 1;
269     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cairo_flag), 0);
270     dont_change_type_engine = 0;
271   }
272 
273   reset_fontname_list();
274   gtk_entry_set_text(
275       GTK_ENTRY(fontname_entry),
276       g_locale_to_utf8(mc_get_font_name(get_font_file(), get_correct_cs(selected_cs)), -1, NULL,
277                        NULL, NULL));
278 
279   return 1;
280 }
281 
cairo_flag_checked(GtkWidget * widget,gpointer data)282 static gint cairo_flag_checked(GtkWidget *widget, gpointer data) {
283   if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) &&
284       !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(xft_flag))) {
285     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(aa_flag), 0);
286   } else if (!dont_change_type_engine) {
287     dont_change_type_engine = 1;
288     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(xft_flag), 0);
289     dont_change_type_engine = 0;
290   }
291 
292   reset_fontname_list();
293   gtk_entry_set_text(
294       GTK_ENTRY(fontname_entry),
295       g_locale_to_utf8(mc_get_font_name(get_font_file(), get_correct_cs(selected_cs)), -1, NULL,
296                        NULL, NULL));
297 
298   return 1;
299 }
300 
vcol_flag_checked(GtkWidget * widget,gpointer data)301 static gint vcol_flag_checked(GtkWidget *widget, gpointer data) {
302   reset_fontname_list();
303   gtk_entry_set_text(
304       GTK_ENTRY(fontname_entry),
305       g_locale_to_utf8(mc_get_font_name(get_font_file(), get_correct_cs(selected_cs)), -1, NULL,
306                        NULL, NULL));
307 
308   return 1;
309 }
310 
vertical_mode_changed(void)311 static void vertical_mode_changed(void) {
312   reset_fontname_list();
313   gtk_entry_set_text(
314       GTK_ENTRY(fontname_entry),
315       g_locale_to_utf8(mc_get_font_name(get_font_file(), get_correct_cs(selected_cs)), -1, NULL,
316                        NULL, NULL));
317 
318   if (mc_radio_get_value(MC_RADIO_VERTICAL_MODE)) {
319     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(vcol_flag), 0);
320     gtk_widget_set_sensitive(vcol_flag, 0);
321   } else {
322     gtk_widget_set_sensitive(vcol_flag, 1);
323   }
324 }
325 
fontsize_selected(GtkWidget * widget,gpointer data)326 static gint fontsize_selected(GtkWidget *widget, gpointer data) {
327   g_free(new_fontsize);
328   new_fontsize = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1);
329 
330 #ifdef __DEBUG
331   bl_debug_printf(BL_DEBUG_TAG " %s font size is selected.\n", new_fontsize);
332 #endif
333 
334   return 1;
335 }
336 
specify_width(GtkWidget * widget,int flag)337 static void specify_width(GtkWidget *widget, int flag) {
338   gchar *fontname;
339 
340   if (((fontname = new_fontname_list[selected_cs]) ||
341        (fontname = gtk_entry_get_text(GTK_ENTRY(fontname_entry)))) &&
342       *fontname) {
343     gchar *p;
344     int percent;
345     size_t len;
346 
347     if (!(p = strrchr(fontname, ':')) || (percent = atoi(p + 1)) == 0) {
348       if (flag == 0) {
349         return;
350       }
351 
352       len = strlen(fontname);
353       percent = (flag < 0 ? 100 : 110);
354     } else {
355       len = p - fontname;
356 
357       if (flag == 0) {
358         percent = 0;
359       } else {
360         percent += (flag < 0 ? -10 : 10);
361 
362         if (percent <= 0 || 200 < percent) {
363           return;
364         }
365       }
366     }
367 
368     if ((p = malloc(len + 5))) {
369       strncpy(p, fontname, len);
370       if (percent == 0) {
371         p[len] = '\0';
372       } else {
373         sprintf(p + len, ":%d", percent);
374       }
375       free(new_fontname_list[selected_cs]);
376       new_fontname_list[selected_cs] = p;
377 
378       dont_change_new_fontname_list = 1;
379       gtk_entry_set_text(GTK_ENTRY(fontname_entry), p);
380       dont_change_new_fontname_list = 0;
381     }
382   }
383 }
384 
widen_width(GtkWidget * widget,gpointer data)385 static void widen_width(GtkWidget *widget, gpointer data) { specify_width(widget, 1); }
386 
narrow_width(GtkWidget * widget,gpointer data)387 static void narrow_width(GtkWidget *widget, gpointer data) { specify_width(widget, -1); }
388 
default_width(GtkWidget * widget,gpointer data)389 static void default_width(GtkWidget *widget, gpointer data) { specify_width(widget, 0); }
390 
fontcs_changed(void)391 static void fontcs_changed(void) {
392   dont_change_new_fontname_list = 1;
393 
394   if (new_fontname_list[selected_cs]) {
395     gtk_entry_set_text(GTK_ENTRY(fontname_entry), new_fontname_list[selected_cs]);
396   } else {
397     gtk_entry_set_text(
398         GTK_ENTRY(fontname_entry),
399         g_locale_to_utf8(mc_get_font_name(get_font_file(), get_correct_cs(selected_cs)), -1, NULL,
400                          NULL, NULL));
401   }
402 
403   dont_change_new_fontname_list = 0;
404 }
405 
406 /* compare two encoding names, returns non-zero if equal
407  */
compare(const char * e1,const char * e2)408 static int compare(const char *e1, const char *e2) {
409   while (1) {
410     /* ')' is for "auto (currently EUC-JP)" */
411     if (*e1 == '-' || *e1 == '_' || *e1 == ')') {
412       e1++;
413       continue;
414     }
415     if (*e2 == '-' || *e2 == '_' || *e2 == ')') {
416       e2++;
417       continue;
418     }
419     if ((*e1 == 0 || *e1 == ' ') && (*e2 == 0 || *e2 == ' ')) {
420       return 1;
421     }
422     if (toupper(*e1) != toupper(*e2)) {
423       return 0;
424     }
425     e1++;
426     e2++;
427   }
428 }
429 
fontcs_map(GtkWidget * widget,gpointer data)430 static void fontcs_map(GtkWidget *widget, gpointer data) {
431   char *encoding;
432   int count;
433 
434   encoding = mc_get_char_encoding();
435 
436   if ((strstr(encoding, "UTF") && mc_radio_get_value(MC_RADIO_FONT_POLICY) != 2) ||
437       mc_radio_get_value(MC_RADIO_FONT_POLICY) == 1) {
438     if (selected_cs == 1) {
439       return;
440     }
441 
442     selected_cs = 1; /* UNICODE */
443   } else {
444     for (count = 0; count < sizeof(cs_info_table) / sizeof(cs_info_table[0]); count++) {
445       if (strcmp(cs_info_table[count].cs, "JISX0201_KATA") == 0) {
446         break;
447       } else if (compare(encoding, cs_info_table[count].cs)) {
448         if (selected_cs == count) {
449           return;
450         }
451 
452         selected_cs = count;
453 
454         goto update_cs;
455       }
456     }
457 
458     if (selected_cs == 0) {
459       return;
460     }
461 
462     selected_cs = 0; /* DEFAULT */
463   }
464 
465 update_cs:
466   gtk_entry_set_text(GTK_ENTRY(widget), cs_info_table[selected_cs].cs);
467   fontcs_changed();
468 }
469 
font_policy_changed(void)470 static void font_policy_changed(void) {
471   fontcs_map(fontcs_entry, NULL);
472 
473   if (noconv_areas_button) {
474     gtk_widget_set_sensitive(noconv_areas_button, (mc_radio_get_value(MC_RADIO_FONT_POLICY) == 2));
475   }
476 }
477 
fontcs_selected(GtkWidget * widget,gpointer data)478 static gint fontcs_selected(GtkWidget *widget, gpointer data) {
479   const char *cs;
480   int count;
481 
482   cs = gtk_entry_get_text(GTK_ENTRY(widget));
483 
484   for (count = 0; count < sizeof(cs_info_table) / sizeof(cs_info_table[0]); count++) {
485     if (strcmp(cs, cs_info_table[count].cs) == 0) {
486       if (selected_cs != count) {
487 #if 0
488         bl_debug_printf("Before: cs %s fontname %s => ", cs_info_table[selected_cs].cs,
489                         new_fontname_list[selected_cs]);
490 #endif
491 
492         selected_cs = count;
493 
494         fontcs_changed();
495 
496 #if 0
497         bl_debug_printf("After: cs %s fontname %s\n", cs, new_fontname_list[selected_cs]);
498 #endif
499 
500         return 1;
501       }
502     }
503   }
504 
505   return 0;
506 }
507 
508 #if defined(GDK_WINDOWING_X11) && !GTK_CHECK_VERSION(2, 90, 0)
509 
get_xlfd_font_name(gpointer dialog)510 static gchar *get_xlfd_font_name(gpointer dialog) {
511   char *name;
512 
513   name = gtk_xlfd_selection_dialog_get_font_name(GTK_XLFD_SELECTION_DIALOG(dialog));
514   if (selected_cs == 0 && name && *name) /* DEFAULT */
515   {
516     /*
517      * Removing font encoding such as "iso8859-1".
518      */
519 
520     char *p;
521 
522     if ((p = strrchr(name, '-'))) {
523       *p = '\0';
524       if ((p = strrchr(name, '-'))) {
525         *(p + 1) = '\0';
526       }
527     }
528   }
529 
530   return name;
531 }
532 
ok_pressed(GtkWidget * widget,gpointer dialog)533 static void ok_pressed(GtkWidget *widget, gpointer dialog) {
534   gchar *name;
535 
536   name = get_xlfd_font_name(dialog);
537   gtk_entry_set_text(GTK_ENTRY(fontname_entry), name);
538   g_free(name);
539 
540   gtk_widget_destroy(GTK_WIDGET(dialog));
541 }
542 
apply_pressed(GtkWidget * widget,gpointer dialog)543 static void apply_pressed(GtkWidget *widget, gpointer dialog) {
544   gchar *name;
545 
546   name = get_xlfd_font_name(dialog);
547   gtk_entry_set_text(GTK_ENTRY(fontname_entry), name);
548   g_free(name);
549 }
550 
cancel_pressed(GtkWidget * widget,gpointer dialog)551 static void cancel_pressed(GtkWidget *widget, gpointer dialog) {
552   gtk_widget_destroy(GTK_WIDGET(dialog));
553 }
554 
set_current_font_name(GtkWidget * dialog)555 static int set_current_font_name(GtkWidget *dialog) {
556   const gchar *font_name;
557 
558   font_name = gtk_entry_get_text(GTK_ENTRY(fontname_entry));
559   if (font_name && *font_name) {
560     char *p;
561 
562     /*
563      * Modify DEFAULT font name. "-*-...-*-" => "-*-...-*-*-*"
564      */
565     if (selected_cs == 0 && (p = alloca(strlen(font_name) + 4))) {
566       sprintf(p, "%s*-*", font_name);
567       font_name = p;
568     }
569 
570     return gtk_xlfd_selection_dialog_set_font_name(GTK_XLFD_SELECTION_DIALOG(dialog), font_name);
571   } else {
572     return 0;
573   }
574 }
575 
select_xlfd_font(GtkWidget * widget,gpointer label)576 static void select_xlfd_font(GtkWidget *widget, gpointer label) {
577   GtkWidget *dialog;
578 
579   dialog = gtk_xlfd_selection_dialog_new("Select Font");
580   if (!set_current_font_name(dialog)) {
581     char *encoding;
582     char *font_name;
583     char format[] = "-misc-fixed-medium-*-normal-*-%s-*-*-*-*-*-%s";
584 
585     if ((encoding = cs_info_table[selected_cs].encoding_names[0]) == NULL) {
586       encoding = "*-*";
587     }
588 
589     if ((font_name = alloca(sizeof(format) + strlen(new_fontsize) + strlen(encoding)))) {
590       sprintf(font_name, format, new_fontsize, encoding);
591 
592       gtk_xlfd_selection_dialog_set_font_name(GTK_XLFD_SELECTION_DIALOG(dialog), font_name);
593     }
594   }
595 
596   if (cs_info_table[selected_cs].encoding_names[0]) {
597     gtk_xlfd_selection_dialog_set_filter(GTK_XLFD_SELECTION_DIALOG(dialog), GTK_XLFD_FILTER_USER,
598                                          GTK_XLFD_ALL, NULL, NULL, NULL, NULL, NULL,
599                                          cs_info_table[selected_cs].encoding_names);
600   }
601 
602   g_signal_connect(GTK_XLFD_SELECTION_DIALOG(dialog)->ok_button, "clicked", G_CALLBACK(ok_pressed),
603                    dialog);
604   g_signal_connect(GTK_XLFD_SELECTION_DIALOG(dialog)->apply_button, "clicked",
605                    G_CALLBACK(apply_pressed), dialog);
606   g_signal_connect(GTK_XLFD_SELECTION_DIALOG(dialog)->cancel_button, "clicked",
607                    G_CALLBACK(cancel_pressed), dialog);
608 
609   gtk_widget_show_all(dialog);
610 }
611 
612 #endif
613 
my_gtk_font_selection_dialog_get_font_name(GtkFontSelectionDialog * dialog)614 static char *my_gtk_font_selection_dialog_get_font_name(GtkFontSelectionDialog *dialog) {
615   char *str;
616   int count;
617   char *p;
618   char *dup_str;
619 
620   str = gtk_font_selection_dialog_get_font_name(dialog);
621 
622   if ((dup_str = malloc(strlen(str) * 2 + 1)) == NULL) {
623     free(str);
624 
625     return NULL;
626   }
627 
628   /* Escape '-' in Xft. */
629   count = 0;
630   p = str;
631   while (*p) {
632 #ifndef USE_WIN32GUI
633     if (*p == '-') {
634       dup_str[count++] = '\\';
635     }
636 #endif
637 
638     dup_str[count++] = *(p++);
639   }
640 
641   dup_str[count] = '\0';
642 
643   g_free(str);
644 
645   return dup_str;
646 }
647 
get_gtk_font_name(const char * font_name)648 static char *get_gtk_font_name(const char *font_name) {
649   int count;
650   char *str;
651 
652   if ((str = malloc(strlen(font_name) + 1)) == NULL) {
653     return NULL;
654   }
655 
656   count = 0;
657   while (*font_name && *font_name != '-') {
658     if (*font_name == '\\') {
659       font_name++;
660     }
661 
662     str[count++] = *(font_name++);
663   }
664 
665   str[count] = '\0';
666 
667   return str;
668 }
669 
fontname_entry_edit(GtkWidget * widget,gpointer p)670 static void fontname_entry_edit(GtkWidget *widget, gpointer p) {
671   /* In case fontname is editted in text entry widget. */
672 
673   if (!dont_change_new_fontname_list) {
674     const char *name;
675 
676     if (!(name = gtk_entry_get_text(GTK_ENTRY(fontname_entry)))) {
677       if (new_fontname_list[selected_cs]) {
678         /*
679          * Font name for selected_cs was specfied, but now
680          * font name for selected_cs is cleared.
681          */
682         name = "";
683       }
684     }
685 
686     if (name) {
687       free(new_fontname_list[selected_cs]);
688       new_fontname_list[selected_cs] = strdup(name);
689     }
690   }
691 }
692 
select_fc_font(GtkWidget * widget,gpointer p)693 static void select_fc_font(GtkWidget *widget, gpointer p) {
694   GtkWidget *dialog;
695   char *font_name;
696   GtkResponseType result;
697 
698   dialog = gtk_font_selection_dialog_new("Select Font");
699 
700   font_name = get_gtk_font_name(gtk_entry_get_text(GTK_ENTRY(fontname_entry)));
701   if (!font_name || !*font_name ||
702       !gtk_font_selection_dialog_set_font_name(GTK_FONT_SELECTION_DIALOG(dialog), font_name)) {
703     free(font_name);
704 
705     if ((font_name = malloc(6 + strlen(new_fontsize))) == NULL) {
706       return;
707     }
708 
709     sprintf(font_name, "Sans %s", new_fontsize);
710 
711     gtk_font_selection_dialog_set_font_name(GTK_FONT_SELECTION_DIALOG(dialog), font_name);
712   }
713 
714   free(font_name);
715 
716   result = gtk_dialog_run(GTK_DIALOG(dialog));
717   if (result == GTK_RESPONSE_OK) {
718     gtk_entry_set_text(GTK_ENTRY(fontname_entry), my_gtk_font_selection_dialog_get_font_name(
719                                                       GTK_FONT_SELECTION_DIALOG(dialog)));
720   }
721 
722   gtk_widget_destroy(dialog);
723 }
724 
select_font(GtkWidget * widget,gpointer p)725 static void select_font(GtkWidget *widget, gpointer p) {
726 #if defined(GDK_WINDOWING_X11) && !GTK_CHECK_VERSION(2, 90, 0)
727   if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(xft_flag)) &&
728       !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cairo_flag)) &&
729       strcmp(mc_get_gui(), "xlib") == 0) {
730     select_xlfd_font(widget, p);
731   } else
732 #endif
733   {
734     select_fc_font(widget, p);
735   }
736 }
737 
edit_noconv_areas(GtkWidget * widget,gpointer data)738 static void edit_noconv_areas(GtkWidget *widget, gpointer data) {
739   char *cur_areas;
740   char *new_areas;
741 
742   if (noconv_areas) {
743     cur_areas = strdup(noconv_areas);
744   } else {
745     cur_areas = mc_get_str_value("unicode_noconv_areas");
746   }
747 
748   if ((new_areas = mc_get_unicode_areas(cur_areas)) &&
749       bl_compare_str(noconv_areas, new_areas) != 0) {
750     free(noconv_areas);
751     noconv_areas = new_areas;
752   }
753 
754   free(cur_areas);
755 }
756 
757 /* --- global functions --- */
758 
mc_font_config_widget_new(void)759 GtkWidget *mc_font_config_widget_new(void) {
760   GtkWidget *vbox;
761   GtkWidget *hbox;
762   GtkWidget *fgcolor;
763   GtkWidget *combo;
764   GtkWidget *entry;
765   GtkWidget *radio;
766   GtkWidget *label;
767   GtkWidget *button;
768   char *fontlist[] = {
769       "6",  "7",  "8",  "9",  "10", "11", "12", "13", "14", "15", "16", "17", "18",
770       "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30",
771   };
772   char **cslist;
773 
774   new_fontsize = strdup(old_fontsize = mc_get_str_value("fontsize"));
775   is_fontsize_changed = 0;
776 
777   vbox = gtk_vbox_new(FALSE, 0);
778 
779   hbox = gtk_hbox_new(FALSE, 0);
780   gtk_widget_show(hbox);
781   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
782 
783   combo =
784       mc_combo_new_with_width(_("Font size (pixels)"), fontlist,
785                               sizeof(fontlist) / sizeof(fontlist[0]), new_fontsize, 1, 30, &entry);
786   g_signal_connect(entry, "changed", G_CALLBACK(fontsize_selected), NULL);
787   gtk_box_pack_start(GTK_BOX(hbox), combo, FALSE, FALSE, 0);
788 #if GTK_CHECK_VERSION(2, 12, 0)
789   gtk_widget_set_tooltip_text(combo,
790                               "If you change fonts from \"Select\" button, "
791                               "it is not recommended to change font size here.");
792 #endif
793 
794   fgcolor = mc_color_config_widget_new(MC_COLOR_FG);
795   gtk_widget_show(fgcolor);
796   gtk_box_pack_start(GTK_BOX(hbox), fgcolor, FALSE, FALSE, 5);
797 
798   hbox = gtk_hbox_new(FALSE, 0);
799   gtk_widget_show(hbox);
800 
801   xft_flag = mc_flag_config_widget_new(MC_FLAG_XFT);
802   gtk_widget_show(xft_flag);
803   gtk_box_pack_start(GTK_BOX(hbox), xft_flag, FALSE, FALSE, 0);
804   g_signal_connect(xft_flag, "toggled", G_CALLBACK(xft_flag_checked), NULL);
805   if (strcmp(mc_get_gui(), "xlib") != 0) {
806     gtk_widget_set_sensitive(xft_flag, 0);
807   }
808 
809   cairo_flag = mc_flag_config_widget_new(MC_FLAG_CAIRO);
810   gtk_widget_show(cairo_flag);
811   gtk_box_pack_start(GTK_BOX(hbox), cairo_flag, FALSE, FALSE, 0);
812   g_signal_connect(cairo_flag, "toggled", G_CALLBACK(cairo_flag_checked), NULL);
813   if (strcmp(mc_get_gui(), "xlib") != 0) {
814     gtk_widget_set_sensitive(cairo_flag, 0);
815   }
816 
817   aa_flag = mc_flag_config_widget_new(MC_FLAG_AA);
818   gtk_widget_show(aa_flag);
819   gtk_box_pack_start(GTK_BOX(hbox), aa_flag, FALSE, FALSE, 0);
820   g_signal_connect(aa_flag, "toggled", G_CALLBACK(aa_flag_checked), NULL);
821 
822   vcol_flag = mc_flag_config_widget_new(MC_FLAG_VCOL);
823   gtk_widget_show(vcol_flag);
824   gtk_box_pack_start(GTK_BOX(hbox), vcol_flag, FALSE, FALSE, 0);
825   g_signal_connect(vcol_flag, "toggled", G_CALLBACK(vcol_flag_checked), NULL);
826   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
827 
828   radio = mc_radio_config_widget_new(MC_RADIO_VERTICAL_MODE);
829   gtk_widget_show(radio);
830   gtk_box_pack_start(GTK_BOX(vbox), radio, FALSE, FALSE, 0);
831   mc_radio_set_callback(MC_RADIO_VERTICAL_MODE, vertical_mode_changed);
832   if (mc_radio_get_value(MC_RADIO_VERTICAL_MODE)) {
833     gtk_widget_set_sensitive(vcol_flag, 0);
834   }
835 
836   hbox = gtk_hbox_new(FALSE, 0);
837   gtk_widget_show(hbox);
838 
839   if ((cslist = alloca(sizeof(char*) * sizeof(cs_info_table) / sizeof(cs_info_table[0])))) {
840     int count;
841 
842     for (count = 0; count < sizeof(cs_info_table) / sizeof(cs_info_table[0]); count++) {
843       cslist[count] = cs_info_table[count].cs;
844     }
845 
846     combo = mc_combo_new_with_width(_("Font name"), cslist, count, cslist[selected_cs], 1, 90,
847                                     &fontcs_entry);
848     g_signal_connect(fontcs_entry, "changed", G_CALLBACK(fontcs_selected), NULL);
849     g_signal_connect(fontcs_entry, "map", G_CALLBACK(fontcs_map), NULL);
850     gtk_box_pack_start(GTK_BOX(hbox), combo, FALSE, FALSE, 0);
851   }
852 
853   fontname_entry = gtk_entry_new();
854   gtk_entry_set_text(
855       GTK_ENTRY(fontname_entry),
856       g_locale_to_utf8(mc_get_font_name(get_font_file(), get_correct_cs(selected_cs)), -1, NULL,
857                        NULL, NULL));
858   gtk_widget_show(fontname_entry);
859   gtk_box_pack_start(GTK_BOX(hbox), fontname_entry, TRUE, TRUE, 1);
860   g_signal_connect(fontname_entry, "changed", G_CALLBACK(fontname_entry_edit), NULL);
861 
862   select_font_button = gtk_button_new_with_label(_("Select"));
863   gtk_widget_show(select_font_button);
864   gtk_box_pack_start(GTK_BOX(hbox), select_font_button, FALSE, FALSE, 1);
865   g_signal_connect(select_font_button, "clicked", G_CALLBACK(select_font), NULL);
866 
867   gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
868 
869   hbox = gtk_hbox_new(FALSE, 0);
870   gtk_widget_show(hbox);
871 
872   label = gtk_label_new(_("Font width"));
873   gtk_widget_show(label);
874   gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
875 
876   button = gtk_button_new_with_label(_("Narrow"));
877   gtk_widget_show(button);
878   gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 5);
879   g_signal_connect(button, "clicked", G_CALLBACK(narrow_width), NULL);
880 
881   button = gtk_button_new_with_label(_("Widen"));
882   gtk_widget_show(button);
883   gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 5);
884   g_signal_connect(button, "clicked", G_CALLBACK(widen_width), NULL);
885 
886   button = gtk_button_new_with_label(_("Default"));
887   gtk_widget_show(button);
888   gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 5);
889   g_signal_connect(button, "clicked", G_CALLBACK(default_width), NULL);
890 
891   gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
892 
893   radio = mc_radio_config_widget_new(MC_RADIO_FONT_POLICY);
894   gtk_widget_show(radio);
895   gtk_box_pack_start(GTK_BOX(vbox), radio, FALSE, FALSE, 0);
896   mc_radio_set_callback(MC_RADIO_FONT_POLICY, font_policy_changed);
897 
898   hbox = gtk_hbox_new(FALSE, 0);
899   gtk_widget_show(hbox);
900 
901   label = gtk_label_new(_("Unicode areas you won't convert to other charsets"));
902   gtk_widget_show(label);
903   gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
904   noconv_areas_button = gtk_button_new_with_label(_(" Edit "));
905   gtk_widget_show(noconv_areas_button);
906   gtk_box_pack_start(GTK_BOX(hbox), noconv_areas_button, FALSE, FALSE, 0);
907   g_signal_connect(noconv_areas_button, "clicked", G_CALLBACK(edit_noconv_areas), NULL);
908   if (mc_radio_get_value(MC_RADIO_FONT_POLICY) != 2) {
909     gtk_widget_set_sensitive(noconv_areas_button, 0);
910   }
911 
912   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
913 
914   radio = mc_radio_config_widget_new(MC_RADIO_BOX_DRAWING);
915   gtk_widget_show(radio);
916   gtk_box_pack_start(GTK_BOX(vbox), radio, FALSE, FALSE, 0);
917 
918   return vbox;
919 }
920 
mc_update_font_misc(void)921 void mc_update_font_misc(void) {
922   if (strcmp(new_fontsize, old_fontsize)) is_fontsize_changed = 1;
923 
924   if (is_fontsize_changed) {
925     mc_set_str_value("fontsize", new_fontsize);
926     free(old_fontsize);
927     old_fontsize = strdup(new_fontsize);
928   }
929 
930   /*
931    * MC_FLAG_{XFT|CAIRO} should be updated last because MC_FLAG_{XFT|CAIRO} are
932    * invalid in some environments.
933    */
934   mc_update_flag_mode(MC_FLAG_AA);
935   mc_update_radio(MC_RADIO_VERTICAL_MODE);
936   /* vcol is forcibly disabled in vertical mode, so update after vertical mode.
937    */
938   mc_update_flag_mode(MC_FLAG_VCOL);
939   mc_update_flag_mode(MC_FLAG_XFT);
940   mc_update_flag_mode(MC_FLAG_CAIRO);
941   mc_update_radio(MC_RADIO_BOX_DRAWING);
942   mc_update_radio(MC_RADIO_FONT_POLICY);
943 
944   if (noconv_areas) {
945     mc_set_str_value("unicode_noconv_areas", noconv_areas);
946   }
947 }
948 
mc_update_font_name(mc_io_t io)949 void mc_update_font_name(mc_io_t io) {
950   size_t count;
951 
952   for (count = 0; count < sizeof(cs_info_table) / sizeof(cs_info_table[0]); count++) {
953     if (new_fontname_list[count]) {
954       mc_set_font_name(io, get_font_file(), get_correct_cs(count), new_fontname_list[count]);
955 
956       if (count == 6) {
957         /* Arabic Supplement */
958         mc_set_font_name(io, get_font_file(), "U+0750-77F", new_fontname_list[count]);
959         /* Arabic Extended-A */
960         mc_set_font_name(io, get_font_file(), "U+08A0-8FF", new_fontname_list[count]);
961         /* Arabic Presentation Forms-A */
962         mc_set_font_name(io, get_font_file(), "U+FB50-FDFF", new_fontname_list[count]);
963         /* Arabic Presentation Forms-B */
964         mc_set_font_name(io, get_font_file(), "U+FE70-FEFF", new_fontname_list[count]);
965         /* Arabic Mathematical Alphabetic Symbols */
966         mc_set_font_name(io, get_font_file(), "U+1EE00-1EEFF", new_fontname_list[count]);
967       }
968     }
969   }
970 }
971