]> code.delx.au - gnu-emacs/blobdiff - src/xfns.c
Rewritten to take advantage of shy-groups and
[gnu-emacs] / src / xfns.c
index 2873b09720f6c95d6eb41630a2377333d0ee859e..cf2ba14bb956aa6baca6c140aa3f759db739c68e 100644 (file)
@@ -236,7 +236,7 @@ Lisp_Object Quser_position;
 Lisp_Object Quser_size;
 extern Lisp_Object Qdisplay;
 Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background;
-Lisp_Object Qscreen_gamma;
+Lisp_Object Qscreen_gamma, Qline_spacing, Qcenter;
 
 /* The below are defined in frame.c.  */
 
@@ -740,6 +740,7 @@ struct x_frame_parm_table
 
 static void x_create_im P_ ((struct frame *));
 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
+static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
@@ -775,30 +776,31 @@ static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
 
 static struct x_frame_parm_table x_frame_parms[] =
 {
-  "auto-raise", x_set_autoraise,
-  "auto-lower", x_set_autolower,
-  "background-color", x_set_background_color,
-  "border-color", x_set_border_color,
-  "border-width", x_set_border_width,
-  "cursor-color", x_set_cursor_color,
-  "cursor-type", x_set_cursor_type,
-  "font", x_set_font,
-  "foreground-color", x_set_foreground_color,
-  "icon-name", x_set_icon_name,
-  "icon-type", x_set_icon_type,
-  "internal-border-width", x_set_internal_border_width,
-  "menu-bar-lines", x_set_menu_bar_lines,
-  "mouse-color", x_set_mouse_color,
-  "name", x_explicitly_set_name,
-  "scroll-bar-width", x_set_scroll_bar_width,
-  "title", x_set_title,
-  "unsplittable", x_set_unsplittable,
-  "vertical-scroll-bars", x_set_vertical_scroll_bars,
-  "visibility", x_set_visibility,
-  "tool-bar-lines", x_set_tool_bar_lines,
-  "scroll-bar-foreground", x_set_scroll_bar_foreground,
-  "scroll-bar-background", x_set_scroll_bar_background,
-  "screen-gamma", x_set_screen_gamma
+  "auto-raise",                        x_set_autoraise,
+  "auto-lower",                        x_set_autolower,
+  "background-color",          x_set_background_color,
+  "border-color",              x_set_border_color,
+  "border-width",              x_set_border_width,
+  "cursor-color",              x_set_cursor_color,
+  "cursor-type",               x_set_cursor_type,
+  "font",                      x_set_font,
+  "foreground-color",          x_set_foreground_color,
+  "icon-name",                 x_set_icon_name,
+  "icon-type",                 x_set_icon_type,
+  "internal-border-width",     x_set_internal_border_width,
+  "menu-bar-lines",            x_set_menu_bar_lines,
+  "mouse-color",               x_set_mouse_color,
+  "name",                      x_explicitly_set_name,
+  "scroll-bar-width",          x_set_scroll_bar_width,
+  "title",                     x_set_title,
+  "unsplittable",              x_set_unsplittable,
+  "vertical-scroll-bars",      x_set_vertical_scroll_bars,
+  "visibility",                        x_set_visibility,
+  "tool-bar-lines",            x_set_tool_bar_lines,
+  "scroll-bar-foreground",     x_set_scroll_bar_foreground,
+  "scroll-bar-background",     x_set_scroll_bar_background,
+  "screen-gamma",              x_set_screen_gamma,
+  "line-spacing",              x_set_line_spacing
 };
 
 /* Attach the `x-frame-parameter' properties to
@@ -1288,6 +1290,26 @@ x_decode_color (f, color_name, mono_color)
 
 
 \f
+/* Change the `line-spacing' frame parameter of frame F.  OLD_VALUE is
+   the previous value of that parameter, NEW_VALUE is the new value.  */
+
+static void
+x_set_line_spacing (f, new_value, old_value)
+     struct frame *f;
+     Lisp_Object new_value, old_value;
+{
+  if (NILP (new_value))
+    f->extra_line_spacing = 0;
+  else if (NATNUMP (new_value))
+    f->extra_line_spacing = XFASTINT (new_value);
+  else
+    Fsignal (Qerror, Fcons (build_string ("Illegal line-spacing"),
+                           Fcons (new_value, Qnil)));
+  if (FRAME_VISIBLE_P (f))
+    redraw_frame (f);
+}
+
+
 /* Change the `screen-gamma' frame parameter of frame F.  OLD_VALUE is
    the previous value of that parameter, NEW_VALUE is the new value.  */
 
@@ -1520,26 +1542,49 @@ x_set_cursor_color (f, arg, oldval)
      Lisp_Object arg, oldval;
 {
   unsigned long fore_pixel, pixel;
+  int fore_pixel_allocated_p = 0, pixel_allocated_p = 0;
 
-  if (!EQ (Vx_cursor_fore_pixel, Qnil))
-    fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
-                                WHITE_PIX_DEFAULT (f));
+  if (!NILP (Vx_cursor_fore_pixel))
+    {
+      fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
+                                  WHITE_PIX_DEFAULT (f));
+      fore_pixel_allocated_p = 1;
+    }
   else
     fore_pixel = f->output_data.x->background_pixel;
