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