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, CCL_MODE_ENCODING);
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);
843 #if defined(HAVE_XIM) && defined(XIM_XLIB)
844 if (cursor && focus && (cursor_start == clip_start) && cursor_height)
846 XIM_SetSpotLocation (f, xpos - 2, dl->ypos + dl->descent - 2);
847 #endif /* HAVE_XIM && XIM_XLIB */
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 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
1402 Display *dpy = DEVICE_X_DISPLAY (d);
1403 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1404 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
1405 Lisp_Object tmp_pixel;
1408 GC top_shadow_gc, bottom_shadow_gc, background_gc;
1413 int x, y1, y2, width, shadow_thickness, spacing, line_width;
1414 face_index div_face = get_builtin_face_cache_index (w, Vvertical_divider_face);
1416 width = window_divider_width (w);
1417 shadow_thickness = XINT (w->vertical_divider_shadow_thickness);
1418 spacing = XINT (w->vertical_divider_spacing);
1419 line_width = XINT (w->vertical_divider_line_width);
1420 x = WINDOW_RIGHT (w) - width;
1421 y1 = WINDOW_TOP (w);
1422 y2 = WINDOW_BOTTOM (w);
1424 memset (&gcv, ~0, sizeof (XGCValues));
1426 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1427 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1429 /* First, get the GC's. */
1430 top_shadow_pixel = tmp_color.pixel;
1431 bottom_shadow_pixel = tmp_color.pixel;
1432 background_pixel = tmp_color.pixel;
1434 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
1435 background_pixel, ef->core.background_pixel);
1437 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, div_face);
1438 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1439 gcv.background = tmp_color.pixel;
1440 gcv.graphics_exposures = False;
1441 mask = GCForeground | GCBackground | GCGraphicsExposures;
1443 /* If we can't distinguish one of the shadows (the color is the same as the
1444 background), it's better to use a pixmap to generate a dithered gray. */
1445 if (top_shadow_pixel == background_pixel ||
1446 bottom_shadow_pixel == background_pixel)
1451 if (DEVICE_X_GRAY_PIXMAP (d) == None)
1453 DEVICE_X_GRAY_PIXMAP (d) =
1454 XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
1455 gray_width, gray_height, 1, 0, 1);
1458 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1459 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1460 gcv.foreground = tmp_color.pixel;
1461 /* this is needed because the GC draws with a pixmap here */
1462 gcv.fill_style = FillOpaqueStippled;
1463 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
1464 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
1465 (mask | GCStipple | GCFillStyle));
1467 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, div_face);
1468 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1469 bottom_shadow_pixel = tmp_color.pixel;
1471 flip_gcs = (bottom_shadow_pixel ==
1472 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
1476 gcv.foreground = top_shadow_pixel;
1477 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1480 gcv.foreground = bottom_shadow_pixel;
1481 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1483 if (use_pixmap && flip_gcs)
1485 GC tmp_gc = bottom_shadow_gc;
1486 bottom_shadow_gc = top_shadow_gc;
1487 top_shadow_gc = tmp_gc;
1490 gcv.foreground = background_pixel;
1491 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1493 /* possibly revert the GC's in case the shadow thickness is < 0.
1494 This will give a depressed look to the divider */
1495 if (shadow_thickness < 0)
1499 temp = top_shadow_gc;
1500 top_shadow_gc = bottom_shadow_gc;
1501 bottom_shadow_gc = temp;
1503 /* better avoid a Bad Address XLib error ;-) */
1504 shadow_thickness = - shadow_thickness;
1507 /* Clear the divider area first. This needs to be done when a
1508 window split occurs. */
1510 XClearArea (dpy, x_win, x, y1, width, y2 - y1, False);
1512 /* Draw the divider line. */
1513 XFillRectangle (dpy, x_win, background_gc,
1514 x + spacing + shadow_thickness, y1,
1515 line_width, y2 - y1);
1517 /* Draw the shadows around the divider line */
1518 x_output_shadows (f, x + spacing, y1,
1519 width - 2 * spacing, y2 - y1,
1520 top_shadow_gc, bottom_shadow_gc,
1521 background_gc, shadow_thickness);
1524 /*****************************************************************************
1527 Output a blank by clearing the area it covers in the foreground color
1529 ****************************************************************************/
1531 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
1532 int start_pixpos, int cursor_start, int cursor_width)
1534 struct frame *f = XFRAME (w->frame);
1535 struct device *d = XDEVICE (f->device);
1537 Display *dpy = DEVICE_X_DISPLAY (d);
1538 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1540 struct face_cachel *cursor_cachel =
1541 WINDOW_FACE_CACHEL (w,
1542 get_builtin_face_cache_index
1543 (w, Vtext_cursor_face));
1544 Lisp_Object bg_pmap;
1545 Lisp_Object buffer = WINDOW_BUFFER (w);
1546 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1550 int y = dl->ypos - dl->ascent;
1551 int width = rb->width;
1552 int height = dl->ascent + dl->descent - dl->clip;
1554 if (start_pixpos > x)
1556 if (start_pixpos >= (x + width))
1560 width -= (start_pixpos - x);
1565 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
1566 if (!IMAGE_INSTANCEP (bg_pmap)
1567 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
1571 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1574 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1575 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
1578 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1580 /* If this rune is marked as having the cursor, then it is actually
1581 representing a tab. */
1582 if (!NILP (w->text_cursor_visible_p)
1583 && (rb->cursor_type == CURSOR_ON
1585 && (cursor_start + cursor_width > x)
1586 && cursor_start < (x + width))))
1588 int cursor_height, cursor_y;
1589 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1590 struct Lisp_Font_Instance *fi;
1592 fi = XFONT_INSTANCE (FACE_CACHEL_FONT
1593 (WINDOW_FACE_CACHEL (w, rb->findex),
1596 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1598 cursor_y = dl->ypos - fi->ascent;
1599 cursor_height = fi->height;
1600 if (cursor_y + cursor_height > y + height)
1601 cursor_height = y + height - cursor_y;
1605 if (NILP (bar_cursor_value))
1607 XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1608 fi->width, cursor_height);
1612 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1614 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1615 make_int (bar_width));
1616 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
1617 cursor_y, cursor_start + bar_width - 1,
1618 cursor_y + cursor_height - 1);
1621 else if (NILP (bar_cursor_value))
1623 XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1624 fi->width - 1, cursor_height - 1);
1629 /*****************************************************************************
1632 Output a horizontal line in the foreground of its face.
1633 ****************************************************************************/
1635 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
1637 struct frame *f = XFRAME (w->frame);
1638 struct device *d = XDEVICE (f->device);
1640 Display *dpy = DEVICE_X_DISPLAY (d);
1641 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1645 int width = rb->width;
1646 int height = dl->ascent + dl->descent - dl->clip;
1647 int ypos1, ypos2, ypos3, ypos4;
1649 ypos1 = dl->ypos - dl->ascent;
1650 ypos2 = ypos1 + rb->object.hline.yoffset;
1651 ypos3 = ypos2 + rb->object.hline.thickness;
1652 ypos4 = dl->ypos + dl->descent - dl->clip;
1654 /* First clear the area not covered by the line. */
1655 if (height - rb->object.hline.thickness > 0)
1657 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1660 if (ypos2 - ypos1 > 0)
1661 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1662 if (ypos4 - ypos3 > 0)
1663 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1666 /* Now draw the line. */
1667 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1675 if (ypos3 - ypos2 > 0)
1676 XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1679 /*****************************************************************************
1682 Draw a shadow around the given area using the given GC's. It is the
1683 callers responsibility to set the GC's appropriately.
1684 ****************************************************************************/
1686 x_output_shadows (struct frame *f, int x, int y, int width, int height,
1687 GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
1688 int shadow_thickness)
1690 struct device *d = XDEVICE (f->device);
1692 Display *dpy = DEVICE_X_DISPLAY (d);
1693 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1695 XSegment top_shadow[20], bottom_shadow[20];
1698 if (shadow_thickness > 10)
1699 shadow_thickness = 10;
1700 else if (shadow_thickness < 0)
1701 shadow_thickness = 0;
1702 if (shadow_thickness > (width / 2))
1703 shadow_thickness = width / 2;
1704 if (shadow_thickness > (height / 2))
1705 shadow_thickness = height / 2;
1707 for (elt = 0; elt < shadow_thickness; elt++)
1710 int seg2 = elt + shadow_thickness;
1712 top_shadow[seg1].x1 = x;
1713 top_shadow[seg1].x2 = x + width - elt - 1;
1714 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
1716 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
1717 top_shadow[seg2].y1 = y + shadow_thickness;
1718 top_shadow[seg2].y2 = y + height - elt - 1;
1720 bottom_shadow[seg1].x1 = x + elt + 1;
1721 bottom_shadow[seg1].x2 = x + width - 1;
1722 bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
1724 bottom_shadow[seg2].x1 = bottom_shadow[seg2].x2 = x + width - elt - 1;
1725 bottom_shadow[seg2].y1 = y + elt + 1;
1726 bottom_shadow[seg2].y2 = y + height - shadow_thickness;
1729 XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow, shadow_thickness * 2);
1730 XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
1731 shadow_thickness * 2);
1734 /*****************************************************************************
1735 x_generate_shadow_pixels
1737 Given three pixels (top shadow, bottom shadow, background) massage
1738 the top and bottom shadow colors to guarantee that they differ. The
1739 background pixels are not allowed to be modified.
1741 This function modifies its parameters.
1743 This code is modified from code blatantly stolen from lwlib/xlwmenu.c
1744 ****************************************************************************/
1745 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
1746 ? ((unsigned long) (x)) : ((unsigned long) (y)))
1749 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
1750 unsigned long *bottom_shadow,
1751 unsigned long background,
1752 unsigned long core_background)
1754 struct device *d = XDEVICE (f->device);
1755 Display *dpy = DEVICE_X_DISPLAY (d);
1756 Colormap cmap = DEVICE_X_COLORMAP (d);
1757 Visual *visual = DEVICE_X_VISUAL (d);
1760 int top_frobbed = 0, bottom_frobbed = 0;
1762 /* If the top shadow is the same color as the background, try to
1764 if (*top_shadow == background)
1766 topc.pixel = background;
1767 XQueryColor (dpy, cmap, &topc);
1768 /* don't overflow/wrap! */
1769 topc.red = MINL (65535, (unsigned long) topc.red * 6 / 5);
1770 topc.green = MINL (65535, (unsigned long) topc.green * 6 / 5);
1771 topc.blue = MINL (65535, (unsigned long) topc.blue * 6 / 5);
1772 if (allocate_nearest_color (dpy, cmap, visual, &topc))
1774 *top_shadow = topc.pixel;
1779 /* If the bottom shadow is the same color as the background, try to
1781 if (*bottom_shadow == background)
1783 botc.pixel = background;
1784 XQueryColor (dpy, cmap, &botc);
1785 botc.red = (unsigned short) ((unsigned long) botc.red * 3 / 5);
1786 botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5);
1787 botc.blue = (unsigned short) ((unsigned long) botc.blue * 3 / 5);
1788 if (allocate_nearest_color (dpy, cmap, visual, &botc))
1790 *bottom_shadow = botc.pixel;
1795 /* If we had to adjust both shadows, then we have to do some
1797 if (top_frobbed && bottom_frobbed)
1799 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
1800 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
1801 if (bot_avg > top_avg)
1803 Pixel tmp = *top_shadow;
1805 *top_shadow = *bottom_shadow;
1806 *bottom_shadow = tmp;
1808 else if (topc.pixel == botc.pixel)
1810 if (botc.pixel == background)
1811 *top_shadow = core_background;
1813 *bottom_shadow = background;
1818 /*****************************************************************************
1819 x_clear_to_window_end
1821 Clear the area between ypos1 and ypos2. Each margin area and the
1822 text area is handled separately since they may each have their own
1824 ****************************************************************************/
1826 x_clear_to_window_end (struct window *w, int ypos1, int ypos2)
1828 int height = ypos2 - ypos1;
1832 struct frame *f = XFRAME (w->frame);
1834 int bflag = (window_needs_vertical_divider (w) ? 0 : 1);
1835 layout_bounds bounds;
1837 bounds = calculate_display_line_boundaries (w, bflag);
1838 XSETWINDOW (window, w);
1840 if (window_is_leftmost (w))
1841 redisplay_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f),
1842 ypos1, FRAME_BORDER_WIDTH (f), height);
1844 if (bounds.left_in - bounds.left_out > 0)
1845 redisplay_clear_region (window,
1846 get_builtin_face_cache_index (w, Vleft_margin_face),
1847 bounds.left_out, ypos1,
1848 bounds.left_in - bounds.left_out, height);
1850 if (bounds.right_in - bounds.left_in > 0)
1851 redisplay_clear_region (window, DEFAULT_INDEX, bounds.left_in, ypos1,
1852 bounds.right_in - bounds.left_in, height);
1854 if (bounds.right_out - bounds.right_in > 0)
1855 redisplay_clear_region (window,
1856 get_builtin_face_cache_index (w, Vright_margin_face),
1857 bounds.right_in, ypos1,
1858 bounds.right_out - bounds.right_in, height);
1860 if (window_is_rightmost (w))
1861 redisplay_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f),
1862 ypos1, FRAME_BORDER_WIDTH (f), height);
1866 /*****************************************************************************
1867 x_redraw_exposed_window
1869 Given a bounding box for an area that needs to be redrawn, determine
1870 what parts of what lines are contained within and re-output their
1872 ****************************************************************************/
1874 x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
1876 struct frame *f = XFRAME (w->frame);
1878 int start_x, start_y, end_x, end_y;
1879 int orig_windows_structure_changed;
1881 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1883 if (!NILP (w->vchild))
1885 x_redraw_exposed_windows (w->vchild, x, y, width, height);
1888 else if (!NILP (w->hchild))
1890 x_redraw_exposed_windows (w->hchild, x, y, width, height);
1894 /* If the window doesn't intersect the exposed region, we're done here. */
1895 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w)
1896 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w))
1902 start_x = max (WINDOW_LEFT (w), x);
1903 end_x = min (WINDOW_RIGHT (w), (x + width));
1904 start_y = max (WINDOW_TOP (w), y);
1905 end_y = min (WINDOW_BOTTOM (w), y + height);
1907 /* We do this to make sure that the 3D modelines get redrawn if
1908 they are in the exposed region. */
1909 orig_windows_structure_changed = f->windows_structure_changed;
1910 f->windows_structure_changed = 1;
1913 if (window_needs_vertical_divider (w))
1915 x_output_vertical_divider (w, 0);
1918 for (line = 0; line < Dynarr_length (cdla); line++)
1920 struct display_line *cdl = Dynarr_atp (cdla, line);
1921 int top_y = cdl->ypos - cdl->ascent;
1922 int bottom_y = cdl->ypos + cdl->descent;
1924 if (bottom_y >= start_y)
1935 output_display_line (w, 0, cdla, line, start_x, end_x);
1940 f->windows_structure_changed = orig_windows_structure_changed;
1942 /* If there have never been any face cache_elements created, then this
1943 expose event doesn't actually have anything to do. */
1944 if (Dynarr_largest (w->face_cachels))
1945 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
1948 /*****************************************************************************
1949 x_redraw_exposed_windows
1951 For each window beneath the given window in the window hierarchy,
1952 ensure that it is redrawn if necessary after an Expose event.
1953 ****************************************************************************/
1955 x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
1958 for (; !NILP (window); window = XWINDOW (window)->next)
1959 x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
1962 /*****************************************************************************
1963 x_redraw_exposed_area
1965 For each window on the given frame, ensure that any area in the
1966 Exposed area is redrawn.
1967 ****************************************************************************/
1969 x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
1971 /* If any window on the frame has had its face cache reset then the
1972 redisplay structures are effectively invalid. If we attempt to
1973 use them we'll blow up. We mark the frame as changed to ensure
1974 that redisplay will do a full update. This probably isn't
1975 necessary but it can't hurt. */
1977 #ifdef HAVE_TOOLBARS
1978 /* #### We would rather put these off as well but there is currently
1979 no combination of flags which will force an unchanged toolbar to
1981 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
1984 if (!f->window_face_cache_reset)
1986 x_redraw_exposed_windows (f->root_window, x, y, width, height);
1988 XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
1991 MARK_FRAME_CHANGED (f);
1994 /****************************************************************************
1997 Clear the area in the box defined by the given parameters using the
1999 ****************************************************************************/
2001 x_clear_region (Lisp_Object locale, struct device* d, struct frame* f, face_index findex,
2003 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
2004 Lisp_Object background_pixmap)
2010 dpy = DEVICE_X_DISPLAY (d);
2011 x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2013 if (!UNBOUNDP (background_pixmap))
2015 gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
2019 XFillRectangle (dpy, x_win, gc, x, y, width, height);
2021 XClearArea (dpy, x_win, x, y, width, height, False);
2024 /*****************************************************************************
2027 Draw a cursor at the end of a line. The end-of-line cursor is
2028 narrower than the normal cursor.
2029 ****************************************************************************/
2031 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos,
2034 struct frame *f = XFRAME (w->frame);
2035 struct device *d = XDEVICE (f->device);
2038 Display *dpy = DEVICE_X_DISPLAY (d);
2039 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2041 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
2042 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
2044 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
2045 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
2049 int y = dl->ypos - dl->ascent;
2050 int width = EOL_CURSOR_WIDTH;
2051 int height = dl->ascent + dl->descent - dl->clip;
2052 int cursor_height, cursor_y;
2053 int defheight, defascent;
2055 XSETWINDOW (window, w);
2056 redisplay_clear_region (window, findex, x, y, width, height);
2058 if (NILP (w->text_cursor_visible_p))
2061 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
2063 default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
2065 /* make sure the cursor is entirely contained between y and y+height */
2066 cursor_height = min (defheight, height);
2067 cursor_y = max (y, min (y + height - cursor_height,
2068 dl->ypos - defascent));
2072 #if defined(HAVE_XIM) && defined(XIM_XLIB)
2074 XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2);
2075 #endif /* HAVE_XIM */
2077 if (NILP (bar_cursor_value))
2079 XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
2083 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
2085 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
2086 make_int (bar_width));
2087 XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
2088 x + bar_width - 1, cursor_y + cursor_height - 1);
2091 else if (NILP (bar_cursor_value))
2093 XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
2099 x_clear_frame_window (Lisp_Object window)
2101 struct window *w = XWINDOW (window);
2103 if (!NILP (w->vchild))
2105 x_clear_frame_windows (w->vchild);
2109 if (!NILP (w->hchild))
2111 x_clear_frame_windows (w->hchild);
2115 x_clear_to_window_end (w, WINDOW_TEXT_TOP (w), WINDOW_TEXT_BOTTOM (w));
2119 x_clear_frame_windows (Lisp_Object window)
2121 for (; !NILP (window); window = XWINDOW (window)->next)
2122 x_clear_frame_window (window);
2126 x_clear_frame (struct frame *f)
2128 struct device *d = XDEVICE (f->device);
2129 Display *dpy = DEVICE_X_DISPLAY (d);
2130 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2131 int x, y, width, height;
2134 x = FRAME_LEFT_BORDER_START (f);
2135 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
2136 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
2137 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) -
2138 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f));
2139 /* #### This adjustment by 1 should be being done in the macros.
2140 There is some small differences between when the menubar is on
2141 and off that we still need to deal with. */
2142 y = FRAME_TOP_BORDER_START (f) - 1;
2143 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
2144 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
2145 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) -
2146 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1;
2148 XClearArea (dpy, x_win, x, y, width, height, False);
2150 XSETFRAME (frame, f);
2152 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
2153 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
2154 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
2156 x_clear_frame_windows (f->root_window);
2159 XFlush (DEVICE_X_DISPLAY (d));
2162 /* briefly swap the foreground and background colors.
2166 x_flash (struct device *d)
2172 XColor tmp_fcolor, tmp_bcolor;
2173 Lisp_Object tmp_pixel, frame;
2174 struct frame *f = device_selected_frame (d);
2175 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f));
2176 Widget shell = FRAME_X_SHELL_WIDGET (f);
2178 XSETFRAME (frame, f);
2180 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
2181 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
2182 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
2183 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
2185 dpy = XtDisplay (shell);
2186 win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2187 memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
2188 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
2189 gcv.function = GXxor;
2190 gcv.graphics_exposures = False;
2191 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
2192 (GCForeground | GCFunction | GCGraphicsExposures));
2193 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2194 w->pixel_width, w->pixel_height);
2201 tv.tv_sec = usecs / 1000000L;
2202 tv.tv_usec = usecs % 1000000L;
2203 /* I'm sure someone is going to complain about this... */
2204 select (0, 0, 0, 0, &tv);
2209 #else /* !HAVE_POLL */
2211 #endif /* HAVE_POLL */
2212 #endif /* HAVE_SELECT */
2214 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2215 w->pixel_width, w->pixel_height);
2221 /* Make audible bell. */
2224 x_ring_bell (struct device *d, int volume, int pitch, int duration)
2226 Display *display = DEVICE_X_DISPLAY (d);
2228 if (volume < 0) volume = 0;
2229 else if (volume > 100) volume = 100;
2230 if (pitch < 0 && duration < 0)
2232 XBell (display, (volume * 2) - 100);
2237 XKeyboardState state;
2238 XKeyboardControl ctl;
2240 /* #### grab server? */
2241 XGetKeyboardControl (display, &state);
2243 ctl.bell_pitch = (pitch >= 0 ? pitch : state.bell_pitch);
2244 ctl.bell_duration = (duration >= 0 ? duration : state.bell_duration);
2245 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2247 XBell (display, (volume * 2) - 100);
2249 ctl.bell_pitch = state.bell_pitch;
2250 ctl.bell_duration = state.bell_duration;
2251 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2253 /* #### ungrab server? */
2259 /************************************************************************/
2260 /* initialization */
2261 /************************************************************************/
2264 console_type_create_redisplay_x (void)
2266 /* redisplay methods */
2267 CONSOLE_HAS_METHOD (x, text_width);
2268 CONSOLE_HAS_METHOD (x, output_display_block);
2269 CONSOLE_HAS_METHOD (x, divider_height);
2270 CONSOLE_HAS_METHOD (x, eol_cursor_width);
2271 CONSOLE_HAS_METHOD (x, output_vertical_divider);
2272 CONSOLE_HAS_METHOD (x, clear_to_window_end);
2273 CONSOLE_HAS_METHOD (x, clear_region);
2274 CONSOLE_HAS_METHOD (x, clear_frame);
2275 CONSOLE_HAS_METHOD (x, output_begin);
2276 CONSOLE_HAS_METHOD (x, output_end);
2277 CONSOLE_HAS_METHOD (x, flash);
2278 CONSOLE_HAS_METHOD (x, ring_bell);