gdkfont-x11.c 21.9 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1 2 3 4
/* GDK - The GIMP Drawing Kit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
6 7 8 9 10 11
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15 16 17
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
18
 */
19 20

/*
21
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22 23 24 25 26
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

Manish Singh's avatar
Manish Singh committed
27 28
#undef GDK_DISABLE_DEPRECATED

Elliot Lee's avatar
Elliot Lee committed
29 30
#include <X11/Xlib.h>
#include <X11/Xos.h>
31
#include <locale.h>
32 33 34

#include <pango/pangox.h>

35
#include "gdkx.h"
Owen Taylor's avatar
Started  
Owen Taylor committed
36
#include "gdkfont.h"
37
#include "gdkprivate-x11.h"
38 39 40
#include "gdkinternals.h"
#include "gdkdisplay-x11.h"
#include "gdkscreen-x11.h"
Elliot Lee's avatar
Elliot Lee committed
41

42 43 44 45 46 47 48 49
typedef struct _GdkFontPrivateX        GdkFontPrivateX;

struct _GdkFontPrivateX
{
  GdkFontPrivate base;
  /* XFontStruct *xfont; */
  /* generic pointer point to XFontStruct or XFontSet */
  gpointer xfont;
50
  GdkDisplay *display;
51 52 53 54

  GSList *names;
};

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
static GHashTable *
gdk_font_name_hash_get (GdkDisplay *display)
{
  GHashTable *result;
  static GQuark font_name_quark = 0;

  if (!font_name_quark)
    font_name_quark = g_quark_from_static_string ("gdk-font-hash");

  result = g_object_get_qdata (G_OBJECT (display), font_name_quark);

  if (!result)
    {
      result = g_hash_table_new (g_str_hash, g_str_equal);
      g_object_set_qdata (G_OBJECT (display), font_name_quark, result);
    }

  return result;
}

static GHashTable *
gdk_fontset_name_hash_get (GdkDisplay *display)
{
  GHashTable *result;
  static GQuark fontset_name_quark = 0;
  
  if (!fontset_name_quark)
    fontset_name_quark = g_quark_from_static_string ("gdk-fontset-hash");

  result = g_object_get_qdata (G_OBJECT (display), fontset_name_quark);

  if (!result)
    {
      result = g_hash_table_new (g_str_hash, g_str_equal);
      g_object_set_qdata (G_OBJECT (display), fontset_name_quark, result);
    }

  return result;
}

/** 
 * gdk_font_get_display:
 * @font: the #GdkFont.
 *
 * Returns the #GdkDisplay for @font.
 *
 * Returns : the corresponding #GdkDisplay.
 **/
GdkDisplay* 
gdk_font_get_display (GdkFont* font)
{
  return ((GdkFontPrivateX *)font)->display;
}
108 109

static void
110 111 112
gdk_font_hash_insert (GdkFontType  type, 
		      GdkFont     *font, 
		      const gchar *font_name)
113
{
114
  GdkFontPrivateX *private = (GdkFontPrivateX *)font;
115 116
  GHashTable *hash = (type == GDK_FONT_FONT) ?
    gdk_font_name_hash_get (private->display) : gdk_fontset_name_hash_get (private->display);
117 118

  private->names = g_slist_prepend (private->names, g_strdup (font_name));
119
  g_hash_table_insert (hash, private->names->data, font);
120 121 122
}

static void
123 124
gdk_font_hash_remove (GdkFontType type, 
		      GdkFont    *font)
125
{
126
  GdkFontPrivateX *private = (GdkFontPrivateX *)font;
127 128
  GSList *tmp_list;
  GHashTable *hash = (type == GDK_FONT_FONT) ?
129
    gdk_font_name_hash_get (private->display) : gdk_fontset_name_hash_get (private->display);
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144

  tmp_list = private->names;
  while (tmp_list)
    {
      g_hash_table_remove (hash, tmp_list->data);
      g_free (tmp_list->data);
      
      tmp_list = tmp_list->next;
    }

  g_slist_free (private->names);
  private->names = NULL;
}

