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