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"
43 #include "redisplay.h"
46 #include <X11/bitmaps/gray>
48 #include "sysproc.h" /* for select() */
52 #include "file-coding.h" /* for CCL conversion */
55 /* Number of pixels below each line. */
56 /* #### implement me */
57 int x_interline_space;
59 #define EOL_CURSOR_WIDTH 5
61 static void x_output_pixmap (struct window *w, struct display_line *dl,
62 Lisp_Object image_instance, int xpos,
64 int start_pixpos, int width, face_index findex,
65 int cursor_start, int cursor_width,
67 static void x_output_vertical_divider (struct window *w, int clear);
68 static void x_output_blank (struct window *w, struct display_line *dl,
69 struct rune *rb, int start_pixpos,
70 int cursor_start, int cursor_width);
71 static void x_output_hline (struct window *w, struct display_line *dl,
73 static void x_redraw_exposed_window (struct window *w, int x, int y,
74 int width, int height);
75 static void x_redraw_exposed_windows (Lisp_Object window, int x, int y,
76 int width, int height);
77 static void x_output_eol_cursor (struct window *w, struct display_line *dl,
78 int xpos, face_index findex);
79 static void x_clear_frame (struct frame *f);
80 static void x_clear_frame_windows (Lisp_Object window);
81 static void x_bevel_modeline (struct window *w, struct display_line *dl);
84 /* Note: We do not use the Xmb*() functions and XFontSets.
85 Those functions are generally losing for a number of reasons:
87 1) They only support one locale (e.g. you could display
88 Japanese and ASCII text, but not mixed Japanese/Chinese
89 text). You could maybe call setlocale() frequently
90 to try to deal with this, but that would generally
91 fail because an XFontSet is tied to one locale and
92 won't have the other character sets in it.
93 2) Not all (or even very many) OS's support the useful
94 locales. For example, as far as I know SunOS and
95 Solaris only support the Japanese locale if you get the
96 special Asian-language version of the OS. Yuck yuck
97 yuck. Linux doesn't support the Japanese locale at
99 3) The locale support in X only exists in R5, not in R4.
100 (Not sure how big of a problem this is: how many
101 people are using R4?)
102 4) Who knows if the multi-byte text format (which is locale-
103 specific) is even the same for the same locale on
104 different OS's? It's not even documented anywhere that
105 I can find what the multi-byte text format for the
106 Japanese locale under SunOS and Solaris is, but I assume
118 /* Separate out the text in DYN into a series of textual runs of a
119 particular charset. Also convert the characters as necessary into
120 the format needed by XDrawImageString(), XDrawImageString16(), et
121 al. (This means converting to one or two byte format, possibly
122 tweaking the high bits, and possibly running a CCL program.) You
123 must pre-allocate the space used and pass it in. (This is done so
124 you can alloca() the space.) You need to allocate (2 * len) bytes
125 of TEXT_STORAGE and (len * sizeof (struct textual_run)) bytes of
126 RUN_STORAGE, where LEN is the length of the dynarr.
128 Returns the number of runs actually used. */
131 separate_textual_runs (unsigned char *text_storage,
132 struct textual_run *run_storage,
133 CONST Emchar *str, Charcount len)
135 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a
136 possible valid charset when
137 MULE is not defined */
141 struct ccl_program char_converter;
142 int need_ccl_conversion = 0;
145 for (i = 0; i < len; i++)
153 BREAKUP_CHAR (ch, charset, byte1, byte2);
154 dimension = XCHARSET_DIMENSION (charset);
155 graphic = XCHARSET_GRAPHIC (charset);
157 if (!EQ (charset, prev_charset))
159 run_storage[runs_so_far].ptr = text_storage;
160 run_storage[runs_so_far].charset = charset;
161 run_storage[runs_so_far].dimension = dimension;
165 run_storage[runs_so_far - 1].len =
166 text_storage - run_storage[runs_so_far - 1].ptr;
167 if (run_storage[runs_so_far - 1].dimension == 2)
168 run_storage[runs_so_far - 1].len >>= 1;
171 prev_charset = charset;
174 Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset);
175 need_ccl_conversion = !NILP (ccl_prog);
176 if (need_ccl_conversion)
177 setup_ccl_program (&char_converter, ccl_prog);
187 else if (graphic == 1)
193 if (need_ccl_conversion)
195 char_converter.reg[0] = XCHARSET_ID (charset);
196 char_converter.reg[1] = byte1;
197 char_converter.reg[2] = byte2;
198 ccl_driver (&char_converter, 0, 0, 0, 0);
199 byte1 = char_converter.reg[1];
200 byte2 = char_converter.reg[2];
203 *text_storage++ = (unsigned char) byte1;
205 *text_storage++ = (unsigned char) byte2;
210 run_storage[runs_so_far - 1].len =
211 text_storage - run_storage[runs_so_far - 1].ptr;
212 if (run_storage[runs_so_far - 1].dimension == 2)
213 run_storage[runs_so_far - 1].len >>= 1;
219 /****************************************************************************/
221 /* X output routines */
223 /****************************************************************************/
226 x_text_width_single_run (struct face_cachel *cachel, struct textual_run *run)
228 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
229 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
230 if (!fi->proportional_p)
231 return fi->width * run->len;
234 if (run->dimension == 2)
235 return XTextWidth16 (FONT_INSTANCE_X_FONT (fi),
236 (XChar2b *) run->ptr, run->len);
238 return XTextWidth (FONT_INSTANCE_X_FONT (fi),
239 (char *) run->ptr, run->len);
246 Given a string and a face, return the string's length in pixels when
247 displayed in the font associated with the face.
251 x_text_width (struct frame *f, struct face_cachel *cachel, CONST Emchar *str,
254 int width_so_far = 0;
255 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
256 struct textual_run *runs = alloca_array (struct textual_run, len);
260 nruns = separate_textual_runs (text_storage, runs, str, len);
262 for (i = 0; i < nruns; i++)
263 width_so_far += x_text_width_single_run (cachel, runs + i);
268 /*****************************************************************************
271 Return the height of the horizontal divider. This is a function because
272 divider_height is a device method.
274 #### If we add etched horizontal divider lines this will have to get
276 ****************************************************************************/
278 x_divider_height (void)
283 /*****************************************************************************
286 Return the width of the end-of-line cursor. This is a function
287 because eol_cursor_width is a device method.
288 ****************************************************************************/
290 x_eol_cursor_width (void)
292 return EOL_CURSOR_WIDTH;
295 /*****************************************************************************
298 Perform any necessary initialization prior to an update.
299 ****************************************************************************/
301 x_output_begin (struct device *d)
305 /*****************************************************************************
308 Perform any necessary flushing of queues when an update has completed.
309 ****************************************************************************/
311 x_output_end (struct device *d)
313 XFlush (DEVICE_X_DISPLAY (d));
316 /*****************************************************************************
317 x_output_display_block
319 Given a display line, a block number for that start line, output all
320 runes between start and end in the specified display block.
321 ****************************************************************************/
323 x_output_display_block (struct window *w, struct display_line *dl, int block,
324 int start, int end, int start_pixpos, int cursor_start,
325 int cursor_width, int cursor_height)
327 struct frame *f = XFRAME (w->frame);
328 Emchar_dynarr *buf = Dynarr_new (Emchar);
331 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
332 rune_dynarr *rba = db->runes;
338 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
339 MULE is not defined */
341 XSETWINDOW (window, w);
342 rb = Dynarr_atp (rba, start);
346 /* Nothing to do so don't do anything. */
354 if (rb->type == RUNE_CHAR)
355 charset = CHAR_CHARSET (rb->object.chr.ch);
359 end = Dynarr_length (rba);
364 rb = Dynarr_atp (rba, elt);
366 if (rb->findex == findex && rb->type == RUNE_CHAR
367 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
368 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
370 Dynarr_add (buf, rb->object.chr.ch);
376 if (Dynarr_length (buf))
378 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
379 findex, 0, cursor_start, cursor_width,
387 if (rb->type == RUNE_CHAR)
391 charset = CHAR_CHARSET (rb->object.chr.ch);
393 if (rb->cursor_type == CURSOR_ON)
395 if (rb->object.chr.ch == '\n')
397 x_output_eol_cursor (w, dl, xpos, findex);
401 Dynarr_add (buf, rb->object.chr.ch);
402 x_output_string (w, dl, buf, xpos, 0, start_pixpos,
403 rb->width, findex, 1,
404 cursor_start, cursor_width,
412 else if (rb->object.chr.ch == '\n')
414 /* Clear in case a cursor was formerly here. */
415 int height = dl->ascent + dl->descent - dl->clip;
417 redisplay_clear_region (window, findex, xpos, dl->ypos - dl->ascent,
422 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
424 if (rb->type == RUNE_BLANK)
425 x_output_blank (w, dl, rb, start_pixpos, cursor_start,
429 /* #### Our flagging of when we need to redraw the
430 modeline shadows sucks. Since RUNE_HLINE is only used
431 by the modeline at the moment it is a good bet
432 that if it gets redrawn then we should also
433 redraw the shadows. This won't be true forever.
434 We borrow the shadow_thickness_changed flag for
436 w->shadow_thickness_changed = 1;
437 x_output_hline (w, dl, rb);
443 rb = Dynarr_atp (rba, elt);
449 else if (rb->type == RUNE_DGLYPH)
451 Lisp_Object instance;
453 XSETWINDOW (window, w);
454 instance = glyph_image_instance (rb->object.dglyph.glyph,
455 window, ERROR_ME_NOT, 1);
458 if (IMAGE_INSTANCEP (instance))
459 switch (XIMAGE_INSTANCE_TYPE (instance))
463 /* #### This is way losing. See the comment in
466 XIMAGE_INSTANCE_TEXT_STRING (instance);
467 convert_bufbyte_string_into_emchar_dynarr
468 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
470 x_output_string (w, dl, buf, xpos,
471 rb->object.dglyph.xoffset,
472 start_pixpos, -1, findex,
473 (rb->cursor_type == CURSOR_ON),
474 cursor_start, cursor_width,
480 case IMAGE_MONO_PIXMAP:
481 case IMAGE_COLOR_PIXMAP:
482 x_output_pixmap (w, dl, instance, xpos,
483 rb->object.dglyph.xoffset, start_pixpos,
484 rb->width, findex, cursor_start,
485 cursor_width, cursor_height);
492 case IMAGE_SUBWINDOW:
493 redisplay_output_subwindow (w, dl, instance, xpos,
494 rb->object.dglyph.xoffset, start_pixpos,
495 rb->width, findex, cursor_start,
496 cursor_width, cursor_height);
499 /* nothing is as nothing does */
514 if (Dynarr_length (buf))
515 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
516 0, cursor_start, cursor_width, cursor_height);
518 /* #### This is really conditionalized well for optimized
521 && !EQ (Qzero, w->modeline_shadow_thickness)
523 || f->windows_structure_changed
524 || w->shadow_thickness_changed))
525 x_bevel_modeline (w, dl);
530 /*****************************************************************************
533 Draw a 3d border around the modeline on window W.
534 ****************************************************************************/
536 x_bevel_modeline (struct window *w, struct display_line *dl)
538 struct frame *f = XFRAME (w->frame);
539 struct device *d = XDEVICE (f->device);
540 Display *dpy = DEVICE_X_DISPLAY (d);
541 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
542 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
543 GC top_shadow_gc, bottom_shadow_gc, background_gc;
544 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
546 Lisp_Object tmp_pixel;
547 int x, y, width, height;
552 int shadow_thickness;
554 memset (&gcv, ~0, sizeof (XGCValues));
556 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, MODELINE_INDEX);
557 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
559 /* First, get the GC's. */
560 top_shadow_pixel = tmp_color.pixel;
561 bottom_shadow_pixel = tmp_color.pixel;
562 background_pixel = tmp_color.pixel;
564 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
565 background_pixel, ef->core.background_pixel);
567 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, MODELINE_INDEX);
568 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
569 gcv.background = tmp_color.pixel;
570 gcv.graphics_exposures = False;
571 mask = GCForeground | GCBackground | GCGraphicsExposures;
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, MODELINE_INDEX);
587 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
588 gcv.foreground = tmp_color.pixel;
589 gcv.fill_style = FillOpaqueStippled;
590 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
591 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
592 (mask | GCStipple | GCFillStyle));
594 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, MODELINE_INDEX);
595 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
596 bottom_shadow_pixel = tmp_color.pixel;
598 flip_gcs = (bottom_shadow_pixel ==
599 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
603 gcv.foreground = top_shadow_pixel;
604 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
607 gcv.foreground = bottom_shadow_pixel;
608 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
610 if (use_pixmap && flip_gcs)
612 GC tmp_gc = bottom_shadow_gc;
613 bottom_shadow_gc = top_shadow_gc;
614 top_shadow_gc = tmp_gc;
617 gcv.foreground = background_pixel;
618 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
620 if (XINT (w->modeline_shadow_thickness) < 0)
624 temp = top_shadow_gc;
625 top_shadow_gc = bottom_shadow_gc;
626 bottom_shadow_gc = temp;
629 shadow_thickness = MODELINE_SHADOW_THICKNESS (w);
631 x = WINDOW_MODELINE_LEFT (w);
632 width = WINDOW_MODELINE_RIGHT (w) - x;
633 y = dl->ypos - dl->ascent - shadow_thickness;
634 height = dl->ascent + dl->descent + 2 * shadow_thickness;
636 x_output_shadows (f, x, y, width, height, top_shadow_gc, bottom_shadow_gc,
637 background_gc, shadow_thickness);
640 /*****************************************************************************
643 Given a number of parameters return a GC with those properties.
644 ****************************************************************************/
646 x_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
647 Lisp_Object bg_pmap, Lisp_Object lwidth)
652 memset (&gcv, ~0, sizeof (XGCValues));
653 gcv.graphics_exposures = False;
654 /* Make absolutely sure that we don't pick up a clipping region in
655 the GC returned by this function. */
656 gcv.clip_mask = None;
657 gcv.clip_x_origin = 0;
658 gcv.clip_y_origin = 0;
659 gcv.fill_style = FillSolid;
660 mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
665 gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
670 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 fprintf (stderr, "Help! x_get_gc got a bogus fg value! fg = ");
681 if (COLOR_INSTANCEP (fg))
682 gcv.foreground = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (fg)).pixel;
684 gcv.foreground = XINT (fg);
685 mask |= GCForeground;
690 if (COLOR_INSTANCEP (bg))
691 gcv.background = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (bg)).pixel;
693 gcv.background = XINT (bg);
694 mask |= GCBackground;
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))
701 assert (DEVICE_X_GRAY_PIXMAP (d) != None);
703 gcv.fill_style = FillStippled;
704 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
705 mask |= (GCFillStyle | GCStipple);
707 else if (IMAGE_INSTANCEP (bg_pmap)
708 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
710 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
712 gcv.fill_style = FillOpaqueStippled;
713 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
714 mask |= (GCStipple | GCFillStyle);
718 gcv.fill_style = FillTiled;
719 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
720 mask |= (GCTile | GCFillStyle);
726 gcv.line_width = XINT (lwidth);
730 return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
733 /*****************************************************************************
736 Given a string and a starting position, output that string in the
737 given face. If cursor is true, draw a cursor around the string.
738 Correctly handles multiple charsets in the string.
740 The meaning of the parameters is something like this:
742 W Window that the text is to be displayed in.
743 DL Display line that this text is on. The values in the
744 structure are used to determine the vertical position and
745 clipping range of the text.
746 BUF Dynamic array of Emchars specifying what is actually to be
748 XPOS X position in pixels where the text should start being drawn.
749 XOFFSET Number of pixels to be chopped off the left side of the
750 text. The effect is as if the text were shifted to the
751 left this many pixels and clipped at XPOS.
752 CLIP_START Clip everything left of this X position.
753 WIDTH Clip everything right of XPOS + WIDTH.
754 FINDEX Index for the face cache element describing how to display
756 CURSOR #### I don't understand this. There's something
757 strange and overcomplexified with this variable.
758 Chuck, explain please?
759 CURSOR_START Starting X position of cursor.
760 CURSOR_WIDTH Width of cursor in pixels.
761 CURSOR_HEIGHT Height of cursor in pixels.
763 Starting Y position of cursor is the top of the text line.
764 The cursor is drawn sometimes whether or not CURSOR is set. ???
765 ****************************************************************************/
767 x_output_string (struct window *w, struct display_line *dl,
768 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
769 int width, face_index findex, int cursor,
770 int cursor_start, int cursor_width, int cursor_height)
772 /* General variables */
773 struct frame *f = XFRAME (w->frame);
774 struct device *d = XDEVICE (f->device);
777 Display *dpy = DEVICE_X_DISPLAY (d);
778 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
782 /* Cursor-related variables */
783 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
785 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
787 struct face_cachel *cursor_cachel = 0;
789 /* Text-related variables */
793 int len = Dynarr_length (buf);
794 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
795 struct textual_run *runs = alloca_array (struct textual_run, len);
798 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
800 XSETDEVICE (device, d);
801 XSETWINDOW (window, w);
804 width = x_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
805 height = dl->ascent + dl->descent - dl->clip;
807 /* Regularize the variables passed in. */
809 if (clip_start < xpos)
811 clip_end = xpos + width;
812 if (clip_start >= clip_end)
813 /* It's all clipped out. */
818 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
819 Dynarr_length (buf));
821 cursor_clip = (cursor_start >= clip_start &&
822 cursor_start < clip_end);
824 /* This cursor code is really a mess. */
825 if (!NILP (w->text_cursor_visible_p)
829 && (cursor_start + cursor_width >= clip_start)
830 && !NILP (bar_cursor_value))))
832 /* These have to be in separate statements in order to avoid a
834 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face);
835 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks);
837 /* We have to reset this since any call to WINDOW_FACE_CACHEL
838 may cause the cache to resize and any pointers to it to
840 cachel = WINDOW_FACE_CACHEL (w, findex);
844 if (cursor && focus && (cursor_start == clip_start) && cursor_height)
845 XIM_SetSpotLocation (f, xpos - 2, dl->ypos + dl->descent - 2);
846 #endif /* HAVE_XIM */
848 bg_pmap = cachel->background_pixmap;
849 if (!IMAGE_INSTANCEP (bg_pmap)
850 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
853 if ((cursor && focus && NILP (bar_cursor_value)
854 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap))
857 bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
861 XFillRectangle (dpy, x_win, bgc, clip_start,
862 dl->ypos - dl->ascent, clip_end - clip_start,
865 for (i = 0; i < nruns; i++)
867 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
868 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
872 if (EQ (font, Vthe_null_font_instance))
875 this_width = x_text_width_single_run (cachel, runs + i);
876 need_clipping = (dl->clip || clip_start > xpos ||
877 clip_end < xpos + this_width);
879 /* XDrawImageString only clears the area equal to the height of
880 the given font. It is possible that a font is being displayed
881 on a line taller than it is, so this would cause us to fail to
883 if ((int) fi->height < (int) (height + dl->clip))
885 int clear_start = max (xpos, clip_start);
886 int clear_end = min (xpos + this_width, clip_end);
890 int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
892 ypos1_string = dl->ypos - fi->ascent;
893 ypos2_string = dl->ypos + fi->descent;
894 ypos1_line = dl->ypos - dl->ascent;
895 ypos2_line = dl->ypos + dl->descent - dl->clip;
897 /* Make sure we don't clear below the real bottom of the
899 if (ypos1_string > ypos2_line)
900 ypos1_string = ypos2_line;
901 if (ypos2_string > ypos2_line)
902 ypos2_string = ypos2_line;
904 if (ypos1_line < ypos1_string)
906 redisplay_clear_region (window, findex, clear_start, ypos1_line,
907 clear_end - clear_start,
908 ypos1_string - ypos1_line);
911 if (ypos2_line > ypos2_string)
913 redisplay_clear_region (window, findex, clear_start, ypos2_string,
914 clear_end - clear_start,
915 ypos2_line - ypos2_string);
920 redisplay_clear_region (window, findex, clear_start,
921 dl->ypos - dl->ascent, clear_end - clear_start,
926 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value))
927 gc = x_get_gc (d, font, cursor_cachel->foreground,
928 cursor_cachel->background, Qnil, Qnil);
929 else if (cachel->dim)
931 /* Ensure the gray bitmap exists */
932 if (DEVICE_X_GRAY_PIXMAP (d) == None)
933 DEVICE_X_GRAY_PIXMAP (d) =
934 XCreateBitmapFromData (dpy, x_win, (char *)gray_bits,
935 gray_width, gray_height);
937 /* Request a GC with the gray stipple pixmap to draw dimmed text */
938 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
942 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
947 XRectangle clip_box[1];
951 clip_box[0].width = clip_end - clip_start;
952 clip_box[0].height = height;
954 XSetClipRectangles (dpy, gc, clip_start, dl->ypos - dl->ascent,
955 clip_box, 1, Unsorted);
958 if (runs[i].dimension == 1)
959 (bgc ? XDrawString : XDrawImageString) (dpy, x_win, gc, xpos,
960 dl->ypos, (char *) runs[i].ptr,
963 (bgc ? XDrawString16 : XDrawImageString16) (dpy, x_win, gc, xpos,
965 (XChar2b *) runs[i].ptr,
968 /* We draw underlines in the same color as the text. */
969 if (cachel->underline)
971 unsigned long upos, uthick;
974 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
975 if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos))
976 upos = dl->descent / 2;
977 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
980 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
982 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
983 uthick = dl->descent - dl->clip - upos;
987 XDrawLine (dpy, x_win, gc, xpos, dl->ypos + upos,
988 xpos + this_width, dl->ypos + upos);
992 XFillRectangle (dpy, x_win, gc, xpos,
993 dl->ypos + upos, this_width, uthick);
998 if (cachel->strikethru) {
999 unsigned long ascent,descent,upos, uthick;
1002 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
1004 if (!XGetFontProperty (xfont, XA_STRIKEOUT_ASCENT, &ascent))
1005 ascent = xfont->ascent;
1006 if (!XGetFontProperty (xfont, XA_STRIKEOUT_DESCENT, &descent))
1007 descent = xfont->descent;
1008 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
1011 upos = ascent - ((ascent + descent) / 2) + 1;
1013 /* Generally, upos will be positive (above the baseline),so subtract */
1014 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip)
1016 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip)
1017 uthick = dl->descent - dl->clip + upos;
1021 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos,
1022 xpos + this_width, dl->ypos - upos);
1024 else if (uthick > 1)
1026 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos,
1027 this_width, uthick);
1032 /* Restore the GC */
1035 XSetClipMask (dpy, gc, None);
1036 XSetClipOrigin (dpy, gc, 0, 0);
1039 /* If we are actually superimposing the cursor then redraw with just
1040 the appropriate section highlighted. */
1041 if (cursor_clip && !cursor && focus && cursor_cachel)
1044 XRectangle clip_box[1];
1046 cgc = x_get_gc (d, font, cursor_cachel->foreground,
1047 cursor_cachel->background, Qnil, Qnil);
1051 clip_box[0].width = cursor_width;
1052 clip_box[0].height = height;
1054 XSetClipRectangles (dpy, cgc, cursor_start, dl->ypos - dl->ascent,
1055 clip_box, 1, Unsorted);
1057 if (runs[i].dimension == 1)
1058 XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
1059 (char *) runs[i].ptr, runs[i].len);
1061 XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
1062 (XChar2b *) runs[i].ptr, runs[i].len);
1064 XSetClipMask (dpy, cgc, None);
1065 XSetClipOrigin (dpy, cgc, 0, 0);
1071 /* Draw the non-focus box or bar-cursor as needed. */
1072 /* Can't this logic be simplified? */
1074 && ((cursor && !focus && NILP (bar_cursor_value))
1076 && (cursor_start + cursor_width >= clip_start)
1077 && !NILP (bar_cursor_value))))
1079 int tmp_height, tmp_y;
1080 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1081 int need_clipping = (cursor_start < clip_start
1082 || clip_end < cursor_start + cursor_width);
1084 /* #### This value is correct (as far as I know) because
1085 all of the times we need to draw this cursor, we will
1086 be called with exactly one character, so we know we
1087 can always use runs[0].
1089 This is bogus as all hell, however. The cursor handling in
1090 this function is way bogus and desperately needs to be
1091 cleaned up. (In particular, the drawing of the cursor should
1092 really really be separated out of this function. This may be
1093 a bit tricky now because this function itself does way too
1094 much stuff, a lot of which needs to be moved into
1095 redisplay.c) This is the only way to be able to easily add
1096 new cursor types or (e.g.) make the bar cursor be able to
1097 span two characters instead of overlaying just one. */
1098 int bogusly_obtained_ascent_value =
1099 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent;
1101 if (!NILP (bar_cursor_value))
1103 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1104 make_int (bar_width));
1108 gc = x_get_gc (d, Qnil, cursor_cachel->background,
1112 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1113 tmp_height = cursor_height;
1114 if (tmp_y + tmp_height > (int) (dl->ypos - dl->ascent + height))
1116 tmp_y = dl->ypos - dl->ascent + height - tmp_height;
1117 if (tmp_y < (int) (dl->ypos - dl->ascent))
1118 tmp_y = dl->ypos - dl->ascent;
1119 tmp_height = dl->ypos - dl->ascent + height - tmp_y;
1124 XRectangle clip_box[1];
1127 clip_box[0].width = clip_end - clip_start;
1128 clip_box[0].height = tmp_height;
1129 XSetClipRectangles (dpy, gc, clip_start, tmp_y,
1130 clip_box, 1, Unsorted);
1133 if (!focus && NILP (bar_cursor_value))
1135 XDrawRectangle (dpy, x_win, gc, cursor_start, tmp_y,
1136 cursor_width - 1, tmp_height - 1);
1138 else if (focus && !NILP (bar_cursor_value))
1140 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1, tmp_y,
1141 cursor_start + bar_width - 1, tmp_y + tmp_height - 1);
1144 /* Restore the GC */
1147 XSetClipMask (dpy, gc, None);
1148 XSetClipOrigin (dpy, gc, 0, 0);
1154 x_output_x_pixmap (struct frame *f, struct Lisp_Image_Instance *p, int x,
1155 int y, int clip_x, int clip_y, int clip_width,
1156 int clip_height, int width, int height, int pixmap_offset,
1157 unsigned long fg, unsigned long bg, GC override_gc)
1159 struct device *d = XDEVICE (f->device);
1160 Display *dpy = DEVICE_X_DISPLAY (d);
1161 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1165 unsigned long pixmap_mask;
1166 int need_clipping = (clip_x || clip_y);
1170 memset (&gcv, ~0, sizeof (XGCValues));
1171 gcv.graphics_exposures = False;
1172 gcv.foreground = fg;
1173 gcv.background = bg;
1174 pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
1176 if (IMAGE_INSTANCE_X_MASK (p))
1178 gcv.function = GXcopy;
1179 gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
1180 gcv.clip_x_origin = x;
1181 gcv.clip_y_origin = y - pixmap_offset;
1182 pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
1184 /* Can't set a clip rectangle below because we already have a mask.
1185 We could conceivably create a new clipmask by zeroing out
1186 everything outside the clip region. Is it worth it?
1187 Is it possible to get an equivalent effect by changing the
1188 args to XCopyArea below rather than messing with a clip box?
1189 - dkindred@cs.cmu.edu */
1193 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
1198 /* override_gc might have a mask already--we don't want to nuke it.
1199 Maybe we can insist that override_gc have no mask, or use
1200 one of the suggestions above. */
1206 XRectangle clip_box[1];
1208 clip_box[0].x = clip_x;
1209 clip_box[0].y = clip_y;
1210 clip_box[0].width = clip_width;
1211 clip_box[0].height = clip_height;
1213 XSetClipRectangles (dpy, gc, x, y, clip_box, 1, Unsorted);
1216 /* depth of 0 means it's a bitmap, not a pixmap, and we should use
1217 XCopyPlane (1 = current foreground color, 0 = background) instead
1218 of XCopyArea, which means that the bits in the pixmap are actual
1219 pixel values, instead of symbolic of fg/bg. */
1220 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
1222 XCopyArea (dpy, IMAGE_INSTANCE_X_PIXMAP (p), x_win, gc, 0,
1223 pixmap_offset, width,
1228 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP (p), x_win, gc, 0,
1241 XSetClipMask (dpy, gc, None);
1242 XSetClipOrigin (dpy, gc, 0, 0);
1247 x_output_pixmap (struct window *w, struct display_line *dl,
1248 Lisp_Object image_instance, int xpos, int xoffset,
1249 int start_pixpos, int width, face_index findex,
1250 int cursor_start, int cursor_width, int cursor_height)
1252 struct frame *f = XFRAME (w->frame);
1253 struct device *d = XDEVICE (f->device);
1254 struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1257 Display *dpy = DEVICE_X_DISPLAY (d);
1258 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1259 int lheight = dl->ascent + dl->descent - dl->clip;
1260 int pheight = ((int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > lheight ? lheight :
1261 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
1262 int pwidth = min (width + xoffset, (int) IMAGE_INSTANCE_PIXMAP_WIDTH (p));
1263 int clip_x, clip_y, clip_width, clip_height;
1265 /* The pixmap_offset is used to center the pixmap on lines which are
1266 shorter than it is. This results in odd effects when scrolling
1267 pixmaps off of the bottom. Let's try not using it. */
1269 int pixmap_offset = (int) (IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - lheight) / 2;
1271 int pixmap_offset = 0;
1274 XSETWINDOW (window, w);
1276 if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
1278 if (start_pixpos > xpos && start_pixpos > xpos + width)
1283 if (start_pixpos > xpos)
1285 clip_x += (start_pixpos - xpos);
1286 clip_width -= (start_pixpos - xpos);
1295 /* Place markers for possible future functionality (clipping the top
1296 half instead of the bottom half; think pixel scrolling). */
1298 clip_height = pheight;
1300 /* Clear the area the pixmap is going into. The pixmap itself will
1301 always take care of the full width. We don't want to clear where
1302 it is going to go in order to avoid flicker. So, all we have to
1303 take care of is any area above or below the pixmap. */
1304 /* #### We take a shortcut for now. We know that since we have
1305 pixmap_offset hardwired to 0 that the pixmap is against the top
1306 edge so all we have to worry about is below it. */
1307 /* #### Unless the pixmap has a mask in which case we have to clear
1308 the whole damn thing since we can't yet clear just the area not
1309 included in the mask. */
1310 if (((int) (dl->ypos - dl->ascent + pheight) <
1311 (int) (dl->ypos + dl->descent - dl->clip))
1312 || IMAGE_INSTANCE_X_MASK (p))
1314 int clear_x, clear_y, clear_width, clear_height;
1316 if (IMAGE_INSTANCE_X_MASK (p))
1318 clear_y = dl->ypos - dl->ascent;
1319 clear_height = lheight;
1323 clear_y = dl->ypos - dl->ascent + pheight;
1324 clear_height = lheight - pheight;
1327 if (start_pixpos >= 0 && start_pixpos > xpos)
1329 clear_x = start_pixpos;
1330 clear_width = xpos + width - start_pixpos;
1335 clear_width = width;
1338 redisplay_clear_region (window, findex, clear_x, clear_y,
1339 clear_width, clear_height);
1342 /* Output the pixmap. */
1344 Lisp_Object tmp_pixel;
1345 XColor tmp_bcolor, tmp_fcolor;
1347 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1348 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1349 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1350 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1352 x_output_x_pixmap (f, p, xpos - xoffset, dl->ypos - dl->ascent, clip_x,
1353 clip_y, clip_width, clip_height,
1354 pwidth, pheight, pixmap_offset,
1355 tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
1358 /* Draw a cursor over top of the pixmap. */
1359 if (cursor_width && cursor_height && (cursor_start >= xpos)
1360 && !NILP (w->text_cursor_visible_p)
1361 && (cursor_start < xpos + pwidth))
1364 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1365 int y = dl->ypos - dl->ascent;
1366 struct face_cachel *cursor_cachel =
1367 WINDOW_FACE_CACHEL (w,
1368 get_builtin_face_cache_index
1369 (w, Vtext_cursor_face));
1371 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1373 if (cursor_width > xpos + pwidth - cursor_start)
1374 cursor_width = xpos + pwidth - cursor_start;
1378 XFillRectangle (dpy, x_win, gc, cursor_start, y, cursor_width,
1383 XDrawRectangle (dpy, x_win, gc, cursor_start, y, cursor_width,
1389 /*****************************************************************************
1390 x_output_vertical_divider
1392 Draw a vertical divider down the right side of the given window.
1393 ****************************************************************************/
1395 x_output_vertical_divider (struct window *w, int clear)
1397 struct frame *f = XFRAME (w->frame);
1398 struct device *d = XDEVICE (f->device);
1400 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
1401 Display *dpy = DEVICE_X_DISPLAY (d);
1402 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1403 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
1404 Lisp_Object tmp_pixel;
1407 GC top_shadow_gc, bottom_shadow_gc, background_gc;
1412 int x, y1, y2, width, shadow_thickness, spacing, line_width;
1413 face_index div_face = get_builtin_face_cache_index (w, Vvertical_divider_face);
1415 width = window_divider_width (w);
1416 shadow_thickness = XINT (w->vertical_divider_shadow_thickness);
1417 spacing = XINT (w->vertical_divider_spacing);
1418 line_width = XINT (w->vertical_divider_line_width);
1419 x = WINDOW_RIGHT (w) - width;
1420 y1 = WINDOW_TOP (w);
1421 y2 = WINDOW_BOTTOM (w);
1423 memset (&gcv, ~0, sizeof (XGCValues));
1425 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1426 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1428 /* First, get the GC's. */
1429 top_shadow_pixel = tmp_color.pixel;
1430 bottom_shadow_pixel = tmp_color.pixel;
1431 background_pixel = tmp_color.pixel;
1433 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
1434 background_pixel, ef->core.background_pixel);
1436 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, div_face);
1437 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1438 gcv.background = tmp_color.pixel;
1439 gcv.graphics_exposures = False;
1440 mask = GCForeground | GCBackground | GCGraphicsExposures;
1442 /* If we can't distinguish one of the shadows (the color is the same as the
1443 background), it's better to use a pixmap to generate a dithered gray. */
1444 if (top_shadow_pixel == background_pixel ||
1445 bottom_shadow_pixel == background_pixel)
1450 if (DEVICE_X_GRAY_PIXMAP (d) == None)
1452 DEVICE_X_GRAY_PIXMAP (d) =
1453 XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
1454 gray_width, gray_height, 1, 0, 1);
1457 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1458 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1459 gcv.foreground = tmp_color.pixel;
1460 /* this is needed because the GC draws with a pixmap here */
1461 gcv.fill_style = FillOpaqueStippled;
1462 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
1463 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
1464 (mask | GCStipple | GCFillStyle));
1466 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, div_face);
1467 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1468 bottom_shadow_pixel = tmp_color.pixel;
1470 flip_gcs = (bottom_shadow_pixel ==
1471 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
1475 gcv.foreground = top_shadow_pixel;
1476 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1479 gcv.foreground = bottom_shadow_pixel;
1480 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1482 if (use_pixmap && flip_gcs)
1484 GC tmp_gc = bottom_shadow_gc;
1485 bottom_shadow_gc = top_shadow_gc;
1486 top_shadow_gc = tmp_gc;
1489 gcv.foreground = background_pixel;
1490 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1492 /* possibly revert the GC's in case the shadow thickness is < 0.
1493 This will give a depressed look to the divider */
1494 if (shadow_thickness < 0)
1498 temp = top_shadow_gc;
1499 top_shadow_gc = bottom_shadow_gc;
1500 bottom_shadow_gc = temp;
1502 /* better avoid a Bad Address XLib error ;-) */
1503 shadow_thickness = - shadow_thickness;
1506 /* Clear the divider area first. This needs to be done when a
1507 window split occurs. */
1509 XClearArea (dpy, x_win, x, y1, width, y2 - y1, False);
1511 /* Draw the divider line. */
1512 XFillRectangle (dpy, x_win, background_gc,
1513 x + spacing + shadow_thickness, y1,
1514 line_width, y2 - y1);
1516 /* Draw the shadows around the divider line */
1517 x_output_shadows (f, x + spacing, y1,
1518 width - 2 * spacing, y2 - y1,
1519 top_shadow_gc, bottom_shadow_gc,
1520 background_gc, shadow_thickness);
1523 /*****************************************************************************
1526 Output a blank by clearing the area it covers in the foreground color
1528 ****************************************************************************/
1530 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
1531 int start_pixpos, int cursor_start, int cursor_width)
1533 struct frame *f = XFRAME (w->frame);
1534 struct device *d = XDEVICE (f->device);
1536 Display *dpy = DEVICE_X_DISPLAY (d);
1537 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1539 struct face_cachel *cursor_cachel =
1540 WINDOW_FACE_CACHEL (w,
1541 get_builtin_face_cache_index
1542 (w, Vtext_cursor_face));
1543 Lisp_Object bg_pmap;
1544 Lisp_Object buffer = WINDOW_BUFFER (w);
1545 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1549 int y = dl->ypos - dl->ascent;
1550 int width = rb->width;
1551 int height = dl->ascent + dl->descent - dl->clip;
1553 if (start_pixpos > x)
1555 if (start_pixpos >= (x + width))
1559 width -= (start_pixpos - x);
1564 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
1565 if (!IMAGE_INSTANCEP (bg_pmap)
1566 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
1570 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1573 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1574 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
1577 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1579 /* If this rune is marked as having the cursor, then it is actually
1580 representing a tab. */
1581 if (!NILP (w->text_cursor_visible_p)
1582 && (rb->cursor_type == CURSOR_ON
1584 && (cursor_start + cursor_width > x)
1585 && cursor_start < (x + width))))
1587 int cursor_height, cursor_y;
1588 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1589 struct Lisp_Font_Instance *fi;
1591 fi = XFONT_INSTANCE (FACE_CACHEL_FONT
1592 (WINDOW_FACE_CACHEL (w, rb->findex),
1595 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1597 cursor_y = dl->ypos - fi->ascent;
1598 cursor_height = fi->height;
1599 if (cursor_y + cursor_height > y + height)
1600 cursor_height = y + height - cursor_y;
1604 if (NILP (bar_cursor_value))
1606 XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1607 fi->width, cursor_height);
1611 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1613 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1614 make_int (bar_width));
1615 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
1616 cursor_y, cursor_start + bar_width - 1,
1617 cursor_y + cursor_height - 1);
1620 else if (NILP (bar_cursor_value))
1622 XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1623 fi->width - 1, cursor_height - 1);
1628 /*****************************************************************************
1631 Output a horizontal line in the foreground of its face.
1632 ****************************************************************************/
1634 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
1636 struct frame *f = XFRAME (w->frame);
1637 struct device *d = XDEVICE (f->device);
1639 Display *dpy = DEVICE_X_DISPLAY (d);
1640 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1644 int width = rb->width;
1645 int height = dl->ascent + dl->descent - dl->clip;
1646 int ypos1, ypos2, ypos3, ypos4;
1648 ypos1 = dl->ypos - dl->ascent;
1649 ypos2 = ypos1 + rb->object.hline.yoffset;
1650 ypos3 = ypos2 + rb->object.hline.thickness;
1651 ypos4 = dl->ypos + dl->descent - dl->clip;
1653 /* First clear the area not covered by the line. */
1654 if (height - rb->object.hline.thickness > 0)
1656 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1659 if (ypos2 - ypos1 > 0)
1660 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1661 if (ypos4 - ypos3 > 0)
1662 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1665 /* Now draw the line. */
1666 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1674 if (ypos3 - ypos2 > 0)
1675 XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1678 /*****************************************************************************
1681 Draw a shadow around the given area using the given GC's. It is the
1682 callers responsibility to set the GC's appropriately.
1683 ****************************************************************************/
1685 x_output_shadows (struct frame *f, int x, int y, int width, int height,
1686 GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
1687 int shadow_thickness)
1689 struct device *d = XDEVICE (f->device);
1691 Display *dpy = DEVICE_X_DISPLAY (d);
1692 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1694 XSegment top_shadow[20], bottom_shadow[20];
1697 if (shadow_thickness > 10)
1698 shadow_thickness = 10;
1699 else if (shadow_thickness < 0)
1700 shadow_thickness = 0;
1701 if (shadow_thickness > (width / 2))
1702 shadow_thickness = width / 2;
1703 if (shadow_thickness > (height / 2))
1704 shadow_thickness = height / 2;
1706 for (elt = 0; elt < shadow_thickness; elt++)
1709 int seg2 = elt + shadow_thickness;
1711 top_shadow[seg1].x1 = x;
1712 top_shadow[seg1].x2 = x + width - elt - 1;
1713 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
1715 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
1716 top_shadow[seg2].y1 = y + shadow_thickness;
1717 top_shadow[seg2].y2 = y + height - elt - 1;
1719 bottom_shadow[seg1].x1 = x + elt + 1;
1720 bottom_shadow[seg1].x2 = x + width - 1;
1721 bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
1723 bottom_shadow[seg2].x1 = bottom_shadow[seg2].x2 = x + width - elt - 1;
1724 bottom_shadow[seg2].y1 = y + elt + 1;
1725 bottom_shadow[seg2].y2 = y + height - shadow_thickness;
1728 XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow, shadow_thickness * 2);
1729 XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
1730 shadow_thickness * 2);
1733 /*****************************************************************************
1734 x_generate_shadow_pixels
1736 Given three pixels (top shadow, bottom shadow, background) massage
1737 the top and bottom shadow colors to guarantee that they differ. The
1738 background pixels are not allowed to be modified.
1740 This function modifies its parameters.
1742 This code is modified from code blatantly stolen from lwlib/xlwmenu.c
1743 ****************************************************************************/
1744 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
1745 ? ((unsigned long) (x)) : ((unsigned long) (y)))
1748 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
1749 unsigned long *bottom_shadow,
1750 unsigned long background,
1751 unsigned long core_background)
1753 struct device *d = XDEVICE (f->device);
1754 Display *dpy = DEVICE_X_DISPLAY (d);
1755 Colormap cmap = DEVICE_X_COLORMAP (d);
1756 Visual *visual = DEVICE_X_VISUAL (d);
1759 int top_frobbed = 0, bottom_frobbed = 0;
1761 /* If the top shadow is the same color as the background, try to
1763 if (*top_shadow == background)
1765 topc.pixel = background;
1766 XQueryColor (dpy, cmap, &topc);
1767 /* don't overflow/wrap! */
1768 topc.red = MINL (65535, (unsigned long) topc.red * 6 / 5);
1769 topc.green = MINL (65535, (unsigned long) topc.green * 6 / 5);
1770 topc.blue = MINL (65535, (unsigned long) topc.blue * 6 / 5);
1771 if (allocate_nearest_color (dpy, cmap, visual, &topc))
1773 *top_shadow = topc.pixel;
1778 /* If the bottom shadow is the same color as the background, try to
1780 if (*bottom_shadow == background)
1782 botc.pixel = background;
1783 XQueryColor (dpy, cmap, &botc);
1784 botc.red = (unsigned short) ((unsigned long) botc.red * 3 / 5);
1785 botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5);
1786 botc.blue = (unsigned short) ((unsigned long) botc.blue * 3 / 5);
1787 if (allocate_nearest_color (dpy, cmap, visual, &botc))
1789 *bottom_shadow = botc.pixel;
1794 /* If we had to adjust both shadows, then we have to do some
1796 if (top_frobbed && bottom_frobbed)
1798 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
1799 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
1800 if (bot_avg > top_avg)
1802 Pixel tmp = *top_shadow;
1804 *top_shadow = *bottom_shadow;
1805 *bottom_shadow = tmp;
1807 else if (topc.pixel == botc.pixel)
1809 if (botc.pixel == background)
1810 *top_shadow = core_background;
1812 *bottom_shadow = background;
1817 /*****************************************************************************
1818 x_clear_to_window_end
1820 Clear the area between ypos1 and ypos2. Each margin area and the
1821 text area is handled separately since they may each have their own
1823 ****************************************************************************/
1825 x_clear_to_window_end (struct window *w, int ypos1, int ypos2)
1827 int height = ypos2 - ypos1;
1831 struct frame *f = XFRAME (w->frame);
1833 int bflag = (window_needs_vertical_divider (w) ? 0 : 1);
1834 layout_bounds bounds;
1836 bounds = calculate_display_line_boundaries (w, bflag);
1837 XSETWINDOW (window, w);
1839 if (window_is_leftmost (w))
1840 redisplay_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f),
1841 ypos1, FRAME_BORDER_WIDTH (f), height);
1843 if (bounds.left_in - bounds.left_out > 0)
1844 redisplay_clear_region (window,
1845 get_builtin_face_cache_index (w, Vleft_margin_face),
1846 bounds.left_out, ypos1,
1847 bounds.left_in - bounds.left_out, height);
1849 if (bounds.right_in - bounds.left_in > 0)
1850 redisplay_clear_region (window, DEFAULT_INDEX, bounds.left_in, ypos1,
1851 bounds.right_in - bounds.left_in, height);
1853 if (bounds.right_out - bounds.right_in > 0)
1854 redisplay_clear_region (window,
1855 get_builtin_face_cache_index (w, Vright_margin_face),
1856 bounds.right_in, ypos1,
1857 bounds.right_out - bounds.right_in, height);
1859 if (window_is_rightmost (w))
1860 redisplay_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f),
1861 ypos1, FRAME_BORDER_WIDTH (f), height);
1865 /*****************************************************************************
1866 x_redraw_exposed_window
1868 Given a bounding box for an area that needs to be redrawn, determine
1869 what parts of what lines are contained within and re-output their
1871 ****************************************************************************/
1873 x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
1875 struct frame *f = XFRAME (w->frame);
1877 int start_x, start_y, end_x, end_y;
1878 int orig_windows_structure_changed;
1880 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1882 if (!NILP (w->vchild))
1884 x_redraw_exposed_windows (w->vchild, x, y, width, height);
1887 else if (!NILP (w->hchild))
1889 x_redraw_exposed_windows (w->hchild, x, y, width, height);
1893 /* If the window doesn't intersect the exposed region, we're done here. */
1894 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w)
1895 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w))
1901 start_x = max (WINDOW_LEFT (w), x);
1902 end_x = min (WINDOW_RIGHT (w), (x + width));
1903 start_y = max (WINDOW_TOP (w), y);
1904 end_y = min (WINDOW_BOTTOM (w), y + height);
1906 /* We do this to make sure that the 3D modelines get redrawn if
1907 they are in the exposed region. */
1908 orig_windows_structure_changed = f->windows_structure_changed;
1909 f->windows_structure_changed = 1;
1912 if (window_needs_vertical_divider (w))
1914 x_output_vertical_divider (w, 0);
1917 for (line = 0; line < Dynarr_length (cdla); line++)
1919 struct display_line *cdl = Dynarr_atp (cdla, line);
1920 int top_y = cdl->ypos - cdl->ascent;
1921 int bottom_y = cdl->ypos + cdl->descent;
1923 if (bottom_y >= start_y)
1934 output_display_line (w, 0, cdla, line, start_x, end_x);
1939 f->windows_structure_changed = orig_windows_structure_changed;
1941 /* If there have never been any face cache_elements created, then this
1942 expose event doesn't actually have anything to do. */
1943 if (Dynarr_largest (w->face_cachels))
1944 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
1947 /*****************************************************************************
1948 x_redraw_exposed_windows
1950 For each window beneath the given window in the window hierarchy,
1951 ensure that it is redrawn if necessary after an Expose event.
1952 ****************************************************************************/
1954 x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
1957 for (; !NILP (window); window = XWINDOW (window)->next)
1958 x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
1961 /*****************************************************************************
1962 x_redraw_exposed_area
1964 For each window on the given frame, ensure that any area in the
1965 Exposed area is redrawn.
1966 ****************************************************************************/
1968 x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
1970 /* If any window on the frame has had its face cache reset then the
1971 redisplay structures are effectively invalid. If we attempt to
1972 use them we'll blow up. We mark the frame as changed to ensure
1973 that redisplay will do a full update. This probably isn't
1974 necessary but it can't hurt. */
1976 #ifdef HAVE_TOOLBARS
1977 /* #### We would rather put these off as well but there is currently
1978 no combination of flags which will force an unchanged toolbar to
1980 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
1983 if (!f->window_face_cache_reset)
1985 x_redraw_exposed_windows (f->root_window, x, y, width, height);
1987 XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
1990 MARK_FRAME_CHANGED (f);
1993 /****************************************************************************
1996 Clear the area in the box defined by the given parameters using the
1998 ****************************************************************************/
2000 x_clear_region (Lisp_Object locale, struct device* d, struct frame* f, face_index findex,
2002 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
2003 Lisp_Object background_pixmap)
2009 dpy = DEVICE_X_DISPLAY (d);
2010 x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2012 if (!UNBOUNDP (background_pixmap))
2014 gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
2018 XFillRectangle (dpy, x_win, gc, x, y, width, height);
2020 XClearArea (dpy, x_win, x, y, width, height, False);
2023 /*****************************************************************************
2026 Draw a cursor at the end of a line. The end-of-line cursor is
2027 narrower than the normal cursor.
2028 ****************************************************************************/
2030 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos,
2033 struct frame *f = XFRAME (w->frame);
2034 struct device *d = XDEVICE (f->device);
2037 Display *dpy = DEVICE_X_DISPLAY (d);
2038 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2040 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
2041 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
2043 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
2044 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
2048 int y = dl->ypos - dl->ascent;
2049 int width = EOL_CURSOR_WIDTH;
2050 int height = dl->ascent + dl->descent - dl->clip;
2051 int cursor_height, cursor_y;
2052 int defheight, defascent;
2054 XSETWINDOW (window, w);
2055 redisplay_clear_region (window, findex, x, y, width, height);
2057 if (NILP (w->text_cursor_visible_p))
2060 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
2062 default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
2064 /* make sure the cursor is entirely contained between y and y+height */
2065 cursor_height = min (defheight, height);
2066 cursor_y = max (y, min (y + height - cursor_height,
2067 dl->ypos - defascent));
2072 XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2);
2073 #endif /* HAVE_XIM */
2075 if (NILP (bar_cursor_value))
2077 XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
2081 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
2083 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
2084 make_int (bar_width));
2085 XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
2086 x + bar_width - 1, cursor_y + cursor_height - 1);
2089 else if (NILP (bar_cursor_value))
2091 XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
2097 x_clear_frame_window (Lisp_Object window)
2099 struct window *w = XWINDOW (window);
2101 if (!NILP (w->vchild))
2103 x_clear_frame_windows (w->vchild);
2107 if (!NILP (w->hchild))
2109 x_clear_frame_windows (w->hchild);
2113 x_clear_to_window_end (w, WINDOW_TEXT_TOP (w), WINDOW_TEXT_BOTTOM (w));
2117 x_clear_frame_windows (Lisp_Object window)
2119 for (; !NILP (window); window = XWINDOW (window)->next)
2120 x_clear_frame_window (window);
2124 x_clear_frame (struct frame *f)
2126 struct device *d = XDEVICE (f->device);
2127 Display *dpy = DEVICE_X_DISPLAY (d);
2128 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2129 int x, y, width, height;
2132 x = FRAME_LEFT_BORDER_START (f);
2133 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
2134 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
2135 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) -
2136 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f));
2137 /* #### This adjustment by 1 should be being done in the macros.
2138 There is some small differences between when the menubar is on
2139 and off that we still need to deal with. */
2140 y = FRAME_TOP_BORDER_START (f) - 1;
2141 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
2142 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
2143 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) -
2144 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1;
2146 XClearArea (dpy, x_win, x, y, width, height, False);
2148 XSETFRAME (frame, f);
2150 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
2151 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
2152 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
2154 x_clear_frame_windows (f->root_window);
2157 XFlush (DEVICE_X_DISPLAY (d));
2160 /* briefly swap the foreground and background colors.
2164 x_flash (struct device *d)
2170 XColor tmp_fcolor, tmp_bcolor;
2171 Lisp_Object tmp_pixel, frame;
2172 struct frame *f = device_selected_frame (d);
2173 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f));
2174 Widget shell = FRAME_X_SHELL_WIDGET (f);
2176 XSETFRAME (frame, f);
2178 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
2179 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
2180 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
2181 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
2183 dpy = XtDisplay (shell);
2184 win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2185 memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
2186 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
2187 gcv.function = GXxor;
2188 gcv.graphics_exposures = False;
2189 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
2190 (GCForeground | GCFunction | GCGraphicsExposures));
2191 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2192 w->pixel_width, w->pixel_height);
2199 tv.tv_sec = usecs / 1000000L;
2200 tv.tv_usec = usecs % 1000000L;
2201 /* I'm sure someone is going to complain about this... */
2202 select (0, 0, 0, 0, &tv);
2207 #else /* !HAVE_POLL */
2209 #endif /* HAVE_POLL */
2210 #endif /* HAVE_SELECT */
2212 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2213 w->pixel_width, w->pixel_height);
2219 /* Make audible bell. */
2222 x_ring_bell (struct device *d, int volume, int pitch, int duration)
2224 Display *display = DEVICE_X_DISPLAY (d);
2226 if (volume < 0) volume = 0;
2227 else if (volume > 100) volume = 100;
2228 if (pitch < 0 && duration < 0)
2230 XBell (display, (volume * 2) - 100);
2235 XKeyboardState state;
2236 XKeyboardControl ctl;
2238 /* #### grab server? */
2239 XGetKeyboardControl (display, &state);
2241 ctl.bell_pitch = (pitch >= 0 ? pitch : state.bell_pitch);
2242 ctl.bell_duration = (duration >= 0 ? duration : state.bell_duration);
2243 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2245 XBell (display, (volume * 2) - 100);
2247 ctl.bell_pitch = state.bell_pitch;
2248 ctl.bell_duration = state.bell_duration;
2249 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2251 /* #### ungrab server? */
2257 /************************************************************************/
2258 /* initialization */
2259 /************************************************************************/
2262 console_type_create_redisplay_x (void)
2264 /* redisplay methods */
2265 CONSOLE_HAS_METHOD (x, text_width);
2266 CONSOLE_HAS_METHOD (x, output_display_block);
2267 CONSOLE_HAS_METHOD (x, divider_height);
2268 CONSOLE_HAS_METHOD (x, eol_cursor_width);
2269 CONSOLE_HAS_METHOD (x, output_vertical_divider);
2270 CONSOLE_HAS_METHOD (x, clear_to_window_end);
2271 CONSOLE_HAS_METHOD (x, clear_region);
2272 CONSOLE_HAS_METHOD (x, clear_frame);
2273 CONSOLE_HAS_METHOD (x, output_begin);
2274 CONSOLE_HAS_METHOD (x, output_end);
2275 CONSOLE_HAS_METHOD (x, flash);
2276 CONSOLE_HAS_METHOD (x, ring_bell);