static GdkFont *
145 146 147
gdk_font_hash_lookup (GdkDisplay  *display, 
		      GdkFontType  type, 
		      const gchar *font_name)
148 149
{
  GdkFont *result;
150 151
  GHashTable *hash;
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
152

153 154
  hash = (type == GDK_FONT_FONT) ? gdk_font_name_hash_get (display) : 
				   gdk_fontset_name_hash_get (display);
155 156 157 158 159 160 161 162 163 164 165 166
  if (!hash)
    return NULL;
  else
    {
      result = g_hash_table_lookup (hash, font_name);
      if (result)
	gdk_font_ref (result);
      
      return result;
    }
}

Matthias Clasen's avatar
Matthias Clasen committed
167 168 169 170 171 172 173 174 175 176 177
/**
 * gdk_font_load_for_display:
 * @display: a #GdkDisplay
 * @font_name: a XLFD describing the font to load.
 * @returns: a #GdkFont, or %NULL if the font could not be loaded.
 *
 * Loads a font for use on @display.
 *
 * The font may be newly loaded or looked up the font in a cache. 
 * You should make no assumptions about the initial reference count.
 */
178 179 180
GdkFont *
gdk_font_load_for_display (GdkDisplay  *display, 
			   const gchar *font_name)
Elliot Lee's avatar
Elliot Lee committed
181 182
{
  GdkFont *font;
183
  GdkFontPrivateX *private;
184
  XFontStruct *xfont;
Elliot Lee's avatar
Elliot Lee committed
185

186
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
187
  g_return_val_if_fail (font_name != NULL, NULL);
188 189
  
  font = gdk_font_hash_lookup (display, GDK_FONT_FONT, font_name);
190 191 192
  if (font)
    return font;

193
  xfont = XLoadQueryFont (GDK_DISPLAY_XDISPLAY (display), font_name);
194 195
  if (xfont == NULL)
    return NULL;
Elliot Lee's avatar
Elliot Lee committed
196

197 198
  font = gdk_font_lookup_for_display (display, xfont->fid);
  if (font != NULL) 
Elliot Lee's avatar
Elliot Lee committed
199
    {
200
      private = (GdkFontPrivateX *) font;
201
      if (xfont != private->xfont)
202
	XFreeFont (GDK_DISPLAY_XDISPLAY (display), xfont);
203 204

      gdk_font_ref (font);
Elliot Lee's avatar
Elliot Lee committed
205 206 207
    }
  else
    {
208
      private = g_new (GdkFontPrivateX, 1);
209
      private->display = display;
210
      private->xfont = xfont;
211
      private->base.ref_count = 1;
212 213
      private->names = NULL;
 
214
      font = (GdkFont*) private;
Elliot Lee's avatar
Elliot Lee committed
215
      font->type = GDK_FONT_FONT;
216 217
      font->ascent =  xfont->ascent;
      font->descent = xfont->descent;
218 219
      
      _gdk_xid_table_insert (display, &xfont->fid, font);
220
    }
Elliot Lee's avatar
Elliot Lee committed
221

222 223
  gdk_font_hash_insert (GDK_FONT_FONT, font, font_name);

Elliot Lee's avatar
Elliot Lee committed
224 225 226
  return font;
}

