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