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