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