227
static char *
228
gdk_font_charset_for_locale (void)
229 230 231
{
  static char *charset_map[][2] = {
    { "ANSI_X3.4-1968", "iso8859-1" },
232
    { "US-ASCII",   "iso8859-1" },
233 234 235 236 237 238 239 240 241
    { "ISO-8859-1", "iso8859-1" },
    { "ISO-8859-2", "iso8859-2" },
    { "ISO-8859-3", "iso8859-3" },
    { "ISO-8859-4", "iso8859-4" },
    { "ISO-8859-5", "iso8859-5" },
    { "ISO-8859-6", "iso8859-6" },
    { "ISO-8859-7", "iso8859-7" },
    { "ISO-8859-8", "iso8859-8" },
    { "ISO-8859-9", "iso8859-9" },
242
    { "UTF-8",      "iso8859-1" }
243 244
  };

245
  const char *codeset;
246 247
  char *result = NULL;
  int i;
248 249

  g_get_charset (&codeset);
250 251 252 253 254 255 256 257 258 259 260
  
  for (i=0; i < G_N_ELEMENTS (charset_map); i++)
    if (strcmp (charset_map[i][0], codeset) == 0)
      {
	result = charset_map[i][1];
	break;
      }

  if (result)
    return g_strdup (result);
  else
261
    return g_strdup ("iso8859-1");
262
}
263

Matthias Clasen's avatar
Matthias Clasen committed
264 265 266 267 268 269 270 271 272 273 274 275 276 277
/**
 * gdk_font_from_description_for_display:
 * @display: a #GdkDisplay
 * @font_desc: a #PangoFontDescription.
 * 
 * Loads a #GdkFont based on a Pango font description for use on @display. 
 * This font will only be an approximation of the Pango font, and
 * internationalization will not be handled correctly. This function
 * should only be used for legacy code that cannot be easily converted
 * to use Pango. Using Pango directly will produce better results.
 * 
 * Return value: the newly loaded font, or %NULL if the font
 * cannot be loaded.
 */
278 279 280
GdkFont *
gdk_font_from_description_for_display (GdkDisplay           *display,
				       PangoFontDescription *font_desc)
281 282 283 284 285
{
  PangoFontMap *font_map;
  PangoFont *font;
  GdkFont *result = NULL;

286
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
287 288
  g_return_val_if_fail (font_desc != NULL, NULL);

289
  font_map = pango_x_font_map_for_display (GDK_DISPLAY_XDISPLAY (display));
Alex Larsson's avatar
Alex Larsson committed
290
  font = pango_font_map_load_font (font_map, NULL, font_desc);
291 292 293 294 295 296 297 298 299 300 301 302 303

  if (font)
    {
      gchar *charset = gdk_font_charset_for_locale ();
      gint n_subfonts;
      PangoXSubfont *subfont_ids;
      gint *subfont_charsets;

      n_subfonts = pango_x_list_subfonts (font, &charset, 1,
					  &subfont_ids, &subfont_charsets);
      if (n_subfonts > 0)
	{
	  gchar *xlfd = pango_x_font_subfont_xlfd (font, subfont_ids[0]);
304
	  result = gdk_font_load_for_display (display, xlfd);
305 306 307 308 309

	  g_free (xlfd);
	}

      g_free (subfont_ids);
310

311 312 313
      g_free (subfont_charsets);

      g_free (charset);
314
      g_object_unref (font);
315 316 317 318 319
    }

  return result;
}

Matthias Clasen's avatar
Matthias Clasen committed
320 321 322 323 324 325 326 327 328 329 330 331
/**
 * gdk_fontset_load_for_display:
 * @display: a #GdkDisplay
 * @fontset_name: a comma-separated list of XLFDs describing
 *   the component fonts of the fontset to load.
 * @returns: a #GdkFont, or %NULL if the fontset could not be loaded.
 * 
 * Loads a fontset for use on @display.
 *
 * The fontset may be newly loaded or looked up in a cache. 
 * You should make no assumptions about the initial reference count.
 */
332 333 334
GdkFont *
gdk_fontset_load_for_display (GdkDisplay  *display,
			      const gchar *fontset_name)
