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