+  
   pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
+  pixel_allocated_p = 1;
 
   /* Make sure that the cursor color differs from the background color.  */
   if (pixel == f->output_data.x->background_pixel)
     {
+      if (pixel_allocated_p)
+       {
+         x_free_colors (f, &pixel, 1);
+         pixel_allocated_p = 0;
+       }
+      
       pixel = f->output_data.x->mouse_pixel;
       if (pixel == fore_pixel)
-       fore_pixel = f->output_data.x->background_pixel;
+       {
+         if (fore_pixel_allocated_p)
+           {
+             x_free_colors (f, &fore_pixel, 1);
+             fore_pixel_allocated_p = 0;
+           }
+         fore_pixel = f->output_data.x->background_pixel;
+       }
     }
 
   unload_color (f, f->output_data.x->cursor_foreground_pixel);
+  if (!fore_pixel_allocated_p)
+    fore_pixel = x_copy_color (f, fore_pixel);
   f->output_data.x->cursor_foreground_pixel = fore_pixel;
 
   unload_color (f, f->output_data.x->cursor_pixel);
+  if (!pixel_allocated_p)
+    pixel = x_copy_color (f, pixel);
   f->output_data.x->cursor_pixel = pixel;
 
   if (FRAME_X_WINDOW (f) != 0)
@@ -1609,31 +1654,51 @@ x_set_border_pixel (f, pix)
     }
 }
 
-void
-x_set_cursor_type (f, arg, oldval)
-     FRAME_PTR f;
-     Lisp_Object arg, oldval;
+
+/* Value is the internal representation of the specified cursor type
+   ARG.  If type is BAR_CURSOR, return in *WIDTH the specified width
+   of the bar cursor.  */
+
+enum text_cursor_kinds
+x_specified_cursor_type (arg, width)
+     Lisp_Object arg;
+     int *width;
 {
+  enum text_cursor_kinds type;
+  
   if (EQ (arg, Qbar))
     {
-      FRAME_DESIRED_CURSOR (f) = BAR_CURSOR;
-      f->output_data.x->cursor_width = 2;
+      type = BAR_CURSOR;
+      *width = 2;
     }
   else if (CONSP (arg)
           && EQ (XCAR (arg), Qbar)
           && INTEGERP (XCDR (arg))
           && XINT (XCDR (arg)) >= 0)
     {
-      FRAME_DESIRED_CURSOR (f) = BAR_CURSOR;
-      f->output_data.x->cursor_width = XINT (XCDR (arg));
+      type = BAR_CURSOR;
+      *width = XINT (XCDR (arg));
     }
   else if (NILP (arg))
-    FRAME_DESIRED_CURSOR (f) = NO_CURSOR;
+    type = NO_CURSOR;
   else
     /* Treat anything unknown as "box cursor".
        It was bad to signal an error; people have trouble fixing
        .Xdefaults with Emacs, when it has something bad in it.  */
-    FRAME_DESIRED_CURSOR (f) = FILLED_BOX_CURSOR;
+    type = FILLED_BOX_CURSOR;
+
+  return type;
+}
+
+void
+x_set_cursor_type (f, arg, oldval)
+     FRAME_PTR f;
+     Lisp_Object arg, oldval;
+{
+  int width;
+  
+  FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
+  f->output_data.x->cursor_width = width;
 
   /* Make sure the cursor gets redrawn.  This is overkill, but how
      often do people change cursor types?  */
@@ -3979,6 +4044,8 @@ This function is an internal primitive--use `make-frame' instead.")
                       "borderColor", "BorderColor", RES_TYPE_STRING);
   x_default_parameter (f, parms, Qscreen_gamma, Qnil,
                       "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
+  x_default_parameter (f, parms, Qline_spacing, Qnil,
+                      "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
 
   x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_foreground,
                                        "scrollBarForeground",
@@ -4830,10 +4897,6 @@ x_sync (f)
 
 static struct image_type *image_types;
 
-/* A list of symbols, one for each supported image type.  */
-
-Lisp_Object Vimage_types;
-
 /* The symbol `image' which is the car of the lists used to represent
    images in Lisp.  */
 
@@ -4957,6 +5020,7 @@ enum image_value_type
   IMAGE_SYMBOL_VALUE,
   IMAGE_POSITIVE_INTEGER_VALUE,
   IMAGE_NON_NEGATIVE_INTEGER_VALUE,
+  IMAGE_ASCENT_VALUE,
   IMAGE_INTEGER_VALUE,
   IMAGE_FUNCTION_VALUE,
   IMAGE_NUMBER_VALUE,
@@ -5059,6 +5123,15 @@ parse_image_spec (spec, keywords, nkeywords, type)
            return 0;
          break;
 
+       case IMAGE_ASCENT_VALUE:
+         if (SYMBOLP (value) && EQ (value, Qcenter))
+           break;
+         else if (INTEGERP (value)
+                  && XINT (value) >= 0
+                  && XINT (value) <= 100)
+           break;
+         return 0;
+             
        case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
          if (!INTEGERP (value) || XINT (value) < 0)
            return 0;
@@ -5221,6 +5294,31 @@ prepare_image_for_display (f, img)
 }
      
 