Elliot Lee's avatar
Elliot Lee committed
335 336
{
  GdkFont *font;
337
  GdkFontPrivateX *private;
Elliot Lee's avatar
Elliot Lee committed
338 339 340 341 342
  XFontSet fontset;
  gint  missing_charset_count;
  gchar **missing_charset_list;
  gchar *def_string;

343 344 345
  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
  
  font = gdk_font_hash_lookup (display, GDK_FONT_FONTSET, fontset_name);
346 347 348
  if (font)
    return font;

349
  private = g_new (GdkFontPrivateX, 1);
Elliot Lee's avatar
Elliot Lee committed
350 351
  font = (GdkFont*) private;

352 353
  private->display = display;
  fontset = XCreateFontSet (GDK_DISPLAY_XDISPLAY (display), fontset_name,
Elliot Lee's avatar
Elliot Lee committed
354 355 356 357 358
			    &missing_charset_list, &missing_charset_count,
			    &def_string);

  if (missing_charset_count)
    {
359
      gint i;
360 361
      g_printerr ("The font \"%s\" does not support all the required character sets for the current locale \"%s\"\n",
                 fontset_name, setlocale (LC_ALL, NULL));
362
      for (i=0;i<missing_charset_count;i++)
363 364
	g_printerr ("  (Missing character set \"%s\")\n",
                    missing_charset_list[i]);
Elliot Lee's avatar
Elliot Lee committed
365 366 367
      XFreeStringList (missing_charset_list);
    }

368
  private->base.ref_count = 1;
Elliot Lee's avatar
Elliot Lee committed
369 370 371 372 373 374 375 376

  if (!fontset)
    {
      g_free (font);
      return NULL;
    }
  else
    {
377 378 379 380 381
      gint num_fonts;
      gint i;
      XFontStruct **font_structs;
      gchar **font_names;
      
Elliot Lee's avatar
Elliot Lee committed
382 383
      private->xfont = fontset;
      font->type = GDK_FONT_FONTSET;
384 385 386 387 388 389 390 391 392
      num_fonts = XFontsOfFontSet (fontset, &font_structs, &font_names);

      font->ascent = font->descent = 0;
      
      for (i = 0; i < num_fonts; i++)
	{
	  font->ascent = MAX (font->ascent, font_structs[i]->ascent);
	  font->descent = MAX (font->descent, font_structs[i]->descent);
	}
393
 
394 395 396 397
      private->names = NULL;
      gdk_font_hash_insert (GDK_FONT_FONTSET, font, fontset_name);
      
      return font;
Elliot Lee's avatar
Elliot Lee committed
398 399
    }
}
400

401 402 403 404 405 406 407 408 409 410 411 412
/**
 * gdk_fontset_load:
 * @fontset_name: a comma-separated list of XLFDs describing
 *     the component fonts of the fontset to load.
 * 
 * Loads a fontset.
 *
 * The fontset may be newly loaded or looked up in a cache. 
 * You should make no assumptions about the initial reference count.
 * 
 * Return value: a #GdkFont, or %NULL if the fontset could not be loaded.
 **/
413 414 415
GdkFont*
gdk_fontset_load (const gchar *fontset_name)
{
Owen Taylor's avatar
Owen Taylor committed
416
  return gdk_fontset_load_for_display (gdk_display_get_default (), fontset_name);
417 418
}

419 420
void
_gdk_font_destroy (GdkFont *font)
Elliot Lee's avatar
Elliot Lee committed
421
{
422 423 424 425 426 427 428
  GdkFontPrivateX *private = (GdkFontPrivateX *)font;
  
  gdk_font_hash_remove (font->type, font);
      
  switch (font->type)
    {
    case GDK_FONT_FONT:
429 430 431
      _gdk_xid_table_remove (private->display, ((XFontStruct *) private->xfont)->fid);
      XFreeFont (GDK_DISPLAY_XDISPLAY (private->display),
		  (XFontStruct *) private->xfont);
432 433
      break;
    case GDK_FONT_FONTSET:
434 435
      XFreeFontSet (GDK_DISPLAY_XDISPLAY (private->display),
		    (XFontSet) private->xfont);
436 437 438 439 440 441
      break;
    default:
      g_error ("unknown font type.");
      break;
    }
  g_free (font);
Elliot Lee's avatar
Elliot Lee committed
442 443
}

