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