+/* Value is the number of pixels for the ascent of image IMG when
+   drawn in face FACE.  */
+
+int
+image_ascent (img, face)
+     struct image *img;
+     struct face *face;
+{
+  int height = img->height + img->margin;
+  int ascent;
+
+  if (img->ascent == CENTERED_IMAGE_ASCENT)
+    {
+      if (face->font)
+       ascent = height / 2 - (face->font->descent - face->font->ascent) / 2;
+      else
+       ascent = height / 2;
+    }
+  else
+    ascent = height * img->ascent / 100.0;
+
+  return ascent;
+}
+
+
 \f
 /***********************************************************************
                  Helper functions for X image types
@@ -5340,8 +5438,8 @@ free_image_cache (f)
       for (i = 0; i < c->used; ++i)
        free_image (f, c->images[i]);
       xfree (c->images);
-      xfree (c);
       xfree (c->buckets);
+      xfree (c);
       FRAME_X_IMAGE_CACHE (f) = NULL;
     }
 }
@@ -5473,13 +5571,15 @@ lookup_image (f, spec)
       else
        {
          /* Handle image type independent image attributes
-            `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'.  */
+            `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF'.  */
          Lisp_Object ascent, margin, relief, algorithm, heuristic_mask;
          Lisp_Object file;
 
          ascent = image_spec_value (spec, QCascent, NULL);
          if (INTEGERP (ascent))
            img->ascent = XFASTINT (ascent);
+         else if (EQ (ascent, Qcenter))
+           img->ascent = CENTERED_IMAGE_ASCENT;
          
          margin = image_spec_value (spec, QCmargin, NULL);
          if (INTEGERP (margin) && XINT (margin) >= 0)
@@ -5670,10 +5770,12 @@ x_put_x_image (f, ximg, pixmap, width, height)
 
 \f
 /***********************************************************************
-                             Searching files
+                             File Handling
  ***********************************************************************/
 
 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
+static char *slurp_file P_ ((char *, int *));
+
 
 /* Find image file FILE.  Look in data-directory, then
    x-bitmap-file-path.  Value is the full name of the file found, or
@@ -5704,17 +5806,55 @@ x_find_image_file (file)
 }
 
 
+/* Read FILE into memory.  Value is a pointer to a buffer allocated
+   with xmalloc holding FILE's contents.  Value is null if an error
+   occured.  *SIZE is set to the size of the file.  */
+
+static char *
+slurp_file (file, size)
+     char *file;
+     int *size;
+{
+  FILE *fp = NULL;
+  char *buf = NULL;
+  struct stat st;
+
+  if (stat (file, &st) == 0
+      && (fp = fopen (file, "r")) != NULL
+      && (buf = (char *) xmalloc (st.st_size),
+         fread (buf, 1, st.st_size, fp) == st.st_size))
+    {
+      *size = st.st_size;
+      fclose (fp);
+    }
+  else
+    {
+      if (fp)
+       fclose (fp);
+      if (buf)
+       {
+         xfree (buf);
+         buf = NULL;
+       }
+    }
+  
+  return buf;
+}
+
+
 \f
 /***********************************************************************
                              XBM images
  ***********************************************************************/
 
+static int xbm_scan P_ ((char **, char *, char *, int *));
 static int xbm_load P_ ((struct frame *f, struct image *img));
-static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
-                                        Lisp_Object file));
+static int xbm_load_image P_ ((struct frame *f, struct image *img,
+                              char *, char *));
 static int xbm_image_p P_ ((Lisp_Object object));
-static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
-                                         unsigned char **));
+static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
+                                    unsigned char **));
+static int xbm_file_p P_ ((Lisp_Object));
 
 
 /* Indices of image specification fields in xbm_format, below.  */
@@ -5748,7 +5888,7 @@ static struct image_keyword xbm_format[XBM_LAST] =
   {":data",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":foreground",      IMAGE_STRING_VALUE,                     0},
   {":background",      IMAGE_STRING_VALUE,                     0},
-  {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
@@ -5795,10 +5935,14 @@ enum xbm_token
    3. a vector of strings or bool-vectors, one for each line of the
    bitmap.
 
+   4. A string containing an in-memory XBM file.  WIDTH and HEIGHT
+   may not be specified in this case because they are defined in the
+   XBM file.
+
    Both the file and data forms may contain the additional entries
    `:background COLOR' and `:foreground COLOR'.  If not present,
    foreground and background of the frame on which the image is
-   displayed, is used.  */
+   displayed is used.  */
 
 static int
 xbm_image_p (object)
@@ -5817,6 +5961,12 @@ xbm_image_p (object)
       if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
        return 0;
     }
+  else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
+    {
+      /* In-memory XBM file.  */
+      if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
+       return 0;
+    }
   else
     {
       Lisp_Object data;
@@ -5878,11 +6028,6 @@ xbm_image_p (object)
        return 0;
     }
 