444 445 446
gint
_gdk_font_strlen (GdkFont     *font,
		  const gchar *str)
Elliot Lee's avatar
Elliot Lee committed
447
{
448 449
  GdkFontPrivateX *font_private;
  gint length = 0;
Elliot Lee's avatar
Elliot Lee committed
450

451 452
  g_return_val_if_fail (font != NULL, -1);
  g_return_val_if_fail (str != NULL, -1);
Elliot Lee's avatar
Elliot Lee committed
453

454 455 456
  font_private = (GdkFontPrivateX*) font;

  if (font->type == GDK_FONT_FONT)
Elliot Lee's avatar
Elliot Lee committed
457
    {
458 459
      XFontStruct *xfont = (XFontStruct *) font_private->xfont;
      if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
460
	{
461
	  length = strlen (str);
462
	}
463 464 465 466 467 468 469 470 471 472 473
      else
	{
	  guint16 *string_2b = (guint16 *)str;
	    
	  while (*(string_2b++))
	    length++;
	}
    }
  else if (font->type == GDK_FONT_FONTSET)
    {
      length = strlen (str);
Elliot Lee's avatar
Elliot Lee committed
474
    }
475 476 477 478
  else
    g_error("undefined font type\n");

  return length;
Elliot Lee's avatar
Elliot Lee committed
479 480
}

481 482 483 484 485 486 487 488
/**
 * gdk_font_id:
 * @font: a #GdkFont.
 * 
 * Returns the X Font ID for the given font. 
 * 
 * Return value: the numeric X Font ID
 **/
Elliot Lee's avatar
Elliot Lee committed
489
gint
490
gdk_font_id (const GdkFont *font)
Elliot Lee's avatar
Elliot Lee committed
491
{
492
  const GdkFontPrivateX *font_private;
Elliot Lee's avatar
Elliot Lee committed
493 494 495

  g_return_val_if_fail (font != NULL, 0);

496
  font_private = (const GdkFontPrivateX*) font;
Elliot Lee's avatar
Elliot Lee committed
497 498 499 500 501 502 503 504 505 506 507

  if (font->type == GDK_FONT_FONT)
    {
      return ((XFontStruct *) font_private->xfont)->fid;
    }
  else
    {
      return 0;
    }
}

508 509 510 511 512 513 514 515 516 517 518
/**
 * gdk_font_equal:
 * @fonta: a #GdkFont.
 * @fontb: another #GdkFont.
 * 
 * Compares two fonts for equality. Single fonts compare equal
 * if they have the same X font ID. This operation does
 * not currently work correctly for fontsets.
 * 
 * Return value: %TRUE if the fonts are equal.
 **/
Owen Taylor's avatar
Owen Taylor committed
519
gboolean
520 521
gdk_font_equal (const GdkFont *fonta,
                const GdkFont *fontb)
Elliot Lee's avatar
Elliot Lee committed
522
{
523 524
  const GdkFontPrivateX *privatea;
  const GdkFontPrivateX *privateb;
Elliot Lee's avatar
Elliot Lee committed
525 526 527 528

  g_return_val_if_fail (fonta != NULL, FALSE);
  g_return_val_if_fail (fontb != NULL, FALSE);

529 530
  privatea = (const GdkFontPrivateX*) fonta;
  privateb = (const GdkFontPrivateX*) fontb;
Elliot Lee's avatar
Elliot Lee committed
531 532 533 534 535 536 537 538

  if (fonta->type == GDK_FONT_FONT && fontb->type == GDK_FONT_FONT)
    {
      return (((XFontStruct *) privatea->xfont)->fid ==
	      ((XFontStruct *) privateb->xfont)->fid);
    }
  else if (fonta->type == GDK_FONT_FONTSET && fontb->type == GDK_FONT_FONTSET)
    {
539 540 541 542 543 544
      gchar *namea, *nameb;

      namea = XBaseFontNameListOfFontSet((XFontSet) privatea->xfont);
      nameb = XBaseFontNameListOfFontSet((XFontSet) privateb->xfont);
      
      return (strcmp(namea, nameb) == 0);
Elliot Lee's avatar
Elliot Lee committed
545 546 547 548 549 550
    }
  else
    /* fontset != font */
    return 0;
}

