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