-  /* Baseline must be a value between 0 and 100 (a percentage).  */
-  if (kw[XBM_ASCENT].count
-      && XFASTINT (kw[XBM_ASCENT].value) > 100)
-    return 0;
-  
   return 1;
 }
 
@@ -5894,30 +6039,31 @@ xbm_image_p (object)
    scanning a number, store its value in *IVAL.  */
 
 static int
-xbm_scan (fp, sval, ival)
-     FILE *fp;
+xbm_scan (s, end, sval, ival)
+     char **s, *end;
      char *sval;
      int *ival;
 {
   int c;
   
   /* Skip white space.  */
-  while ((c = fgetc (fp)) != EOF && isspace (c))
+  while (*s < end && (c = *(*s)++, isspace (c)))
     ;
 
-  if (c == EOF)
+  if (*s >= end)
     c = 0;
   else if (isdigit (c))
     {
       int value = 0, digit;
       
-      if (c == '0')
+      if (c == '0' && *s < end)
        {
-         c = fgetc (fp);
+         c = *(*s)++;
          if (c == 'x' || c == 'X')
            {
-             while ((c = fgetc (fp)) != EOF)
+             while (*s < end)
                {
+                 c = *(*s)++;
                  if (isdigit (c))
                    digit = c - '0';
                  else if (c >= 'a' && c <= 'f')
@@ -5932,33 +6078,33 @@ xbm_scan (fp, sval, ival)
          else if (isdigit (c))
            {
              value = c - '0';
-             while ((c = fgetc (fp)) != EOF
-                    && isdigit (c))
+             while (*s < end
+                    && (c = *(*s)++, isdigit (c)))
                value = 8 * value + c - '0';
            }
        }
       else
        {
          value = c - '0';
-         while ((c = fgetc (fp)) != EOF
-                && isdigit (c))
+         while (*s < end
+                && (c = *(*s)++, isdigit (c)))
            value = 10 * value + c - '0';
        }
 
-      if (c != EOF)
-       ungetc (c, fp);
+      if (*s < end)
+       *s = *s - 1;
       *ival = value;
       c = XBM_TK_NUMBER;
     }
   else if (isalpha (c) || c == '_')
     {
       *sval++ = c;
-      while ((c = fgetc (fp)) != EOF
-            && (isalnum (c) || c == '_'))
+      while (*s < end
+            && (c = *(*s)++, (isalnum (c) || c == '_')))
        *sval++ = c;
       *sval = 0;
-      if (c != EOF)
-       ungetc (c, fp);
+      if (*s < end)
+       *s = *s - 1;
       c = XBM_TK_IDENT;
     }
 
@@ -5967,18 +6113,19 @@ xbm_scan (fp, sval, ival)
 
 
 /* Replacement for XReadBitmapFileData which isn't available under old
-   X versions.  FILE is the name of the bitmap file to read.  Set
-   *WIDTH and *HEIGHT to the width and height of the image.  Return in
-   *DATA the bitmap data allocated with xmalloc.  Value is non-zero if
-   successful.  */
+   X versions.  CONTENTS is a pointer to a buffer to parse; END is the
+   buffer's end.  Set *WIDTH and *HEIGHT to the width and height of
+   the image.  Return in *DATA the bitmap data allocated with xmalloc.
+   Value is non-zero if successful.  DATA null means just test if
+   CONTENTS looks like an im-memory XBM file.  */
 
 static int
-xbm_read_bitmap_file_data (file, width, height, data)
-     char *file;
+xbm_read_bitmap_data (contents, end, width, height, data)
+     char *contents, *end;
      int *width, *height;
      unsigned char **data;
 {
-  FILE *fp;
+  char *s = contents;
   char buffer[BUFSIZ];
   int padding_p = 0;
   int v10 = 0;
@@ -5988,7 +6135,7 @@ xbm_read_bitmap_file_data (file, width, height, data)
   int LA1;
 
 #define match() \
-     LA1 = xbm_scan (fp, buffer, &value)
+     LA1 = xbm_scan (&s, end, buffer, &value)
 
 #define expect(TOKEN)          \
      if (LA1 != (TOKEN))       \
@@ -6002,13 +6149,10 @@ xbm_read_bitmap_file_data (file, width, height, data)
      else                                                      \
        goto failure
 
-  fp = fopen (file, "r");
-  if (fp == NULL)
-    return 0;
-
   *width = *height = -1;
-  *data = NULL;
-  LA1 = xbm_scan (fp, buffer, &value);
+  if (data)
+    *data = NULL;
+  LA1 = xbm_scan (&s, end, buffer, &value);
 
   /* Parse defines for width, height and hot-spots.  */
   while (LA1 == '#')
@@ -6031,6 +6175,8 @@ xbm_read_bitmap_file_data (file, width, height, data)
 
   if (*width < 0 || *height < 0)
     goto failure;
+  else if (data == NULL)
+    goto success;
 
   /* Parse bits.  Must start with `static'.  */
   expect_ident ("static");
@@ -6068,7 +6214,6 @@ xbm_read_bitmap_file_data (file, width, height, data)
 
   if (v10)
     {
-      
       for (i = 0; i < nbytes; i += 2)
        {
          int val = value;
@@ -6100,13 +6245,12 @@ xbm_read_bitmap_file_data (file, width, height, data)
        }
     }
 
-  fclose (fp);
+ success:
   return 1;
 
  failure:
   
-  fclose (fp);
-  if (*data)
+  if (data && *data)
     {
       xfree (*data);
       *data = NULL;
@@ -6119,35 +6263,21 @@ xbm_read_bitmap_file_data (file, width, height, data)
 }
 
 
-/* Load XBM image IMG which will be displayed on frame F from file
-   SPECIFIED_FILE.  Value is non-zero if successful.  */
+/* Load XBM image IMG which will be displayed on frame F from buffer
+   CONTENTS.  END is the end of the buffer.  Value is non-zero if
+   successful.  */
 
 static int
-xbm_load_image_from_file (f, img, specified_file)
+xbm_load_image (f, img, contents, end)
      struct frame *f;
      struct image *img;
-     Lisp_Object specified_file;
+     char *contents, *end;
 {
   int rc;
   unsigned char *data;
   int success_p = 0;
-  Lisp_Object file;
-  struct gcpro gcpro1;
   
-  xassert (STRINGP (specified_file));
-  file = Qnil;
-  GCPRO1 (file);
-
-  file = x_find_image_file (specified_file);
-  if (!STRINGP (file))
-    {
-      image_error ("Cannot find image file `%s'", specified_file, Qnil);
-      UNGCPRO;
-      return 0;
-    }
-         
-  rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width,
-                                 &img->height, &data);
+  rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
   if (rc)
     {
       int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
@@ -6179,7 +6309,7 @@ xbm_load_image_from_file (f, img, specified_file)
       if (img->pixmap == 0)
        {
          x_clear_image (f, img);
-         image_error ("Unable to create X pixmap for `%s'", file, Qnil);
+         image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
        }
       else
        success_p = 1;
@@ -6189,11 +6319,25 @@ xbm_load_image_from_file (f, img, specified_file)
   else
     image_error ("Error loading XBM image `%s'", img->spec, Qnil);
 
-  UNGCPRO;
   return success_p;
 }
 
 
+/* Value is non-zero if DATA looks like an in-memory XBM file.  */
+
+static int
+xbm_file_p (data)
+     Lisp_Object data;
+{
+  int w, h;
+  return (STRINGP (data)
+         && xbm_read_bitmap_data (XSTRING (data)->data,
+                                  (XSTRING (data)->data
+                                   + STRING_BYTES (XSTRING (data))),
+                                  &w, &h, NULL));
+}
+
+    
 /* Fill image IMG which is used on frame F with pixmap data.  Value is
    non-zero if successful.  */
 
@@ -6210,32 +6354,63 @@ xbm_load (f, img)
   /* If IMG->spec specifies a file name, create a non-file spec from it.  */
   file_name = image_spec_value (img->spec, QCfile, NULL);
   if (STRINGP (file_name))
-    success_p = xbm_load_image_from_file (f, img, file_name);
+    {
+      Lisp_Object file;
+      char *contents;
+      int size;
+      struct gcpro gcpro1;
+      
+      file = x_find_image_file (file_name);
+      GCPRO1 (file);
+      if (!STRINGP (file))
+       {
+         image_error ("Cannot find image file `%s'", file_name, Qnil);
+         UNGCPRO;
+         return 0;
+       }
+
+      contents = slurp_file (XSTRING (file)->data, &size);
+      if (contents == NULL)
+       {
+         image_error ("Error loading XBM image `%s'", img->spec, Qnil);
+         UNGCPRO;
+         return 0;
+       }
+
+      success_p = xbm_load_image (f, img, contents, contents + size);
+      UNGCPRO;
+    }
   else
     {
       struct image_keyword fmt[XBM_LAST];
       Lisp_Object data;
+      unsigned char *bitmap_data;
       int depth;
       unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
       unsigned long background = FRAME_BACKGROUND_PIXEL (f);
       char *bits;
-      int parsed_p;
+      int parsed_p, height, width;
+      int in_memory_file_p = 0;
+
+      /* See if data looks like an in-memory XBM file.  */
+      data = image_spec_value (img->spec, QCdata, NULL);
+      in_memory_file_p = xbm_file_p (data);
 
-      /* Parse the list specification.  */
+      /* Parse the image specification.  */
       bcopy (xbm_format, fmt, sizeof fmt);
       parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
       xassert (parsed_p);
 
       /* Get specified width, and height.  */
-      img->width = XFASTINT (fmt[XBM_WIDTH].value);
-      img->height = XFASTINT (fmt[XBM_HEIGHT].value);
-      xassert (img->width > 0 && img->height > 0);
+      if (!in_memory_file_p)
+       {
+         img->width = XFASTINT (fmt[XBM_WIDTH].value);
+         img->height = XFASTINT (fmt[XBM_HEIGHT].value);
+         xassert (img->width > 0 && img->height > 0);
+       }
 
       BLOCK_INPUT;
       
-      if (fmt[XBM_ASCENT].count)
-       img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
-
       /* Get foreground and background colors, maybe allocate colors.  */
       if (fmt[XBM_FOREGROUND].count)
        foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
@@ -6244,46 +6419,51 @@ xbm_load (f, img)
        background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
                                          background);
 
-      /* Set bits to the bitmap image data.  */
-      data = fmt[XBM_DATA].value;
-      if (VECTORP (data))
+      if (in_memory_file_p)
+       success_p = xbm_load_image (f, img, XSTRING (data)->data,
+                                   (XSTRING (data)->data
+                                    + STRING_BYTES (XSTRING (data))));
+      else
        {
-         int i;
-         char *p;
-         int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
+         if (VECTORP (data))
+           {
+             int i;
+             char *p;
+             int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
          
-         p = bits = (char *) alloca (nbytes * img->height);
-         for (i = 0; i < img->height; ++i, p += nbytes)
+             p = bits = (char *) alloca (nbytes * img->height);
+             for (i = 0; i < img->height; ++i, p += nbytes)
+               {
+                 Lisp_Object line = XVECTOR (data)->contents[i];
+                 if (STRINGP (line))
+                   bcopy (XSTRING (line)->data, p, nbytes);
+                 else
+                   bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
+               }
+           }
+         else if (STRINGP (data))
+           bits = XSTRING (data)->data;
+         else
+           bits = XBOOL_VECTOR (data)->data;
+
+         /* Create the pixmap.  */
+         depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
+         img->pixmap
+           = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
+                                          FRAME_X_WINDOW (f),
+                                          bits,
+                                          img->width, img->height,
+                                          foreground, background,
+                                          depth);
+         if (img->pixmap)
+           success_p = 1;
+         else
            {
-             Lisp_Object line = XVECTOR (data)->contents[i];
-             if (STRINGP (line))
-               bcopy (XSTRING (line)->data, p, nbytes);
-             else
-               bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
+             image_error ("Unable to create pixmap for XBM image `%s'",
+                          img->spec, Qnil);
+             x_clear_image (f, img);
            }
        }
-      else if (STRINGP (data))
-       bits = XSTRING (data)->data;
-      else
-       bits = XBOOL_VECTOR (data)->data;
-
-      /* Create the pixmap.  */
-      depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
-      img->pixmap
-       = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
-                                      FRAME_X_WINDOW (f),
-                                      bits,
-                                      img->width, img->height,
-                                      foreground, background,
-                                      depth);
-      if (img->pixmap)
-       success_p = 1;
-      else
-       {
-         image_error ("Unable to create pixmap for XBM image `%s'",
-                      img->spec, Qnil);
-         x_clear_image (f, img);
-       }
 
       UNBLOCK_INPUT;
     }
@@ -6333,7 +6513,7 @@ static struct image_keyword xpm_format[XPM_LAST] =
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
   {":file",            IMAGE_STRING_VALUE,                     0},
   {":data",            IMAGE_STRING_VALUE,                     0},
-  {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
@@ -6389,9 +6569,7 @@ xpm_image_p (object)
          /* Either no `:color-symbols' or it's a list of conses
             whose car and cdr are strings.  */
          && (fmt[XPM_COLOR_SYMBOLS].count == 0
-             || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
-         && (fmt[XPM_ASCENT].count == 0
-             || XFASTINT (fmt[XPM_ASCENT].value) < 100));
+             || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
 }
 
 
@@ -6494,7 +6672,12 @@ xpm_load (f, img)
       img->colors = (unsigned long *) xmalloc (img->ncolors
                                               * sizeof *img->colors);
       for (i = 0; i < attrs.nalloc_pixels; ++i)
-       img->colors[i] = attrs.alloc_pixels[i];
+       {
+         img->colors[i] = attrs.alloc_pixels[i];
+#ifdef DEBUG_X_COLORS
+         register_color (img->colors[i]);
+#endif
+       }
 
       img->width = attrs.width;
       img->height = attrs.height;
@@ -7027,7 +7210,7 @@ static struct image_keyword pbm_format[PBM_LAST] =
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
   {":file",            IMAGE_STRING_VALUE,                     0},
   {":data",            IMAGE_STRING_VALUE,                     0},
-  {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
@@ -7056,9 +7239,7 @@ pbm_image_p (object)
   
   bcopy (pbm_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
-      || (fmt[PBM_ASCENT].count 
-         && XFASTINT (fmt[PBM_ASCENT].value) > 100))
+  if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
     return 0;
 
   /* Must specify either :data or :file.  */
@@ -7104,42 +7285,6 @@ pbm_scan_number (s, end)
 }
 
 
-/* Read FILE into memory.  Value is a pointer to a buffer allocated
-   with xmalloc holding FILE's contents.  Value is null if an error
-   occured.  *SIZE is set to the size of the file.  */
-
-static char *
-pbm_read_file (file, size)
-     Lisp_Object file;
-     int *size;
-{
-  FILE *fp = NULL;
-  char *buf = NULL;
-  struct stat st;
-
-  if (stat (XSTRING (file)->data, &st) == 0
-      && (fp = fopen (XSTRING (file)->data, "r")) != NULL
-      && (buf = (char *) xmalloc (st.st_size),
-         fread (buf, 1, st.st_size, fp) == st.st_size))
-    {
-      *size = st.st_size;
-      fclose (fp);
-    }
-  else
-    {
-      if (fp)
-       fclose (fp);
-      if (buf)
-       {
-         xfree (buf);
-         buf = NULL;
-       }
-    }
-  
-  return buf;
-}
-
-
 /* Load PBM image IMG for use on frame F.  */
 
 static int 
@@ -7171,7 +7316,7 @@ pbm_load (f, img)
          return 0;
        }
 