551 552 553 554 555 556 557 558 559 560
/**
 * gdk_text_width:
 * @font: a #GdkFont
 * @text: the text to measure.
 * @text_length: the length of the text in bytes.
 * 
 * Determines the width of a given string.
 * 
 * Return value: the width of the string in pixels.
 **/
Elliot Lee's avatar
Elliot Lee committed
561 562 563 564 565
gint
gdk_text_width (GdkFont      *font,
		const gchar  *text,
		gint          text_length)
{
566
  GdkFontPrivateX *private;
Elliot Lee's avatar
Elliot Lee committed
567 568 569 570 571 572 573
  gint width;
  XFontStruct *xfont;
  XFontSet fontset;

  g_return_val_if_fail (font != NULL, -1);
  g_return_val_if_fail (text != NULL, -1);

574
  private = (GdkFontPrivateX*) font;
Elliot Lee's avatar
Elliot Lee committed
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598

  switch (font->type)
    {
    case GDK_FONT_FONT:
      xfont = (XFontStruct *) private->xfont;
      if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
	{
	  width = XTextWidth (xfont, text, text_length);
	}
      else
	{
	  width = XTextWidth16 (xfont, (XChar2b *) text, text_length / 2);
	}
      break;
    case GDK_FONT_FONTSET:
      fontset = (XFontSet) private->xfont;
      width = XmbTextEscapement (fontset, text, text_length);
      break;
    default:
      width = 0;
    }
  return width;
}

599 600 601 602 603 604 605 606 607 608
/**
 * gdk_text_width_wc:
 * @font: a #GdkFont
 * @text: the text to measure.
 * @text_length: the length of the text in characters.
 * 
 * Determines the width of a given wide-character string.
 * 
 * Return value: the width of the string in pixels.
 **/
609 610 611 612 613
gint
gdk_text_width_wc (GdkFont	  *font,
		   const GdkWChar *text,
		   gint		   text_length)
{
614
  GdkFontPrivateX *private;
615 616 617 618 619 620 621
  gint width;
  XFontStruct *xfont;
  XFontSet fontset;

  g_return_val_if_fail (font != NULL, -1);
  g_return_val_if_fail (text != NULL, -1);

622
  private = (GdkFontPrivateX*) font;
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664

  switch (font->type)
    {
    case GDK_FONT_FONT:
      xfont = (XFontStruct *) private->xfont;
      if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
        {
          gchar *text_8bit;
          gint i;
          text_8bit = g_new (gchar, text_length);
          for (i=0; i<text_length; i++) text_8bit[i] = text[i];
          width = XTextWidth (xfont, text_8bit, text_length);
          g_free (text_8bit);
        }
      else
        {
          width = 0;
        }
      break;
    case GDK_FONT_FONTSET:
      if (sizeof(GdkWChar) == sizeof(wchar_t))
	{
	  fontset = (XFontSet) private->xfont;
	  width = XwcTextEscapement (fontset, (wchar_t *)text, text_length);
	}
      else
	{
	  wchar_t *text_wchar;
	  gint i;
	  fontset = (XFontSet) private->xfont;
	  text_wchar = g_new(wchar_t, text_length);
	  for (i=0; i<text_length; i++) text_wchar[i] = text[i];
	  width = XwcTextEscapement (fontset, text_wchar, text_length);
	  g_free (text_wchar);
	}
      break;
    default:
      width = 0;
    }
  return width;
}

