home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.004 / xemacs-1 / xemacs-19.13 / src / redisplay-x.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-08-26  |  61.0 KB  |  2,135 lines

  1. /* X output and frame manipulation routines.
  2.    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois
  3.    Copyright (C) 1994 Lucid, Inc.
  4.  
  5. This file is part of XEmacs.
  6.  
  7. XEmacs is free software; you can redistribute it and/or modify it
  8. under the terms of the GNU General Public License as published by the
  9. Free Software Foundation; either version 2, or (at your option) any
  10. later version.
  11.  
  12. XEmacs is distributed in the hope that it will be useful, but WITHOUT
  13. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with XEmacs; see the file COPYING.  If not, write to the Free
  19. Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21. /* Synched up with:  Not in FSF. */
  22.  
  23. /* This file has been Mule-ized, but needs more work before it will
  24.    compile with Mule support enabled. */
  25.  
  26. /* Author: Chuck Thompson */
  27.  
  28. #include <config.h>
  29. #include "lisp.h"
  30.  
  31. #include "device-x.h"
  32. #include "frame-x.h"
  33. #include "EmacsFrame.h"
  34. #include "EmacsFrameP.h"
  35. #include "xgccache.h"
  36. #include "glyphs-x.h"
  37. #include "objects-x.h"
  38.  
  39. #include "buffer.h"
  40. #include "debug.h"
  41. #include "faces.h"
  42. #include "redisplay.h"
  43. #include "sysdep.h"
  44. #include "window.h"
  45. #include <X11/bitmaps/gray>
  46.  
  47. #include "sysproc.h" /* for select() */
  48.  
  49. /* X_DIVIDER_LINE_WIDTH is the width of the line drawn in the gutter.
  50.    X_DIVIDER_SPACING is the amount of blank space on each side of the line.
  51.    X_DIVIDER_WIDTH = X_DIVIDER_LINE_WIDTH + 2*X_DIVIDER_SPACING
  52. */
  53.  
  54. /* Number of pixels below each line. */
  55. /* #### implement me */
  56. int x_interline_space;
  57.  
  58. #define X_DIVIDER_LINE_WIDTH    3
  59. #define X_DIVIDER_SPACING    2
  60. #define X_DIVIDER_WIDTH        (X_DIVIDER_LINE_WIDTH + 2 * X_DIVIDER_SPACING)
  61.  
  62. #define EOL_CURSOR_WIDTH    5
  63.  
  64. /*
  65.  * Prototypes for all functions defined in redisplay-x.c.
  66.  */
  67. static int x_text_width (struct window *w, Lisp_Object font,
  68.              CONST Emchar *s, Charcount len);
  69. static void x_font_metric_info (struct device *d, Lisp_Object font,
  70.                 struct font_metric_info *fm);
  71. static int x_divider_width (void);
  72. static int x_divider_height (void);
  73. static int x_eol_cursor_width (void);
  74. static void x_output_end (struct device *d);
  75. static void x_output_display_block (struct window *w, struct display_line *dl,
  76.                     int block, int start, int end,
  77.                     int start_pixpos, int cursor_start,
  78.                     int cursor_width, int cursor_height);
  79. static void x_bevel_modeline (struct window *w, struct display_line *dl);
  80. void x_output_string (struct window *w, struct display_line *dl,
  81.               emchar_dynarr *buf, int xpos, int xoffset,
  82.               int start_pixpos, int width, face_index findex,
  83.               int cursor, int cursor_start, int cursor_width,
  84.               int cursor_height);
  85. static void x_output_pixmap (struct window *w, struct display_line *dl,
  86.                  Lisp_Object image_instance, int xpos,
  87.                  int xoffset,
  88.                  int start_pixpos, int width, face_index findex,
  89.                  int cursor_start, int cursor_width,
  90.                  int cursor_height);
  91. static void x_output_vertical_divider (struct window *w, int clear);
  92. static void x_output_blank (struct window *w, struct display_line *dl,
  93.                 struct rune *rb, int start_pixpos,
  94.                 int cursor_start, int cursor_width);
  95. static void x_output_hline (struct window *w, struct display_line *dl,
  96.                 struct rune *rb);
  97. static void x_clear_to_window_end (struct window *w, int ypos1, int ypos2);
  98. static void x_redraw_exposed_window (struct window *w, int x, int y,
  99.                      int width, int height);
  100. static void x_redraw_exposed_windows (Lisp_Object window, int x, int y,
  101.                       int width, int height);
  102. static void x_clear_region (Lisp_Object window, face_index findex, int x,
  103.                 int y, int width, int height);
  104. static void x_output_eol_cursor (struct window *w, struct display_line *dl,
  105.                  int xpos);
  106. static void x_clear_frame (struct frame *f);
  107.  
  108. #ifdef MULE
  109.  
  110. static XFontStruct *
  111. first_font_struct_of (XFontSet font)
  112. {
  113.   XFontStruct **font_struct_list;
  114.   char **font_name_list;
  115.   int fonts;
  116.  
  117.   fonts = XFontsOfFontSet (font, &font_struct_list, &font_name_list);
  118.   assert (fonts > 0);
  119.   return font_struct_list[0];
  120. }
  121.  
  122. #endif
  123.  
  124. /*
  125.  * X output and frame manipulation global variables.
  126.  */
  127.  
  128. /*****************************************************************************
  129.  x_text_width
  130.  
  131.  Given a string and a face, return the string's length in pixels when
  132.  displayed in the font associated with the face.
  133.  ****************************************************************************/
  134. static int
  135. x_text_width (struct window *w, Lisp_Object font, CONST Emchar *s,
  136.           Charcount len)
  137. {
  138.   struct Lisp_Font_Instance *fnt;
  139.  
  140.   fnt = XFONT_INSTANCE (font);
  141.  
  142.   if (!fnt->proportional_p)
  143.     return fnt->width * len;
  144.   else
  145.     {
  146. #ifdef MULE
  147.       /* !!#### temporary glue */
  148.  
  149.       /* Note: The current glue provided substitutes an X for all
  150.      non-ASCII characters (i.e. >= 0x80).  The code is written
  151.      in such a way as to imply that the Xmb*() functions and
  152.      XFontSets should be used to draw text and compute text
  153.      widths.  This is not true.  Those functions are generally
  154.      losing for a number of reasons:
  155.  
  156.      1) They only support one locale (e.g. you could display
  157.         Japanese and ASCII text, but not mixed Japanese/Chinese
  158.         text).  You could maybe call setlocale() frequently
  159.         to try to deal with this, but that would generally
  160.         fail because an XFontSet is tied to one locale and
  161.         won't have the other character sets in it.
  162.      2) Not all (or even very many) OS's support the useful
  163.         locales.  For example, as far as I know SunOS and
  164.         Solaris only support the Japanese locale if you get the
  165.         special Asian-language version of the OS.  Yuck yuck
  166.         yuck.  Linux doesn't support the Japanese locale at
  167.         all.
  168.      3) The locale support in X only exists in R5, not in R4.
  169.         (Not sure how big of a problem this is: how many
  170.         people are using R4?)
  171.      4) Who knows if the multi-byte text format (which is locale-
  172.         specific) is even the same for the same locale on
  173.         different OS's?  It's not even documented anywhere that
  174.         I can find what the multi-byte text format for the
  175.         Japanese locale under SunOS and Solaris is, but I assume
  176.         it's EUC.
  177.  
  178.       In other words, fuck all this losing shit.  What we need to do
  179.       instead is provide our own font-set management routines (this
  180.       is what the original Mule does, but of course their implementation
  181.       is shitty).  A `font' object under Mule should be allowed to
  182.       have multiple fonts associated with it, just like an XFontSet.
  183.       We can do our own lookup and text-drawing using the *16 functions.
  184.       */
  185.       int i;
  186.       char *one_byte_string = (char *) alloca (len);
  187.       for (i = 0; i < len; i++)
  188.     {
  189.       if (s[i] < 0x80)
  190.         one_byte_string[i] = (char) s[i];
  191.       else
  192.         one_byte_string[i] = 'X';
  193.     }
  194.  
  195.       return XmbTextEscapement (FONT_INSTANCE_X_FONT (fnt),
  196.                 one_byte_string, len);
  197. #else
  198.       int i;
  199.       char *one_byte_string = (char *) alloca (len);
  200.       for (i = 0; i < len; i++)
  201.     {
  202.       /* #### perhaps should use DASSERT? */
  203.       assert (s[i] < 0x100);
  204.       one_byte_string[i] = (char) s[i];
  205.     }
  206.  
  207.       return XTextWidth (FONT_INSTANCE_X_FONT (fnt), one_byte_string, len);
  208. #endif
  209.     }
  210. }
  211.  
  212. /*****************************************************************************
  213.  x_font_metric_info
  214.  
  215.  Given a font, return a structure with its average width, maximum ascent,
  216.  maximum descent and a flag indicating if it is a proportional font.
  217.  ****************************************************************************/
  218. static void
  219. x_font_metric_info (struct device *d, Lisp_Object font,
  220.             struct font_metric_info *fm)
  221. {
  222.   struct Lisp_Font_Instance *fnt = XFONT_INSTANCE (font);
  223.   Lisp_Object dev;
  224.  
  225.   XSETDEVICE (dev, d);
  226.  
  227.   fm->width = fnt->width;
  228.   fm->ascent = fnt->ascent;
  229.   fm->descent = fnt->descent;
  230.   fm->height = fm->ascent + fm->descent;
  231.   fm->proportional = fnt->proportional_p;
  232. }
  233.  
  234. /*****************************************************************************
  235.  x_divider_width
  236.  
  237.  Return the width of the vertical divider.  This is a function because
  238.  divider_width is a device method.
  239.  ****************************************************************************/
  240. static int
  241. x_divider_width (void)
  242. {
  243.   return X_DIVIDER_WIDTH;
  244. }
  245.  
  246. /*****************************************************************************
  247.  x_divider_height
  248.  
  249.  Return the height of the horizontal divider.  This is a function because
  250.  divider_height is a device method.
  251.  
  252.  #### If we add etched horizontal divider lines this will have to get
  253.  smarter.
  254.  ****************************************************************************/
  255. static int
  256. x_divider_height (void)
  257. {
  258.   return 1;
  259. }
  260.  
  261. /*****************************************************************************
  262.  x_eol_cursor_width
  263.  
  264.  Return the width of the end-of-line cursor.  This is a function
  265.  because eol_cursor_width is a device method.
  266.  ****************************************************************************/
  267. static int
  268. x_eol_cursor_width (void)
  269. {
  270.   return EOL_CURSOR_WIDTH;
  271. }
  272.  
  273. /*****************************************************************************
  274.  x_output_begin
  275.  
  276.  Perform any necessary initialization prior to an update.
  277.  ****************************************************************************/
  278. static void
  279. x_output_begin (struct device *d)
  280. {
  281. }
  282.  
  283. /*****************************************************************************
  284.  x_output_end
  285.  
  286.  Perform any necessary flushing of queues when an update has completed.
  287.  ****************************************************************************/
  288. static void
  289. x_output_end (struct device *d)
  290. {
  291.   XFlush (DEVICE_X_DISPLAY (d));
  292. }
  293.  
  294. /*****************************************************************************
  295.  x_output_display_block
  296.  
  297.  Given a display line, a block number for that start line, output all
  298.  runes between start and end in the specified display block.
  299.  ****************************************************************************/
  300. static void
  301. x_output_display_block (struct window *w, struct display_line *dl, int block,
  302.             int start, int end, int start_pixpos, int cursor_start,
  303.             int cursor_width, int cursor_height)
  304. {
  305.   struct frame *f = XFRAME (w->frame);
  306.   emchar_dynarr *buf = Dynarr_new (Emchar);
  307.   Lisp_Object window;
  308.  
  309.   struct display_block *db = Dynarr_atp (dl->display_blocks, block);
  310.   rune_dynarr *rba = db->runes;
  311.   struct rune *rb;
  312.  
  313.   int elt = start;
  314.   face_index findex;
  315.   int xpos, width;
  316.  
  317.   XSETWINDOW (window, w);
  318.   rb = Dynarr_atp (rba, start);
  319.  
  320.   if (!rb)
  321.     {
  322.       /* Nothing to do so don't do anything. */
  323.       return;
  324.     }
  325.   else
  326.     {
  327.       findex = rb->findex;
  328.       xpos = rb->xpos;
  329.       width = 0;
  330.     }
  331.  
  332.   if (end < 0)
  333.     end = Dynarr_length (rba);
  334.   Dynarr_reset (buf);
  335.  
  336.   while (elt < end)
  337.     {
  338.       rb = Dynarr_atp (rba, elt);
  339.  
  340.       if (rb->findex == findex && rb->type == CHAR
  341.       && rb->object.ch != '\n' && rb->cursor_type != CURSOR_ON)
  342.     {
  343.       Dynarr_add (buf, rb->object.ch);
  344.       width += rb->width;
  345.       elt++;
  346.     }
  347.       else
  348.     {
  349.       if (Dynarr_length (buf))
  350.         {
  351.           x_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
  352.                    findex, 0, cursor_start, cursor_width,
  353.                    cursor_height);
  354.           xpos = rb->xpos;
  355.           width = 0;
  356.         }
  357.       Dynarr_reset (buf);
  358.       width = 0;
  359.  
  360.       if (rb->type == CHAR)
  361.         {
  362.           findex = rb->findex;
  363.           xpos = rb->xpos;
  364.  
  365.           if (rb->cursor_type == CURSOR_ON)
  366.         {
  367.           if (rb->object.ch == '\n')
  368.             {
  369.               x_output_eol_cursor (w, dl, xpos);
  370.             }
  371.           else
  372.             {
  373.               Dynarr_add (buf, rb->object.ch);
  374.               x_output_string (w, dl, buf, xpos, 0, start_pixpos,
  375.                        rb->width, findex, 1, cursor_start,
  376.                        cursor_width, cursor_height);
  377.               Dynarr_reset (buf);
  378.             }
  379.  
  380.           xpos += rb->width;
  381.           elt++;
  382.         }
  383.           else if (rb->object.ch == '\n')
  384.         {
  385.           /* Clear in case a cursor was formerly here. */
  386.           int height = dl->ascent + dl->descent - dl->clip;
  387.  
  388.           x_clear_region (window, findex, xpos, dl->ypos - dl->ascent,
  389.                   rb->width, height);
  390.           elt++;
  391.         }
  392.         }
  393.       else if (rb->type == BLANK || rb->type == HLINE)
  394.         {
  395.           if (rb->type == BLANK)
  396.         x_output_blank (w, dl, rb, start_pixpos, cursor_start,
  397.                 cursor_width);
  398.           else 
  399.         {
  400.           /* #### Our flagging of when we need to redraw the
  401.                      modeline shadows sucks.  Since HLINE is only used
  402.                      by the modeline at the moment it is a good bet
  403.                      that if it gets redrawn then we should also
  404.                      redraw the shadows.  This won't be true forever.
  405.                      We borrow the shadow_thickness_changed flag for
  406.                      now. */
  407.           w->shadow_thickness_changed = 1;
  408.           x_output_hline (w, dl, rb);
  409.         }
  410.  
  411.           elt++;
  412.           if (elt < end)
  413.         {
  414.           rb = Dynarr_atp (rba, elt);
  415.  
  416.           findex = rb->findex;
  417.           xpos = rb->xpos;
  418.         }
  419.         }
  420.       else if (rb->type == DGLYPH)
  421.         {
  422.           Lisp_Object instance;
  423.  
  424.           XSETWINDOW (window, w);
  425.           instance = glyph_image_instance (rb->object.dglyph.glyph,
  426.                            window, 1);
  427.           findex = rb->findex;
  428.  
  429.           switch (XIMAGE_INSTANCE_TYPE (instance))
  430.         {
  431.         case IMAGE_TEXT:
  432.           {
  433.             /* #### This is way losing.  See the comment in
  434.                add_glyph_rune(). */
  435. #ifdef MULE
  436.             /* lose; */
  437.             /* !!#### Chuck, you need to lower this stuff
  438.                to the device-independent level. */
  439.             Dynarr_add (buf, 'l');
  440.             Dynarr_add (buf, 'o');
  441.             Dynarr_add (buf, 's');
  442.             Dynarr_add (buf, 'e');
  443. #else
  444.             Bytecount lossage;
  445.             Lisp_Object string =
  446.               XIMAGE_INSTANCE_TEXT_STRING (instance);
  447.  
  448.             for (lossage = 0;
  449.              lossage < string_length (XSTRING (string));
  450.              lossage++)
  451.               Dynarr_add (buf,
  452.                   (Emchar) string_byte (XSTRING (string),
  453.                             lossage));
  454.             
  455.             x_output_string (w, dl, buf, xpos,
  456.                      rb->object.dglyph.xoffset,
  457.                      start_pixpos, -1, findex,
  458.                      (rb->cursor_type == CURSOR_ON),
  459.                      cursor_start, cursor_width,
  460.                      cursor_height);
  461.             Dynarr_reset (buf);
  462. #endif
  463.         }
  464.           break;
  465.  
  466.         case IMAGE_MONO_PIXMAP:
  467.         case IMAGE_COLOR_PIXMAP:
  468.           x_output_pixmap (w, dl, instance, xpos,
  469.                    rb->object.dglyph.xoffset, start_pixpos,
  470.                    rb->width, findex, cursor_start,
  471.                    cursor_width, cursor_height);
  472.           break;
  473.  
  474.         case IMAGE_CURSOR:
  475.           abort ();
  476.  
  477.         case IMAGE_SUBWINDOW:
  478.           /* #### implement me */
  479.           break;
  480.  
  481.         case IMAGE_NOTHING:
  482.           /* nothing is as nothing does */
  483.           break;
  484.  
  485.         default:
  486.           abort ();
  487.         }
  488.  
  489.           xpos += rb->width;
  490.           elt++;
  491.         }
  492.       else
  493.         abort ();
  494.     }
  495.     }
  496.  
  497.   if (Dynarr_length (buf))
  498.     x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex, 0,
  499.              cursor_start, cursor_width, cursor_height);
  500.  
  501.   /* #### This is really conditionalized well for optimized
  502.      performance. */
  503.   if (dl->modeline
  504.       && !EQ (Qzero, w->modeline_shadow_thickness)
  505.       && (f->clear
  506.       || f->windows_structure_changed
  507.       || w->shadow_thickness_changed))
  508.     x_bevel_modeline (w, dl);
  509.  
  510.   Dynarr_free (buf);
  511. }
  512.  
  513. /*****************************************************************************
  514.  x_bevel_modeline
  515.  
  516.  Draw a 3d border around the modeline on window W.
  517.  ****************************************************************************/
  518. static void
  519. x_bevel_modeline (struct window *w, struct display_line *dl)
  520. {
  521.   struct frame *f = XFRAME (w->frame);
  522.   struct device *d = XDEVICE (f->device);
  523.   Display *dpy = DEVICE_X_DISPLAY (d);
  524.   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
  525.   EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
  526.   GC top_shadow_gc, bottom_shadow_gc, background_gc;
  527.   Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
  528.   XColor tmp_color;
  529.   Lisp_Object tmp_pixel;
  530.   int x, y, width, height;
  531.   XGCValues gcv;
  532.   unsigned long mask;
  533.   int use_pixmap = 0;
  534.   int flip_gcs = 0;
  535.   int shadow_thickness;
  536.  
  537.   memset (&gcv, ~0, sizeof (XGCValues));
  538.  
  539.   tmp_pixel = FACE_CACHE_ELEMENT_BACKGROUND (w, MODELINE_INDEX);
  540.   tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
  541.  
  542.   /* First, get the GC's. */
  543.   top_shadow_pixel = tmp_color.pixel;
  544.   bottom_shadow_pixel = tmp_color.pixel;
  545.   background_pixel = tmp_color.pixel;
  546.  
  547.   x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
  548.                 background_pixel, ef->core.background_pixel);
  549.  
  550.   tmp_pixel = FACE_CACHE_ELEMENT_FOREGROUND (w, MODELINE_INDEX);
  551.   tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
  552.   gcv.background = tmp_color.pixel;
  553.   gcv.graphics_exposures = False;
  554.   mask = GCForeground | GCBackground | GCGraphicsExposures;
  555.  
  556.   if (top_shadow_pixel == background_pixel ||
  557.       bottom_shadow_pixel == background_pixel)
  558.     use_pixmap = 1;
  559.  
  560.   if (use_pixmap)
  561.     {
  562.       if (DEVICE_X_GRAY_PIXMAP (d) == None)
  563.     {
  564.       DEVICE_X_GRAY_PIXMAP (d) =
  565.         XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
  566.                      gray_width, gray_height, 1, 0, 1);
  567.     }
  568.  
  569.       tmp_pixel = FACE_CACHE_ELEMENT_BACKGROUND (w, MODELINE_INDEX);
  570.       tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
  571.       gcv.foreground = tmp_color.pixel;
  572.       gcv.fill_style = FillOpaqueStippled;
  573.       gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
  574.       top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
  575.                        (mask | GCStipple | GCFillStyle));
  576.  
  577.       tmp_pixel = FACE_CACHE_ELEMENT_FOREGROUND (w, MODELINE_INDEX);
  578.       tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
  579.       bottom_shadow_pixel = tmp_color.pixel;
  580.  
  581.       flip_gcs = (bottom_shadow_pixel ==
  582.           WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
  583.     }
  584.   else
  585.     {
  586.       gcv.foreground = top_shadow_pixel;
  587.       top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
  588.     }
  589.  
  590.   gcv.foreground = bottom_shadow_pixel;
  591.   bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
  592.  
  593.   if (use_pixmap && flip_gcs)
  594.     {
  595.       GC tmp_gc = bottom_shadow_gc;
  596.       bottom_shadow_gc = top_shadow_gc;
  597.       top_shadow_gc = tmp_gc;
  598.     }
  599.  
  600.   gcv.foreground = background_pixel;
  601.   background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
  602.  
  603.   if (XINT (w->modeline_shadow_thickness) < 0)
  604.     {
  605.       GC temp;
  606.  
  607.       temp = top_shadow_gc;
  608.       top_shadow_gc = bottom_shadow_gc;
  609.       bottom_shadow_gc = temp;
  610.     }
  611.  
  612.   shadow_thickness = MODELINE_SHADOW_THICKNESS (w);
  613.  
  614.   x = WINDOW_MODELINE_LEFT (w);
  615.   width = WINDOW_MODELINE_RIGHT (w) - x;
  616.   y = dl->ypos - dl->ascent - shadow_thickness;
  617.   height = dl->ascent + dl->descent + 2 * shadow_thickness;
  618.  
  619.   x_output_shadows (f, x, y, width, height, top_shadow_gc, bottom_shadow_gc,
  620.             background_gc, shadow_thickness);
  621. }
  622.  
  623. /*****************************************************************************
  624.  x_get_gc
  625.  
  626.  Given a number of parameters return a GC with those properties.
  627.  ****************************************************************************/
  628. static GC
  629. x_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
  630.       Lisp_Object bg_pmap, Lisp_Object lwidth)
  631. {
  632.   XGCValues gcv;
  633.   unsigned long mask;
  634.  
  635.   memset (&gcv, ~0, sizeof (XGCValues));
  636.   gcv.graphics_exposures = False;
  637.   /* Make absolutely sure that we don't pick up a clipping region in
  638.      the GC returned by this function. */
  639.   gcv.clip_mask = None;
  640.   gcv.clip_x_origin = 0;
  641.   gcv.clip_y_origin = 0;
  642.   gcv.fill_style = FillSolid;
  643.   mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
  644.   mask |= GCFillStyle;
  645.  
  646.   if (!NILP (font))
  647.     {
  648.       gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
  649.       mask |= GCFont;
  650.     }
  651.  
  652.   if (!NILP (fg))
  653.     {
  654.       if (COLOR_INSTANCEP (fg))
  655.     gcv.foreground = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (fg)).pixel;
  656.       else
  657.     gcv.foreground = XINT (fg);
  658.       mask |= GCForeground;
  659.     }
  660.  
  661.   if (!NILP (bg))
  662.     {
  663.       if (COLOR_INSTANCEP (bg))
  664.     gcv.background = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (bg)).pixel;
  665.       else
  666.     gcv.background = XINT (bg);
  667.       mask |= GCBackground;
  668.     }
  669.  
  670.   if (IMAGE_INSTANCEP (bg_pmap)
  671.       && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
  672.     {
  673.       if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
  674.     {
  675.       gcv.fill_style = FillOpaqueStippled;
  676.       gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
  677.       mask |= (GCStipple | GCFillStyle);
  678.     }
  679.       else
  680.     {
  681.       gcv.fill_style = FillTiled;
  682.       gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
  683.       mask |= (GCTile | GCFillStyle);
  684.     }
  685.     }
  686.  
  687.   if (!NILP (lwidth))
  688.     {
  689.       gcv.line_width = XINT (lwidth);
  690.       mask |= GCLineWidth;
  691.     }
  692.  
  693.   return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
  694. }
  695.  
  696. /*****************************************************************************
  697.  x_output_string
  698.  
  699.  Given a string and a starting position, output that string in the
  700.  given face.  If cursor is true, draw a cursor around the string.
  701.  ****************************************************************************/
  702. void
  703. x_output_string (struct window *w, struct display_line *dl,
  704.          emchar_dynarr *buf, int xpos, int xoffset, int start_pixpos,
  705.          int width, face_index findex, int cursor, int cursor_start,
  706.          int cursor_width, int cursor_height)
  707. {
  708.   struct frame *f = XFRAME (w->frame);
  709.   struct device *d = XDEVICE (f->device);
  710.   Lisp_Object device = Qnil;
  711.   Lisp_Object window = Qnil;
  712.   Lisp_Object font, bg_pmap;
  713.   Display *dpy = DEVICE_X_DISPLAY (d);
  714.   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
  715.   GC bgc, gc;
  716.   Pixel cursor_color;
  717.   int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS (d));
  718.   int cursor_clip;
  719.  
  720.   struct font_metric_info fm;
  721.   int height, font_height, clip_x, clip_width;
  722.  
  723.   XSETDEVICE (device, d);
  724.   XSETWINDOW (window, w);
  725.  
  726.   font = FACE_CACHE_ELEMENT_FONT (w, findex);
  727.   x_font_metric_info (d, font, &fm);
  728.   font_height = fm.ascent + fm.descent;
  729.  
  730.   bg_pmap = FACE_CACHE_ELEMENT_BACKGROUND_PIXMAP (w, findex);
  731.   if (!IMAGE_INSTANCEP (bg_pmap)
  732.       || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
  733.     bg_pmap = Qnil;
  734.  
  735.   if (width < 0)
  736.     width = x_text_width (w, font, Dynarr_atp (buf, 0), Dynarr_length (buf));
  737.   height = dl->ascent + dl->descent - dl->clip;
  738.  
  739.   cursor_clip = (cursor_start >= max (xpos, start_pixpos) &&
  740.          cursor_start < (xpos + width));
  741.  
  742.   if (cursor
  743.       || cursor_clip
  744.       || (cursor_width
  745.       && (cursor_start + cursor_width >= xpos)
  746.       && !NILP (Vbar_cursor)))
  747.     {
  748.       XtVaGetValues (FRAME_X_TEXT_WIDGET (f), XtNcursorColor,
  749.              &cursor_color, 0);
  750.     }
  751.  
  752.   /* Adjust for any possible clipping of the left side. */
  753.   if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
  754.     {
  755.       if (start_pixpos > xpos && start_pixpos > xpos + width)
  756.     return;
  757.  
  758.       clip_x = xoffset;
  759.       clip_width = width;
  760.  
  761.       if (start_pixpos > xpos)
  762.     {
  763.       clip_x += (start_pixpos - xpos);
  764.       clip_width -= (start_pixpos - xpos);
  765.     }
  766.     }
  767.   else
  768.     {
  769.       clip_x = 0;
  770.       clip_width = width;
  771.     }
  772.  
  773.   if (cursor && focus && NILP (Vbar_cursor))
  774.     {
  775.       gc = x_get_gc (d, font, FACE_CACHE_ELEMENT_BACKGROUND (w, findex),
  776.              make_number (cursor_color), Qnil, Qnil);
  777.       bgc = 0;
  778.     }
  779.   else
  780.     {
  781.       gc = x_get_gc (d, font, FACE_CACHE_ELEMENT_FOREGROUND (w, findex),
  782.              FACE_CACHE_ELEMENT_BACKGROUND (w, findex), Qnil, Qnil);
  783.       bgc = x_get_gc (d, font, FACE_CACHE_ELEMENT_FOREGROUND (w, findex),
  784.               FACE_CACHE_ELEMENT_BACKGROUND (w, findex),
  785.               bg_pmap, Qnil);
  786.     }
  787.  
  788.   if (dl->clip || clip_x)
  789.     {
  790.       XRectangle clip_box[1];
  791.  
  792.       clip_box[0].x = clip_x;
  793.       clip_box[0].y = 0;
  794.       clip_box[0].width = clip_width;
  795.       clip_box[0].height = height;
  796.  
  797.       XSetClipRectangles (dpy, gc, xpos - xoffset, dl->ypos - dl->ascent,
  798.               clip_box, 1, Unsorted);
  799.     }
  800.  
  801.   /* XDrawImageString only clears the area equal to the height of
  802.      the given font.  It is possible that a font is being displayed
  803.      on a line taller than it is, so this would cause us to fail to
  804.      clear some areas. */
  805.   if (font_height < (int) (height + dl->clip))
  806.     {
  807.       if (cursor)
  808.     {
  809.       int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
  810.  
  811.       ypos1_string = dl->ypos - fm.ascent;
  812.       ypos2_string = dl->ypos + fm.descent;
  813.       ypos1_line = dl->ypos - dl->ascent;
  814.       ypos2_line = dl->ypos + dl->descent - dl->clip;
  815.  
  816.       /* Make sure we don't clear below the real bottom of the
  817.              line. */
  818.       if (ypos1_string > ypos2_line)
  819.         ypos1_string = ypos2_line;
  820.       if (ypos2_string > ypos2_line)
  821.         ypos2_string = ypos2_line;
  822.  
  823.       if (ypos1_line < ypos1_string)
  824.         {
  825.           x_clear_region (window, findex, xpos + clip_x, ypos1_line,
  826.                   clip_width, ypos1_string - ypos1_line);
  827.         }
  828.  
  829.       if (ypos2_line > ypos2_string)
  830.         {
  831.           x_clear_region (window, findex, xpos + clip_x, ypos2_string,
  832.                   clip_width, ypos2_line - ypos2_string);
  833.         }
  834.     }
  835.       else
  836.     {
  837.       x_clear_region (window, findex, xpos + clip_x,
  838.               dl->ypos - dl->ascent, clip_width, height);
  839.     }
  840.     }
  841.  
  842. #ifdef MULE
  843.   {
  844.     /* !!#### temporary glue */
  845.     int i;
  846.     Emchar *s = Dynarr_atp (buf, 0);
  847.     int len = Dynarr_length (buf);
  848.     char *one_byte_string = (char *) alloca (len);
  849.     for (i = 0; i < len; i++)
  850.       {
  851.     if (s[i] < 0x80)
  852.       one_byte_string[i] = (char) s[i];
  853.     else
  854.       one_byte_string[i] = 'X';
  855.       }
  856.  
  857.     XmbDrawImageString (dpy, x_win, FONT_INSTANCE_X_FONT (font), gc, xpos,
  858.             dl->ypos, one_byte_string, len);
  859.   }
  860. #else
  861.   {
  862.     int i;
  863.     Emchar *s = Dynarr_atp (buf, 0);
  864.     int len = Dynarr_length (buf);
  865.     char *one_byte_string = (char *) alloca (len);
  866.     for (i = 0; i < len; i++)
  867.       {
  868.     /* #### perhaps should use DASSERT? */
  869.     assert (s[i] < 0x100);
  870.     one_byte_string[i] = (char) s[i];
  871.       }
  872.  
  873.     if (!NILP (bg_pmap) && bgc)
  874.       {
  875.     XFillRectangle (dpy, x_win, bgc, xpos + clip_x, dl->ypos - dl->ascent,
  876.             clip_width, height);
  877.     XDrawString (dpy, x_win, gc, xpos - xoffset, dl->ypos,
  878.              one_byte_string, len);
  879.       }
  880.     else
  881.       XDrawImageString (dpy, x_win, gc, xpos - xoffset, dl->ypos,
  882.             one_byte_string, len);
  883.   }
  884. #endif
  885.  
  886.   /* We draw underlines in the same color as the text. */
  887.   if (FACE_CACHE_ELEMENT_UNDERLINE_P (w, findex))
  888.     {
  889.       unsigned long upos, uthick;
  890.       XFontStruct *xfont;
  891.  
  892. #ifdef MULE
  893.       xfont =
  894.     first_font_struct_of (FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font)));
  895. #else
  896.       xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
  897. #endif
  898.       if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos))
  899.     upos = 0;
  900.       if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
  901.     uthick = 1;
  902.  
  903.       if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
  904.     {
  905.       if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
  906.         uthick = dl->descent - dl->clip - upos;
  907.  
  908.       if (uthick == 1)
  909.         {
  910.           XDrawLine (dpy, x_win, gc, xpos + clip_x, dl->ypos + upos,
  911.              xpos + clip_x + clip_width, dl->ypos + upos);
  912.         }
  913.       else if (uthick > 1)
  914.         {
  915.           XFillRectangle (dpy, x_win, gc, xpos + clip_x, dl->ypos + upos,
  916.                   clip_width, uthick);
  917.         }
  918.     }
  919.     }
  920.  
  921.   /* Restore the GC */
  922.   if (dl->clip || clip_x)
  923.     {
  924.       XSetClipMask (dpy, gc, None);
  925.       XSetClipOrigin (dpy, gc, 0, 0);
  926.     }
  927.  
  928.   /* If we are actually superimposing the cursor then redraw with just
  929.      the appropriate section highlighted. */
  930.   if (cursor_clip && !cursor && focus)
  931.     {
  932.       GC cgc;
  933.       XRectangle clip_box[1];
  934.  
  935.       cgc = x_get_gc (d, font, FACE_CACHE_ELEMENT_BACKGROUND (w, findex),
  936.               make_number (cursor_color), Qnil, Qnil);
  937.  
  938.       clip_box[0].x = cursor_start - start_pixpos;
  939.       clip_box[0].y = 0;
  940.       clip_box[0].width =
  941.     min (cursor_width, (start_pixpos + width - cursor_start));
  942.       clip_box[0].height = height;
  943.  
  944.       XSetClipRectangles (dpy, cgc, cursor_start, dl->ypos - dl->ascent,
  945.               clip_box, 1, Unsorted);
  946. #ifdef MULE
  947.       no way jose
  948. #else
  949.     {
  950.       /* #### Should reuse the string we create above. */
  951.       int i;
  952.       Emchar *s = Dynarr_atp (buf, 0);
  953.       int len = Dynarr_length (buf);
  954.       char *one_byte_string = (char *) alloca (len);
  955.       for (i = 0; i < len; i++)
  956.         {
  957.           /* #### perhaps should use DASSERT? */
  958.           assert (s[i] < 0x100);
  959.           one_byte_string[i] = (char) s[i];
  960.         }
  961.  
  962.       XDrawImageString (dpy, x_win, cgc, cursor_start, dl->ypos,
  963.                 one_byte_string, len);
  964.     }
  965. #endif
  966.  
  967.       XSetClipMask (dpy, cgc, None);
  968.       XSetClipOrigin (dpy, cgc, 0, 0);
  969.     }
  970.  
  971.   /* Draw the non-focus box or bar-cursor as needed. */
  972.   if ((cursor && !focus && NILP (Vbar_cursor))
  973.       || (cursor_width
  974.       && (cursor_start + cursor_width >= xpos)
  975.       && !NILP (Vbar_cursor)))
  976.     {
  977.       int tmp_height, tmp_y;
  978.       int bar_width = EQ (Vbar_cursor, Qt) ? 1 : 2;
  979.       int cursor_x;
  980.  
  981.       if (!NILP (Vbar_cursor))
  982.     {
  983.       gc = x_get_gc (d, Qnil, make_number (cursor_color), Qnil, Qnil,
  984.              make_number (bar_width));
  985.     }
  986.       else
  987.     {
  988.       gc = x_get_gc (d, Qnil, make_number (cursor_color),
  989.              Qnil, Qnil, Qnil);
  990.     }
  991.  
  992.       if (cursor)
  993.     cursor_x = xpos;
  994.       else
  995.     cursor_x = cursor_start;
  996.  
  997.       tmp_y = dl->ypos - fm.ascent;
  998.       tmp_height = cursor_height;
  999.       if (tmp_y + tmp_height > (int) (dl->ypos - dl->ascent + height))
  1000.     {
  1001.       tmp_y = dl->ypos - dl->ascent + height - tmp_height;
  1002.       if (tmp_y < (int) (dl->ypos - dl->ascent))
  1003.           tmp_y = dl->ypos - dl->ascent;
  1004.       tmp_height = dl->ypos - dl->ascent + height - tmp_y;
  1005.     }
  1006.  
  1007.       if (!focus && NILP (Vbar_cursor))
  1008.     {
  1009.       XDrawRectangle (dpy, x_win, gc, cursor_x, tmp_y, cursor_width - 1,
  1010.               tmp_height - 1);
  1011.     }
  1012.       else if (focus && !NILP (Vbar_cursor))
  1013.     {
  1014.       XDrawLine (dpy, x_win, gc, cursor_x + bar_width - 1, tmp_y,
  1015.              cursor_x + bar_width - 1, tmp_y + tmp_height - 1);
  1016.     }
  1017.     }
  1018. }
  1019.  
  1020. void
  1021. x_output_x_pixmap (struct frame *f, struct Lisp_Image_Instance *p, int x,
  1022.            int y, int clip_x, int clip_y, int clip_width,
  1023.            int clip_height, int width, int height, int pixmap_offset,
  1024.            unsigned long fg, unsigned long bg, GC override_gc)
  1025. {
  1026.   struct device *d = XDEVICE (f->device);
  1027.   Display *dpy = DEVICE_X_DISPLAY (d);
  1028.   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
  1029.  
  1030.   GC gc;
  1031.   XGCValues gcv;
  1032.   unsigned long pixmap_mask;
  1033.  
  1034.   if (!override_gc)
  1035.     {
  1036.       memset (&gcv, ~0, sizeof (XGCValues));
  1037.       gcv.graphics_exposures = False;
  1038.       gcv.foreground = fg;
  1039.       gcv.background = bg;
  1040.       pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
  1041.  
  1042.       if (IMAGE_INSTANCE_X_MASK (p))
  1043.     {
  1044.       gcv.function = GXcopy;
  1045.       gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
  1046.       gcv.clip_x_origin = x;
  1047.       gcv.clip_y_origin = y - pixmap_offset;
  1048.       pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
  1049.               GCClipYOrigin);
  1050.     }
  1051.  
  1052.       gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
  1053.     }
  1054.   else
  1055.     gc = override_gc;
  1056.  
  1057.   if (clip_x || clip_y)
  1058.     {
  1059.       XRectangle clip_box[1];
  1060.  
  1061.       clip_box[0].x = clip_x;
  1062.       clip_box[0].y = clip_y;
  1063.       clip_box[0].width = clip_width;
  1064.       clip_box[0].height = clip_height;
  1065.  
  1066.       XSetClipRectangles (dpy, gc, x, y, clip_box, 1, Unsorted);
  1067.     }
  1068.  
  1069.   /* depth of 0 means it's a bitmap, not a pixmap, and we should use
  1070.      XCopyPlane (1 = current foreground color, 0 = background) instead
  1071.      of XCopyArea, which means that the bits in the pixmap are actual
  1072.      pixel values, instead of symbolic of fg/bg. */
  1073.   if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
  1074.     {
  1075.       XCopyArea (dpy, IMAGE_INSTANCE_X_PIXMAP (p), x_win, gc, 0,
  1076.          pixmap_offset, width,
  1077.          height, x, y);
  1078.     }
  1079.   else
  1080.     {
  1081.       XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP (p), x_win, gc, 0,
  1082.           (pixmap_offset < 0
  1083.            ? 0
  1084.            : pixmap_offset),
  1085.           width, height, x,
  1086.           (pixmap_offset < 0
  1087.            ? y - pixmap_offset
  1088.            : y),
  1089.           1L);
  1090.     }
  1091.  
  1092.   if (clip_x || clip_y)
  1093.     {
  1094.       XSetClipMask (dpy, gc, None);
  1095.       XSetClipOrigin (dpy, gc, 0, 0);
  1096.     }
  1097. }
  1098.  
  1099. static void
  1100. x_output_pixmap (struct window *w, struct display_line *dl,
  1101.          Lisp_Object image_instance, int xpos, int xoffset,
  1102.          int start_pixpos, int width, face_index findex,
  1103.          int cursor_start, int cursor_width, int cursor_height)
  1104. {
  1105.   struct frame *f = XFRAME (w->frame);
  1106.   struct device *d = XDEVICE (f->device);
  1107.   struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
  1108.   Lisp_Object window;
  1109.  
  1110.   Display *dpy = DEVICE_X_DISPLAY (d);
  1111.   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
  1112.   int lheight = dl->ascent + dl->descent - dl->clip;
  1113.   int pheight = ((int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > lheight ? lheight :
  1114.          IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
  1115.   int pwidth = min (width + xoffset, (int) IMAGE_INSTANCE_PIXMAP_WIDTH (p));
  1116.   int clip_x, clip_y, clip_width, clip_height;
  1117.  
  1118.   /* The pixmap_offset is used to center the pixmap on lines which are
  1119.      shorter than it is.  This results in odd effects when scrolling
  1120.      pixmaps off of the bottom.  Let's try not using it. */
  1121. #if 0
  1122.   int pixmap_offset = (int) (IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - lheight) / 2;
  1123. #else
  1124.   int pixmap_offset = 0;
  1125. #endif
  1126.  
  1127.   XSETWINDOW (window, w);
  1128.  
  1129.   if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
  1130.     {
  1131.       if (start_pixpos > xpos && start_pixpos > xpos + width)
  1132.     return;
  1133.  
  1134.       clip_x = xoffset;
  1135.       clip_width = width;
  1136.       if (start_pixpos > xpos)
  1137.     {
  1138.       clip_x += (start_pixpos - xpos);
  1139.       clip_width -= (start_pixpos - xpos);
  1140.     }
  1141.     }
  1142.   else
  1143.     {
  1144.       clip_x = 0;
  1145.       clip_width = 0;
  1146.     }
  1147.  
  1148.   /* Place markers for possible future functionality (clipping the top
  1149.      half instead of the bottom half; think pixel scrolling). */
  1150.   clip_y = 0;
  1151.   clip_height = pheight;
  1152.  
  1153.   /* Clear the area the pixmap is going into.  The pixmap itself will
  1154.      always take care of the full width.  We don't want to clear where
  1155.      it is going to go in order to avoid flicker.  So, all we have to
  1156.      take care of is any area above or below the pixmap. */
  1157.   /* #### We take a shortcut for now.  We know that since we have
  1158.      pixmap_offset hardwired to 0 that the pixmap is against the top
  1159.      edge so all we have to worry about is below it. */
  1160.   /* #### Unless the pixmap has a mask in which case we have to clear
  1161.      the whole damn thing since we can't yet clear just the area not
  1162.      included in the mask. */
  1163.   if (((int) (dl->ypos - dl->ascent + pheight) <
  1164.        (int) (dl->ypos + dl->descent - dl->clip))
  1165.       || IMAGE_INSTANCE_X_MASK (p))
  1166.     {
  1167.       int clear_x, clear_y, clear_width, clear_height;
  1168.  
  1169.       if (IMAGE_INSTANCE_X_MASK (p))
  1170.     {
  1171.       clear_y = dl->ypos - dl->ascent;
  1172.       clear_height = lheight;
  1173.     }
  1174.       else
  1175.     {
  1176.       clear_y = dl->ypos - dl->ascent + pheight;
  1177.       clear_height = lheight - pheight;
  1178.     }
  1179.  
  1180.       if (start_pixpos >= 0 && start_pixpos > xpos)
  1181.     {
  1182.       clear_x = start_pixpos;
  1183.       clear_width = xpos + width - start_pixpos;
  1184.     }
  1185.       else
  1186.     {
  1187.       clear_x = xpos;
  1188.       clear_width = width;
  1189.     }
  1190.  
  1191.       x_clear_region (window, findex, clear_x, clear_y,
  1192.               clear_width, clear_height);
  1193.     }
  1194.  
  1195.   /* Output the pixmap. */
  1196.   {
  1197.     Lisp_Object tmp_pixel;
  1198.     XColor tmp_bcolor, tmp_fcolor;
  1199.  
  1200.     tmp_pixel = FACE_CACHE_ELEMENT_FOREGROUND (w, findex);
  1201.     tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
  1202.     tmp_pixel = FACE_CACHE_ELEMENT_BACKGROUND (w, findex);
  1203.     tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
  1204.  
  1205.     x_output_x_pixmap (f, p, xpos - xoffset, dl->ypos - dl->ascent, clip_x,
  1206.                clip_y, clip_width, clip_height,
  1207.                pwidth, pheight, pixmap_offset,
  1208.                tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
  1209.   }
  1210.  
  1211.   /* Draw a cursor over top of the pixmap. */
  1212.   if (cursor_width && cursor_height && (cursor_start >= xpos)
  1213.       && (cursor_start < xpos + pwidth))
  1214.     {
  1215.       Pixel cursor_color;
  1216.       GC gc;
  1217.       int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS (d));
  1218.       int y = dl->ypos - dl->ascent;
  1219.  
  1220.  
  1221.       XtVaGetValues (FRAME_X_TEXT_WIDGET (f), XtNcursorColor,
  1222.              &cursor_color, 0);
  1223.       gc = x_get_gc (d, Qnil, make_number (cursor_color), Qnil, Qnil, Qnil);
  1224.  
  1225.       if (cursor_width > xpos + pwidth - cursor_start)
  1226.     cursor_width = xpos + pwidth - cursor_start;
  1227.  
  1228.       if (focus)
  1229.     {
  1230.       XFillRectangle (dpy, x_win, gc, cursor_start, y, cursor_width,
  1231.               cursor_height);
  1232.     }
  1233.       else
  1234.     {
  1235.       XDrawRectangle (dpy, x_win, gc, cursor_start, y, cursor_width,
  1236.               cursor_height);
  1237.     }
  1238.     }
  1239. }
  1240.  
  1241. /*****************************************************************************
  1242.  x_output_vertical_divider
  1243.  
  1244.  Draw a vertical divider down the left side of the given window.
  1245.  ****************************************************************************/
  1246. static void
  1247. x_output_vertical_divider (struct window *w, int clear)
  1248. {
  1249.   struct frame *f = XFRAME (w->frame);
  1250.   struct device *d = XDEVICE (f->device);
  1251.  
  1252.   Display *dpy = DEVICE_X_DISPLAY (d);
  1253.   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
  1254.   GC gc;
  1255.  
  1256.   /* We don't use the normal gutter measurements here because the
  1257.      horizontal scrollbars and toolbars do not stretch completely over
  1258.      to the right edge of the window.  Only the modeline does. */
  1259.   int modeline_height = window_modeline_height (w);
  1260.   int x1, x2;
  1261.   int y1, y2;
  1262.  
  1263.   if (f->scrollbar_on_left)
  1264.     x1 = WINDOW_LEFT (w);
  1265.   else
  1266.     x1 = WINDOW_RIGHT (w) - X_DIVIDER_WIDTH;
  1267.   x2 = x1 + X_DIVIDER_SPACING;
  1268.  
  1269.   if (f->scrollbar_on_top)
  1270.     y1 = WINDOW_TOP (w);
  1271.   else
  1272.     y1 = WINDOW_TEXT_TOP (w);
  1273.   y2 = WINDOW_BOTTOM (w) - modeline_height;
  1274.  
  1275.   /* Draw the divider in the window. */
  1276.   {
  1277.     /* Clear the divider area first.  This needs to be done when a
  1278.        window split occurs. */
  1279.     if (clear)
  1280.       XClearArea (dpy, x_win, x1, y1, X_DIVIDER_WIDTH, y2 - y1, False);
  1281.  
  1282.     /* #### There needs to be some checks to make sure that whatever
  1283.        colors we choose, the line will be visible (not same color as
  1284.        default background. */
  1285.     gc = x_get_gc (d, Qnil, FACE_CACHE_ELEMENT_BACKGROUND (w, MODELINE_INDEX),
  1286.            FACE_CACHE_ELEMENT_FOREGROUND (w, MODELINE_INDEX),
  1287.            Qnil, Qnil);
  1288.  
  1289.     /* Draw the divider line. */
  1290.     XFillRectangle (dpy, x_win, gc, x2, y1, X_DIVIDER_LINE_WIDTH, y2 - y1);
  1291.   }
  1292.  
  1293.   /* Draw the divider in the modeline but only if we are using 2D
  1294.      modelines. */
  1295.   if (EQ (Qzero, w->modeline_shadow_thickness))
  1296.     {
  1297.       XFillRectangle (dpy, x_win, gc, x1, y2, X_DIVIDER_WIDTH,
  1298.               modeline_height);
  1299.  
  1300.       /* #### There needs to be some checks to make sure that whatever
  1301.      colors we choose, the line will be visible (not same color as
  1302.      default background. */
  1303.       gc = x_get_gc (d, Qnil,
  1304.              FACE_CACHE_ELEMENT_FOREGROUND (w, MODELINE_INDEX),
  1305.              FACE_CACHE_ELEMENT_BACKGROUND (w, MODELINE_INDEX),
  1306.              Qnil, Qnil);
  1307.  
  1308.       /* Draw the divider line. */
  1309.       XFillRectangle (dpy, x_win, gc, x2, y2, X_DIVIDER_LINE_WIDTH,
  1310.               modeline_height);
  1311.     }
  1312. }
  1313.  
  1314. /*****************************************************************************
  1315.  x_output_blank
  1316.  
  1317.  Output a blank by clearing the area it covers in the foreground color
  1318.  of its face.
  1319.  ****************************************************************************/
  1320. static void
  1321. x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
  1322.         int start_pixpos, int cursor_start, int cursor_width)
  1323. {
  1324.   struct frame *f = XFRAME (w->frame);
  1325.   struct device *d = XDEVICE (f->device);
  1326.  
  1327.   Display *dpy = DEVICE_X_DISPLAY (d);
  1328.   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
  1329.   GC gc;
  1330.   Pixel cursor_color;
  1331.   Lisp_Object bg_pmap;
  1332.  
  1333.   int x = rb->xpos;
  1334.   int y = dl->ypos - dl->ascent;
  1335.   int width = rb->width;
  1336.   int height = dl->ascent + dl->descent - dl->clip;
  1337.  
  1338.   if (start_pixpos > x)
  1339.     {
  1340.       if (start_pixpos >= (x + width))
  1341.     return;
  1342.       else
  1343.     {
  1344.       width -= (start_pixpos - x);
  1345.       x = start_pixpos;
  1346.     }
  1347.     }
  1348.  
  1349.   bg_pmap = FACE_CACHE_ELEMENT_BACKGROUND_PIXMAP (w, rb->findex);
  1350.   if (!IMAGE_INSTANCEP (bg_pmap)
  1351.       || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
  1352.     bg_pmap = Qnil;
  1353.  
  1354.   if (NILP (bg_pmap))
  1355.     gc = x_get_gc (d, Qnil, FACE_CACHE_ELEMENT_BACKGROUND (w, rb->findex),
  1356.            Qnil, Qnil, Qnil);
  1357.   else
  1358.     gc = x_get_gc (d, Qnil, FACE_CACHE_ELEMENT_FOREGROUND (w, rb->findex),
  1359.            FACE_CACHE_ELEMENT_BACKGROUND (w, rb->findex), bg_pmap,
  1360.            Qnil);
  1361.  
  1362.   XFillRectangle (dpy, x_win, gc, x, y, width, height);
  1363.  
  1364.   /* If this rune is marked as having the cursor, then it is actually
  1365.      representing a tab. */
  1366.   if (rb->cursor_type == CURSOR_ON
  1367.       || (cursor_width
  1368.       && (cursor_start + cursor_width > x)
  1369.       && cursor_start < (x + width)))
  1370.     {
  1371.       struct font_metric_info fm;
  1372.       int cursor_height, cursor_y;
  1373.       int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS (d));
  1374.  
  1375.       XtVaGetValues (FRAME_X_TEXT_WIDGET (f), XtNcursorColor,
  1376.              &cursor_color, 0);
  1377.       gc = x_get_gc (d, Qnil, make_number (cursor_color), Qnil, Qnil, Qnil);
  1378.  
  1379.       x_font_metric_info (d, FACE_CACHE_ELEMENT_FONT (w, rb->findex), &fm);
  1380.  
  1381.       cursor_y = dl->ypos - fm.ascent;
  1382.       cursor_height = fm.height;
  1383.       if (cursor_y + cursor_height > y + height)
  1384.     cursor_height = y + height - cursor_y;
  1385.  
  1386.       if (focus)
  1387.     {
  1388.       if (NILP (Vbar_cursor))
  1389.         {
  1390.           XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y, fm.width,
  1391.                   cursor_height);
  1392.         }
  1393.       else
  1394.         {
  1395.           int bar_width = EQ (Vbar_cursor, Qt) ? 1 : 2;
  1396.  
  1397.           gc = x_get_gc (d, Qnil, make_number (cursor_color), Qnil, Qnil,
  1398.                  make_number (bar_width));
  1399.           XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
  1400.              cursor_y, cursor_start + bar_width - 1,
  1401.              cursor_y + cursor_height - 1);
  1402.         }
  1403.     }
  1404.       else if (NILP (Vbar_cursor))
  1405.     {
  1406.       XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y, fm.width - 1,
  1407.               cursor_height - 1);
  1408.     }
  1409.     }
  1410. }
  1411.  
  1412. /*****************************************************************************
  1413.  x_output_hline
  1414.  
  1415.  Output a horizontal line in the foreground of its face.
  1416.  ****************************************************************************/
  1417. static void
  1418. x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
  1419. {
  1420.   struct frame *f = XFRAME (w->frame);
  1421.   struct device *d = XDEVICE (f->device);
  1422.  
  1423.   Display *dpy = DEVICE_X_DISPLAY (d);
  1424.   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
  1425.   GC gc;
  1426.  
  1427.   int x = rb->xpos;
  1428.   int width = rb->width;
  1429.   int height = dl->ascent + dl->descent - dl->clip;
  1430.   int ypos1, ypos2, ypos3, ypos4;
  1431.  
  1432.   ypos1 = dl->ypos - dl->ascent;
  1433.   ypos2 = ypos1 + rb->object.hline.yoffset;
  1434.   ypos3 = ypos2 + rb->object.hline.thickness;
  1435.   ypos4 = dl->ypos + dl->descent - dl->clip;
  1436.  
  1437.   /* First clear the area not covered by the line. */
  1438.   if (height - rb->object.hline.thickness > 0)
  1439.     {
  1440.       gc = x_get_gc (d, Qnil, FACE_CACHE_ELEMENT_FOREGROUND (w, rb->findex),
  1441.              Qnil, Qnil, Qnil);
  1442.  
  1443.       if (ypos2 - ypos1 > 0)
  1444.     XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
  1445.       if (ypos4 - ypos3 > 0)
  1446.     XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
  1447.     }
  1448.  
  1449.   /* Now draw the line. */
  1450.   gc = x_get_gc (d, Qnil, FACE_CACHE_ELEMENT_BACKGROUND (w, rb->findex),
  1451.          Qnil, Qnil, Qnil);
  1452.  
  1453.   if (ypos2 < ypos1)
  1454.     ypos2 = ypos1;
  1455.   if (ypos3 > ypos4)
  1456.     ypos3 = ypos4;
  1457.  
  1458.   if (ypos3 - ypos2 > 0)
  1459.     XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
  1460. }
  1461.  
  1462. /*****************************************************************************
  1463.  x_output_shadows
  1464.  
  1465.  Draw a shadow around the given area using the given GC's.  It is the
  1466.  callers responsibility to ste the GC's appropriately.
  1467.  ****************************************************************************/
  1468. void
  1469. x_output_shadows (struct frame *f, int x, int y, int width, int height,
  1470.           GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
  1471.           int shadow_thickness)
  1472. {
  1473.   struct device *d = XDEVICE (f->device);
  1474.  
  1475.   Display *dpy = DEVICE_X_DISPLAY (d);
  1476.   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
  1477.  
  1478.   XSegment top_shadow[20], bottom_shadow[20];
  1479.   int elt;
  1480.  
  1481.   if (shadow_thickness > 10)
  1482.     shadow_thickness = 10;
  1483.   else if (shadow_thickness < 0)
  1484.     shadow_thickness = 0;
  1485.   if (shadow_thickness > (width / 2))
  1486.     shadow_thickness = width / 2;
  1487.   if (shadow_thickness > (height / 2))
  1488.     shadow_thickness = height / 2;
  1489.  
  1490.   for (elt = 0; elt < shadow_thickness; elt++)
  1491.     {
  1492.       int seg1 = elt;
  1493.       int seg2 = elt + shadow_thickness;
  1494.  
  1495.       top_shadow[seg1].x1 = x;
  1496.       top_shadow[seg1].x2 = x + width - elt - 1;
  1497.       top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
  1498.  
  1499.       top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
  1500.       top_shadow[seg2].y1 = y + shadow_thickness;
  1501.       top_shadow[seg2].y2 = y + height - elt - 1;
  1502.  
  1503.       bottom_shadow[seg1].x1 = x + elt + 1;
  1504.       bottom_shadow[seg1].x2 = x + width - 1;
  1505.       bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
  1506.  
  1507.       bottom_shadow[seg2].x1 = bottom_shadow[seg2].x2 = x + width - elt - 1;
  1508.       bottom_shadow[seg2].y1 = y + elt + 1;
  1509.       bottom_shadow[seg2].y2 = y + height - shadow_thickness;
  1510.     }
  1511.  
  1512.   XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow, shadow_thickness * 2);
  1513.   XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
  1514.          shadow_thickness * 2);
  1515. }
  1516.  
  1517. /*****************************************************************************
  1518.  x_generate_shadow_pixels
  1519.  
  1520.  Given three pixels (top shadow, bottom shadow, background) massage
  1521.  the top and bottom shadow colors to guarantee that they differ.  The
  1522.  background pixels are not allowed to be modified.
  1523.  
  1524.  This function modifies its parameters.
  1525.  
  1526.  This code is modified from code blatantly stolen from lwlib/xlwmenu.c
  1527.  ****************************************************************************/
  1528. #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
  1529.            ? ((unsigned long) (x)) : ((unsigned long) (y)))
  1530.  
  1531. void
  1532. x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
  1533.               unsigned long *bottom_shadow,
  1534.               unsigned long background,
  1535.               unsigned long core_background)
  1536. {
  1537.   struct device *d = XDEVICE (f->device);
  1538.   Display *dpy = DEVICE_X_DISPLAY (d);
  1539.   Colormap cmap =
  1540.     DefaultColormapOfScreen (XtScreen ((Widget) FRAME_X_TEXT_WIDGET (f)));
  1541.  
  1542.   XColor topc, botc;
  1543.   int top_frobbed = 0, bottom_frobbed = 0;
  1544.  
  1545.   /* If the top shadow is the same color as the background, try and
  1546.      adjust it. */
  1547.   if (*top_shadow == background)
  1548.     {
  1549.       topc.pixel = background;
  1550.       XQueryColor (dpy, cmap, &topc);
  1551.       /* don't overflow/wrap! */
  1552.       topc.red   = MINL (65535, topc.red   * 1.2);
  1553.       topc.green = MINL (65535, topc.green * 1.2);
  1554.       topc.blue  = MINL (65535, topc.blue  * 1.2);
  1555.       if (allocate_nearest_color (dpy, cmap, &topc))
  1556.     {
  1557.       *top_shadow = topc.pixel;
  1558.       top_frobbed = 1;
  1559.     }
  1560.     }
  1561.  
  1562.   /* If the bottom shadow is the same color as the background, try and
  1563.      adjust it. */
  1564.   if (*bottom_shadow == background)
  1565.     {
  1566.       botc.pixel = background;
  1567.       XQueryColor (dpy, cmap, &botc);
  1568.       botc.red   *= 0.6;
  1569.       botc.green *= 0.6;
  1570.       botc.blue  *= 0.6;
  1571.       if (allocate_nearest_color (dpy, cmap, &botc))
  1572.     {
  1573.       *bottom_shadow = botc.pixel;
  1574.       bottom_frobbed = 1;
  1575.     }
  1576.     }
  1577.  
  1578.   /* If we had to adjust both shadows, then we have to do some
  1579.      additional work. */
  1580.   if (top_frobbed && bottom_frobbed)
  1581.     {
  1582.       int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
  1583.       int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
  1584.       if (bot_avg > top_avg)
  1585.     {
  1586.       Pixel tmp = *top_shadow;
  1587.  
  1588.       *top_shadow = *bottom_shadow;
  1589.       *bottom_shadow = tmp;
  1590.     }
  1591.       else if (topc.pixel == botc.pixel)
  1592.     {
  1593.       if (botc.pixel == background)
  1594.         *top_shadow = core_background;
  1595.       else
  1596.         *bottom_shadow = background;
  1597.     }
  1598.     }
  1599. }
  1600.  
  1601. /*****************************************************************************
  1602.  x_clear_to_window_end
  1603.  
  1604.  Clear the area between ypos1 and ypos2.  Each margin area and the
  1605.  text area is handled separately since they may each have their own
  1606.  background color.
  1607.  ****************************************************************************/
  1608. static void
  1609. x_clear_to_window_end (struct window *w, int ypos1, int ypos2)
  1610. {
  1611.   int height = ypos2 - ypos1;
  1612.  
  1613.   if (height)
  1614.     {
  1615.       struct frame *f = XFRAME (w->frame);
  1616.       Lisp_Object window;
  1617.       int bflag = (window_needs_vertical_divider (w) ? 0 : 1);
  1618.       layout_bounds bounds;
  1619.  
  1620.       bounds = calculate_display_line_boundaries (w, bflag);
  1621.       XSETWINDOW (window, w);
  1622.  
  1623.       if (window_is_leftmost (w))
  1624.     x_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f),
  1625.             ypos1, FRAME_BORDER_WIDTH (f), height);
  1626.  
  1627.       if (bounds.left_in - bounds.left_out > 0)
  1628.     x_clear_region (window,
  1629.             get_builtin_face_cache_index (w, Vleft_margin_face),
  1630.             bounds.left_out, ypos1,
  1631.             bounds.left_in - bounds.left_out, height);
  1632.  
  1633.       if (bounds.right_in - bounds.left_in > 0)
  1634.     x_clear_region (window, DEFAULT_INDEX, bounds.left_in, ypos1,
  1635.             bounds.right_in - bounds.left_in, height);
  1636.  
  1637.       if (bounds.right_out - bounds.right_in > 0)
  1638.     x_clear_region (window,
  1639.             get_builtin_face_cache_index (w, Vright_margin_face),
  1640.             bounds.right_in, ypos1,
  1641.             bounds.right_out - bounds.right_in, height);
  1642.  
  1643.       if (window_is_rightmost (w))
  1644.     x_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f),
  1645.             ypos1, FRAME_BORDER_WIDTH (f), height);
  1646.     }
  1647. }
  1648.  
  1649. /*****************************************************************************
  1650.  x_redraw_exposed_window
  1651.  
  1652.  Given a bounding box for an area that needs to be redrawn, determine
  1653.  what parts of what lines are contained within and re-output their
  1654.  contents.
  1655.  ****************************************************************************/
  1656. static void
  1657. x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
  1658. {
  1659.   struct frame *f = XFRAME (w->frame);
  1660.   int line;
  1661.   int start_x, start_y, end_x, end_y;
  1662.   int orig_windows_structure_changed;
  1663.  
  1664.   display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
  1665.  
  1666.   if (!NILP (w->vchild))
  1667.     {
  1668.       x_redraw_exposed_windows (w->vchild, x, y, width, height);
  1669.       return;
  1670.     }
  1671.   else if (!NILP (w->hchild))
  1672.     {
  1673.       x_redraw_exposed_windows (w->hchild, x, y, width, height);
  1674.       return;
  1675.     }
  1676.  
  1677.   /* If the window doesn't intersect the exposed region, we're done here. */
  1678.   if (x > WINDOW_RIGHT (w) || (x + width) < WINDOW_LEFT (w)
  1679.       || y > WINDOW_BOTTOM (w) || (y + height) < WINDOW_TOP (w))
  1680.     {
  1681.       return;
  1682.     }
  1683.   else
  1684.     {
  1685.       start_x = max (WINDOW_LEFT (w), x);
  1686.       end_x = min (WINDOW_RIGHT (w), (x + width));
  1687.       start_y = max (WINDOW_TOP (w), y);
  1688.       end_y = min (WINDOW_BOTTOM (w), y + height);
  1689.  
  1690.       /* We do this to make sure that the 3D modelines get redrawn if
  1691.          they are in the exposed region. */
  1692.       orig_windows_structure_changed = f->windows_structure_changed;
  1693.       f->windows_structure_changed = 1;
  1694.     } 
  1695.  
  1696.   if (window_needs_vertical_divider (w))
  1697.     {
  1698.       x_output_vertical_divider (w, 0);
  1699.     }
  1700.  
  1701.   for (line = 0; line < Dynarr_length (cdla); line++)
  1702.     {
  1703.       struct display_line *cdl = Dynarr_atp (cdla, line);
  1704.       int top_y = cdl->ypos - cdl->ascent;
  1705.       int bottom_y = cdl->ypos + cdl->descent;
  1706.  
  1707.       if (bottom_y >= start_y)
  1708.     {
  1709.       if (top_y > end_y)
  1710.         {
  1711.           if (line == 0)
  1712.         continue;
  1713.           else
  1714.         break;
  1715.         }
  1716.       else
  1717.         {
  1718.           output_display_line (w, 0, cdla, line, start_x, end_x);
  1719.         }
  1720.     }
  1721.     }
  1722.  
  1723.   f->windows_structure_changed = orig_windows_structure_changed;
  1724.  
  1725.   /* If there have never been any face cache_elements created, then this
  1726.      expose event doesn't actually have anything to do. */
  1727.   if (Dynarr_largest (w->face_cache_elements))
  1728.     redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
  1729. }
  1730.  
  1731. /*****************************************************************************
  1732.  x_redraw_exposed_windows
  1733.  
  1734.  For each window beneath the given window in the window hierarchy,
  1735.  ensure that it is redrawn if necessary after an Expose event.
  1736.  ****************************************************************************/
  1737. static void
  1738. x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
  1739.               int height)
  1740. {
  1741.   for (; !NILP (window); window = XWINDOW (window)->next)
  1742.     x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
  1743. }
  1744.  
  1745. /*****************************************************************************
  1746.  x_redraw_exposed_area
  1747.  
  1748.  For each window on the given frame, ensure that any area in the
  1749.  Exposed area is redrawn.
  1750.  ****************************************************************************/
  1751. void
  1752. x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
  1753. {
  1754.   /* If any window on the frame has had its face cache reset then the
  1755.      redisplay structures are effectively invalid.  If we attempt to
  1756.      use them we'll blow up.  We mark the frame as changed to ensure
  1757.      that redisplay will do a full update.  This probably isn't
  1758.      necessary but it can't hurt. */
  1759.  
  1760.   /* #### We would rather put these off as well but there is currently
  1761.      no combination of flags which will force an unchanged toolbar to
  1762.      redraw anyhow. */
  1763.   x_redraw_exposed_toolbars (f, x, y, width, height);
  1764.  
  1765.   if (!f->window_face_cache_reset)
  1766.     {
  1767.       x_redraw_exposed_windows (f->root_window, x, y, width, height);
  1768.  
  1769.       XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
  1770.     }
  1771.   else
  1772.     MARK_FRAME_CHANGED (f);
  1773. }
  1774.  
  1775. /****************************************************************************
  1776.  x_clear_region
  1777.  
  1778.  Clear the area in the box defined by the given parameters using the
  1779.  given face.
  1780.  ****************************************************************************/
  1781. static void
  1782. x_clear_region (Lisp_Object locale, face_index findex, int x, int y,
  1783.         int width, int height)
  1784. {
  1785.   struct window *w = 0;
  1786.   struct frame *f = 0;
  1787.   struct device *d;
  1788.   Lisp_Object background_pixmap;
  1789.  
  1790.   Display *dpy;
  1791.   Window x_win;
  1792.  
  1793.   if (WINDOWP (locale))
  1794.     {
  1795.       w = XWINDOW (locale);
  1796.       f = XFRAME (w->frame);
  1797.     }
  1798.   else if (FRAMEP (locale))
  1799.     {
  1800.       w = 0;
  1801.       f = XFRAME (locale);
  1802.     }
  1803.   else
  1804.     abort ();
  1805.  
  1806.   d = XDEVICE (f->device);
  1807.   dpy = DEVICE_X_DISPLAY (d);
  1808.   x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
  1809.  
  1810.   /* #### This function is going to have to be made cursor aware. */
  1811.   if (width && height)
  1812.     {
  1813.       int values_set = 0;
  1814.       GC gc;
  1815.  
  1816.       /* #### This isn't quite right for when this function is called
  1817.          from the toolbar code. */
  1818.       background_pixmap = Qunbound;
  1819.  
  1820.       /* Don't use a backing pixmap in the border area */
  1821.       if (x >= FRAME_LEFT_BORDER_END (f)
  1822.       && x < FRAME_RIGHT_BORDER_START (f)
  1823.       && y >= FRAME_TOP_BORDER_END (f)
  1824.       && y < FRAME_BOTTOM_BORDER_START (f))
  1825.     {
  1826.       Lisp_Object temp;
  1827.  
  1828.       if (w)
  1829.         {
  1830.           temp = FACE_CACHE_ELEMENT_BACKGROUND_PIXMAP (w, findex);
  1831.  
  1832.           if (IMAGE_INSTANCEP (temp)
  1833.           && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
  1834.         {
  1835.           /* #### maybe we could implement such that a string
  1836.              can be a background pixmap? */
  1837.           background_pixmap = temp;
  1838.         }
  1839.         }
  1840.       else
  1841.         {
  1842.           temp = FACE_BACKGROUND_PIXMAP (Vdefault_face, locale);
  1843.  
  1844.           if (IMAGE_INSTANCEP (temp)
  1845.           && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
  1846.         {
  1847.           background_pixmap = temp;
  1848.         }
  1849.         }
  1850.  
  1851.       if (!UNBOUNDP (background_pixmap) &&
  1852.           XIMAGE_INSTANCE_PIXMAP_DEPTH (background_pixmap) == 0)
  1853.         {
  1854.           Lisp_Object fcolor, bcolor;
  1855.  
  1856.           if (w)
  1857.         {
  1858.           fcolor = FACE_CACHE_ELEMENT_FOREGROUND (w, findex);
  1859.           bcolor = FACE_CACHE_ELEMENT_BACKGROUND (w, findex);
  1860.         }
  1861.           else
  1862.         {
  1863.           fcolor = FACE_FOREGROUND (Vdefault_face, locale);
  1864.           bcolor = FACE_BACKGROUND (Vdefault_face, locale);
  1865.         }
  1866.  
  1867.           gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap,
  1868.                  Qnil);
  1869.           values_set = 1;
  1870.         }
  1871.       else
  1872.         {
  1873.           Lisp_Object color;
  1874.  
  1875.           if (UNBOUNDP (background_pixmap))
  1876.         background_pixmap = Qnil;
  1877.  
  1878.           if (w)
  1879.         color = FACE_CACHE_ELEMENT_BACKGROUND (w, findex);
  1880.           else
  1881.         color = FACE_BACKGROUND (Vdefault_face, locale);
  1882.  
  1883.           gc = x_get_gc (d, Qnil, color, Qnil, background_pixmap,
  1884.                  Qnil);
  1885.           values_set = 1;
  1886.         }
  1887.     }
  1888.  
  1889.       if (values_set)
  1890.     {
  1891.       XFillRectangle (dpy, x_win, gc, x, y, width, height);
  1892.     }
  1893.       else
  1894.     {
  1895.       XClearArea (dpy, x_win, x, y, width, height, False);
  1896.     }
  1897.     }
  1898. }
  1899.  
  1900. /*****************************************************************************
  1901.  x_output_eol_cursor
  1902.  
  1903.  Draw a cursor at the end of a line.  The end-of-line cursor is
  1904.  narrower than the normal cursor.
  1905.  ****************************************************************************/
  1906. static void
  1907. x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos)
  1908. {
  1909.   struct frame *f = XFRAME (w->frame);
  1910.   struct device *d = XDEVICE (f->device);
  1911.  
  1912.   Display *dpy = DEVICE_X_DISPLAY (d);
  1913.   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
  1914.   GC gc;
  1915.   Pixel cursor_color;
  1916.   struct font_metric_info fm;
  1917.   int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS (d));
  1918.  
  1919.   int x = xpos;
  1920.   int y = dl->ypos - dl->ascent;
  1921.   int width = EOL_CURSOR_WIDTH;
  1922.   int height = dl->ascent + dl->descent - dl->clip;
  1923.   int cursor_height, cursor_y;
  1924.  
  1925.   XtVaGetValues (FRAME_X_TEXT_WIDGET (f), XtNcursorColor, &cursor_color, 0);
  1926.  
  1927.   gc = x_get_gc (d, Qnil, make_number (cursor_color), Qnil, Qnil, Qnil);
  1928.  
  1929.   XClearArea (dpy, x_win, x, y, width, height, False);
  1930.  
  1931.   x_font_metric_info (d, FACE_CACHE_ELEMENT_FONT (w, DEFAULT_INDEX), &fm);
  1932.   cursor_y = dl->ypos - fm.ascent;
  1933.   if (cursor_y < y)
  1934.     cursor_y = y;
  1935.   cursor_height = fm.height;
  1936.   if (cursor_y + cursor_height > y + height)
  1937.     cursor_height = y + height - cursor_y;
  1938.   
  1939.   if (focus)
  1940.     {
  1941.       if (NILP (Vbar_cursor))
  1942.     {
  1943.       XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
  1944.     }
  1945.       else
  1946.     {
  1947.       int bar_width = EQ (Vbar_cursor, Qt) ? 1 : 2;
  1948.  
  1949.       gc = x_get_gc (d, Qnil, make_number (cursor_color), Qnil, Qnil,
  1950.              make_number (bar_width));
  1951.       XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
  1952.              x + bar_width - 1, cursor_y + cursor_height - 1);
  1953.     }
  1954.     }
  1955.   else if (NILP (Vbar_cursor))
  1956.     {
  1957.       XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
  1958.               cursor_height - 1);
  1959.     }
  1960. }
  1961.  
  1962. static void x_clear_frame_windows (Lisp_Object window);
  1963.  
  1964. static void
  1965. x_clear_frame_window (Lisp_Object window)
  1966. {
  1967.   struct window *w = XWINDOW (window);
  1968.  
  1969.   if (!NILP (w->vchild))
  1970.     {
  1971.       x_clear_frame_windows (w->vchild);
  1972.       return;
  1973.     }
  1974.  
  1975.   if (!NILP (w->hchild))
  1976.     {
  1977.       x_clear_frame_windows (w->hchild);
  1978.       return;
  1979.     }
  1980.  
  1981.   x_clear_to_window_end (w, WINDOW_TEXT_TOP (w), WINDOW_TEXT_BOTTOM (w));
  1982. }
  1983.  
  1984. static void
  1985. x_clear_frame_windows (Lisp_Object window)
  1986. {
  1987.   for (; !NILP (window); window = XWINDOW (window)->next)
  1988.     x_clear_frame_window (window);
  1989. }
  1990.  
  1991. static void
  1992. x_clear_frame (struct frame *f)
  1993. {
  1994.   struct device *d = XDEVICE (f->device);
  1995.   Display *dpy = DEVICE_X_DISPLAY (d);
  1996.   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
  1997.   int x, y, width, height;
  1998.   Lisp_Object frame;
  1999.  
  2000.   x = FRAME_LEFT_BORDER_START (f);
  2001.   width = (FRAME_PIXWIDTH (f) - FRAME_LEFT_TOOLBAR_WIDTH (f) -
  2002.        FRAME_RIGHT_TOOLBAR_WIDTH (f));
  2003.   /* #### This adjustment by 1 should be being done in the macros.
  2004.      There is some small differences between when the menubar is on
  2005.      and off that we still need to deal with. */
  2006.   y = FRAME_TOP_BORDER_START (f) - 1;
  2007.   height = (FRAME_PIXHEIGHT (f) - FRAME_TOP_TOOLBAR_HEIGHT (f) -
  2008.         FRAME_BOTTOM_TOOLBAR_HEIGHT (f)) + 1;
  2009.  
  2010.   XClearArea (dpy, x_win, x, y, width, height, False);
  2011.  
  2012.   XSETFRAME (frame, f);
  2013.  
  2014.   if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
  2015.       || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
  2016.       || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
  2017.     {
  2018.       x_clear_frame_windows (f->root_window);
  2019.     }
  2020.  
  2021.   XFlush (DEVICE_X_DISPLAY (d));
  2022. }
  2023.  
  2024. /* briefly swap the foreground and background colors.
  2025.  */
  2026.  
  2027. static int
  2028. x_flash (struct device *d)
  2029. {
  2030.   Display *dpy;
  2031.   Window w;
  2032.   XGCValues gcv;
  2033.   GC gc;
  2034.   XColor tmp_fcolor, tmp_bcolor;
  2035.   Lisp_Object tmp_pixel, frame;
  2036.   struct frame *f = device_selected_frame (d);
  2037.   Widget shell = FRAME_X_SHELL_WIDGET (f);
  2038.   Dimension width, height;
  2039.  
  2040.   XtVaGetValues (shell, XtNwidth, &width, XtNheight, &height, 0);
  2041.   XSETFRAME (frame, f);
  2042.  
  2043.   tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
  2044.   tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
  2045.   tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
  2046.   tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
  2047.  
  2048.   dpy = XtDisplay (shell);
  2049.   w = XtWindow (FRAME_X_TEXT_WIDGET (f));
  2050.   memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
  2051.   gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
  2052.   gcv.function = GXxor;
  2053.   gcv.graphics_exposures = False;
  2054.   gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
  2055.             (GCForeground | GCFunction | GCGraphicsExposures));
  2056.   XFillRectangle (dpy, w, gc, 0, 0, width, height);
  2057.   XSync (dpy, False);
  2058.  
  2059.   {
  2060.     int usecs = 100000;
  2061.     struct timeval tv;
  2062.     tv.tv_sec  = usecs / 1000000L;
  2063.     tv.tv_usec = usecs % 1000000L;
  2064.     /* I'm sure someone is going to complain about this... */
  2065.     (void) select (0, 0, 0, 0, &tv);
  2066.   }
  2067.  
  2068.   XFillRectangle (dpy, w, gc, 0, 0, width, height);
  2069.   XSync (dpy, False);
  2070.  
  2071.   return 1;
  2072. }
  2073.  
  2074. /* Make audible bell.  */
  2075.  
  2076. static void
  2077. x_ring_bell (struct device *d, int volume, int pitch, int duration)
  2078. {
  2079.   Display *display = DEVICE_X_DISPLAY (d);
  2080.  
  2081.   if (volume < 0) volume = 0;
  2082.   else if (volume > 100) volume = 100;
  2083.   if (pitch < 0 && duration < 0)
  2084.     {
  2085.       XBell (display, (volume * 2) - 100);
  2086.       XFlush (display);
  2087.     }
  2088.   else
  2089.     {
  2090.       XKeyboardState state;
  2091.       XKeyboardControl ctl;
  2092.       XSync (display, 0);
  2093.       /* #### grab server? */
  2094.       XGetKeyboardControl (display, &state);
  2095.  
  2096.       ctl.bell_pitch    = (pitch    >= 0 ? pitch    : state.bell_pitch);
  2097.       ctl.bell_duration = (duration >= 0 ? duration : state.bell_duration);
  2098.       XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
  2099.  
  2100.       XBell (display, (volume * 2) - 100);
  2101.  
  2102.       ctl.bell_pitch    = state.bell_pitch;
  2103.       ctl.bell_duration = state.bell_duration;
  2104.       XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
  2105.  
  2106.       /* #### ungrab server? */
  2107.       XSync (display, 0);
  2108.     }
  2109. }
  2110.  
  2111.  
  2112. /************************************************************************/
  2113. /*                            initialization                            */
  2114. /************************************************************************/
  2115.  
  2116. void
  2117. device_type_create_redisplay_x (void)
  2118. {
  2119.   /* redisplay methods */
  2120.   DEVICE_HAS_METHOD (x, text_width);
  2121.   DEVICE_HAS_METHOD (x, font_metric_info);
  2122.   DEVICE_HAS_METHOD (x, output_display_block);
  2123.   DEVICE_HAS_METHOD (x, divider_width);
  2124.   DEVICE_HAS_METHOD (x, divider_height);
  2125.   DEVICE_HAS_METHOD (x, eol_cursor_width);
  2126.   DEVICE_HAS_METHOD (x, output_vertical_divider);
  2127.   DEVICE_HAS_METHOD (x, clear_to_window_end);
  2128.   DEVICE_HAS_METHOD (x, clear_region);
  2129.   DEVICE_HAS_METHOD (x, clear_frame);
  2130.   DEVICE_HAS_METHOD (x, output_begin);
  2131.   DEVICE_HAS_METHOD (x, output_end);
  2132.   DEVICE_HAS_METHOD (x, flash);
  2133.   DEVICE_HAS_METHOD (x, ring_bell);
  2134. }
  2135.