-      contents = pbm_read_file (file, &size);
+      contents = slurp_file (XSTRING (file)->data, &size);
       if (contents == NULL)
        {
          image_error ("Error reading `%s'", file, Qnil);
@@ -7383,7 +7528,7 @@ static struct image_keyword png_format[PNG_LAST] =
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
   {":data",            IMAGE_STRING_VALUE,                     0},
   {":file",            IMAGE_STRING_VALUE,                     0},
-  {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
@@ -7411,9 +7556,7 @@ png_image_p (object)
   struct image_keyword fmt[PNG_LAST];
   bcopy (png_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
-      || (fmt[PNG_ASCENT].count 
-         && XFASTINT (fmt[PNG_ASCENT].value) > 100))
+  if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
     return 0;
 
   /* Must specify either the :data or :file keyword.  */
@@ -7869,7 +8012,7 @@ static struct image_keyword jpeg_format[JPEG_LAST] =
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
   {":data",            IMAGE_STRING_VALUE,                     0},
   {":file",            IMAGE_STRING_VALUE,                     0},
-  {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
@@ -7898,9 +8041,7 @@ jpeg_image_p (object)
   
   bcopy (jpeg_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
-      || (fmt[JPEG_ASCENT].count 
-         && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
+  if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
     return 0;
 
   /* Must specify either the :data or :file keyword.  */
@@ -7914,6 +8055,7 @@ struct my_jpeg_error_mgr
   jmp_buf setjmp_buffer;
 };
 
+
 static void
 my_error_exit (cinfo)
      j_common_ptr cinfo;
@@ -7922,6 +8064,7 @@ my_error_exit (cinfo)
   longjmp (mgr->setjmp_buffer, 1);
 }
 
+
 /* Init source method for JPEG data source manager.  Called by
    jpeg_read_header() before any data is actually read.  See
    libjpeg.doc from the JPEG lib distribution.  */
@@ -8231,7 +8374,7 @@ static struct image_keyword tiff_format[TIFF_LAST] =
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
   {":data",            IMAGE_STRING_VALUE,                     0},
   {":file",            IMAGE_STRING_VALUE,                     0},
-  {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
@@ -8259,9 +8402,7 @@ tiff_image_p (object)
   struct image_keyword fmt[TIFF_LAST];
   bcopy (tiff_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
-      || (fmt[TIFF_ASCENT].count 
-         && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
+  if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
     return 0;
   
   /* Must specify either the :data or :file keyword.  */
@@ -8286,6 +8427,7 @@ typedef struct
 }
 tiff_memory_source;
 
+
 static size_t
 tiff_read_from_memory (data, buf, size)
      thandle_t data;
@@ -8301,6 +8443,7 @@ tiff_read_from_memory (data, buf, size)
   return size;
 }
 
+
 static size_t
 tiff_write_from_memory (data, buf, size)
      thandle_t data;
@@ -8310,6 +8453,7 @@ tiff_write_from_memory (data, buf, size)
   return (size_t) -1;
 }
 
+
 static toff_t
 tiff_seek_in_memory (data, off, whence)
      thandle_t data;
@@ -8344,6 +8488,7 @@ tiff_seek_in_memory (data, off, whence)
   return src->index;
 }
 
+
 static int
 tiff_close_memory (data)
      thandle_t data;
@@ -8352,6 +8497,7 @@ tiff_close_memory (data)
   return 0;
 }
 
+
 static int
 tiff_mmap_memory (data, pbase, psize)
      thandle_t data;
@@ -8362,6 +8508,7 @@ tiff_mmap_memory (data, pbase, psize)
   return 0;
 }
 