665 666 667 668 669 670 671 672 673 674 675 676 677
/**
 * gdk_text_extents:
 * @font: a #GdkFont
 * @text: the text to measure
 * @text_length: the length of the text in bytes. (If the
 *    font is a 16-bit font, this is twice the length
 *    of the text in characters.)
 * @lbearing: the left bearing of the string.
 * @rbearing: the right bearing of the string.
 * @width: the width of the string.
 * @ascent: the ascent of the string.
 * @descent: the descent of the string.
 * 
678
 * Gets the metrics of a string.
679
 **/
680 681 682 683 684 685 686 687 688 689
void
gdk_text_extents (GdkFont     *font,
                  const gchar *text,
                  gint         text_length,
		  gint        *lbearing,
		  gint        *rbearing,
		  gint        *width,
		  gint        *ascent,
		  gint        *descent)
{
690
  GdkFontPrivateX *private;
691 692 693 694 695 696 697 698 699 700 701
  XCharStruct overall;
  XFontStruct *xfont;
  XFontSet    fontset;
  XRectangle  ink, logical;
  int direction;
  int font_ascent;
  int font_descent;

  g_return_if_fail (font != NULL);
  g_return_if_fail (text != NULL);

702
  private = (GdkFontPrivateX*) font;
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734

  switch (font->type)
    {
    case GDK_FONT_FONT:
      xfont = (XFontStruct *) private->xfont;
      if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0))
	{
	  XTextExtents (xfont, text, text_length,
			&direction, &font_ascent, &font_descent,
			&overall);
	}
      else
	{
	  XTextExtents16 (xfont, (XChar2b *) text, text_length / 2,
			  &direction, &font_ascent, &font_descent,
			  &overall);
	}
      if (lbearing)
	*lbearing = overall.lbearing;
      if (rbearing)
	*rbearing = overall.rbearing;
      if (width)
	*width = overall.width;
      if (ascent)
	*ascent = overall.ascent;
      if (descent)
	*descent = overall.descent;
      break;
    case GDK_FONT_FONTSET:
      fontset = (XFontSet) private->xfont;
      XmbTextExtents (fontset, text, text_length, &ink, &logical);
      if (lbearing)
735
	*lbearing = ink.x;
736
      if (rbearing)
737
	*rbearing = ink.x + ink.width;
738 739 740
      if (width)
	*width = logical.width;
      if (ascent)
741
	*ascent = -ink.y;
742
      if (descent)
743
	*descent = ink.y + ink.height;
744 745 746 747 748
      break;
    }

}

749 750 751 752 753 754 755 756 757 758 759
/**
 * gdk_text_extents_wc:
 * @font: a #GdkFont
 * @text: the text to measure.
 * @text_length: the length of the text in character.
 * @lbearing: the left bearing of the string.
 * @rbearing: the right bearing of the string.
 * @width: the width of the string.
 * @ascent: the ascent of the string.
 * @descent: the descent of the string.
 * 
760
 * Gets the metrics of a string of wide characters.
761
 **/
