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