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