Initial revision
[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   if (IMAGE_INSTANCEP (bg_pmap)
697       && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
698     {
699       if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
700         {
701           gcv.fill_style = FillOpaqueStippled;
702           gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
703           mask |= (GCStipple | GCFillStyle);
704         }
705       else
706         {
707           gcv.fill_style = FillTiled;
708           gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
709           mask |= (GCTile | GCFillStyle);
710         }
711     }
712
713   if (!NILP (lwidth))
714     {
715       gcv.line_width = XINT (lwidth);
716       mask |= GCLineWidth;
717     }
718
719   return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
720 }
721
722 /*****************************************************************************
723  x_output_string
724
725  Given a string and a starting position, output that string in the
726  given face.  If cursor is true, draw a cursor around the string.
727  Correctly handles multiple charsets in the string.
728
729  The meaning of the parameters is something like this:
730
731  W              Window that the text is to be displayed in.
732  DL             Display line that this text is on.  The values in the
733                 structure are used to determine the vertical position and
734                 clipping range of the text.
735  BUF            Dynamic array of Emchars specifying what is actually to be
736                 drawn.
737  XPOS           X position in pixels where the text should start being drawn.
738  XOFFSET        Number of pixels to be chopped off the left side of the
739                 text.  The effect is as if the text were shifted to the
740                 left this many pixels and clipped at XPOS.
741  CLIP_START     Clip everything left of this X position.
742  WIDTH          Clip everything right of XPOS + WIDTH.
743  FINDEX         Index for the face cache element describing how to display
744                 the text.
745  CURSOR         #### I don't understand this.  There's something
746                 strange and overcomplexified with this variable.
747                 Chuck, explain please?
748  CURSOR_START   Starting X position of cursor.
749  CURSOR_WIDTH   Width of cursor in pixels.
750  CURSOR_HEIGHT  Height of cursor in pixels.
751
752  Starting Y position of cursor is the top of the text line.
753  The cursor is drawn sometimes whether or not CURSOR is set. ???
754  ****************************************************************************/
755 void
756 x_output_string (struct window *w, struct display_line *dl,
757                  Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
758                  int width, face_index findex, int cursor,
759                  int cursor_start, int cursor_width, int cursor_height)
760 {
761   /* General variables */
762   struct frame *f = XFRAME (w->frame);
763   struct device *d = XDEVICE (f->device);
764   Lisp_Object device;
765   Lisp_Object window;
766   Display *dpy = DEVICE_X_DISPLAY (d);
767   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
768
769   int clip_end;
770
771   /* Cursor-related variables */
772   int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
773   int cursor_clip;
774   Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
775                                                          WINDOW_BUFFER (w));
776   struct face_cachel *cursor_cachel = 0;
777
778   /* Text-related variables */
779   Lisp_Object bg_pmap;
780   GC bgc, gc;
781   int height;
782   int len = Dynarr_length (buf);
783   unsigned char *text_storage = (unsigned char *) alloca (2 * len);
784   struct textual_run *runs = alloca_array (struct textual_run, len);
785   int nruns;
786   int i;
787   struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
788
789   XSETDEVICE (device, d);
790   XSETWINDOW (window, w);
791
792   if (width < 0)
793     width = x_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
794   height = dl->ascent + dl->descent - dl->clip;
795
796   /* Regularize the variables passed in. */
797
798   if (clip_start < xpos)
799     clip_start = xpos;
800   clip_end = xpos + width;
801   if (clip_start >= clip_end)
802     /* It's all clipped out. */
803     return;
804
805   xpos -= xoffset;
806
807   nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
808                                  Dynarr_length (buf));
809
810   cursor_clip = (cursor_start >= clip_start &&
811                  cursor_start < clip_end);
812
813   /* This cursor code is really a mess. */
814   if (!NILP (w->text_cursor_visible_p)
815       && (cursor
816           || cursor_clip
817           || (cursor_width
818               && (cursor_start + cursor_width >= clip_start)
819               && !NILP (bar_cursor_value))))
820     {
821       /* These have to be in separate statements in order to avoid a
822          compiler bug. */
823       face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face);
824       cursor_cachel = WINDOW_FACE_CACHEL (w, sucks);
825
826       /* We have to reset this since any call to WINDOW_FACE_CACHEL
827          may cause the cache to resize and any pointers to it to
828          become invalid. */
829       cachel = WINDOW_FACE_CACHEL (w, findex);
830     }
831
832 #ifdef HAVE_XIM
833   if (cursor && focus && (cursor_start == clip_start) && cursor_height)
834     XIM_SetSpotLocation (f, xpos - 2, dl->ypos + dl->descent - 2);
835 #endif /* HAVE_XIM */
836
837   bg_pmap = cachel->background_pixmap;
838   if (!IMAGE_INSTANCEP (bg_pmap)
839       || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
840     bg_pmap = Qnil;
841
842   if ((cursor && focus && NILP (bar_cursor_value)
843        && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap))
844     bgc = 0;
845   else
846     bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
847                     bg_pmap, Qnil);
848
849   if (bgc)
850     XFillRectangle (dpy, x_win, bgc, clip_start,
851                     dl->ypos - dl->ascent, clip_end - clip_start,
852                     height);
853
854   for (i = 0; i < nruns; i++)
855     {
856       Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
857       struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
858       int this_width;
859       int need_clipping;
860
861       if (EQ (font, Vthe_null_font_instance))
862         continue;
863
864       this_width = x_text_width_single_run (cachel, runs + i);
865       need_clipping = (dl->clip || clip_start > xpos ||
866                        clip_end < xpos + this_width);
867
868       /* XDrawImageString only clears the area equal to the height of
869          the given font.  It is possible that a font is being displayed
870          on a line taller than it is, so this would cause us to fail to
871          clear some areas. */
872       if ((int) fi->height < (int) (height + dl->clip))
873         {
874           int clear_start = max (xpos, clip_start);
875           int clear_end = min (xpos + this_width, clip_end);
876
877           if (cursor)
878             {
879               int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
880
881               ypos1_string = dl->ypos - fi->ascent;
882               ypos2_string = dl->ypos + fi->descent;
883               ypos1_line = dl->ypos - dl->ascent;
884               ypos2_line = dl->ypos + dl->descent - dl->clip;
885
886               /* Make sure we don't clear below the real bottom of the
887                  line. */
888               if (ypos1_string > ypos2_line)
889                 ypos1_string = ypos2_line;
890               if (ypos2_string > ypos2_line)
891                 ypos2_string = ypos2_line;
892
893               if (ypos1_line < ypos1_string)
894                 {
895                   x_clear_region (window, findex, clear_start, ypos1_line,
896                                   clear_end - clear_start,
897                                   ypos1_string - ypos1_line);
898                 }
899
900               if (ypos2_line > ypos2_string)
901                 {
902                   x_clear_region (window, findex, clear_start, ypos2_string,
903                                   clear_end - clear_start,
904                                   ypos2_line - ypos2_string);
905                 }
906             }
907           else
908             {
909               x_clear_region (window, findex, clear_start,
910                               dl->ypos - dl->ascent, clear_end - clear_start,
911                               height);
912             }
913         }
914
915       if (cursor && cursor_cachel && focus && NILP (bar_cursor_value))
916         gc = x_get_gc (d, font, cursor_cachel->foreground,
917                        cursor_cachel->background, Qnil, Qnil);
918       else
919         gc = x_get_gc (d, font, cachel->foreground, cachel->background,
920                        Qnil, Qnil);
921
922       if (need_clipping)
923         {
924           XRectangle clip_box[1];
925
926           clip_box[0].x = 0;
927           clip_box[0].y = 0;
928           clip_box[0].width = clip_end - clip_start;
929           clip_box[0].height = height;
930
931           XSetClipRectangles (dpy, gc, clip_start, dl->ypos - dl->ascent,
932                               clip_box, 1, Unsorted);
933         }
934
935       if (runs[i].dimension == 1)
936         (bgc ? XDrawString : XDrawImageString) (dpy, x_win, gc, xpos,
937                                                 dl->ypos, (char *) runs[i].ptr,
938                                                 runs[i].len);
939       else
940         (bgc ? XDrawString16 : XDrawImageString16) (dpy, x_win, gc, xpos,
941                                                     dl->ypos,
942                                                     (XChar2b *) runs[i].ptr,
943                                                     runs[i].len);
944
945       /* We draw underlines in the same color as the text. */
946       if (cachel->underline)
947         {
948           unsigned long upos, uthick;
949           XFontStruct *xfont;
950
951           xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
952           if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos))
953             upos = dl->descent / 2;
954           if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
955             uthick = 1;
956
957           if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
958             {
959               if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
960                 uthick = dl->descent - dl->clip - upos;
961
962               if (uthick == 1)
963                 {
964                   XDrawLine (dpy, x_win, gc, xpos, dl->ypos + upos,
965                              xpos + this_width, dl->ypos + upos);
966                 }
967               else if (uthick > 1)
968                 {
969                   XFillRectangle (dpy, x_win, gc, xpos,
970                                   dl->ypos + upos, this_width, uthick);
971                 }
972             }
973         }
974
975       if (cachel->strikethru) {
976         unsigned long ascent,descent,upos, uthick;
977         XFontStruct *xfont;
978
979         xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
980
981         if (!XGetFontProperty (xfont, XA_STRIKEOUT_ASCENT, &ascent))
982           ascent = xfont->ascent;
983         if (!XGetFontProperty (xfont, XA_STRIKEOUT_DESCENT, &descent))
984           descent = xfont->descent;
985         if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
986           uthick = 1;
987
988         upos = ascent - ((ascent + descent) / 2) + 1;
989
990         /* Generally, upos will be positive (above the baseline),so subtract */
991         if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip)
992           {
993             if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip)
994               uthick = dl->descent - dl->clip + upos;
995
996             if (uthick == 1)
997               {
998                 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos,
999                            xpos + this_width, dl->ypos - upos);
1000               }
1001             else if (uthick > 1)
1002               {
1003                 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos,
1004                                 this_width, uthick);
1005               }
1006           }
1007       }
1008
1009       /* Restore the GC */
1010       if (need_clipping)
1011         {
1012           XSetClipMask (dpy, gc, None);
1013           XSetClipOrigin (dpy, gc, 0, 0);
1014         }
1015
1016       /* If we are actually superimposing the cursor then redraw with just
1017          the appropriate section highlighted. */
1018       if (cursor_clip && !cursor && focus && cursor_cachel)
1019         {
1020           GC cgc;
1021           XRectangle clip_box[1];
1022
1023           cgc = x_get_gc (d, font, cursor_cachel->foreground,
1024                           cursor_cachel->background, Qnil, Qnil);
1025
1026           clip_box[0].x = 0;
1027           clip_box[0].y = 0;
1028           clip_box[0].width = cursor_width;
1029           clip_box[0].height = height;
1030
1031           XSetClipRectangles (dpy, cgc, cursor_start, dl->ypos - dl->ascent,
1032                               clip_box, 1, Unsorted);
1033
1034           if (runs[i].dimension == 1)
1035             XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
1036                               (char *) runs[i].ptr, runs[i].len);
1037           else
1038             XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
1039                                 (XChar2b *) runs[i].ptr, runs[i].len);
1040
1041           XSetClipMask (dpy, cgc, None);
1042           XSetClipOrigin (dpy, cgc, 0, 0);
1043         }
1044
1045       xpos += this_width;
1046     }
1047
1048   /* Draw the non-focus box or bar-cursor as needed. */
1049   /* Can't this logic be simplified? */
1050   if (cursor_cachel
1051       && ((cursor && !focus && NILP (bar_cursor_value))
1052           || (cursor_width
1053               && (cursor_start + cursor_width >= clip_start)
1054               && !NILP (bar_cursor_value))))
1055     {
1056       int tmp_height, tmp_y;
1057       int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1058       int need_clipping = (cursor_start < clip_start
1059                            || clip_end < cursor_start + cursor_width);
1060
1061       /* #### This value is correct (as far as I know) because
1062          all of the times we need to draw this cursor, we will
1063          be called with exactly one character, so we know we
1064          can always use runs[0].
1065
1066          This is bogus as all hell, however.  The cursor handling in
1067          this function is way bogus and desperately needs to be
1068          cleaned up. (In particular, the drawing of the cursor should
1069          really really be separated out of this function.  This may be
1070          a bit tricky now because this function itself does way too
1071          much stuff, a lot of which needs to be moved into
1072          redisplay.c) This is the only way to be able to easily add
1073          new cursor types or (e.g.) make the bar cursor be able to
1074          span two characters instead of overlaying just one. */
1075       int bogusly_obtained_ascent_value =
1076         XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent;
1077
1078       if (!NILP (bar_cursor_value))
1079         {
1080           gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1081                          make_int (bar_width));
1082         }
1083       else
1084         {
1085           gc = x_get_gc (d, Qnil, cursor_cachel->background,
1086                          Qnil, Qnil, Qnil);
1087         }
1088
1089       tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1090       tmp_height = cursor_height;
1091       if (tmp_y + tmp_height > (int) (dl->ypos - dl->ascent + height))
1092         {
1093           tmp_y = dl->ypos - dl->ascent + height - tmp_height;
1094           if (tmp_y < (int) (dl->ypos - dl->ascent))
1095             tmp_y = dl->ypos - dl->ascent;
1096           tmp_height = dl->ypos - dl->ascent + height - tmp_y;
1097         }
1098
1099       if (need_clipping)
1100         {
1101           XRectangle clip_box[1];
1102           clip_box[0].x = 0;
1103           clip_box[0].y = 0;
1104           clip_box[0].width = clip_end - clip_start;
1105           clip_box[0].height = tmp_height;
1106           XSetClipRectangles (dpy, gc, clip_start, tmp_y,
1107                               clip_box, 1, Unsorted);
1108         }
1109
1110       if (!focus && NILP (bar_cursor_value))
1111         {
1112           XDrawRectangle (dpy, x_win, gc, cursor_start, tmp_y,
1113                           cursor_width - 1, tmp_height - 1);
1114         }
1115       else if (focus && !NILP (bar_cursor_value))
1116         {
1117           XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1, tmp_y,
1118                      cursor_start + bar_width - 1, tmp_y + tmp_height - 1);
1119         }
1120
1121       /* Restore the GC */
1122       if (need_clipping)
1123         {
1124           XSetClipMask (dpy, gc, None);
1125           XSetClipOrigin (dpy, gc, 0, 0);
1126         }
1127     }
1128 }
1129
1130 void
1131 x_output_x_pixmap (struct frame *f, struct Lisp_Image_Instance *p, int x,
1132                    int y, int clip_x, int clip_y, int clip_width,
1133                    int clip_height, int width, int height, int pixmap_offset,
1134                    unsigned long fg, unsigned long bg, GC override_gc)
1135 {
1136   struct device *d = XDEVICE (f->device);
1137   Display *dpy = DEVICE_X_DISPLAY (d);
1138   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1139
1140   GC gc;
1141   XGCValues gcv;
1142   unsigned long pixmap_mask;
1143   int need_clipping = (clip_x || clip_y);
1144
1145   if (!override_gc)
1146     {
1147       memset (&gcv, ~0, sizeof (XGCValues));
1148       gcv.graphics_exposures = False;
1149       gcv.foreground = fg;
1150       gcv.background = bg;
1151       pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
1152
1153       if (IMAGE_INSTANCE_X_MASK (p))
1154         {
1155           gcv.function = GXcopy;
1156           gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
1157           gcv.clip_x_origin = x;
1158           gcv.clip_y_origin = y - pixmap_offset;
1159           pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
1160                           GCClipYOrigin);
1161           /* Can't set a clip rectangle below because we already have a mask.
1162              We could conceivably create a new clipmask by zeroing out
1163              everything outside the clip region.  Is it worth it?
1164              Is it possible to get an equivalent effect by changing the
1165              args to XCopyArea below rather than messing with a clip box?
1166              - dkindred@cs.cmu.edu */
1167           need_clipping = 0;
1168         }
1169
1170       gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
1171     }
1172   else
1173     {
1174       gc = override_gc;
1175       /* override_gc might have a mask already--we don't want to nuke it.
1176          Maybe we can insist that override_gc have no mask, or use
1177          one of the suggestions above. */
1178       need_clipping = 0;
1179     }
1180
1181   if (need_clipping)
1182     {
1183       XRectangle clip_box[1];
1184
1185       clip_box[0].x = clip_x;
1186       clip_box[0].y = clip_y;
1187       clip_box[0].width = clip_width;
1188       clip_box[0].height = clip_height;
1189
1190       XSetClipRectangles (dpy, gc, x, y, clip_box, 1, Unsorted);
1191     }
1192
1193   /* depth of 0 means it's a bitmap, not a pixmap, and we should use
1194      XCopyPlane (1 = current foreground color, 0 = background) instead
1195      of XCopyArea, which means that the bits in the pixmap are actual
1196      pixel values, instead of symbolic of fg/bg. */
1197   if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
1198     {
1199       XCopyArea (dpy, IMAGE_INSTANCE_X_PIXMAP (p), x_win, gc, 0,
1200                  pixmap_offset, width,
1201                  height, x, y);
1202     }
1203   else
1204     {
1205       XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP (p), x_win, gc, 0,
1206                   (pixmap_offset < 0
1207                    ? 0
1208                    : pixmap_offset),
1209                   width, height, x,
1210                   (pixmap_offset < 0
1211                    ? y - pixmap_offset
1212                    : y),
1213                   1L);
1214     }
1215
1216   if (need_clipping)
1217     {
1218       XSetClipMask (dpy, gc, None);
1219       XSetClipOrigin (dpy, gc, 0, 0);
1220     }
1221 }
1222
1223 static void
1224 x_output_pixmap (struct window *w, struct display_line *dl,
1225                  Lisp_Object image_instance, int xpos, int xoffset,
1226                  int start_pixpos, int width, face_index findex,
1227                  int cursor_start, int cursor_width, int cursor_height)
1228 {
1229   struct frame *f = XFRAME (w->frame);
1230   struct device *d = XDEVICE (f->device);
1231   struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1232   Lisp_Object window;
1233
1234   Display *dpy = DEVICE_X_DISPLAY (d);
1235   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1236   int lheight = dl->ascent + dl->descent - dl->clip;
1237   int pheight = ((int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > lheight ? lheight :
1238                  IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
1239   int pwidth = min (width + xoffset, (int) IMAGE_INSTANCE_PIXMAP_WIDTH (p));
1240   int clip_x, clip_y, clip_width, clip_height;
1241
1242   /* The pixmap_offset is used to center the pixmap on lines which are
1243      shorter than it is.  This results in odd effects when scrolling
1244      pixmaps off of the bottom.  Let's try not using it. */
1245 #if 0
1246   int pixmap_offset = (int) (IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - lheight) / 2;
1247 #else
1248   int pixmap_offset = 0;
1249 #endif
1250
1251   XSETWINDOW (window, w);
1252
1253   if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
1254     {
1255       if (start_pixpos > xpos && start_pixpos > xpos + width)
1256         return;
1257
1258       clip_x = xoffset;
1259       clip_width = width;
1260       if (start_pixpos > xpos)
1261         {
1262           clip_x += (start_pixpos - xpos);
1263           clip_width -= (start_pixpos - xpos);
1264         }
1265     }
1266   else
1267     {
1268       clip_x = 0;
1269       clip_width = 0;
1270     }
1271
1272   /* Place markers for possible future functionality (clipping the top
1273      half instead of the bottom half; think pixel scrolling). */
1274   clip_y = 0;
1275   clip_height = pheight;
1276
1277   /* Clear the area the pixmap is going into.  The pixmap itself will
1278      always take care of the full width.  We don't want to clear where
1279      it is going to go in order to avoid flicker.  So, all we have to
1280      take care of is any area above or below the pixmap. */
1281   /* #### We take a shortcut for now.  We know that since we have
1282      pixmap_offset hardwired to 0 that the pixmap is against the top
1283      edge so all we have to worry about is below it. */
1284   /* #### Unless the pixmap has a mask in which case we have to clear
1285      the whole damn thing since we can't yet clear just the area not
1286      included in the mask. */
1287   if (((int) (dl->ypos - dl->ascent + pheight) <
1288        (int) (dl->ypos + dl->descent - dl->clip))
1289       || IMAGE_INSTANCE_X_MASK (p))
1290     {
1291       int clear_x, clear_y, clear_width, clear_height;
1292
1293       if (IMAGE_INSTANCE_X_MASK (p))
1294         {
1295           clear_y = dl->ypos - dl->ascent;
1296           clear_height = lheight;
1297         }
1298       else
1299         {
1300           clear_y = dl->ypos - dl->ascent + pheight;
1301           clear_height = lheight - pheight;
1302         }
1303
1304       if (start_pixpos >= 0 && start_pixpos > xpos)
1305         {
1306           clear_x = start_pixpos;
1307           clear_width = xpos + width - start_pixpos;
1308         }
1309       else
1310         {
1311           clear_x = xpos;
1312           clear_width = width;
1313         }
1314
1315       x_clear_region (window, findex, clear_x, clear_y,
1316                       clear_width, clear_height);
1317     }
1318
1319   /* Output the pixmap. */
1320   {
1321     Lisp_Object tmp_pixel;
1322     XColor tmp_bcolor, tmp_fcolor;
1323
1324     tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1325     tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1326     tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1327     tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1328
1329     x_output_x_pixmap (f, p, xpos - xoffset, dl->ypos - dl->ascent, clip_x,
1330                        clip_y, clip_width, clip_height,
1331                        pwidth, pheight, pixmap_offset,
1332                        tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
1333   }
1334
1335   /* Draw a cursor over top of the pixmap. */
1336   if (cursor_width && cursor_height && (cursor_start >= xpos)
1337       && !NILP (w->text_cursor_visible_p)
1338       && (cursor_start < xpos + pwidth))
1339     {
1340       GC gc;
1341       int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1342       int y = dl->ypos - dl->ascent;
1343       struct face_cachel *cursor_cachel =
1344         WINDOW_FACE_CACHEL (w,
1345                             get_builtin_face_cache_index
1346                             (w, Vtext_cursor_face));
1347
1348       gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1349
1350       if (cursor_width > xpos + pwidth - cursor_start)
1351         cursor_width = xpos + pwidth - cursor_start;
1352
1353       if (focus)
1354         {
1355           XFillRectangle (dpy, x_win, gc, cursor_start, y, cursor_width,
1356                           cursor_height);
1357         }
1358       else
1359         {
1360           XDrawRectangle (dpy, x_win, gc, cursor_start, y, cursor_width,
1361                           cursor_height);
1362         }
1363     }
1364 }
1365
1366 /*****************************************************************************
1367  x_output_vertical_divider
1368
1369  Draw a vertical divider down the right side of the given window.
1370  ****************************************************************************/
1371 static void
1372 x_output_vertical_divider (struct window *w, int clear)
1373 {
1374   struct frame *f = XFRAME (w->frame);
1375   struct device *d = XDEVICE (f->device);
1376
1377   EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
1378   Display *dpy = DEVICE_X_DISPLAY (d);
1379   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1380   Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
1381   Lisp_Object tmp_pixel;
1382   XColor tmp_color;
1383   XGCValues gcv;
1384   GC top_shadow_gc, bottom_shadow_gc, background_gc;
1385
1386   int use_pixmap = 0;
1387   int flip_gcs = 0;
1388   unsigned long mask;
1389   int x, y1, y2, width, shadow_thickness, spacing, line_width;
1390   face_index div_face = get_builtin_face_cache_index (w, Vvertical_divider_face);
1391   
1392   width = window_divider_width (w);
1393   shadow_thickness = XINT (w->vertical_divider_shadow_thickness);
1394   spacing = XINT (w->vertical_divider_spacing);
1395   line_width = XINT (w->vertical_divider_line_width);
1396   x = WINDOW_RIGHT (w) - width;
1397   y1 = WINDOW_TOP (w);
1398   y2 = WINDOW_BOTTOM (w);
1399   
1400   memset (&gcv, ~0, sizeof (XGCValues));
1401   
1402   tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1403   tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1404   
1405   /* First, get the GC's. */
1406   top_shadow_pixel = tmp_color.pixel;
1407   bottom_shadow_pixel = tmp_color.pixel;
1408   background_pixel = tmp_color.pixel;
1409   
1410   x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
1411                             background_pixel, ef->core.background_pixel);
1412   
1413   tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, div_face);
1414   tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1415   gcv.background = tmp_color.pixel;
1416   gcv.graphics_exposures = False;
1417   mask = GCForeground | GCBackground | GCGraphicsExposures;
1418
1419   /* If we can't distinguish one of the shadows (the color is the same as the
1420      background), it's better to use a pixmap to generate a dithrered gray. */
1421   if (top_shadow_pixel == background_pixel ||
1422       bottom_shadow_pixel == background_pixel)
1423     use_pixmap = 1;
1424   
1425   if (use_pixmap)
1426     {
1427       if (DEVICE_X_GRAY_PIXMAP (d) == None)
1428         {
1429           DEVICE_X_GRAY_PIXMAP (d) =
1430             XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
1431                                          gray_width, gray_height, 1, 0, 1);
1432         }
1433       
1434       tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1435       tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1436       gcv.foreground = tmp_color.pixel;
1437       /* this is needed because the GC draws with a pixmap here */
1438       gcv.fill_style = FillOpaqueStippled;
1439       gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
1440       top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
1441                                        (mask | GCStipple | GCFillStyle));
1442       
1443       tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, div_face);
1444       tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1445       bottom_shadow_pixel = tmp_color.pixel;
1446       
1447       flip_gcs = (bottom_shadow_pixel ==
1448                   WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
1449     }
1450   else
1451     {
1452       gcv.foreground = top_shadow_pixel;
1453       top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1454     }
1455   
1456   gcv.foreground = bottom_shadow_pixel;
1457   bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1458   
1459   if (use_pixmap && flip_gcs)
1460     {
1461       GC tmp_gc = bottom_shadow_gc;
1462       bottom_shadow_gc = top_shadow_gc;
1463       top_shadow_gc = tmp_gc;
1464     }
1465   
1466   gcv.foreground = background_pixel;
1467   background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1468   
1469   /* possibly revert the GC's in case the shadow thickness is < 0.
1470      This will give a depressed look to the divider */
1471   if (shadow_thickness < 0)
1472     {
1473       GC temp;
1474
1475       temp = top_shadow_gc;
1476       top_shadow_gc = bottom_shadow_gc;
1477       bottom_shadow_gc = temp;
1478       
1479       /* better avoid a Bad Adress XLib error ;-) */
1480       shadow_thickness = - shadow_thickness;
1481     }
1482
1483   /* Clear the divider area first.  This needs to be done when a
1484      window split occurs. */
1485   if (clear)
1486     XClearArea (dpy, x_win, x, y1, width, y2 - y1, False);
1487
1488   /* Draw the divider line. */
1489   XFillRectangle (dpy, x_win, background_gc, 
1490                   x + spacing + shadow_thickness, y1,
1491                   line_width, y2 - y1);
1492   
1493   /* Draw the shadows around the divider line */
1494   x_output_shadows (f, x + spacing, y1, 
1495                     width - 2 * spacing, y2 - y1,
1496                     top_shadow_gc, bottom_shadow_gc,
1497                     background_gc, shadow_thickness);
1498 }
1499
1500 /*****************************************************************************
1501  x_output_blank
1502
1503  Output a blank by clearing the area it covers in the foreground color
1504  of its face.
1505  ****************************************************************************/
1506 static void
1507 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
1508                 int start_pixpos, int cursor_start, int cursor_width)
1509 {
1510   struct frame *f = XFRAME (w->frame);
1511   struct device *d = XDEVICE (f->device);
1512
1513   Display *dpy = DEVICE_X_DISPLAY (d);
1514   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1515   GC gc;
1516   struct face_cachel *cursor_cachel =
1517     WINDOW_FACE_CACHEL (w,
1518                         get_builtin_face_cache_index
1519                         (w, Vtext_cursor_face));
1520   Lisp_Object bg_pmap;
1521   Lisp_Object buffer = WINDOW_BUFFER (w);
1522   Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1523                                                          buffer);
1524
1525   int x = rb->xpos;
1526   int y = dl->ypos - dl->ascent;
1527   int width = rb->width;
1528   int height = dl->ascent + dl->descent - dl->clip;
1529
1530   if (start_pixpos > x)
1531     {
1532       if (start_pixpos >= (x + width))
1533         return;
1534       else
1535         {
1536           width -= (start_pixpos - x);
1537           x = start_pixpos;
1538         }
1539     }
1540
1541   bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
1542   if (!IMAGE_INSTANCEP (bg_pmap)
1543       || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
1544     bg_pmap = Qnil;
1545
1546   if (NILP (bg_pmap))
1547     gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1548                    Qnil, Qnil, Qnil);
1549   else
1550     gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1551                    WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
1552                    Qnil);
1553
1554   XFillRectangle (dpy, x_win, gc, x, y, width, height);
1555
1556   /* If this rune is marked as having the cursor, then it is actually
1557      representing a tab. */
1558   if (!NILP (w->text_cursor_visible_p)
1559       && (rb->cursor_type == CURSOR_ON
1560           || (cursor_width
1561               && (cursor_start + cursor_width > x)
1562               && cursor_start < (x + width))))
1563     {
1564       int cursor_height, cursor_y;
1565       int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1566       struct Lisp_Font_Instance *fi;
1567
1568       fi = XFONT_INSTANCE (FACE_CACHEL_FONT
1569                            (WINDOW_FACE_CACHEL (w, rb->findex),
1570                             Vcharset_ascii));
1571
1572       gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1573
1574       cursor_y = dl->ypos - fi->ascent;
1575       cursor_height = fi->height;
1576       if (cursor_y + cursor_height > y + height)
1577         cursor_height = y + height - cursor_y;
1578
1579       if (focus)
1580         {
1581           if (NILP (bar_cursor_value))
1582             {
1583               XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1584                               fi->width, cursor_height);
1585             }
1586           else
1587             {
1588               int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1589
1590               gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1591                              make_int (bar_width));
1592               XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
1593                          cursor_y, cursor_start + bar_width - 1,
1594                          cursor_y + cursor_height - 1);
1595             }
1596         }
1597       else if (NILP (bar_cursor_value))
1598         {
1599           XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1600                           fi->width - 1, cursor_height - 1);
1601         }
1602     }
1603 }
1604
1605 /*****************************************************************************
1606  x_output_hline
1607
1608  Output a horizontal line in the foreground of its face.
1609  ****************************************************************************/
1610 static void
1611 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
1612 {
1613   struct frame *f = XFRAME (w->frame);
1614   struct device *d = XDEVICE (f->device);
1615
1616   Display *dpy = DEVICE_X_DISPLAY (d);
1617   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1618   GC gc;
1619
1620   int x = rb->xpos;
1621   int width = rb->width;
1622   int height = dl->ascent + dl->descent - dl->clip;
1623   int ypos1, ypos2, ypos3, ypos4;
1624
1625   ypos1 = dl->ypos - dl->ascent;
1626   ypos2 = ypos1 + rb->object.hline.yoffset;
1627   ypos3 = ypos2 + rb->object.hline.thickness;
1628   ypos4 = dl->ypos + dl->descent - dl->clip;
1629
1630   /* First clear the area not covered by the line. */
1631   if (height - rb->object.hline.thickness > 0)
1632     {
1633       gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1634                      Qnil, Qnil, Qnil);
1635
1636       if (ypos2 - ypos1 > 0)
1637         XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1638       if (ypos4 - ypos3 > 0)
1639         XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1640     }
1641
1642   /* Now draw the line. */
1643   gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1644                  Qnil, Qnil, Qnil);
1645
1646   if (ypos2 < ypos1)
1647     ypos2 = ypos1;
1648   if (ypos3 > ypos4)
1649     ypos3 = ypos4;
1650
1651   if (ypos3 - ypos2 > 0)
1652     XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1653 }
1654
1655 /*****************************************************************************
1656  x_output_shadows
1657
1658  Draw a shadow around the given area using the given GC's.  It is the
1659  callers responsibility to ste the GC's appropriately.
1660  ****************************************************************************/
1661 void
1662 x_output_shadows (struct frame *f, int x, int y, int width, int height,
1663                   GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
1664                   int shadow_thickness)
1665 {
1666   struct device *d = XDEVICE (f->device);
1667
1668   Display *dpy = DEVICE_X_DISPLAY (d);
1669   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1670
1671   XSegment top_shadow[20], bottom_shadow[20];
1672   int elt;
1673
1674   if (shadow_thickness > 10)
1675     shadow_thickness = 10;
1676   else if (shadow_thickness < 0)
1677     shadow_thickness = 0;
1678   if (shadow_thickness > (width / 2))
1679     shadow_thickness = width / 2;
1680   if (shadow_thickness > (height / 2))
1681     shadow_thickness = height / 2;
1682
1683   for (elt = 0; elt < shadow_thickness; elt++)
1684     {
1685       int seg1 = elt;
1686       int seg2 = elt + shadow_thickness;
1687
1688       top_shadow[seg1].x1 = x;
1689       top_shadow[seg1].x2 = x + width - elt - 1;
1690       top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
1691
1692       top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
1693       top_shadow[seg2].y1 = y + shadow_thickness;
1694       top_shadow[seg2].y2 = y + height - elt - 1;
1695
1696       bottom_shadow[seg1].x1 = x + elt + 1;
1697       bottom_shadow[seg1].x2 = x + width - 1;
1698       bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
1699
1700       bottom_shadow[seg2].x1 = bottom_shadow[seg2].x2 = x + width - elt - 1;
1701       bottom_shadow[seg2].y1 = y + elt + 1;
1702       bottom_shadow[seg2].y2 = y + height - shadow_thickness;
1703     }
1704
1705   XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow, shadow_thickness * 2);
1706   XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
1707                  shadow_thickness * 2);
1708 }
1709
1710 /*****************************************************************************
1711  x_generate_shadow_pixels
1712
1713  Given three pixels (top shadow, bottom shadow, background) massage
1714  the top and bottom shadow colors to guarantee that they differ.  The
1715  background pixels are not allowed to be modified.
1716
1717  This function modifies its parameters.
1718
1719  This code is modified from code blatantly stolen from lwlib/xlwmenu.c
1720  ****************************************************************************/
1721 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
1722                    ? ((unsigned long) (x)) : ((unsigned long) (y)))
1723
1724 void
1725 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
1726                           unsigned long *bottom_shadow,
1727                           unsigned long background,
1728                           unsigned long core_background)
1729 {
1730   struct device *d = XDEVICE (f->device);
1731   Display *dpy = DEVICE_X_DISPLAY (d);
1732   Colormap cmap = DEVICE_X_COLORMAP (d);
1733   Visual *visual = DEVICE_X_VISUAL (d);
1734
1735   XColor topc, botc;
1736   int top_frobbed = 0, bottom_frobbed = 0;
1737
1738   /* If the top shadow is the same color as the background, try to
1739      adjust it. */
1740   if (*top_shadow == background)
1741     {
1742       topc.pixel = background;
1743       XQueryColor (dpy, cmap, &topc);
1744       /* don't overflow/wrap! */
1745       topc.red   = MINL (65535, (unsigned long) topc.red   * 6 / 5);
1746       topc.green = MINL (65535, (unsigned long) topc.green * 6 / 5);
1747       topc.blue  = MINL (65535, (unsigned long) topc.blue  * 6 / 5);
1748       if (allocate_nearest_color (dpy, cmap, visual, &topc))
1749         {
1750           *top_shadow = topc.pixel;
1751           top_frobbed = 1;
1752         }
1753     }
1754
1755   /* If the bottom shadow is the same color as the background, try to
1756      adjust it. */
1757   if (*bottom_shadow == background)
1758     {
1759       botc.pixel = background;
1760       XQueryColor (dpy, cmap, &botc);
1761       botc.red   = (unsigned short) ((unsigned long) botc.red   * 3 / 5);
1762       botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5);
1763       botc.blue  = (unsigned short) ((unsigned long) botc.blue  * 3 / 5);
1764       if (allocate_nearest_color (dpy, cmap, visual, &botc))
1765         {
1766           *bottom_shadow = botc.pixel;
1767           bottom_frobbed = 1;
1768         }
1769     }
1770
1771   /* If we had to adjust both shadows, then we have to do some
1772      additional work. */
1773   if (top_frobbed && bottom_frobbed)
1774     {
1775       int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
1776       int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
1777       if (bot_avg > top_avg)
1778         {
1779           Pixel tmp = *top_shadow;
1780
1781           *top_shadow = *bottom_shadow;
1782           *bottom_shadow = tmp;
1783         }
1784       else if (topc.pixel == botc.pixel)
1785         {
1786           if (botc.pixel == background)
1787             *top_shadow = core_background;
1788           else
1789             *bottom_shadow = background;
1790         }
1791     }
1792 }
1793
1794 /*****************************************************************************
1795  x_clear_to_window_end
1796
1797  Clear the area between ypos1 and ypos2.  Each margin area and the
1798  text area is handled separately since they may each have their own
1799  background color.
1800  ****************************************************************************/
1801 static void
1802 x_clear_to_window_end (struct window *w, int ypos1, int ypos2)
1803 {
1804   int height = ypos2 - ypos1;
1805
1806   if (height)
1807     {
1808       struct frame *f = XFRAME (w->frame);
1809       Lisp_Object window;
1810       int bflag = (window_needs_vertical_divider (w) ? 0 : 1);
1811       layout_bounds bounds;
1812
1813       bounds = calculate_display_line_boundaries (w, bflag);
1814       XSETWINDOW (window, w);
1815
1816       if (window_is_leftmost (w))
1817         x_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f),
1818                         ypos1, FRAME_BORDER_WIDTH (f), height);
1819
1820       if (bounds.left_in - bounds.left_out > 0)
1821         x_clear_region (window,
1822                         get_builtin_face_cache_index (w, Vleft_margin_face),
1823                         bounds.left_out, ypos1,
1824                         bounds.left_in - bounds.left_out, height);
1825
1826       if (bounds.right_in - bounds.left_in > 0)
1827         x_clear_region (window, DEFAULT_INDEX, bounds.left_in, ypos1,
1828                         bounds.right_in - bounds.left_in, height);
1829
1830       if (bounds.right_out - bounds.right_in > 0)
1831         x_clear_region (window,
1832                         get_builtin_face_cache_index (w, Vright_margin_face),
1833                         bounds.right_in, ypos1,
1834                         bounds.right_out - bounds.right_in, height);
1835
1836       if (window_is_rightmost (w))
1837         x_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f),
1838                         ypos1, FRAME_BORDER_WIDTH (f), height);
1839     }
1840 }
1841
1842 /*****************************************************************************
1843  x_redraw_exposed_window
1844
1845  Given a bounding box for an area that needs to be redrawn, determine
1846  what parts of what lines are contained within and re-output their
1847  contents.
1848  ****************************************************************************/
1849 static void
1850 x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
1851 {
1852   struct frame *f = XFRAME (w->frame);
1853   int line;
1854   int start_x, start_y, end_x, end_y;
1855   int orig_windows_structure_changed;
1856
1857   display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1858
1859   if (!NILP (w->vchild))
1860     {
1861       x_redraw_exposed_windows (w->vchild, x, y, width, height);
1862       return;
1863     }
1864   else if (!NILP (w->hchild))
1865     {
1866       x_redraw_exposed_windows (w->hchild, x, y, width, height);
1867       return;
1868     }
1869
1870   /* If the window doesn't intersect the exposed region, we're done here. */
1871   if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w)
1872       || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w))
1873     {
1874       return;
1875     }
1876   else
1877     {
1878       start_x = max (WINDOW_LEFT (w), x);
1879       end_x = min (WINDOW_RIGHT (w), (x + width));
1880       start_y = max (WINDOW_TOP (w), y);
1881       end_y = min (WINDOW_BOTTOM (w), y + height);
1882
1883       /* We do this to make sure that the 3D modelines get redrawn if
1884          they are in the exposed region. */
1885       orig_windows_structure_changed = f->windows_structure_changed;
1886       f->windows_structure_changed = 1;
1887     }
1888
1889   if (window_needs_vertical_divider (w))
1890     {
1891       x_output_vertical_divider (w, 0);
1892     }
1893
1894   for (line = 0; line < Dynarr_length (cdla); line++)
1895     {
1896       struct display_line *cdl = Dynarr_atp (cdla, line);
1897       int top_y = cdl->ypos - cdl->ascent;
1898       int bottom_y = cdl->ypos + cdl->descent;
1899
1900       if (bottom_y >= start_y)
1901         {
1902           if (top_y > end_y)
1903             {
1904               if (line == 0)
1905                 continue;
1906               else
1907                 break;
1908             }
1909           else
1910             {
1911               output_display_line (w, 0, cdla, line, start_x, end_x);
1912             }
1913         }
1914     }
1915
1916   f->windows_structure_changed = orig_windows_structure_changed;
1917
1918   /* If there have never been any face cache_elements created, then this
1919      expose event doesn't actually have anything to do. */
1920   if (Dynarr_largest (w->face_cachels))
1921     redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
1922 }
1923
1924 /*****************************************************************************
1925  x_redraw_exposed_windows
1926
1927  For each window beneath the given window in the window hierarchy,
1928  ensure that it is redrawn if necessary after an Expose event.
1929  ****************************************************************************/
1930 static void
1931 x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
1932                           int height)
1933 {
1934   for (; !NILP (window); window = XWINDOW (window)->next)
1935     x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
1936 }
1937
1938 /*****************************************************************************
1939  x_redraw_exposed_area
1940
1941  For each window on the given frame, ensure that any area in the
1942  Exposed area is redrawn.
1943  ****************************************************************************/
1944 void
1945 x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
1946 {
1947   /* If any window on the frame has had its face cache reset then the
1948      redisplay structures are effectively invalid.  If we attempt to
1949      use them we'll blow up.  We mark the frame as changed to ensure
1950      that redisplay will do a full update.  This probably isn't
1951      necessary but it can't hurt. */
1952
1953 #ifdef HAVE_TOOLBARS
1954   /* #### We would rather put these off as well but there is currently
1955      no combination of flags which will force an unchanged toolbar to
1956      redraw anyhow. */
1957   MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
1958 #endif
1959
1960   if (!f->window_face_cache_reset)
1961     {
1962       x_redraw_exposed_windows (f->root_window, x, y, width, height);
1963
1964       XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
1965     }
1966   else
1967     MARK_FRAME_CHANGED (f);
1968 }
1969
1970 /****************************************************************************
1971  x_clear_region
1972
1973  Clear the area in the box defined by the given parameters using the
1974  given face.
1975  ****************************************************************************/
1976 static void
1977 x_clear_region (Lisp_Object locale, face_index findex, int x, int y,
1978                 int width, int height)
1979 {
1980   struct window *w = NULL;
1981   struct frame *f = NULL;
1982   struct device *d;
1983   Lisp_Object background_pixmap;
1984
1985   Display *dpy;
1986   Window x_win;
1987
1988   if (WINDOWP (locale))
1989     {
1990       w = XWINDOW (locale);
1991       f = XFRAME (w->frame);
1992     }
1993   else if (FRAMEP (locale))
1994     {
1995       w = NULL;
1996       f = XFRAME (locale);
1997     }
1998   else
1999     abort ();
2000
2001   d = XDEVICE (f->device);
2002   dpy = DEVICE_X_DISPLAY (d);
2003   x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2004
2005   /* #### This function is going to have to be made cursor aware. */
2006   if (width && height)
2007     {
2008       GC gc = NULL;
2009
2010       /* #### This isn't quite right for when this function is called
2011          from the toolbar code. */
2012       background_pixmap = Qunbound;
2013
2014       /* Don't use a backing pixmap in the border area */
2015       if (x >= FRAME_LEFT_BORDER_END (f)
2016           && x < FRAME_RIGHT_BORDER_START (f)
2017           && y >= FRAME_TOP_BORDER_END (f)
2018           && y < FRAME_BOTTOM_BORDER_START (f))
2019         {
2020           Lisp_Object temp;
2021
2022           if (w)
2023             {
2024               temp = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, findex);
2025
2026               if (IMAGE_INSTANCEP (temp)
2027                   && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
2028                 {
2029                   /* #### maybe we could implement such that a string
2030                      can be a background pixmap? */
2031                   background_pixmap = temp;
2032                 }
2033             }
2034           else
2035             {
2036               temp = FACE_BACKGROUND_PIXMAP (Vdefault_face, locale);
2037
2038               if (IMAGE_INSTANCEP (temp)
2039                   && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
2040                 {
2041                   background_pixmap = temp;
2042                 }
2043             }
2044
2045           if (!UNBOUNDP (background_pixmap) &&
2046               XIMAGE_INSTANCE_PIXMAP_DEPTH (background_pixmap) == 0)
2047             {
2048               Lisp_Object fcolor, bcolor;
2049
2050               if (w)
2051                 {
2052                   fcolor = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
2053                   bcolor = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
2054                 }
2055               else
2056                 {
2057                   fcolor = FACE_FOREGROUND (Vdefault_face, locale);
2058                   bcolor = FACE_BACKGROUND (Vdefault_face, locale);
2059                 }
2060
2061               gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
2062             }
2063           else
2064             {
2065               Lisp_Object color = (w ?
2066                                    WINDOW_FACE_CACHEL_BACKGROUND (w, findex) :
2067                                    FACE_BACKGROUND (Vdefault_face, locale));
2068
2069               if (UNBOUNDP (background_pixmap))
2070                 background_pixmap = Qnil;
2071
2072               gc = x_get_gc (d, Qnil, color, Qnil, background_pixmap, Qnil);
2073             }
2074         }
2075
2076       if (gc)
2077         XFillRectangle (dpy, x_win, gc, x, y, width, height);
2078       else
2079         XClearArea (dpy, x_win, x, y, width, height, False);
2080     }
2081 }
2082
2083 /*****************************************************************************
2084  x_output_eol_cursor
2085
2086  Draw a cursor at the end of a line.  The end-of-line cursor is
2087  narrower than the normal cursor.
2088  ****************************************************************************/
2089 static void
2090 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos,
2091                      face_index findex)
2092 {
2093   struct frame *f = XFRAME (w->frame);
2094   struct device *d = XDEVICE (f->device);
2095   Lisp_Object window;
2096
2097   Display *dpy = DEVICE_X_DISPLAY (d);
2098   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2099   GC gc;
2100   face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
2101   struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
2102
2103   int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
2104   Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
2105                                                          WINDOW_BUFFER (w));
2106
2107   int x = xpos;
2108   int y = dl->ypos - dl->ascent;
2109   int width = EOL_CURSOR_WIDTH;
2110   int height = dl->ascent + dl->descent - dl->clip;
2111   int cursor_height, cursor_y;
2112   int defheight, defascent;
2113
2114   XSETWINDOW (window, w);
2115   x_clear_region (window, findex, x, y, width, height);
2116
2117   if (NILP (w->text_cursor_visible_p))
2118     return;
2119
2120   gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
2121
2122   default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
2123
2124   /* make sure the cursor is entirely contained between y and y+height */
2125   cursor_height = min (defheight, height);
2126   cursor_y = max (y, min (y + height - cursor_height,
2127                           dl->ypos - defascent));
2128
2129   if (focus)
2130     {
2131 #ifdef HAVE_XIM
2132       XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2);
2133 #endif /* HAVE_XIM */
2134
2135       if (NILP (bar_cursor_value))
2136         {
2137           XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
2138         }
2139       else
2140         {
2141           int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
2142
2143           gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
2144                          make_int (bar_width));
2145           XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
2146                      x + bar_width - 1, cursor_y + cursor_height - 1);
2147         }
2148     }
2149   else if (NILP (bar_cursor_value))
2150     {
2151       XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
2152                       cursor_height - 1);
2153     }
2154 }
2155
2156 static void
2157 x_clear_frame_window (Lisp_Object window)
2158 {
2159   struct window *w = XWINDOW (window);
2160
2161   if (!NILP (w->vchild))
2162     {
2163       x_clear_frame_windows (w->vchild);
2164       return;
2165     }
2166
2167   if (!NILP (w->hchild))
2168     {
2169       x_clear_frame_windows (w->hchild);
2170       return;
2171     }
2172
2173   x_clear_to_window_end (w, WINDOW_TEXT_TOP (w), WINDOW_TEXT_BOTTOM (w));
2174 }
2175
2176 static void
2177 x_clear_frame_windows (Lisp_Object window)
2178 {
2179   for (; !NILP (window); window = XWINDOW (window)->next)
2180     x_clear_frame_window (window);
2181 }
2182
2183 static void
2184 x_clear_frame (struct frame *f)
2185 {
2186   struct device *d = XDEVICE (f->device);
2187   Display *dpy = DEVICE_X_DISPLAY (d);
2188   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2189   int x, y, width, height;
2190   Lisp_Object frame;
2191
2192   x = FRAME_LEFT_BORDER_START (f);
2193   width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
2194            FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
2195            2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) -
2196            2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f));
2197   /* #### This adjustment by 1 should be being done in the macros.
2198      There is some small differences between when the menubar is on
2199      and off that we still need to deal with. */
2200   y = FRAME_TOP_BORDER_START (f) - 1;
2201   height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
2202             FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
2203             2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) -
2204             2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1;
2205
2206   XClearArea (dpy, x_win, x, y, width, height, False);
2207
2208   XSETFRAME (frame, f);
2209
2210   if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
2211       || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
2212       || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
2213     {
2214       x_clear_frame_windows (f->root_window);
2215     }
2216
2217   XFlush (DEVICE_X_DISPLAY (d));
2218 }
2219
2220 /* briefly swap the foreground and background colors.
2221  */
2222
2223 static int
2224 x_flash (struct device *d)
2225 {
2226   Display *dpy;
2227   Window win;
2228   XGCValues gcv;
2229   GC gc;
2230   XColor tmp_fcolor, tmp_bcolor;
2231   Lisp_Object tmp_pixel, frame;
2232   struct frame *f = device_selected_frame (d);
2233   struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f));
2234   Widget shell = FRAME_X_SHELL_WIDGET (f);
2235
2236   XSETFRAME (frame, f);
2237
2238   tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
2239   tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
2240   tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
2241   tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
2242
2243   dpy = XtDisplay (shell);
2244   win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2245   memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
2246   gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
2247   gcv.function = GXxor;
2248   gcv.graphics_exposures = False;
2249   gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
2250                         (GCForeground | GCFunction | GCGraphicsExposures));
2251   XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2252                   w->pixel_width, w->pixel_height);
2253   XSync (dpy, False);
2254
2255 #ifdef HAVE_SELECT
2256   {
2257     int usecs = 100000;
2258     struct timeval tv;
2259     tv.tv_sec  = usecs / 1000000L;
2260     tv.tv_usec = usecs % 1000000L;
2261     /* I'm sure someone is going to complain about this... */
2262     select (0, 0, 0, 0, &tv);
2263   }
2264 #else
2265 #ifdef HAVE_POLL
2266   poll (0, 0, 100);
2267 #else /* !HAVE_POLL */
2268   bite me
2269 #endif /* HAVE_POLL */
2270 #endif /* HAVE_SELECT */
2271
2272   XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2273                   w->pixel_width, w->pixel_height);
2274   XSync (dpy, False);
2275
2276   return 1;
2277 }
2278
2279 /* Make audible bell.  */
2280
2281 static void
2282 x_ring_bell (struct device *d, int volume, int pitch, int duration)
2283 {
2284   Display *display = DEVICE_X_DISPLAY (d);
2285
2286   if (volume < 0) volume = 0;
2287   else if (volume > 100) volume = 100;
2288   if (pitch < 0 && duration < 0)
2289     {
2290       XBell (display, (volume * 2) - 100);
2291       XFlush (display);
2292     }
2293   else
2294     {
2295       XKeyboardState state;
2296       XKeyboardControl ctl;
2297       XSync (display, 0);
2298       /* #### grab server? */
2299       XGetKeyboardControl (display, &state);
2300
2301       ctl.bell_pitch    = (pitch    >= 0 ? pitch    : state.bell_pitch);
2302       ctl.bell_duration = (duration >= 0 ? duration : state.bell_duration);
2303       XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2304
2305       XBell (display, (volume * 2) - 100);
2306
2307       ctl.bell_pitch    = state.bell_pitch;
2308       ctl.bell_duration = state.bell_duration;
2309       XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2310
2311       /* #### ungrab server? */
2312       XSync (display, 0);
2313     }
2314 }
2315
2316 \f
2317 /************************************************************************/
2318 /*                            initialization                            */
2319 /************************************************************************/
2320
2321 void
2322 console_type_create_redisplay_x (void)
2323 {
2324   /* redisplay methods */
2325   CONSOLE_HAS_METHOD (x, text_width);
2326   CONSOLE_HAS_METHOD (x, output_display_block);
2327   CONSOLE_HAS_METHOD (x, divider_height);
2328   CONSOLE_HAS_METHOD (x, eol_cursor_width);
2329   CONSOLE_HAS_METHOD (x, output_vertical_divider);
2330   CONSOLE_HAS_METHOD (x, clear_to_window_end);
2331   CONSOLE_HAS_METHOD (x, clear_region);
2332   CONSOLE_HAS_METHOD (x, clear_frame);
2333   CONSOLE_HAS_METHOD (x, output_begin);
2334   CONSOLE_HAS_METHOD (x, output_end);
2335   CONSOLE_HAS_METHOD (x, flash);
2336   CONSOLE_HAS_METHOD (x, ring_bell);
2337 }