Owen Taylor's avatar
Owen Taylor committed
762 763 764 765 766 767 768 769 770 771
void
gdk_text_extents_wc (GdkFont        *font,
		     const GdkWChar *text,
		     gint            text_length,
		     gint           *lbearing,
		     gint           *rbearing,
		     gint           *width,
		     gint           *ascent,
		     gint           *descent)
{
772
  GdkFontPrivateX *private;
Owen Taylor's avatar
Owen Taylor committed
773 774 775 776 777 778 779 780 781 782 783
  XCharStruct overall;
  XFontStruct *xfont;
  XFontSet    fontset;
  XRectangle  ink, logical;
  int direction;
  int font_ascent;
  int font_descent;

  g_return_if_fail (font != NULL);
  g_return_if_fail (text != NULL);

784
  private = (GdkFontPrivateX*) font;
Owen Taylor's avatar
Owen Taylor committed
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818

  switch (font->type)
    {
    case GDK_FONT_FONT:
      {
	gchar *text_8bit;
	gint i;

	xfont = (XFontStruct *) private->xfont;
	g_return_if_fail ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0));

	text_8bit = g_new (gchar, text_length);
	for (i=0; i<text_length; i++) 
	  text_8bit[i] = text[i];

	XTextExtents (xfont, text_8bit, text_length,
		      &direction, &font_ascent, &font_descent,
		      &overall);
	g_free (text_8bit);
	
	if (lbearing)
	  *lbearing = overall.lbearing;
	if (rbearing)
	  *rbearing = overall.rbearing;
	if (width)
	  *width = overall.width;
	if (ascent)
	  *ascent = overall.ascent;
	if (descent)
	  *descent = overall.descent;
	break;
      }
    case GDK_FONT_FONTSET:
      fontset = (XFontSet) private->xfont;
819 820 821 822 823 824 825 826 827 828 829 830 831 832

      if (sizeof(GdkWChar) == sizeof(wchar_t))
	XwcTextExtents (fontset, (wchar_t *)text, text_length, &ink, &logical);
      else
	{
	  wchar_t *text_wchar;
	  gint i;
	  
	  text_wchar = g_new (wchar_t, text_length);
	  for (i = 0; i < text_length; i++)
	    text_wchar[i] = text[i];
	  XwcTextExtents (fontset, text_wchar, text_length, &ink, &logical);
	  g_free (text_wchar);
	}
Owen Taylor's avatar
Owen Taylor committed
833 834 835 836 837 838 839 840 841 842 843 844 845 846
      if (lbearing)
	*lbearing = ink.x;
      if (rbearing)
	*rbearing = ink.x + ink.width;
      if (width)
	*width = logical.width;
      if (ascent)
	*ascent = -ink.y;
      if (descent)
	*descent = ink.y + ink.height;
      break;
    }

}
847

Matthias Clasen's avatar
Matthias Clasen committed
848 849 850 851 852 853 854 855
/**
 * gdk_x11_font_get_xdisplay:
 * @font: a #GdkFont.
 * 
 * Returns the display of a #GdkFont.
 * 
 * Return value:  an Xlib <type>Display*</type>.
 **/
856 857 858 859 860
Display *
gdk_x11_font_get_xdisplay (GdkFont *font)
{
  g_return_val_if_fail (font != NULL, NULL);

861
  return GDK_DISPLAY_XDISPLAY (((GdkFontPrivateX *)font)->display);
862 863
}

Matthias Clasen's avatar
Matthias Clasen committed
864 865 866 867 868 869 870 871
/**
 * gdk_x11_font_get_xfont:
 * @font: a #GdkFont.
 * 
 * Returns the X font belonging to a #GdkFont.
 * 
 * Return value: an Xlib <type>XFontStruct*</type> or an <type>XFontSet</type>.
 **/
872 873 874 875 876 877 878 879
gpointer
gdk_x11_font_get_xfont (GdkFont *font)
{
  g_return_val_if_fail (font != NULL, NULL);

  return ((GdkFontPrivateX *)font)->xfont;
}

880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903
/**
 * gdk_x11_font_get_name:
 * @font: a #GdkFont.
 * 
 * Return the X Logical Font Description (for font->type == GDK_FONT_FONT)
 * or comma separated list of XLFDs (for font->type == GDK_FONT_FONTSET)
 * that was used to load the font. If the same font was loaded
 * via multiple names, which name is returned is undefined.
 * 
 * Return value: the name of the font. This string is owned
 *   by GDK and must not be modified or freed.
 **/
G_CONST_RETURN char *
gdk_x11_font_get_name (GdkFont *font)
{
  GdkFontPrivateX *private = (GdkFontPrivateX *)font;

  g_return_val_if_fail (font != NULL, NULL);

  g_assert (private->names);

  return private->names->data;
}