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