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