2 * Utilities to use for font manipulation
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 #include <epan/packet.h>
41 #include <epan/prefs.h>
43 #include "gtkglobals.h"
45 #include "compat_macros.h"
46 #include "font_utils.h"
47 #include "simple_dialog.h"
49 #include "packet_list.h"
50 #include "proto_draw.h"
51 #include "follow_dlg.h"
55 #if GTK_MAJOR_VERSION < 2
56 guint m_font_height, m_font_width;
58 FONT_TYPE *m_r_font, *m_b_font;
61 /* Get the regular user font.
63 * @return the regular user font
65 FONT_TYPE *user_font_get_regular(void)
70 /* Get the bold user font.
72 * @return the bold user font
74 FONT_TYPE *user_font_get_bold(void)
79 #if GTK_MAJOR_VERSION < 2
80 /* Get the regular user font height.
82 * @return the regular user font height
84 guint user_font_get_regular_height(void)
89 /* Get the regular user font width.
91 * @return the regular user font width
93 guint user_font_get_regular_width(void)
101 set_fonts(FONT_TYPE *regular, FONT_TYPE *bold)
103 /* Yes, assert. The code that loads the font should check
104 * for NULL and provide its own error message. */
105 g_assert(m_r_font && m_b_font);
109 #if GTK_MAJOR_VERSION < 2
110 m_font_height = m_r_font->ascent + m_r_font->descent;
111 m_font_width = gdk_string_width(m_r_font, "0");
116 view_zoom_in_cb(GtkWidget *w _U_, gpointer d _U_)
118 gint save_gui_zoom_level;
120 save_gui_zoom_level = recent.gui_zoom_level;
121 recent.gui_zoom_level++;
122 switch (user_font_apply()) {
127 case FA_FONT_NOT_RESIZEABLE:
128 /* "font_apply()" popped up an alert box. */
129 recent.gui_zoom_level = save_gui_zoom_level; /* undo zoom */
132 case FA_FONT_NOT_AVAILABLE:
133 /* We assume this means that the specified size isn't available. */
134 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
135 "Your current font isn't available in the next larger size.\n");
136 recent.gui_zoom_level = save_gui_zoom_level; /* undo zoom */
142 view_zoom_out_cb(GtkWidget *w _U_, gpointer d _U_)
144 gint save_gui_zoom_level;
146 save_gui_zoom_level = recent.gui_zoom_level;
147 recent.gui_zoom_level--;
148 switch (user_font_apply()) {
153 case FA_FONT_NOT_RESIZEABLE:
154 /* "font_apply()" popped up an alert box. */
155 recent.gui_zoom_level = save_gui_zoom_level; /* undo zoom */
158 case FA_FONT_NOT_AVAILABLE:
159 /* We assume this means that the specified size isn't available. */
160 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
161 "Your current font isn't available in the next smaller size.\n");
162 recent.gui_zoom_level = save_gui_zoom_level; /* undo zoom */
168 view_zoom_100_cb(GtkWidget *w _U_, gpointer d _U_)
170 gint save_gui_zoom_level;
172 save_gui_zoom_level = recent.gui_zoom_level;
173 recent.gui_zoom_level = 0;
174 switch (user_font_apply()) {
179 case FA_FONT_NOT_RESIZEABLE:
180 /* "font_apply()" popped up an alert box. */
181 recent.gui_zoom_level = save_gui_zoom_level; /* undo zoom */
184 case FA_FONT_NOT_AVAILABLE:
185 /* We assume this means that the specified size isn't available.
186 XXX - this "shouldn't happen". */
187 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
188 "Your current font couldn't be reloaded at the size you selected.\n");
189 recent.gui_zoom_level = save_gui_zoom_level; /* undo zoom */
195 #if GTK_MAJOR_VERSION < 2
196 /* Given a font name, construct the name of the next heavier version of
199 #define XLFD_WEIGHT 3 /* index of the "weight" field */
201 /* Map from a given weight to the appropriate weight for the "bold"
203 XXX - the XLFD says these strings shouldn't be used for font matching;
204 can we get the weight, as a number, from GDK, and ask GDK to find us
205 a font just like the given font, but with the appropriate higher
207 static const struct {
211 { "ultralight", "light" },
212 { "extralight", "semilight" },
213 { "light", "medium" },
214 { "semilight", "semibold" },
215 { "medium", "bold" },
216 { "normal", "bold" },
217 { "semibold", "extrabold" },
218 { "bold", "ultrabold" }
220 #define N_WEIGHTS (sizeof weight_map / sizeof weight_map[0])
222 /* Try to convert a font name to it's bold version.
224 * @param the font to convert
225 * @return the bold font
228 user_font_boldify(const char *font_name)
230 char *bold_font_name;
234 /* Is this an XLFD font? If it begins with "-", yes, otherwise no. */
235 if (font_name[0] == '-') {
236 xlfd_tokens = g_strsplit(font_name, "-", XLFD_WEIGHT+1);
239 * Make sure we *have* a weight (this might not be a valid
242 for (i = 0; i < XLFD_WEIGHT+1; i++) {
243 if (xlfd_tokens[i] == NULL) {
245 * We don't, so treat this as a non-XLFD
251 for (i = 0; i < N_WEIGHTS; i++) {
252 if (strcmp(xlfd_tokens[XLFD_WEIGHT],
253 weight_map[i].light) == 0) {
254 g_free(xlfd_tokens[XLFD_WEIGHT]);
255 xlfd_tokens[XLFD_WEIGHT] =
256 g_strdup(weight_map[i].heavier);
260 bold_font_name = g_strjoinv("-", xlfd_tokens);
261 g_strfreev(xlfd_tokens);
262 return bold_font_name;
267 * This isn't an XLFD font name; just append "bold" to the name
270 bold_font_name = g_strconcat(font_name, "bold", NULL);
271 return bold_font_name;
277 user_font_test(gchar *font_name)
279 #if GTK_MAJOR_VERSION < 2
280 gchar *bold_font_name;
282 FONT_TYPE *new_r_font, *new_b_font;
284 #if GTK_MAJOR_VERSION < 2
285 /* Get the name that the boldface version of that font would have. */
286 bold_font_name = user_font_boldify(font_name);
288 /* Now load those fonts, just to make sure we can. */
289 new_r_font = gdk_font_load(font_name);
291 new_r_font = pango_font_description_from_string(font_name);
293 if (new_r_font == NULL) {
294 /* Oops, that font didn't work.
295 Tell the user, but don't tear down the font selection
296 dialog, so that they can try again. */
297 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
298 "The font you selected can't be loaded.");
300 #if GTK_MAJOR_VERSION < 2
301 g_free(bold_font_name);
306 #if GTK_MAJOR_VERSION < 2
307 new_b_font = gdk_font_load(bold_font_name);
309 new_b_font = pango_font_description_copy(new_r_font);
310 pango_font_description_set_weight(new_b_font, PANGO_WEIGHT_BOLD);
312 if (new_b_font == NULL) {
313 /* Oops, that font didn't work.
314 Tell the user, but don't tear down the font selection
315 dialog, so that they can try again. */
316 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
317 "The font you selected doesn't have a boldface version.");
319 #if GTK_MAJOR_VERSION < 2
320 g_free(bold_font_name);
321 gdk_font_unref(new_r_font);
323 pango_font_description_free(new_r_font);
333 /* Given a font name, construct the name of a version of that font with
334 the current zoom factor applied. */
336 font_zoom(char *gui_font_name)
341 long font_point_size_l;
342 #if GTK_MAJOR_VERSION < 2
348 char *font_set_width;
349 char *font_add_style;
350 char *font_pixel_size;
351 char *font_point_size;
355 char *font_aver_width;
356 char *font_charset_reg;
357 char *font_charset_encoding;
360 if (recent.gui_zoom_level == 0) {
361 /* There is no zoom factor - just return the name, so that if
362 this is GTK+ 1.2[.x] and the font name isn't an XLFD font
363 name, we don't fail. */
364 return g_strdup(gui_font_name);
367 font_name_dup = g_strdup(gui_font_name);
368 font_name_p = font_name_dup;
370 #if GTK_MAJOR_VERSION >= 2
371 /* find the start of the font_size string */
372 font_name_p = strrchr(font_name_dup, ' ');
376 /* calculate the new font size */
377 font_point_size_l = strtol(font_name_p, NULL, 10);
378 font_point_size_l += recent.gui_zoom_level;
380 /* build a new font name */
381 new_font_name = g_strdup_printf("%s %ld", font_name_dup, font_point_size_l);
384 /* replace all '-' chars by NUL and count them */
385 while ((font_name_p = strchr(font_name_p, '-')) != NULL) {
391 if (minus_chars != 14) {
393 * Not a valid XLFD font name.
394 * XXX - can we try scaling it by looking for a size at the end
395 * and tweaking that? Unfortunately, some fonts have numbers
396 * at the end that aren't, as far as I know, sizes, e.g. "nil2".
401 /* first element (font name registry) empty */
402 font_name_p = font_name_dup;
403 font_name_p += strlen(font_name_p);
406 /* get pointers to all font name elements */
407 font_foundry = font_name_p;
408 font_name_p += strlen(font_name_p);
411 font_family = font_name_p;
412 font_name_p += strlen(font_name_p);
415 font_weight = font_name_p;
416 font_name_p += strlen(font_name_p);
419 font_slant = font_name_p;
420 font_name_p += strlen(font_name_p);
423 font_set_width = font_name_p;
424 font_name_p += strlen(font_name_p);
427 font_add_style = font_name_p;
428 font_name_p += strlen(font_name_p);
431 font_pixel_size = font_name_p;
432 font_name_p += strlen(font_name_p);
435 font_point_size = font_name_p;
436 font_name_p += strlen(font_name_p);
439 font_res_x = font_name_p;
440 font_name_p += strlen(font_name_p);
443 font_res_y = font_name_p;
444 font_name_p += strlen(font_name_p);
447 font_spacing = font_name_p;
448 font_name_p += strlen(font_name_p);
451 font_aver_width = font_name_p;
452 font_name_p += strlen(font_name_p);
455 font_charset_reg = font_name_p;
456 font_name_p += strlen(font_name_p);
459 font_charset_encoding = font_name_p;
460 font_name_p += strlen(font_name_p);
463 /* calculate the new font size */
464 font_point_size_l = strtol(font_point_size, NULL, 10);
465 font_point_size_l += recent.gui_zoom_level*10;
466 if (font_point_size_l <= 0)
467 font_point_size_l = 10;
469 /* build a new font name */
470 new_font_name = g_strdup_printf("-%s-%s-%s-%s-%s-%s-%s-%ld-%s-%s-%s-%s-%s-%s",
471 font_foundry, font_family, font_weight, font_slant, font_set_width,
472 font_add_style, font_pixel_size, font_point_size_l, font_res_x,
473 font_res_y, font_spacing, font_aver_width, font_charset_reg,
474 font_charset_encoding);
477 g_free(font_name_dup);
479 return new_font_name;
483 user_font_apply(void) {
485 #if GTK_MAJOR_VERSION < 2
486 char *bold_font_name;
488 FONT_TYPE *new_r_font, *new_b_font;
489 FONT_TYPE *old_r_font = NULL, *old_b_font = NULL;
491 /* convert font name to reflect the zoom level */
492 gui_font_name = font_zoom(prefs.PREFS_GUI_FONT_NAME);
493 if (gui_font_name == NULL) {
495 * This means the font name isn't an XLFD font name.
496 * We just report that for now as a font not available in
499 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
500 "Your current font isn't available in any other sizes.\n");
501 return FA_FONT_NOT_RESIZEABLE;
504 /* load normal and bold font */
505 #if GTK_MAJOR_VERSION < 2
506 new_r_font = gdk_font_load(gui_font_name);
507 bold_font_name = user_font_boldify(gui_font_name);
508 new_b_font = gdk_font_load(bold_font_name);
510 new_r_font = pango_font_description_from_string(gui_font_name);
511 new_b_font = pango_font_description_copy(new_r_font);
512 pango_font_description_set_weight(new_b_font, PANGO_WEIGHT_BOLD);
515 if (new_r_font == NULL || new_b_font == NULL) {
516 /* We're no longer using the new fonts; unreference them. */
517 #if GTK_MAJOR_VERSION < 2
518 if (new_r_font != NULL)
519 gdk_font_unref(new_r_font);
520 if (new_b_font != NULL)
521 gdk_font_unref(new_b_font);
523 if (new_r_font != NULL)
524 pango_font_description_free(new_r_font);
525 if (new_b_font != NULL)
526 pango_font_description_free(new_b_font);
528 g_free(gui_font_name);
530 /* We let our caller pop up a dialog box, as the error message
531 depends on the context (did they zoom in or out, or did they
532 do something else? */
533 return FA_FONT_NOT_AVAILABLE;
536 /* the font(s) seem to be ok */
537 set_plist_font(new_r_font);
538 set_ptree_font_all(new_r_font);
539 old_r_font = m_r_font;
540 old_b_font = m_b_font;
541 set_fonts(new_r_font, new_b_font);
542 #if GTK_MAJOR_VERSION < 2
543 g_free(bold_font_name);
546 /* Redraw the hex dump windows. */
547 redraw_hex_dump_all();
549 /* Redraw the "Follow TCP Stream" windows. */
552 /* We're no longer using the old fonts; unreference them. */
553 #if GTK_MAJOR_VERSION < 2
554 if (old_r_font != NULL)
555 gdk_font_unref(old_r_font);
556 if (old_b_font != NULL)
557 gdk_font_unref(old_b_font);
559 if (old_r_font != NULL)
560 pango_font_description_free(old_r_font);
561 if (old_b_font != NULL)
562 pango_font_description_free(old_b_font);
564 g_free(gui_font_name);
572 #define NAME_BUFFER_LEN 32
574 #if GTK_MAJOR_VERSION < 2
577 /* The setting of the MS default font for system stuff (menus, dialogs, ...),
578 * coming from: Allin Cottrell, http://www.ecn.wfu.edu/~cottrell/gtk_win32,
579 * Thank you very much for this! */
580 static int get_windows_font_gtk1(char *fontspec, int fontspec_len)
585 char name[NAME_BUFFER_LEN];
588 h_dc = CreateDC("DISPLAY", NULL, NULL, NULL);
589 if (h_dc == NULL) return 1;
590 h_font = GetStockObject(DEFAULT_GUI_FONT);
591 if (h_font == NULL || !SelectObject(h_dc, h_font)) {
595 len = GetTextFace(h_dc, NAME_BUFFER_LEN, name);
600 if (!GetTextMetrics(h_dc, &tm)) {
604 pix_height = tm.tmHeight;
606 g_snprintf(fontspec, fontspec_len, "-*-%s-*-*-*-*-%i-*-*-*-p-*-iso8859-1", name,
611 void app_font_gtk1_init(GtkWidget *top_level_w)
616 style = gtk_widget_get_style(top_level_w);
617 if (get_windows_font_gtk1(winfont, sizeof(winfont)) == 0)
618 style->font = gdk_font_load(winfont);
619 if (style->font) gtk_widget_set_style(top_level_w, style);
623 #else /* GTK_MAJOR_VERSION */
624 static char appfontname[128] = "tahoma 8";
627 set_app_font_gtk2(const char *fontname)
629 GtkSettings *settings;
631 if (fontname != NULL && *fontname == 0) return;
633 settings = gtk_settings_get_default();
635 if (fontname == NULL) {
636 g_object_set(G_OBJECT(settings), "gtk-font-name", appfontname, NULL);
639 PangoFontDescription *pfd;
643 w = gtk_label_new(NULL);
644 pfd = pango_font_description_from_string(fontname);
645 pc = gtk_widget_get_pango_context(w);
646 pfont = pango_context_load_font(pc, pfd);
649 strcpy(appfontname, fontname);
650 g_object_set(G_OBJECT(settings), "gtk-font-name", appfontname, NULL);
653 gtk_widget_destroy(w);
654 pango_font_description_free(pfd);
658 static char *default_windows_menu_fontspec_gtk2(void)
660 gchar *fontspec = NULL;
661 NONCLIENTMETRICS ncm;
663 memset(&ncm, 0, sizeof ncm);
664 ncm.cbSize = sizeof ncm;
666 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0)) {
667 HDC screen = GetDC(0);
668 double y_scale = 72.0 / GetDeviceCaps(screen, LOGPIXELSY);
669 int point_size = (int) (ncm.lfMenuFont.lfHeight * y_scale);
671 if (point_size < 0) point_size = -point_size;
672 fontspec = g_strdup_printf("%s %d", ncm.lfMenuFont.lfFaceName,
674 ReleaseDC(0, screen);
680 static void try_to_get_windows_font_gtk2(void)
684 fontspec = default_windows_menu_fontspec_gtk2();
686 if (fontspec != NULL) {
688 PangoFontDescription *pfd;
693 pfd = pango_font_description_from_string(fontspec);
695 w = gtk_label_new(NULL);
696 pc = gtk_widget_get_pango_context(w);
697 pfont = pango_context_load_font(pc, pfd);
698 match = (pfont != NULL);
700 pango_font_description_free(pfd);
701 g_object_unref(G_OBJECT(pc));
702 gtk_widget_destroy(w);
704 if (match) set_app_font_gtk2(fontspec);
708 #endif /* GTK_MAJOR_VERSION */
713 void font_init(gboolean capture_child
719 #if GTK_MAJOR_VERSION < 2
720 gchar *bold_font_name;
724 #if GTK_MAJOR_VERSION >= 2
725 /* try to load the application font for GTK2 */
726 try_to_get_windows_font_gtk2();
730 /* Try to load the regular and boldface fixed-width fonts */
731 #if GTK_MAJOR_VERSION < 2
732 bold_font_name = user_font_boldify(prefs.gui_font_name1);
733 m_r_font = gdk_font_load(prefs.gui_font_name1);
734 m_b_font = gdk_font_load(bold_font_name);
735 if (m_r_font == NULL || m_b_font == NULL) {
736 /* XXX - pop this up as a dialog box? no */
737 if (m_r_font == NULL) {
741 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
742 prefs.gui_font_name1);
744 gdk_font_unref(m_r_font);
746 if (m_b_font == NULL) {
750 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to 6x13 and 6x13bold\n",
753 gdk_font_unref(m_b_font);
755 g_free(bold_font_name);
756 if ((m_r_font = gdk_font_load("6x13")) == NULL) {
757 fprintf(stderr, "ethereal: Error: font 6x13 not found\n");
760 if ((m_b_font = gdk_font_load("6x13bold")) == NULL) {
761 fprintf(stderr, "ethereal: Error: font 6x13bold not found\n");
764 g_free(prefs.gui_font_name1);
765 prefs.gui_font_name1 = g_strdup("6x13");
767 #else /* GTK_MAJOR_VERSION */
768 m_r_font = pango_font_description_from_string(prefs.gui_font_name2);
769 m_b_font = pango_font_description_copy(m_r_font);
770 pango_font_description_set_weight(m_b_font, PANGO_WEIGHT_BOLD);
771 if (m_r_font == NULL || m_b_font == NULL) {
772 /* XXX - pop this up as a dialog box? no */
773 if (m_r_font == NULL) {
777 fprintf(stderr, "ethereal: Warning: font %s not found - defaulting to Monospace 9\n",
778 prefs.gui_font_name2);
780 pango_font_description_free(m_r_font);
782 if (m_b_font == NULL) {
786 fprintf(stderr, "ethereal: Warning: bold font %s not found - defaulting"
787 " to Monospace 9\n", prefs.gui_font_name2);
789 pango_font_description_free(m_b_font);
791 if ((m_r_font = pango_font_description_from_string("Monospace 9")) == NULL)
793 fprintf(stderr, "ethereal: Error: font Monospace 9 not found\n");
796 if ((m_b_font = pango_font_description_copy(m_r_font)) == NULL) {
797 fprintf(stderr, "ethereal: Error: font Monospace 9 bold not found\n");
800 g_free(prefs.gui_font_name2);
801 pango_font_description_set_weight(m_b_font, PANGO_WEIGHT_BOLD);
802 prefs.gui_font_name2 = g_strdup("Monospace 9");
804 #endif /* GTK_MAJOR_VERSION */
806 /* Call this for the side-effects that set_fonts() produces */
807 set_fonts(m_r_font, m_b_font);