+
 static void
 tiff_unmap_memory (data, base, size)
      thandle_t data;
@@ -8371,6 +8518,7 @@ tiff_unmap_memory (data, base, size)
   /* We don't need to do this. */
 }
 
+
 static toff_t
 tiff_size_of_memory (data)
      thandle_t data;
@@ -8378,6 +8526,7 @@ tiff_size_of_memory (data)
   return ((tiff_memory_source *) data)->len;
 }
 
+
 /* Load TIFF image IMG for use on frame F.  Value is non-zero if
    successful.  */
 
@@ -8550,7 +8699,7 @@ static struct image_keyword gif_format[GIF_LAST] =
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
   {":data",            IMAGE_STRING_VALUE,                     0},
   {":file",            IMAGE_STRING_VALUE,                     0},
-  {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
@@ -8569,6 +8718,7 @@ static struct image_type gif_type =
   NULL
 };
 
+
 /* Return non-zero if OBJECT is a valid GIF image specification.  */
 
 static int
@@ -8578,15 +8728,14 @@ gif_image_p (object)
   struct image_keyword fmt[GIF_LAST];
   bcopy (gif_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
-      || (fmt[GIF_ASCENT].count 
-         && XFASTINT (fmt[GIF_ASCENT].value) > 100))
+  if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
     return 0;
   
   /* Must specify either the :data or :file keyword.  */
   return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
 }
 
