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