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.
6 This file is part of XEmacs.
8 XEmacs is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
13 XEmacs is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License
19 along with XEmacs; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
23 /* Synched up with: Not in FSF. */
25 /* Author: Chuck Thompson */
27 /* Lots of work done by Ben Wing for Mule */
32 #include "console-x.h"
33 #include "EmacsFrame.h"
34 #include "EmacsFrameP.h"
37 #include "objects-x.h"
44 #include "redisplay.h"
47 #include <X11/bitmaps/gray>
49 #include "sysproc.h" /* for select() */
53 #include "file-coding.h" /* for CCL conversion */
56 /* Number of pixels below each line. */
57 /* #### implement me */
58 int x_interline_space;
60 #define EOL_CURSOR_WIDTH 5
62 static void x_output_pixmap (struct window *w, struct display_line *dl,
63 Lisp_Object image_instance, int xpos,
65 int start_pixpos, int width, face_index findex,
66 int cursor_start, int cursor_width,
68 static void x_output_vertical_divider (struct window *w, int clear);
69 static void x_output_blank (struct window *w, struct display_line *dl,
70 struct rune *rb, int start_pixpos,
71 int cursor_start, int cursor_width);
72 static void x_output_hline (struct window *w, struct display_line *dl,
74 static void x_redraw_exposed_window (struct window *w, int x, int y,
75 int width, int height);
76 static void x_redraw_exposed_windows (Lisp_Object window, int x, int y,
77 int width, int height);
78 static void x_output_eol_cursor (struct window *w, struct display_line *dl,
79 int xpos, face_index findex);
80 static void x_clear_frame (struct frame *f);
81 static void x_clear_frame_windows (Lisp_Object window);
82 void bevel_modeline (struct window *w, struct display_line *dl);
85 /* Note: We do not use the Xmb*() functions and XFontSets.
86 Those functions are generally losing for a number of reasons:
88 1) They only support one locale (e.g. you could display
89 Japanese and ASCII text, but not mixed Japanese/Chinese
90 text). You could maybe call setlocale() frequently
91 to try to deal with this, but that would generally
92 fail because an XFontSet is tied to one locale and
93 won't have the other character sets in it.
94 2) Not all (or even very many) OS's support the useful
95 locales. For example, as far as I know SunOS and
96 Solaris only support the Japanese locale if you get the
97 special Asian-language version of the OS. Yuck yuck
98 yuck. Linux doesn't support the Japanese locale at
100 3) The locale support in X only exists in R5, not in R4.
101 (Not sure how big of a problem this is: how many
102 people are using R4?)
103 4) Who knows if the multi-byte text format (which is locale-
104 specific) is even the same for the same locale on
105 different OS's? It's not even documented anywhere that
106 I can find what the multi-byte text format for the
107 Japanese locale under SunOS and Solaris is, but I assume
119 /* Separate out the text in DYN into a series of textual runs of a
120 particular charset. Also convert the characters as necessary into
121 the format needed by XDrawImageString(), XDrawImageString16(), et
122 al. (This means converting to one or two byte format, possibly
123 tweaking the high bits, and possibly running a CCL program.) You
124 must pre-allocate the space used and pass it in. (This is done so
125 you can alloca() the space.) You need to allocate (2 * len) bytes
126 of TEXT_STORAGE and (len * sizeof (struct textual_run)) bytes of
127 RUN_STORAGE, where LEN is the length of the dynarr.
129 Returns the number of runs actually used. */
132 separate_textual_runs (unsigned char *text_storage,
133 struct textual_run *run_storage,
134 CONST Emchar *str, Charcount len)
136 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a
137 possible valid charset when
138 MULE is not defined */
142 struct ccl_program char_converter;
143 int need_ccl_conversion = 0;
146 for (i = 0; i < len; i++)
154 BREAKUP_CHAR (ch, charset, byte1, byte2);
155 dimension = XCHARSET_DIMENSION (charset);
156 graphic = XCHARSET_GRAPHIC (charset);
158 if (!EQ (charset, prev_charset))
160 run_storage[runs_so_far].ptr = text_storage;
161 run_storage[runs_so_far].charset = charset;
162 run_storage[runs_so_far].dimension = dimension;
166 run_storage[runs_so_far - 1].len =
167 text_storage - run_storage[runs_so_far - 1].ptr;
168 if (run_storage[runs_so_far - 1].dimension == 2)
169 run_storage[runs_so_far - 1].len >>= 1;
172 prev_charset = charset;
175 Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset);
176 need_ccl_conversion = !NILP (ccl_prog);
177 if (need_ccl_conversion)
178 setup_ccl_program (&char_converter, ccl_prog);
188 else if (graphic == 1)
194 if (need_ccl_conversion)
196 char_converter.reg[0] = XCHARSET_ID (charset);
197 char_converter.reg[1] = byte1;
198 char_converter.reg[2] = byte2;
199 ccl_driver (&char_converter, 0, 0, 0, 0, CCL_MODE_ENCODING);
200 byte1 = char_converter.reg[1];
201 byte2 = char_converter.reg[2];
204 *text_storage++ = (unsigned char) byte1;
206 *text_storage++ = (unsigned char) byte2;
211 run_storage[runs_so_far - 1].len =
212 text_storage - run_storage[runs_so_far - 1].ptr;
213 if (run_storage[runs_so_far - 1].dimension == 2)
214 run_storage[runs_so_far - 1].len >>= 1;
220 /****************************************************************************/
222 /* X output routines */
224 /****************************************************************************/
227 x_text_width_single_run (struct face_cachel *cachel, struct textual_run *run)
229 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
230 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
231 if (!fi->proportional_p)
232 return fi->width * run->len;
235 if (run->dimension == 2)
236 return XTextWidth16 (FONT_INSTANCE_X_FONT (fi),
237 (XChar2b *) run->ptr, run->len);
239 return XTextWidth (FONT_INSTANCE_X_FONT (fi),
240 (char *) run->ptr, run->len);
247 Given a string and a face, return the string's length in pixels when
248 displayed in the font associated with the face.
252 x_text_width (struct frame *f, struct face_cachel *cachel, CONST Emchar *str,
255 int width_so_far = 0;
256 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
257 struct textual_run *runs = alloca_array (struct textual_run, len);
261 nruns = separate_textual_runs (text_storage, runs, str, len);
263 for (i = 0; i < nruns; i++)
264 width_so_far += x_text_width_single_run (cachel, runs + i);
269 /*****************************************************************************
272 Return the height of the horizontal divider. This is a function because
273 divider_height is a device method.
275 #### If we add etched horizontal divider lines this will have to get
277 ****************************************************************************/
279 x_divider_height (void)
284 /*****************************************************************************
287 Return the width of the end-of-line cursor. This is a function
288 because eol_cursor_width is a device method.
289 ****************************************************************************/
291 x_eol_cursor_width (void)
293 return EOL_CURSOR_WIDTH;
296 /*****************************************************************************
299 Perform any necessary initialization prior to an update.
300 ****************************************************************************/
302 x_output_begin (struct device *d)
306 /*****************************************************************************
309 Perform any necessary flushing of queues when an update has completed.
310 ****************************************************************************/
312 x_output_end (struct device *d)
314 XFlush (DEVICE_X_DISPLAY (d));
317 /*****************************************************************************
318 x_output_display_block
320 Given a display line, a block number for that start line, output all
321 runes between start and end in the specified display block.
322 ****************************************************************************/
324 x_output_display_block (struct window *w, struct display_line *dl, int block,
325 int start, int end, int start_pixpos, int cursor_start,
326 int cursor_width, int cursor_height)
328 struct frame *f = XFRAME (w->frame);
329 Emchar_dynarr *buf = Dynarr_new (Emchar);
332 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
333 rune_dynarr *rba = db->runes;
339 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
340 MULE is not defined */
342 XSETWINDOW (window, w);
343 rb = Dynarr_atp (rba, start);
346 /* Nothing to do so don't do anything. */
351 if (rb->type == RUNE_CHAR)
352 charset = CHAR_CHARSET (rb->object.chr.ch);
355 end = Dynarr_length (rba);
360 rb = Dynarr_atp (rba, elt);
362 if (rb->findex == findex && rb->type == RUNE_CHAR
363 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
364 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
366 Dynarr_add (buf, rb->object.chr.ch);
372 if (Dynarr_length (buf))
374 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
375 findex, 0, cursor_start, cursor_width,
383 if (rb->type == RUNE_CHAR)
387 charset = CHAR_CHARSET (rb->object.chr.ch);
389 if (rb->cursor_type == CURSOR_ON)
391 if (rb->object.chr.ch == '\n')
393 x_output_eol_cursor (w, dl, xpos, findex);
397 Dynarr_add (buf, rb->object.chr.ch);
398 x_output_string (w, dl, buf, xpos, 0, start_pixpos,
399 rb->width, findex, 1,
400 cursor_start, cursor_width,
408 else if (rb->object.chr.ch == '\n')
410 /* Clear in case a cursor was formerly here. */
411 int height = dl->ascent + dl->descent - dl->clip;
413 redisplay_clear_region (window, findex, xpos, dl->ypos - dl->ascent,
418 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
420 if (rb->type == RUNE_BLANK)
421 x_output_blank (w, dl, rb, start_pixpos, cursor_start,
425 /* #### Our flagging of when we need to redraw the
426 modeline shadows sucks. Since RUNE_HLINE is only used
427 by the modeline at the moment it is a good bet
428 that if it gets redrawn then we should also
429 redraw the shadows. This won't be true forever.
430 We borrow the shadow_thickness_changed flag for
432 w->shadow_thickness_changed = 1;
433 x_output_hline (w, dl, rb);
439 rb = Dynarr_atp (rba, elt);
445 else if (rb->type == RUNE_DGLYPH)
447 Lisp_Object instance;
449 XSETWINDOW (window, w);
450 instance = glyph_image_instance (rb->object.dglyph.glyph,
451 window, ERROR_ME_NOT, 1);
454 if (IMAGE_INSTANCEP (instance))
455 switch (XIMAGE_INSTANCE_TYPE (instance))
459 /* #### This is way losing. See the comment in
462 XIMAGE_INSTANCE_TEXT_STRING (instance);
463 convert_bufbyte_string_into_emchar_dynarr
464 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
466 x_output_string (w, dl, buf, xpos,
467 rb->object.dglyph.xoffset,
468 start_pixpos, -1, findex,
469 (rb->cursor_type == CURSOR_ON),
470 cursor_start, cursor_width,
476 case IMAGE_MONO_PIXMAP:
477 case IMAGE_COLOR_PIXMAP:
478 x_output_pixmap (w, dl, instance, xpos,
479 rb->object.dglyph.xoffset, start_pixpos,
480 rb->width, findex, cursor_start,
481 cursor_width, cursor_height);
488 case IMAGE_SUBWINDOW:
489 redisplay_output_subwindow (w, dl, instance, xpos,
490 rb->object.dglyph.xoffset, start_pixpos,
491 rb->width, findex, cursor_start,
492 cursor_width, cursor_height);
495 /* nothing is as nothing does */
510 if (Dynarr_length (buf))
511 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
512 0, cursor_start, cursor_width, cursor_height);
514 /* #### This is really conditionalized well for optimized
517 && !EQ (Qzero, w->modeline_shadow_thickness)
519 || f->windows_structure_changed
520 || w->shadow_thickness_changed))
521 bevel_modeline (w, dl);
526 /*****************************************************************************
529 Draw a shadows for the given area in the given face.
530 ****************************************************************************/
532 x_bevel_area (struct window *w, face_index findex,
533 int x, int y, int width, int height,
534 int shadow_thickness)
536 struct frame *f = XFRAME (w->frame);
537 struct device *d = XDEVICE (f->device);
539 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
540 Display *dpy = DEVICE_X_DISPLAY (d);
541 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
542 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
543 Lisp_Object tmp_pixel;
546 GC top_shadow_gc, bottom_shadow_gc, background_gc;
552 memset (&gcv, ~0, sizeof (XGCValues));
554 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
555 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
557 /* First, get the GC's. */
558 top_shadow_pixel = tmp_color.pixel;
559 bottom_shadow_pixel = tmp_color.pixel;
560 background_pixel = tmp_color.pixel;
562 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
563 background_pixel, ef->core.background_pixel);
565 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
566 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
567 gcv.background = tmp_color.pixel;
568 gcv.graphics_exposures = False;
569 mask = GCForeground | GCBackground | GCGraphicsExposures;
571 /* If we can't distinguish one of the shadows (the color is the same as the
572 background), it's better to use a pixmap to generate a dithered gray. */
573 if (top_shadow_pixel == background_pixel ||
574 bottom_shadow_pixel == background_pixel)
579 if (DEVICE_X_GRAY_PIXMAP (d) == None)
581 DEVICE_X_GRAY_PIXMAP (d) =
582 XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
583 gray_width, gray_height, 1, 0, 1);
586 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
587 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
588 gcv.foreground = tmp_color.pixel;
589 /* this is needed because the GC draws with a pixmap here */
590 gcv.fill_style = FillOpaqueStippled;
591 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
592 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
593 (mask | GCStipple | GCFillStyle));
595 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
596 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
597 bottom_shadow_pixel = tmp_color.pixel;
599 flip_gcs = (bottom_shadow_pixel ==
600 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
604 gcv.foreground = top_shadow_pixel;
605 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
608 gcv.foreground = bottom_shadow_pixel;
609 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
611 if (use_pixmap && flip_gcs)
613 GC tmp_gc = bottom_shadow_gc;
614 bottom_shadow_gc = top_shadow_gc;
615 top_shadow_gc = tmp_gc;
618 gcv.foreground = background_pixel;
619 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
621 /* possibly revert the GC's in case the shadow thickness is < 0.
622 This will give a depressed look to the divider */
623 if (shadow_thickness < 0)
627 temp = top_shadow_gc;
628 top_shadow_gc = bottom_shadow_gc;
629 bottom_shadow_gc = temp;
631 /* better avoid a Bad Address XLib error ;-) */
632 shadow_thickness = - shadow_thickness;
635 /* Draw the shadows around the divider line */
636 x_output_shadows (f, x, y, width, height,
637 top_shadow_gc, bottom_shadow_gc,
638 background_gc, shadow_thickness);
641 /*****************************************************************************
644 Given a number of parameters return a GC with those properties.
645 ****************************************************************************/
647 x_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
648 Lisp_Object bg_pmap, Lisp_Object lwidth)
653 memset (&gcv, ~0, sizeof (XGCValues));
654 gcv.graphics_exposures = False;
655 /* Make absolutely sure that we don't pick up a clipping region in
656 the GC returned by this function. */
657 gcv.clip_mask = None;
658 gcv.clip_x_origin = 0;
659 gcv.clip_y_origin = 0;
660 gcv.fill_style = FillSolid;
661 mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
666 gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
671 if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg))
673 /* #### I fixed once case where this was getting it. It was a
674 bad macro expansion (compiler bug). */
675 fprintf (stderr, "Help! x_get_gc got a bogus fg value! fg = ");
682 if (COLOR_INSTANCEP (fg))
683 gcv.foreground = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (fg)).pixel;
685 gcv.foreground = XINT (fg);
686 mask |= GCForeground;
691 if (COLOR_INSTANCEP (bg))
692 gcv.background = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (bg)).pixel;
694 gcv.background = XINT (bg);
695 mask |= GCBackground;
698 /* This special case comes from a request to draw text with a face which has
699 the dim property. We'll use a stippled foreground GC. */
700 if (EQ (bg_pmap, Qdim))
702 assert (DEVICE_X_GRAY_PIXMAP (d) != None);
704 gcv.fill_style = FillStippled;
705 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
706 mask |= (GCFillStyle | GCStipple);
708 else if (IMAGE_INSTANCEP (bg_pmap)
709 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
711 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
713 gcv.fill_style = FillOpaqueStippled;
714 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
715 mask |= (GCStipple | GCFillStyle);
719 gcv.fill_style = FillTiled;
720 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
721 mask |= (GCTile | GCFillStyle);
727 gcv.line_width = XINT (lwidth);
731 return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
734 /*****************************************************************************
737 Given a string and a starting position, output that string in the
738 given face. If cursor is true, draw a cursor around the string.
739 Correctly handles multiple charsets in the string.
741 The meaning of the parameters is something like this:
743 W Window that the text is to be displayed in.
744 DL Display line that this text is on. The values in the
745 structure are used to determine the vertical position and
746 clipping range of the text.
747 BUF Dynamic array of Emchars specifying what is actually to be
749 XPOS X position in pixels where the text should start being drawn.
750 XOFFSET Number of pixels to be chopped off the left side of the
751 text. The effect is as if the text were shifted to the
752 left this many pixels and clipped at XPOS.
753 CLIP_START Clip everything left of this X position.
754 WIDTH Clip everything right of XPOS + WIDTH.
755 FINDEX Index for the face cache element describing how to display
757 CURSOR #### I don't understand this. There's something
758 strange and overcomplexified with this variable.
759 Chuck, explain please?
760 CURSOR_START Starting X position of cursor.
761 CURSOR_WIDTH Width of cursor in pixels.
762 CURSOR_HEIGHT Height of cursor in pixels.
764 Starting Y position of cursor is the top of the text line.
765 The cursor is drawn sometimes whether or not CURSOR is set. ???
766 ****************************************************************************/
768 x_output_string (struct window *w, struct display_line *dl,
769 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
770 int width, face_index findex, int cursor,
771 int cursor_start, int cursor_width, int cursor_height)
773 /* General variables */
774 struct frame *f = XFRAME (w->frame);
775 struct device *d = XDEVICE (f->device);
778 Display *dpy = DEVICE_X_DISPLAY (d);
779 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
783 /* Cursor-related variables */
784 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
786 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
788 struct face_cachel *cursor_cachel = 0;
790 /* Text-related variables */
794 int len = Dynarr_length (buf);
795 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
796 struct textual_run *runs = alloca_array (struct textual_run, len);
799 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
801 XSETDEVICE (device, d);
802 XSETWINDOW (window, w);
805 width = x_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
806 height = dl->ascent + dl->descent - dl->clip;
808 /* Regularize the variables passed in. */
810 if (clip_start < xpos)
812 clip_end = xpos + width;
813 if (clip_start >= clip_end)
814 /* It's all clipped out. */
819 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
820 Dynarr_length (buf));
822 cursor_clip = (cursor_start >= clip_start &&
823 cursor_start < clip_end);
825 /* This cursor code is really a mess. */
826 if (!NILP (w->text_cursor_visible_p)
830 && (cursor_start + cursor_width >= clip_start)
831 && !NILP (bar_cursor_value))))
833 /* These have to be in separate statements in order to avoid a
835 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face);
836 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks);
838 /* We have to reset this since any call to WINDOW_FACE_CACHEL
839 may cause the cache to resize and any pointers to it to
841 cachel = WINDOW_FACE_CACHEL (w, findex);
845 if (cursor && focus && (cursor_start == clip_start) && cursor_height)
846 XIM_SetSpotLocation (f, xpos - 2, dl->ypos + dl->descent - 2);
847 #endif /* HAVE_XIM */
849 bg_pmap = cachel->background_pixmap;
850 if (!IMAGE_INSTANCEP (bg_pmap)
851 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
854 if ((cursor && focus && NILP (bar_cursor_value)
855 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap))
858 bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
862 XFillRectangle (dpy, x_win, bgc, clip_start,
863 dl->ypos - dl->ascent, clip_end - clip_start,
866 for (i = 0; i < nruns; i++)
868 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
869 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
873 if (EQ (font, Vthe_null_font_instance))
876 this_width = x_text_width_single_run (cachel, runs + i);
877 need_clipping = (dl->clip || clip_start > xpos ||
878 clip_end < xpos + this_width);
880 /* XDrawImageString only clears the area equal to the height of
881 the given font. It is possible that a font is being displayed
882 on a line taller than it is, so this would cause us to fail to
884 if ((int) fi->height < (int) (height + dl->clip))
886 int clear_start = max (xpos, clip_start);
887 int clear_end = min (xpos + this_width, clip_end);
891 int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
893 ypos1_string = dl->ypos - fi->ascent;
894 ypos2_string = dl->ypos + fi->descent;
895 ypos1_line = dl->ypos - dl->ascent;
896 ypos2_line = dl->ypos + dl->descent - dl->clip;
898 /* Make sure we don't clear below the real bottom of the
900 if (ypos1_string > ypos2_line)
901 ypos1_string = ypos2_line;
902 if (ypos2_string > ypos2_line)
903 ypos2_string = ypos2_line;
905 if (ypos1_line < ypos1_string)
907 redisplay_clear_region (window, findex, clear_start, ypos1_line,
908 clear_end - clear_start,
909 ypos1_string - ypos1_line);
912 if (ypos2_line > ypos2_string)
914 redisplay_clear_region (window, findex, clear_start, ypos2_string,
915 clear_end - clear_start,
916 ypos2_line - ypos2_string);
921 redisplay_clear_region (window, findex, clear_start,
922 dl->ypos - dl->ascent, clear_end - clear_start,
927 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value))
928 gc = x_get_gc (d, font, cursor_cachel->foreground,
929 cursor_cachel->background, Qnil, Qnil);
930 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, (char *)gray_bits,
936 gray_width, gray_height);
938 /* Request a GC with the gray stipple pixmap to draw dimmed text */
939 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
943 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
948 XRectangle clip_box[1];
952 clip_box[0].width = clip_end - clip_start;
953 clip_box[0].height = height;
955 XSetClipRectangles (dpy, gc, clip_start, dl->ypos - dl->ascent,
956 clip_box, 1, Unsorted);
959 if (runs[i].dimension == 1)
960 (bgc ? XDrawString : XDrawImageString) (dpy, x_win, gc, xpos,
961 dl->ypos, (char *) runs[i].ptr,
964 (bgc ? XDrawString16 : XDrawImageString16) (dpy, x_win, gc, xpos,
966 (XChar2b *) runs[i].ptr,
969 /* We draw underlines in the same color as the text. */
970 if (cachel->underline)
972 unsigned long upos, uthick;
975 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
976 if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos))
977 upos = dl->descent / 2;
978 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
981 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
983 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
984 uthick = dl->descent - dl->clip - upos;
988 XDrawLine (dpy, x_win, gc, xpos, dl->ypos + upos,
989 xpos + this_width, dl->ypos + upos);
993 XFillRectangle (dpy, x_win, gc, xpos,
994 dl->ypos + upos, this_width, uthick);
999 if (cachel->strikethru) {
1000 unsigned long ascent,descent,upos, uthick;
1003 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
1005 if (!XGetFontProperty (xfont, XA_STRIKEOUT_ASCENT, &ascent))
1006 ascent = xfont->ascent;
1007 if (!XGetFontProperty (xfont, XA_STRIKEOUT_DESCENT, &descent))
1008 descent = xfont->descent;
1009 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
1012 upos = ascent - ((ascent + descent) / 2) + 1;
1014 /* Generally, upos will be positive (above the baseline),so subtract */
1015 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip)
1017 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip)
1018 uthick = dl->descent - dl->clip + upos;
1022 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos,
1023 xpos + this_width, dl->ypos - upos);
1025 else if (uthick > 1)
1027 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos,
1028 this_width, uthick);
1033 /* Restore the GC */
1036 XSetClipMask (dpy, gc, None);
1037 XSetClipOrigin (dpy, gc, 0, 0);
1040 /* If we are actually superimposing the cursor then redraw with just
1041 the appropriate section highlighted. */
1042 if (cursor_clip && !cursor && focus && cursor_cachel)
1045 XRectangle clip_box[1];
1047 cgc = x_get_gc (d, font, cursor_cachel->foreground,
1048 cursor_cachel->background, Qnil, Qnil);
1052 clip_box[0].width = cursor_width;
1053 clip_box[0].height = height;
1055 XSetClipRectangles (dpy, cgc, cursor_start, dl->ypos - dl->ascent,
1056 clip_box, 1, Unsorted);
1058 if (runs[i].dimension == 1)
1059 XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
1060 (char *) runs[i].ptr, runs[i].len);
1062 XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
1063 (XChar2b *) runs[i].ptr, runs[i].len);
1065 XSetClipMask (dpy, cgc, None);
1066 XSetClipOrigin (dpy, cgc, 0, 0);
1072 /* Draw the non-focus box or bar-cursor as needed. */
1073 /* Can't this logic be simplified? */
1075 && ((cursor && !focus && NILP (bar_cursor_value))
1077 && (cursor_start + cursor_width >= clip_start)
1078 && !NILP (bar_cursor_value))))
1080 int tmp_height, tmp_y;
1081 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1082 int need_clipping = (cursor_start < clip_start
1083 || clip_end < cursor_start + cursor_width);
1085 /* #### This value is correct (as far as I know) because
1086 all of the times we need to draw this cursor, we will
1087 be called with exactly one character, so we know we
1088 can always use runs[0].
1090 This is bogus as all hell, however. The cursor handling in
1091 this function is way bogus and desperately needs to be
1092 cleaned up. (In particular, the drawing of the cursor should
1093 really really be separated out of this function. This may be
1094 a bit tricky now because this function itself does way too
1095 much stuff, a lot of which needs to be moved into
1096 redisplay.c) This is the only way to be able to easily add
1097 new cursor types or (e.g.) make the bar cursor be able to
1098 span two characters instead of overlaying just one. */
1099 int bogusly_obtained_ascent_value =
1100 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent;
1102 if (!NILP (bar_cursor_value))
1104 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1105 make_int (bar_width));
1109 gc = x_get_gc (d, Qnil, cursor_cachel->background,
1113 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1114 tmp_height = cursor_height;
1115 if (tmp_y + tmp_height > (int) (dl->ypos - dl->ascent + height))
1117 tmp_y = dl->ypos - dl->ascent + height - tmp_height;
1118 if (tmp_y < (int) (dl->ypos - dl->ascent))
1119 tmp_y = dl->ypos - dl->ascent;
1120 tmp_height = dl->ypos - dl->ascent + height - tmp_y;
1125 XRectangle clip_box[1];
1128 clip_box[0].width = clip_end - clip_start;
1129 clip_box[0].height = tmp_height;
1130 XSetClipRectangles (dpy, gc, clip_start, tmp_y,
1131 clip_box, 1, Unsorted);
1134 if (!focus && NILP (bar_cursor_value))
1136 XDrawRectangle (dpy, x_win, gc, cursor_start, tmp_y,
1137 cursor_width - 1, tmp_height - 1);
1139 else if (focus && !NILP (bar_cursor_value))
1141 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1, tmp_y,
1142 cursor_start + bar_width - 1, tmp_y + tmp_height - 1);
1145 /* Restore the GC */
1148 XSetClipMask (dpy, gc, None);
1149 XSetClipOrigin (dpy, gc, 0, 0);
1155 x_output_x_pixmap (struct frame *f, struct Lisp_Image_Instance *p, int x,
1156 int y, int clip_x, int clip_y, int clip_width,
1157 int clip_height, int width, int height, int pixmap_offset,
1158 unsigned long fg, unsigned long bg, GC override_gc)
1160 struct device *d = XDEVICE (f->device);
1161 Display *dpy = DEVICE_X_DISPLAY (d);
1162 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1166 unsigned long pixmap_mask;
1167 int need_clipping = (clip_x || clip_y);
1171 memset (&gcv, ~0, sizeof (XGCValues));
1172 gcv.graphics_exposures = False;
1173 gcv.foreground = fg;
1174 gcv.background = bg;
1175 pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
1177 if (IMAGE_INSTANCE_X_MASK (p))
1179 gcv.function = GXcopy;
1180 gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
1181 gcv.clip_x_origin = x;
1182 gcv.clip_y_origin = y - pixmap_offset;
1183 pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
1185 /* Can't set a clip rectangle below because we already have a mask.
1186 We could conceivably create a new clipmask by zeroing out
1187 everything outside the clip region. Is it worth it?
1188 Is it possible to get an equivalent effect by changing the
1189 args to XCopyArea below rather than messing with a clip box?
1190 - dkindred@cs.cmu.edu */
1194 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
1199 /* override_gc might have a mask already--we don't want to nuke it.
1200 Maybe we can insist that override_gc have no mask, or use
1201 one of the suggestions above. */
1207 XRectangle clip_box[1];
1209 clip_box[0].x = clip_x;
1210 clip_box[0].y = clip_y;
1211 clip_box[0].width = clip_width;
1212 clip_box[0].height = clip_height;
1214 XSetClipRectangles (dpy, gc, x, y, clip_box, 1, Unsorted);
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)
1223 XCopyArea (dpy, IMAGE_INSTANCE_X_PIXMAP (p), x_win, gc, 0,
1224 pixmap_offset, width,
1229 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP (p), x_win, gc, 0,
1242 XSetClipMask (dpy, gc, None);
1243 XSetClipOrigin (dpy, gc, 0, 0);
1248 x_output_pixmap (struct window *w, struct display_line *dl,
1249 Lisp_Object image_instance, int xpos, int xoffset,
1250 int start_pixpos, int width, face_index findex,
1251 int cursor_start, int cursor_width, int cursor_height)
1253 struct frame *f = XFRAME (w->frame);
1254 struct device *d = XDEVICE (f->device);
1255 struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1258 Display *dpy = DEVICE_X_DISPLAY (d);
1259 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1260 int lheight = dl->ascent + dl->descent - dl->clip;
1261 int pheight = ((int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > lheight ? lheight :
1262 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
1263 int pwidth = min (width + xoffset, (int) IMAGE_INSTANCE_PIXMAP_WIDTH (p));
1264 int clip_x, clip_y, clip_width, clip_height;
1266 /* The pixmap_offset is used to center the pixmap on lines which are
1267 shorter than it is. This results in odd effects when scrolling
1268 pixmaps off of the bottom. Let's try not using it. */
1270 int pixmap_offset = (int) (IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - lheight) / 2;
1272 int pixmap_offset = 0;
1275 XSETWINDOW (window, w);
1277 if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
1279 if (start_pixpos > xpos && start_pixpos > xpos + width)
1284 if (start_pixpos > xpos)
1286 clip_x += (start_pixpos - xpos);
1287 clip_width -= (start_pixpos - xpos);
1296 /* Place markers for possible future functionality (clipping the top
1297 half instead of the bottom half; think pixel scrolling). */
1299 clip_height = pheight;
1301 /* Clear the area the pixmap is going into. The pixmap itself will
1302 always take care of the full width. We don't want to clear where
1303 it is going to go in order to avoid flicker. So, all we have to
1304 take care of is any area above or below the pixmap. */
1305 /* #### We take a shortcut for now. We know that since we have
1306 pixmap_offset hardwired to 0 that the pixmap is against the top
1307 edge so all we have to worry about is below it. */
1308 /* #### Unless the pixmap has a mask in which case we have to clear
1309 the whole damn thing since we can't yet clear just the area not
1310 included in the mask. */
1311 if (((int) (dl->ypos - dl->ascent + pheight) <
1312 (int) (dl->ypos + dl->descent - dl->clip))
1313 || IMAGE_INSTANCE_X_MASK (p))
1315 int clear_x, clear_y, clear_width, clear_height;
1317 if (IMAGE_INSTANCE_X_MASK (p))
1319 clear_y = dl->ypos - dl->ascent;
1320 clear_height = lheight;
1324 clear_y = dl->ypos - dl->ascent + pheight;
1325 clear_height = lheight - pheight;
1328 if (start_pixpos >= 0 && start_pixpos > xpos)
1330 clear_x = start_pixpos;
1331 clear_width = xpos + width - start_pixpos;
1336 clear_width = width;
1339 redisplay_clear_region (window, findex, clear_x, clear_y,
1340 clear_width, clear_height);
1343 /* Output the pixmap. */
1345 Lisp_Object tmp_pixel;
1346 XColor tmp_bcolor, tmp_fcolor;
1348 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1349 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1350 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1351 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1353 x_output_x_pixmap (f, p, xpos - xoffset, dl->ypos - dl->ascent, clip_x,
1354 clip_y, clip_width, clip_height,
1355 pwidth, pheight, pixmap_offset,
1356 tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
1359 /* Draw a cursor over top of the pixmap. */
1360 if (cursor_width && cursor_height && (cursor_start >= xpos)
1361 && !NILP (w->text_cursor_visible_p)
1362 && (cursor_start < xpos + pwidth))
1365 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1366 int y = dl->ypos - dl->ascent;
1367 struct face_cachel *cursor_cachel =
1368 WINDOW_FACE_CACHEL (w,
1369 get_builtin_face_cache_index
1370 (w, Vtext_cursor_face));
1372 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1374 if (cursor_width > xpos + pwidth - cursor_start)
1375 cursor_width = xpos + pwidth - cursor_start;
1379 XFillRectangle (dpy, x_win, gc, cursor_start, y, cursor_width,
1384 XDrawRectangle (dpy, x_win, gc, cursor_start, y, cursor_width,
1390 /*****************************************************************************
1391 x_output_vertical_divider
1393 Draw a vertical divider down the right side of the given window.
1394 ****************************************************************************/
1396 x_output_vertical_divider (struct window *w, int clear)
1398 struct frame *f = XFRAME (w->frame);
1399 struct device *d = XDEVICE (f->device);
1401 Display *dpy = DEVICE_X_DISPLAY (d);
1402 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1403 Lisp_Object tmp_pixel;
1409 int x, y1, y2, width, shadow_thickness, spacing, line_width;
1410 face_index div_face = get_builtin_face_cache_index (w, Vvertical_divider_face);
1412 width = window_divider_width (w);
1413 shadow_thickness = XINT (w->vertical_divider_shadow_thickness);
1414 spacing = XINT (w->vertical_divider_spacing);
1415 line_width = XINT (w->vertical_divider_line_width);
1416 x = WINDOW_RIGHT (w) - width;
1417 y1 = WINDOW_TOP (w) + FRAME_TOP_GUTTER_BOUNDS (f);
1418 y2 = WINDOW_BOTTOM (w) + FRAME_BOTTOM_GUTTER_BOUNDS (f);
1420 memset (&gcv, ~0, sizeof (XGCValues));
1422 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1423 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1425 /* First, get the GC's. */
1426 gcv.background = tmp_color.pixel;
1427 gcv.foreground = tmp_color.pixel;
1428 gcv.graphics_exposures = False;
1429 mask = GCForeground | GCBackground | GCGraphicsExposures;
1430 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1432 /* Clear the divider area first. This needs to be done when a
1433 window split occurs. */
1435 XClearArea (dpy, x_win, x, y1, width, y2 - y1, False);
1437 /* Draw the divider line. */
1438 XFillRectangle (dpy, x_win, background_gc,
1439 x + spacing + shadow_thickness, y1,
1440 line_width, y2 - y1);
1442 /* Draw the shadows around the divider line */
1443 x_bevel_area (w, div_face, x + spacing, y1,
1444 width - 2 * spacing, y2 - y1,
1448 /*****************************************************************************
1451 Output a blank by clearing the area it covers in the foreground color
1453 ****************************************************************************/
1455 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
1456 int start_pixpos, int cursor_start, int cursor_width)
1458 struct frame *f = XFRAME (w->frame);
1459 struct device *d = XDEVICE (f->device);
1461 Display *dpy = DEVICE_X_DISPLAY (d);
1462 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1464 struct face_cachel *cursor_cachel =
1465 WINDOW_FACE_CACHEL (w,
1466 get_builtin_face_cache_index
1467 (w, Vtext_cursor_face));
1468 Lisp_Object bg_pmap;
1469 Lisp_Object buffer = WINDOW_BUFFER (w);
1470 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1474 int y = dl->ypos - dl->ascent;
1475 int width = rb->width;
1476 int height = dl->ascent + dl->descent - dl->clip;
1478 if (start_pixpos > x)
1480 if (start_pixpos >= (x + width))
1484 width -= (start_pixpos - x);
1489 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
1490 if (!IMAGE_INSTANCEP (bg_pmap)
1491 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
1495 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1498 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1499 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
1502 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1504 /* If this rune is marked as having the cursor, then it is actually
1505 representing a tab. */
1506 if (!NILP (w->text_cursor_visible_p)
1507 && (rb->cursor_type == CURSOR_ON
1509 && (cursor_start + cursor_width > x)
1510 && cursor_start < (x + width))))
1512 int cursor_height, cursor_y;
1513 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1514 struct Lisp_Font_Instance *fi;
1516 fi = XFONT_INSTANCE (FACE_CACHEL_FONT
1517 (WINDOW_FACE_CACHEL (w, rb->findex),
1520 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1522 cursor_y = dl->ypos - fi->ascent;
1523 cursor_height = fi->height;
1524 if (cursor_y + cursor_height > y + height)
1525 cursor_height = y + height - cursor_y;
1529 if (NILP (bar_cursor_value))
1531 XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1532 fi->width, cursor_height);
1536 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1538 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1539 make_int (bar_width));
1540 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
1541 cursor_y, cursor_start + bar_width - 1,
1542 cursor_y + cursor_height - 1);
1545 else if (NILP (bar_cursor_value))
1547 XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1548 fi->width - 1, cursor_height - 1);
1553 /*****************************************************************************
1556 Output a horizontal line in the foreground of its face.
1557 ****************************************************************************/
1559 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
1561 struct frame *f = XFRAME (w->frame);
1562 struct device *d = XDEVICE (f->device);
1564 Display *dpy = DEVICE_X_DISPLAY (d);
1565 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1569 int width = rb->width;
1570 int height = dl->ascent + dl->descent - dl->clip;
1571 int ypos1, ypos2, ypos3, ypos4;
1573 ypos1 = dl->ypos - dl->ascent;
1574 ypos2 = ypos1 + rb->object.hline.yoffset;
1575 ypos3 = ypos2 + rb->object.hline.thickness;
1576 ypos4 = dl->ypos + dl->descent - dl->clip;
1578 /* First clear the area not covered by the line. */
1579 if (height - rb->object.hline.thickness > 0)
1581 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1584 if (ypos2 - ypos1 > 0)
1585 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1586 if (ypos4 - ypos3 > 0)
1587 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1590 /* Now draw the line. */
1591 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1599 if (ypos3 - ypos2 > 0)
1600 XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1603 /*****************************************************************************
1606 Draw a shadow around the given area using the given GC's. It is the
1607 callers responsibility to set the GC's appropriately.
1608 ****************************************************************************/
1610 x_output_shadows (struct frame *f, int x, int y, int width, int height,
1611 GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
1612 int shadow_thickness)
1614 struct device *d = XDEVICE (f->device);
1616 Display *dpy = DEVICE_X_DISPLAY (d);
1617 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1619 XSegment top_shadow[20], bottom_shadow[20];
1622 if (shadow_thickness > 10)
1623 shadow_thickness = 10;
1624 else if (shadow_thickness < 0)
1625 shadow_thickness = 0;
1626 if (shadow_thickness > (width / 2))
1627 shadow_thickness = width / 2;
1628 if (shadow_thickness > (height / 2))
1629 shadow_thickness = height / 2;
1631 for (elt = 0; elt < shadow_thickness; elt++)
1634 int seg2 = elt + shadow_thickness;
1636 top_shadow[seg1].x1 = x;
1637 top_shadow[seg1].x2 = x + width - elt - 1;
1638 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
1640 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
1641 top_shadow[seg2].y1 = y + shadow_thickness;
1642 top_shadow[seg2].y2 = y + height - elt - 1;
1644 bottom_shadow[seg1].x1 = x + elt + 1;
1645 bottom_shadow[seg1].x2 = x + width - 1;
1646 bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
1648 bottom_shadow[seg2].x1 = bottom_shadow[seg2].x2 = x + width - elt - 1;
1649 bottom_shadow[seg2].y1 = y + elt + 1;
1650 bottom_shadow[seg2].y2 = y + height - shadow_thickness;
1653 XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow, shadow_thickness * 2);
1654 XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
1655 shadow_thickness * 2);
1658 /*****************************************************************************
1659 x_generate_shadow_pixels
1661 Given three pixels (top shadow, bottom shadow, background) massage
1662 the top and bottom shadow colors to guarantee that they differ. The
1663 background pixels are not allowed to be modified.
1665 This function modifies its parameters.
1667 This code is modified from code blatantly stolen from lwlib/xlwmenu.c
1668 ****************************************************************************/
1669 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
1670 ? ((unsigned long) (x)) : ((unsigned long) (y)))
1673 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
1674 unsigned long *bottom_shadow,
1675 unsigned long background,
1676 unsigned long core_background)
1678 struct device *d = XDEVICE (f->device);
1679 Display *dpy = DEVICE_X_DISPLAY (d);
1680 Colormap cmap = DEVICE_X_COLORMAP (d);
1681 Visual *visual = DEVICE_X_VISUAL (d);
1684 int top_frobbed = 0, bottom_frobbed = 0;
1686 /* If the top shadow is the same color as the background, try to
1688 if (*top_shadow == background)
1690 topc.pixel = background;
1691 XQueryColor (dpy, cmap, &topc);
1692 /* don't overflow/wrap! */
1693 topc.red = MINL (65535, (unsigned long) topc.red * 6 / 5);
1694 topc.green = MINL (65535, (unsigned long) topc.green * 6 / 5);
1695 topc.blue = MINL (65535, (unsigned long) topc.blue * 6 / 5);
1696 if (allocate_nearest_color (dpy, cmap, visual, &topc))
1698 *top_shadow = topc.pixel;
1703 /* If the bottom shadow is the same color as the background, try to
1705 if (*bottom_shadow == background)
1707 botc.pixel = background;
1708 XQueryColor (dpy, cmap, &botc);
1709 botc.red = (unsigned short) ((unsigned long) botc.red * 3 / 5);
1710 botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5);
1711 botc.blue = (unsigned short) ((unsigned long) botc.blue * 3 / 5);
1712 if (allocate_nearest_color (dpy, cmap, visual, &botc))
1714 *bottom_shadow = botc.pixel;
1719 /* If we had to adjust both shadows, then we have to do some
1721 if (top_frobbed && bottom_frobbed)
1723 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
1724 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
1725 if (bot_avg > top_avg)
1727 Pixel tmp = *top_shadow;
1729 *top_shadow = *bottom_shadow;
1730 *bottom_shadow = tmp;
1732 else if (topc.pixel == botc.pixel)
1734 if (botc.pixel == background)
1735 *top_shadow = core_background;
1737 *bottom_shadow = background;
1742 /*****************************************************************************
1743 x_redraw_exposed_window
1745 Given a bounding box for an area that needs to be redrawn, determine
1746 what parts of what lines are contained within and re-output their
1748 ****************************************************************************/
1750 x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
1752 struct frame *f = XFRAME (w->frame);
1754 int start_x, start_y, end_x, end_y;
1755 int orig_windows_structure_changed;
1757 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1759 if (!NILP (w->vchild))
1761 x_redraw_exposed_windows (w->vchild, x, y, width, height);
1764 else if (!NILP (w->hchild))
1766 x_redraw_exposed_windows (w->hchild, x, y, width, height);
1770 /* If the window doesn't intersect the exposed region, we're done here. */
1771 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w)
1772 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w))
1778 start_x = max (WINDOW_LEFT (w), x);
1779 end_x = min (WINDOW_RIGHT (w), (x + width));
1780 start_y = max (WINDOW_TOP (w), y);
1781 end_y = min (WINDOW_BOTTOM (w), y + height);
1783 /* We do this to make sure that the 3D modelines get redrawn if
1784 they are in the exposed region. */
1785 orig_windows_structure_changed = f->windows_structure_changed;
1786 f->windows_structure_changed = 1;
1789 if (window_needs_vertical_divider (w))
1791 x_output_vertical_divider (w, 0);
1794 for (line = 0; line < Dynarr_length (cdla); line++)
1796 struct display_line *cdl = Dynarr_atp (cdla, line);
1797 int top_y = cdl->ypos - cdl->ascent;
1798 int bottom_y = cdl->ypos + cdl->descent;
1800 if (bottom_y >= start_y)
1811 output_display_line (w, 0, cdla, line, start_x, end_x);
1816 f->windows_structure_changed = orig_windows_structure_changed;
1818 /* If there have never been any face cache_elements created, then this
1819 expose event doesn't actually have anything to do. */
1820 if (Dynarr_largest (w->face_cachels))
1821 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
1824 /*****************************************************************************
1825 x_redraw_exposed_windows
1827 For each window beneath the given window in the window hierarchy,
1828 ensure that it is redrawn if necessary after an Expose event.
1829 ****************************************************************************/
1831 x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
1834 for (; !NILP (window); window = XWINDOW (window)->next)
1835 x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
1838 /*****************************************************************************
1839 x_redraw_exposed_area
1841 For each window on the given frame, ensure that any area in the
1842 Exposed area is redrawn.
1843 ****************************************************************************/
1845 x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
1847 /* If any window on the frame has had its face cache reset then the
1848 redisplay structures are effectively invalid. If we attempt to
1849 use them we'll blow up. We mark the frame as changed to ensure
1850 that redisplay will do a full update. This probably isn't
1851 necessary but it can't hurt. */
1853 #ifdef HAVE_TOOLBARS
1854 /* #### We would rather put these off as well but there is currently
1855 no combination of flags which will force an unchanged toolbar to
1857 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
1859 redraw_exposed_gutters (f, x, y, width, height);
1861 if (!f->window_face_cache_reset)
1863 x_redraw_exposed_windows (f->root_window, x, y, width, height);
1865 XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
1868 MARK_FRAME_CHANGED (f);
1871 /****************************************************************************
1874 Clear the area in the box defined by the given parameters using the
1876 ****************************************************************************/
1878 x_clear_region (Lisp_Object locale, struct device* d, struct frame* f, face_index findex,
1880 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1881 Lisp_Object background_pixmap)
1887 dpy = DEVICE_X_DISPLAY (d);
1888 x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1890 if (!UNBOUNDP (background_pixmap))
1892 gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
1896 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1898 XClearArea (dpy, x_win, x, y, width, height, False);
1901 /*****************************************************************************
1904 Draw a cursor at the end of a line. The end-of-line cursor is
1905 narrower than the normal cursor.
1906 ****************************************************************************/
1908 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos,
1911 struct frame *f = XFRAME (w->frame);
1912 struct device *d = XDEVICE (f->device);
1915 Display *dpy = DEVICE_X_DISPLAY (d);
1916 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1918 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
1919 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
1921 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1922 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1926 int y = dl->ypos - dl->ascent;
1927 int width = EOL_CURSOR_WIDTH;
1928 int height = dl->ascent + dl->descent - dl->clip;
1929 int cursor_height, cursor_y;
1930 int defheight, defascent;
1932 XSETWINDOW (window, w);
1933 redisplay_clear_region (window, findex, x, y, width, height);
1935 if (NILP (w->text_cursor_visible_p))
1938 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1940 default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
1942 /* make sure the cursor is entirely contained between y and y+height */
1943 cursor_height = min (defheight, height);
1944 cursor_y = max (y, min (y + height - cursor_height,
1945 dl->ypos - defascent));
1950 XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2);
1951 #endif /* HAVE_XIM */
1953 if (NILP (bar_cursor_value))
1955 XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
1959 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1961 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1962 make_int (bar_width));
1963 XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
1964 x + bar_width - 1, cursor_y + cursor_height - 1);
1967 else if (NILP (bar_cursor_value))
1969 XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
1975 x_clear_frame_window (Lisp_Object window)
1977 struct window *w = XWINDOW (window);
1979 if (!NILP (w->vchild))
1981 x_clear_frame_windows (w->vchild);
1985 if (!NILP (w->hchild))
1987 x_clear_frame_windows (w->hchild);
1991 redisplay_clear_to_window_end (w, WINDOW_TEXT_TOP (w),
1992 WINDOW_TEXT_BOTTOM (w));
1996 x_clear_frame_windows (Lisp_Object window)
1998 for (; !NILP (window); window = XWINDOW (window)->next)
1999 x_clear_frame_window (window);
2003 x_clear_frame (struct frame *f)
2005 struct device *d = XDEVICE (f->device);
2006 Display *dpy = DEVICE_X_DISPLAY (d);
2007 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2008 int x, y, width, height;
2011 x = FRAME_LEFT_BORDER_START (f);
2012 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
2013 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
2014 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) -
2015 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f));
2016 /* #### This adjustment by 1 should be being done in the macros.
2017 There is some small differences between when the menubar is on
2018 and off that we still need to deal with. */
2019 y = FRAME_TOP_BORDER_START (f) - 1;
2020 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
2021 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
2022 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) -
2023 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1;
2025 XClearArea (dpy, x_win, x, y, width, height, False);
2027 XSETFRAME (frame, f);
2029 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
2030 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
2031 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
2033 x_clear_frame_windows (f->root_window);
2036 XFlush (DEVICE_X_DISPLAY (d));
2039 /* briefly swap the foreground and background colors.
2043 x_flash (struct device *d)
2049 XColor tmp_fcolor, tmp_bcolor;
2050 Lisp_Object tmp_pixel, frame;
2051 struct frame *f = device_selected_frame (d);
2052 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f));
2053 Widget shell = FRAME_X_SHELL_WIDGET (f);
2055 XSETFRAME (frame, f);
2057 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
2058 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
2059 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
2060 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
2062 dpy = XtDisplay (shell);
2063 win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2064 memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
2065 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
2066 gcv.function = GXxor;
2067 gcv.graphics_exposures = False;
2068 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
2069 (GCForeground | GCFunction | GCGraphicsExposures));
2070 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2071 w->pixel_width, w->pixel_height);
2078 tv.tv_sec = usecs / 1000000L;
2079 tv.tv_usec = usecs % 1000000L;
2080 /* I'm sure someone is going to complain about this... */
2081 select (0, 0, 0, 0, &tv);
2086 #else /* !HAVE_POLL */
2088 #endif /* HAVE_POLL */
2089 #endif /* HAVE_SELECT */
2091 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2092 w->pixel_width, w->pixel_height);
2098 /* Make audible bell. */
2101 x_ring_bell (struct device *d, int volume, int pitch, int duration)
2103 Display *display = DEVICE_X_DISPLAY (d);
2105 if (volume < 0) volume = 0;
2106 else if (volume > 100) volume = 100;
2107 if (pitch < 0 && duration < 0)
2109 XBell (display, (volume * 2) - 100);
2114 XKeyboardState state;
2115 XKeyboardControl ctl;
2117 /* #### grab server? */
2118 XGetKeyboardControl (display, &state);
2120 ctl.bell_pitch = (pitch >= 0 ? pitch : state.bell_pitch);
2121 ctl.bell_duration = (duration >= 0 ? duration : state.bell_duration);
2122 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2124 XBell (display, (volume * 2) - 100);
2126 ctl.bell_pitch = state.bell_pitch;
2127 ctl.bell_duration = state.bell_duration;
2128 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2130 /* #### ungrab server? */
2136 /************************************************************************/
2137 /* initialization */
2138 /************************************************************************/
2141 console_type_create_redisplay_x (void)
2143 /* redisplay methods */
2144 CONSOLE_HAS_METHOD (x, text_width);
2145 CONSOLE_HAS_METHOD (x, output_display_block);
2146 CONSOLE_HAS_METHOD (x, divider_height);
2147 CONSOLE_HAS_METHOD (x, eol_cursor_width);
2148 CONSOLE_HAS_METHOD (x, output_vertical_divider);
2149 CONSOLE_HAS_METHOD (x, clear_region);
2150 CONSOLE_HAS_METHOD (x, clear_frame);
2151 CONSOLE_HAS_METHOD (x, output_begin);
2152 CONSOLE_HAS_METHOD (x, output_end);
2153 CONSOLE_HAS_METHOD (x, flash);
2154 CONSOLE_HAS_METHOD (x, ring_bell);
2155 CONSOLE_HAS_METHOD (x, bevel_area);