+
 /* Reading a GIF image from memory
    Based on the PNG memory stuff to a certain extent. */
 
@@ -8598,6 +8747,7 @@ typedef struct
 }
 gif_memory_source;
 
+
 /* Make the current memory source available to gif_read_from_memory.
    It's done this way because not all versions of libungif support
    a UserData field in the GifFileType structure.  */
@@ -8864,7 +9014,7 @@ static struct image_keyword gs_format[GS_LAST] =
   {":file",            IMAGE_STRING_VALUE,                     1},
   {":loader",          IMAGE_FUNCTION_VALUE,                   0},
   {":bounding-box",    IMAGE_DONT_CHECK_VALUE_TYPE,            1},
-  {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
@@ -8909,9 +9059,7 @@ gs_image_p (object)
   
   bcopy (gs_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
-      || (fmt[GS_ASCENT].count 
-         && XFASTINT (fmt[GS_ASCENT].value) > 100))
+  if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
     return 0;
 
   /* Bounding box must be a list or vector containing 4 integers.  */
@@ -9672,8 +9820,8 @@ TIMEOUT nil means use the default timeout of 5 seconds.")
      will loose.  I don't think this is a realistic case.  */
   w = XWINDOW (FRAME_ROOT_WINDOW (f));
   w->left = w->top = make_number (0);
-  w->width = 80;
-  w->height = 40;
+  w->width = make_number (80);
+  w->height = make_number (40);
   adjust_glyphs (f);
   w->pseudo_window_p = 1;
 
@@ -9683,7 +9831,7 @@ TIMEOUT nil means use the default timeout of 5 seconds.")
   old_buffer = current_buffer;
   set_buffer_internal_1 (XBUFFER (buffer));
   Ferase_buffer ();
-  Finsert (make_number (1), &string);
+  Finsert (1, &string);
   clear_glyph_matrix (w->desired_matrix);
   clear_glyph_matrix (w->current_matrix);
   SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
@@ -9704,7 +9852,7 @@ TIMEOUT nil means use the default timeout of 5 seconds.")
       /* Let the row go over the full width of the frame.  */
       row->full_width_p = 1;
 
-      /* There's a glyph at the end of rows that is use to place
+      /* There's a glyph at the end of rows that is used to place
         the cursor there.  Don't include the width of this glyph.  */
       if (row->used[TEXT_AREA])
        {
@@ -9955,37 +10103,6 @@ selection dialog's entry field, if MUSTMATCH is non-nil.")
 
 #endif /* USE_MOTIF */
 
-\f
-/***********************************************************************
-                               Tests
- ***********************************************************************/
-
-#if GLYPH_DEBUG
-
-DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
-  "Value is non-nil if SPEC is a valid image specification.")
-  (spec)
-     Lisp_Object spec;
-{
-  return valid_image_p (spec) ? Qt : Qnil;
-}
-
-
-DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
-  (spec)
-     Lisp_Object spec;
-{
-  int id = -1;
-  
-  if (valid_image_p (spec))
-    id = lookup_image (SELECTED_FRAME (), spec);
-
-  debug_print (spec);
-  return make_number (id);
-}
-
-#endif /* GLYPH_DEBUG != 0 */
-
 
 \f
 /***********************************************************************
@@ -10067,6 +10184,10 @@ syms_of_xfns ()
   staticpro (&Qscroll_bar_background);
   Qscreen_gamma = intern ("screen-gamma");
   staticpro (&Qscreen_gamma);
+  Qline_spacing = intern ("line-spacing");
+  staticpro (&Qline_spacing);
+  Qcenter = intern ("center");
+  staticpro (&Qcenter);
   /* This is the end of symbol initialization.  */
 
   /* Text property `display' should be nonsticky by default.  */
@@ -10187,11 +10308,6 @@ from the image cache.  Value must be an integer or nil with nil\n\
 meaning don't clear the cache.");
   Vimage_cache_eviction_delay = make_number (30 * 60);
 
-  DEFVAR_LISP ("image-types", &Vimage_types,
-     "List of supported image types.\n\
-Each element of the list is a symbol for a supported image type.");
-  Vimage_types = Qnil;
-
 #ifdef USE_X_TOOLKIT
   Fprovide (intern ("x-toolkit"));
 #endif
@@ -10304,11 +10420,6 @@ Each element of the list is a symbol for a supported image type.");
 
   defsubr (&Sclear_image_cache);
 
-#if GLYPH_DEBUG
-  defsubr (&Simagep);
-  defsubr (&Slookup_image);
-#endif
-
   busy_cursor_atimer = NULL;
   busy_cursor_shown_p = 0;