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