1 /* X output and frame manipulation routines.
2 Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3 Copyright (C) 1994 Lucid, Inc.
4 Copyright (C) 1995 Sun Microsystems, Inc.
6 This file is part of XEmacs.
8 XEmacs is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
13 XEmacs is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License
19 along with XEmacs; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
23 /* Synched up with: Not in FSF. */
25 /* Author: Chuck Thompson */
27 /* Lots of work done by Ben Wing for Mule */
32 #include "console-x.h"
33 #include "EmacsFrame.h"
34 #include "EmacsFrameP.h"
37 #include "objects-x.h"
44 #include "redisplay.h"
47 #include <X11/bitmaps/gray>
49 #include "sysproc.h" /* for select() */
53 #include "file-coding.h" /* for CCL conversion */
56 /* Number of pixels below each line. */
57 /* #### implement me */
58 int x_interline_space;
60 #define EOL_CURSOR_WIDTH 5
62 static void x_output_pixmap (struct window *w, struct display_line *dl,
63 Lisp_Object image_instance, int xpos,
65 int start_pixpos, int width, face_index findex,
66 int cursor_start, int cursor_width,
68 static void x_output_vertical_divider (struct window *w, int clear);
69 static void x_output_blank (struct window *w, struct display_line *dl,
70 struct rune *rb, int start_pixpos,
71 int cursor_start, int cursor_width);
72 static void x_output_hline (struct window *w, struct display_line *dl,
74 static void x_redraw_exposed_window (struct window *w, int x, int y,
75 int width, int height);
76 static void x_redraw_exposed_windows (Lisp_Object window, int x, int y,
77 int width, int height);
78 static void x_output_eol_cursor (struct window *w, struct display_line *dl,
79 int xpos, face_index findex);
80 static void x_clear_frame (struct frame *f);
81 static void x_clear_frame_windows (Lisp_Object window);
82 void bevel_modeline (struct window *w, struct display_line *dl);
85 /* Note: We do not use the Xmb*() functions and XFontSets.
86 Those functions are generally losing for a number of reasons:
88 1) They only support one locale (e.g. you could display
89 Japanese and ASCII text, but not mixed Japanese/Chinese
90 text). You could maybe call setlocale() frequently
91 to try to deal with this, but that would generally
92 fail because an XFontSet is tied to one locale and
93 won't have the other character sets in it.
94 2) Not all (or even very many) OS's support the useful
95 locales. For example, as far as I know SunOS and
96 Solaris only support the Japanese locale if you get the
97 special Asian-language version of the OS. Yuck yuck
98 yuck. Linux doesn't support the Japanese locale at
100 3) The locale support in X only exists in R5, not in R4.
101 (Not sure how big of a problem this is: how many
102 people are using R4?)
103 4) Who knows if the multi-byte text format (which is locale-
104 specific) is even the same for the same locale on
105 different OS's? It's not even documented anywhere that
106 I can find what the multi-byte text format for the
107 Japanese locale under SunOS and Solaris is, but I assume
119 /* Separate out the text in DYN into a series of textual runs of a
120 particular charset. Also convert the characters as necessary into
121 the format needed by XDrawImageString(), XDrawImageString16(), et
122 al. (This means converting to one or two byte format, possibly
123 tweaking the high bits, and possibly running a CCL program.) You
124 must pre-allocate the space used and pass it in. (This is done so
125 you can alloca() the space.) You need to allocate (2 * len) bytes
126 of TEXT_STORAGE and (len * sizeof (struct textual_run)) bytes of
127 RUN_STORAGE, where LEN is the length of the dynarr.
129 Returns the number of runs actually used. */
132 separate_textual_runs (unsigned char *text_storage,
133 struct textual_run *run_storage,
134 CONST Emchar *str, Charcount len)
136 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a
137 possible valid charset when
138 MULE is not defined */
142 struct ccl_program char_converter;
143 int need_ccl_conversion = 0;
146 for (i = 0; i < len; i++)
154 if (EQ (Vdefault_coded_charset_priority_list_for_font, Qnil))
155 BREAKUP_CHAR (ch, charset, byte1, byte2);
158 Lisp_Object original_default_coded_charset_priority_list
159 = Vdefault_coded_charset_priority_list;
161 Vdefault_coded_charset_priority_list
162 = Vdefault_coded_charset_priority_list_for_font;
163 BREAKUP_CHAR (ch, charset, byte1, byte2);
164 Vdefault_coded_charset_priority_list
165 = original_default_coded_charset_priority_list;
167 dimension = XCHARSET_DIMENSION (charset);
168 graphic = XCHARSET_GRAPHIC (charset);
170 if (!EQ (charset, prev_charset))
172 run_storage[runs_so_far].ptr = text_storage;
173 run_storage[runs_so_far].charset = charset;
174 run_storage[runs_so_far].dimension = dimension;
178 run_storage[runs_so_far - 1].len =
179 text_storage - run_storage[runs_so_far - 1].ptr;
180 if (run_storage[runs_so_far - 1].dimension == 2)
181 run_storage[runs_so_far - 1].len >>= 1;
184 prev_charset = charset;
187 Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset);
188 need_ccl_conversion = !NILP (ccl_prog);
189 if (need_ccl_conversion)
190 setup_ccl_program (&char_converter, ccl_prog);
200 else if (graphic == 1)
206 if (need_ccl_conversion)
208 char_converter.reg[0] = XCHARSET_ID (charset);
209 char_converter.reg[1] = byte1;
210 char_converter.reg[2] = byte2;
211 ccl_driver (&char_converter, 0, 0, 0, 0, CCL_MODE_ENCODING);
212 byte1 = char_converter.reg[1];
213 byte2 = char_converter.reg[2];
216 *text_storage++ = (unsigned char) byte1;
218 *text_storage++ = (unsigned char) byte2;
223 run_storage[runs_so_far - 1].len =
224 text_storage - run_storage[runs_so_far - 1].ptr;
225 if (run_storage[runs_so_far - 1].dimension == 2)
226 run_storage[runs_so_far - 1].len >>= 1;
232 /****************************************************************************/
234 /* X output routines */
236 /****************************************************************************/
239 x_text_width_single_run (struct face_cachel *cachel, struct textual_run *run)
241 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
242 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
243 if (!fi->proportional_p)
244 return fi->width * run->len;
247 if (run->dimension == 2)
248 return XTextWidth16 (FONT_INSTANCE_X_FONT (fi),
249 (XChar2b *) run->ptr, run->len);
251 return XTextWidth (FONT_INSTANCE_X_FONT (fi),
252 (char *) run->ptr, run->len);
259 Given a string and a face, return the string's length in pixels when
260 displayed in the font associated with the face.
264 x_text_width (struct frame *f, struct face_cachel *cachel, CONST Emchar *str,
267 int width_so_far = 0;
268 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
269 struct textual_run *runs = alloca_array (struct textual_run, len);
273 nruns = separate_textual_runs (text_storage, runs, str, len);
275 for (i = 0; i < nruns; i++)
276 width_so_far += x_text_width_single_run (cachel, runs + i);
281 /*****************************************************************************
284 Return the height of the horizontal divider. This is a function because
285 divider_height is a device method.
287 #### If we add etched horizontal divider lines this will have to get
289 ****************************************************************************/
291 x_divider_height (void)
296 /*****************************************************************************
299 Return the width of the end-of-line cursor. This is a function
300 because eol_cursor_width is a device method.
301 ****************************************************************************/
303 x_eol_cursor_width (void)
305 return EOL_CURSOR_WIDTH;
308 /*****************************************************************************
311 Perform any necessary initialization prior to an update.
312 ****************************************************************************/
314 x_output_begin (struct device *d)
318 /*****************************************************************************
321 Perform any necessary flushing of queues when an update has completed.
322 ****************************************************************************/
324 x_output_end (struct device *d)
326 XFlush (DEVICE_X_DISPLAY (d));
329 /*****************************************************************************
330 x_output_display_block
332 Given a display line, a block number for that start line, output all
333 runes between start and end in the specified display block.
334 ****************************************************************************/
336 x_output_display_block (struct window *w, struct display_line *dl, int block,
337 int start, int end, int start_pixpos, int cursor_start,
338 int cursor_width, int cursor_height)
340 struct frame *f = XFRAME (w->frame);
341 Emchar_dynarr *buf = Dynarr_new (Emchar);
344 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
345 rune_dynarr *rba = db->runes;
351 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
352 MULE is not defined */
354 XSETWINDOW (window, w);
355 rb = Dynarr_atp (rba, start);
358 /* Nothing to do so don't do anything. */
363 if (rb->type == RUNE_CHAR)
364 charset = CHAR_CHARSET (rb->object.chr.ch);
367 end = Dynarr_length (rba);
372 rb = Dynarr_atp (rba, elt);
374 if (rb->findex == findex && rb->type == RUNE_CHAR
375 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
376 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
378 Dynarr_add (buf, rb->object.chr.ch);
384 if (Dynarr_length (buf))
386 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
387 findex, 0, cursor_start, cursor_width,
395 if (rb->type == RUNE_CHAR)
399 charset = CHAR_CHARSET (rb->object.chr.ch);
401 if (rb->cursor_type == CURSOR_ON)
403 if (rb->object.chr.ch == '\n')
405 x_output_eol_cursor (w, dl, xpos, findex);
409 Dynarr_add (buf, rb->object.chr.ch);
410 x_output_string (w, dl, buf, xpos, 0, start_pixpos,
411 rb->width, findex, 1,
412 cursor_start, cursor_width,
420 else if (rb->object.chr.ch == '\n')
422 /* Clear in case a cursor was formerly here. */
423 int height = dl->ascent + dl->descent - dl->clip;
425 redisplay_clear_region (window, findex, xpos, dl->ypos - dl->ascent,
430 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
432 if (rb->type == RUNE_BLANK)
433 x_output_blank (w, dl, rb, start_pixpos, cursor_start,
437 /* #### Our flagging of when we need to redraw the
438 modeline shadows sucks. Since RUNE_HLINE is only used
439 by the modeline at the moment it is a good bet
440 that if it gets redrawn then we should also
441 redraw the shadows. This won't be true forever.
442 We borrow the shadow_thickness_changed flag for
444 w->shadow_thickness_changed = 1;
445 x_output_hline (w, dl, rb);
451 rb = Dynarr_atp (rba, elt);
457 else if (rb->type == RUNE_DGLYPH)
459 Lisp_Object instance;
461 XSETWINDOW (window, w);
462 instance = glyph_image_instance (rb->object.dglyph.glyph,
463 window, ERROR_ME_NOT, 1);
466 if (IMAGE_INSTANCEP (instance))
467 switch (XIMAGE_INSTANCE_TYPE (instance))
471 /* #### This is way losing. See the comment in
474 XIMAGE_INSTANCE_TEXT_STRING (instance);
475 convert_bufbyte_string_into_emchar_dynarr
476 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
478 x_output_string (w, dl, buf, xpos,
479 rb->object.dglyph.xoffset,
480 start_pixpos, -1, findex,
481 (rb->cursor_type == CURSOR_ON),
482 cursor_start, cursor_width,
488 case IMAGE_MONO_PIXMAP:
489 case IMAGE_COLOR_PIXMAP:
490 x_output_pixmap (w, dl, instance, xpos,
491 rb->object.dglyph.xoffset, start_pixpos,
492 rb->width, findex, cursor_start,
493 cursor_width, cursor_height);
500 case IMAGE_SUBWINDOW:
501 redisplay_output_subwindow (w, dl, instance, xpos,
502 rb->object.dglyph.xoffset, start_pixpos,
503 rb->width, findex, cursor_start,
504 cursor_width, cursor_height);
507 /* nothing is as nothing does */
522 if (Dynarr_length (buf))
523 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
524 0, cursor_start, cursor_width, cursor_height);
526 /* #### This is really conditionalized well for optimized
529 && !EQ (Qzero, w->modeline_shadow_thickness)
531 || f->windows_structure_changed
532 || w->shadow_thickness_changed))
533 bevel_modeline (w, dl);
538 /*****************************************************************************
541 Draw a shadows for the given area in the given face.
542 ****************************************************************************/
544 x_bevel_area (struct window *w, face_index findex,
545 int x, int y, int width, int height,
546 int shadow_thickness)
548 struct frame *f = XFRAME (w->frame);
549 struct device *d = XDEVICE (f->device);
551 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
552 Display *dpy = DEVICE_X_DISPLAY (d);
553 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
554 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
555 Lisp_Object tmp_pixel;
558 GC top_shadow_gc, bottom_shadow_gc, background_gc;
564 memset (&gcv, ~0, sizeof (XGCValues));
566 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
567 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
569 /* First, get the GC's. */
570 top_shadow_pixel = tmp_color.pixel;
571 bottom_shadow_pixel = tmp_color.pixel;
572 background_pixel = tmp_color.pixel;
574 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
575 background_pixel, ef->core.background_pixel);
577 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
578 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
579 gcv.background = tmp_color.pixel;
580 gcv.graphics_exposures = False;
581 mask = GCForeground | GCBackground | GCGraphicsExposures;
583 /* If we can't distinguish one of the shadows (the color is the same as the
584 background), it's better to use a pixmap to generate a dithered gray. */
585 if (top_shadow_pixel == background_pixel ||
586 bottom_shadow_pixel == background_pixel)
591 if (DEVICE_X_GRAY_PIXMAP (d) == None)
593 DEVICE_X_GRAY_PIXMAP (d) =
594 XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
595 gray_width, gray_height, 1, 0, 1);
598 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
599 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
600 gcv.foreground = tmp_color.pixel;
601 /* this is needed because the GC draws with a pixmap here */
602 gcv.fill_style = FillOpaqueStippled;
603 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
604 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
605 (mask | GCStipple | GCFillStyle));
607 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
608 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
609 bottom_shadow_pixel = tmp_color.pixel;
611 flip_gcs = (bottom_shadow_pixel ==
612 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
616 gcv.foreground = top_shadow_pixel;
617 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
620 gcv.foreground = bottom_shadow_pixel;
621 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
623 if (use_pixmap && flip_gcs)
625 GC tmp_gc = bottom_shadow_gc;
626 bottom_shadow_gc = top_shadow_gc;
627 top_shadow_gc = tmp_gc;
630 gcv.foreground = background_pixel;
631 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
633 /* possibly revert the GC's in case the shadow thickness is < 0.
634 This will give a depressed look to the divider */
635 if (shadow_thickness < 0)
639 temp = top_shadow_gc;
640 top_shadow_gc = bottom_shadow_gc;
641 bottom_shadow_gc = temp;
643 /* better avoid a Bad Address XLib error ;-) */
644 shadow_thickness = - shadow_thickness;
647 /* Draw the shadows around the divider line */
648 x_output_shadows (f, x, y, width, height,
649 top_shadow_gc, bottom_shadow_gc,
650 background_gc, shadow_thickness);
653 /*****************************************************************************
656 Given a number of parameters return a GC with those properties.
657 ****************************************************************************/
659 x_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
660 Lisp_Object bg_pmap, Lisp_Object lwidth)
665 memset (&gcv, ~0, sizeof (XGCValues));
666 gcv.graphics_exposures = False;
667 /* Make absolutely sure that we don't pick up a clipping region in
668 the GC returned by this function. */
669 gcv.clip_mask = None;
670 gcv.clip_x_origin = 0;
671 gcv.clip_y_origin = 0;
672 gcv.fill_style = FillSolid;
673 mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
678 gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
683 if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg))
685 /* #### I fixed once case where this was getting it. It was a
686 bad macro expansion (compiler bug). */
687 fprintf (stderr, "Help! x_get_gc got a bogus fg value! fg = ");
694 if (COLOR_INSTANCEP (fg))
695 gcv.foreground = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (fg)).pixel;
697 gcv.foreground = XINT (fg);
698 mask |= GCForeground;
703 if (COLOR_INSTANCEP (bg))
704 gcv.background = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (bg)).pixel;
706 gcv.background = XINT (bg);
707 mask |= GCBackground;
710 /* This special case comes from a request to draw text with a face which has
711 the dim property. We'll use a stippled foreground GC. */
712 if (EQ (bg_pmap, Qdim))
714 assert (DEVICE_X_GRAY_PIXMAP (d) != None);
716 gcv.fill_style = FillStippled;
717 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
718 mask |= (GCFillStyle | GCStipple);
720 else if (IMAGE_INSTANCEP (bg_pmap)
721 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
723 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
725 gcv.fill_style = FillOpaqueStippled;
726 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
727 mask |= (GCStipple | GCFillStyle);
731 gcv.fill_style = FillTiled;
732 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
733 mask |= (GCTile | GCFillStyle);
739 gcv.line_width = XINT (lwidth);
743 return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
746 /*****************************************************************************
749 Given a string and a starting position, output that string in the
750 given face. If cursor is true, draw a cursor around the string.
751 Correctly handles multiple charsets in the string.
753 The meaning of the parameters is something like this:
755 W Window that the text is to be displayed in.
756 DL Display line that this text is on. The values in the
757 structure are used to determine the vertical position and
758 clipping range of the text.
759 BUF Dynamic array of Emchars specifying what is actually to be
761 XPOS X position in pixels where the text should start being drawn.
762 XOFFSET Number of pixels to be chopped off the left side of the
763 text. The effect is as if the text were shifted to the
764 left this many pixels and clipped at XPOS.
765 CLIP_START Clip everything left of this X position.
766 WIDTH Clip everything right of XPOS + WIDTH.
767 FINDEX Index for the face cache element describing how to display
769 CURSOR #### I don't understand this. There's something
770 strange and overcomplexified with this variable.
771 Chuck, explain please?
772 CURSOR_START Starting X position of cursor.
773 CURSOR_WIDTH Width of cursor in pixels.
774 CURSOR_HEIGHT Height of cursor in pixels.
776 Starting Y position of cursor is the top of the text line.
777 The cursor is drawn sometimes whether or not CURSOR is set. ???
778 ****************************************************************************/
780 x_output_string (struct window *w, struct display_line *dl,
781 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
782 int width, face_index findex, int cursor,
783 int cursor_start, int cursor_width, int cursor_height)
785 /* General variables */
786 struct frame *f = XFRAME (w->frame);
787 struct device *d = XDEVICE (f->device);
790 Display *dpy = DEVICE_X_DISPLAY (d);
791 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
795 /* Cursor-related variables */
796 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
798 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
800 struct face_cachel *cursor_cachel = 0;
802 /* Text-related variables */
806 int len = Dynarr_length (buf);
807 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
808 struct textual_run *runs = alloca_array (struct textual_run, len);
811 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
813 XSETDEVICE (device, d);
814 XSETWINDOW (window, w);
817 width = x_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
818 height = dl->ascent + dl->descent - dl->clip;
820 /* Regularize the variables passed in. */
822 if (clip_start < xpos)
824 clip_end = xpos + width;
825 if (clip_start >= clip_end)
826 /* It's all clipped out. */
831 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
832 Dynarr_length (buf));
834 cursor_clip = (cursor_start >= clip_start &&
835 cursor_start < clip_end);
837 /* This cursor code is really a mess. */
838 if (!NILP (w->text_cursor_visible_p)
842 && (cursor_start + cursor_width >= clip_start)
843 && !NILP (bar_cursor_value))))
845 /* These have to be in separate statements in order to avoid a
847 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face);
848 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks);
850 /* We have to reset this since any call to WINDOW_FACE_CACHEL
851 may cause the cache to resize and any pointers to it to
853 cachel = WINDOW_FACE_CACHEL (w, findex);
857 if (cursor && focus && (cursor_start == clip_start) && cursor_height)
858 XIM_SetSpotLocation (f, xpos - 2, dl->ypos + dl->descent - 2);
859 #endif /* HAVE_XIM */
861 bg_pmap = cachel->background_pixmap;
862 if (!IMAGE_INSTANCEP (bg_pmap)
863 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
866 if ((cursor && focus && NILP (bar_cursor_value)
867 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap))
870 bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
874 XFillRectangle (dpy, x_win, bgc, clip_start,
875 dl->ypos - dl->ascent, clip_end - clip_start,
878 for (i = 0; i < nruns; i++)
880 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
881 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
885 if (EQ (font, Vthe_null_font_instance))
888 this_width = x_text_width_single_run (cachel, runs + i);
889 need_clipping = (dl->clip || clip_start > xpos ||
890 clip_end < xpos + this_width);
892 /* XDrawImageString only clears the area equal to the height of
893 the given font. It is possible that a font is being displayed
894 on a line taller than it is, so this would cause us to fail to
896 if ((int) fi->height < (int) (height + dl->clip))
898 int clear_start = max (xpos, clip_start);
899 int clear_end = min (xpos + this_width, clip_end);
903 int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
905 ypos1_string = dl->ypos - fi->ascent;
906 ypos2_string = dl->ypos + fi->descent;
907 ypos1_line = dl->ypos - dl->ascent;
908 ypos2_line = dl->ypos + dl->descent - dl->clip;
910 /* Make sure we don't clear below the real bottom of the
912 if (ypos1_string > ypos2_line)
913 ypos1_string = ypos2_line;
914 if (ypos2_string > ypos2_line)
915 ypos2_string = ypos2_line;
917 if (ypos1_line < ypos1_string)
919 redisplay_clear_region (window, findex, clear_start, ypos1_line,
920 clear_end - clear_start,
921 ypos1_string - ypos1_line);
924 if (ypos2_line > ypos2_string)
926 redisplay_clear_region (window, findex, clear_start, ypos2_string,
927 clear_end - clear_start,
928 ypos2_line - ypos2_string);
933 redisplay_clear_region (window, findex, clear_start,
934 dl->ypos - dl->ascent, clear_end - clear_start,
939 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value))
940 gc = x_get_gc (d, font, cursor_cachel->foreground,
941 cursor_cachel->background, Qnil, Qnil);
942 else if (cachel->dim)
944 /* Ensure the gray bitmap exists */
945 if (DEVICE_X_GRAY_PIXMAP (d) == None)
946 DEVICE_X_GRAY_PIXMAP (d) =
947 XCreateBitmapFromData (dpy, x_win, (char *)gray_bits,
948 gray_width, gray_height);
950 /* Request a GC with the gray stipple pixmap to draw dimmed text */
951 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
955 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
960 XRectangle clip_box[1];
964 clip_box[0].width = clip_end - clip_start;
965 clip_box[0].height = height;
967 XSetClipRectangles (dpy, gc, clip_start, dl->ypos - dl->ascent,
968 clip_box, 1, Unsorted);
971 if (runs[i].dimension == 1)
972 (bgc ? XDrawString : XDrawImageString) (dpy, x_win, gc, xpos,
973 dl->ypos, (char *) runs[i].ptr,
976 (bgc ? XDrawString16 : XDrawImageString16) (dpy, x_win, gc, xpos,
978 (XChar2b *) runs[i].ptr,
981 /* We draw underlines in the same color as the text. */
982 if (cachel->underline)
984 unsigned long upos, uthick;
987 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
988 if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos))
989 upos = dl->descent / 2;
990 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
993 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
995 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
996 uthick = dl->descent - dl->clip - upos;
1000 XDrawLine (dpy, x_win, gc, xpos, dl->ypos + upos,
1001 xpos + this_width, dl->ypos + upos);
1003 else if (uthick > 1)
1005 XFillRectangle (dpy, x_win, gc, xpos,
1006 dl->ypos + upos, this_width, uthick);
1011 if (cachel->strikethru) {
1012 unsigned long ascent,descent,upos, uthick;
1015 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
1017 if (!XGetFontProperty (xfont, XA_STRIKEOUT_ASCENT, &ascent))
1018 ascent = xfont->ascent;
1019 if (!XGetFontProperty (xfont, XA_STRIKEOUT_DESCENT, &descent))
1020 descent = xfont->descent;
1021 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
1024 upos = ascent - ((ascent + descent) / 2) + 1;
1026 /* Generally, upos will be positive (above the baseline),so subtract */
1027 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip)
1029 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip)
1030 uthick = dl->descent - dl->clip + upos;
1034 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos,
1035 xpos + this_width, dl->ypos - upos);
1037 else if (uthick > 1)
1039 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos,
1040 this_width, uthick);
1045 /* Restore the GC */
1048 XSetClipMask (dpy, gc, None);
1049 XSetClipOrigin (dpy, gc, 0, 0);
1052 /* If we are actually superimposing the cursor then redraw with just
1053 the appropriate section highlighted. */
1054 if (cursor_clip && !cursor && focus && cursor_cachel)
1057 XRectangle clip_box[1];
1059 cgc = x_get_gc (d, font, cursor_cachel->foreground,
1060 cursor_cachel->background, Qnil, Qnil);
1064 clip_box[0].width = cursor_width;
1065 clip_box[0].height = height;
1067 XSetClipRectangles (dpy, cgc, cursor_start, dl->ypos - dl->ascent,
1068 clip_box, 1, Unsorted);
1070 if (runs[i].dimension == 1)
1071 XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
1072 (char *) runs[i].ptr, runs[i].len);
1074 XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
1075 (XChar2b *) runs[i].ptr, runs[i].len);
1077 XSetClipMask (dpy, cgc, None);
1078 XSetClipOrigin (dpy, cgc, 0, 0);
1084 /* Draw the non-focus box or bar-cursor as needed. */
1085 /* Can't this logic be simplified? */
1087 && ((cursor && !focus && NILP (bar_cursor_value))
1089 && (cursor_start + cursor_width >= clip_start)
1090 && !NILP (bar_cursor_value))))
1092 int tmp_height, tmp_y;
1093 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1094 int need_clipping = (cursor_start < clip_start
1095 || clip_end < cursor_start + cursor_width);
1097 /* #### This value is correct (as far as I know) because
1098 all of the times we need to draw this cursor, we will
1099 be called with exactly one character, so we know we
1100 can always use runs[0].
1102 This is bogus as all hell, however. The cursor handling in
1103 this function is way bogus and desperately needs to be
1104 cleaned up. (In particular, the drawing of the cursor should
1105 really really be separated out of this function. This may be
1106 a bit tricky now because this function itself does way too
1107 much stuff, a lot of which needs to be moved into
1108 redisplay.c) This is the only way to be able to easily add
1109 new cursor types or (e.g.) make the bar cursor be able to
1110 span two characters instead of overlaying just one. */
1111 int bogusly_obtained_ascent_value =
1112 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent;
1114 if (!NILP (bar_cursor_value))
1116 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1117 make_int (bar_width));
1121 gc = x_get_gc (d, Qnil, cursor_cachel->background,
1125 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1126 tmp_height = cursor_height;
1127 if (tmp_y + tmp_height > (int) (dl->ypos - dl->ascent + height))
1129 tmp_y = dl->ypos - dl->ascent + height - tmp_height;
1130 if (tmp_y < (int) (dl->ypos - dl->ascent))
1131 tmp_y = dl->ypos - dl->ascent;
1132 tmp_height = dl->ypos - dl->ascent + height - tmp_y;
1137 XRectangle clip_box[1];
1140 clip_box[0].width = clip_end - clip_start;
1141 clip_box[0].height = tmp_height;
1142 XSetClipRectangles (dpy, gc, clip_start, tmp_y,
1143 clip_box, 1, Unsorted);
1146 if (!focus && NILP (bar_cursor_value))
1148 XDrawRectangle (dpy, x_win, gc, cursor_start, tmp_y,
1149 cursor_width - 1, tmp_height - 1);
1151 else if (focus && !NILP (bar_cursor_value))
1153 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1, tmp_y,
1154 cursor_start + bar_width - 1, tmp_y + tmp_height - 1);
1157 /* Restore the GC */
1160 XSetClipMask (dpy, gc, None);
1161 XSetClipOrigin (dpy, gc, 0, 0);
1167 x_output_x_pixmap (struct frame *f, struct Lisp_Image_Instance *p, int x,
1168 int y, int clip_x, int clip_y, int clip_width,
1169 int clip_height, int width, int height, int pixmap_offset,
1170 unsigned long fg, unsigned long bg, GC override_gc)
1172 struct device *d = XDEVICE (f->device);
1173 Display *dpy = DEVICE_X_DISPLAY (d);
1174 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1178 unsigned long pixmap_mask;
1179 int need_clipping = (clip_x || clip_y);
1183 memset (&gcv, ~0, sizeof (XGCValues));
1184 gcv.graphics_exposures = False;
1185 gcv.foreground = fg;
1186 gcv.background = bg;
1187 pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
1189 if (IMAGE_INSTANCE_X_MASK (p))
1191 gcv.function = GXcopy;
1192 gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
1193 gcv.clip_x_origin = x;
1194 gcv.clip_y_origin = y - pixmap_offset;
1195 pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
1197 /* Can't set a clip rectangle below because we already have a mask.
1198 We could conceivably create a new clipmask by zeroing out
1199 everything outside the clip region. Is it worth it?
1200 Is it possible to get an equivalent effect by changing the
1201 args to XCopyArea below rather than messing with a clip box?
1202 - dkindred@cs.cmu.edu */
1206 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
1211 /* override_gc might have a mask already--we don't want to nuke it.
1212 Maybe we can insist that override_gc have no mask, or use
1213 one of the suggestions above. */
1219 XRectangle clip_box[1];
1221 clip_box[0].x = clip_x;
1222 clip_box[0].y = clip_y;
1223 clip_box[0].width = clip_width;
1224 clip_box[0].height = clip_height;
1226 XSetClipRectangles (dpy, gc, x, y, clip_box, 1, Unsorted);
1229 /* depth of 0 means it's a bitmap, not a pixmap, and we should use
1230 XCopyPlane (1 = current foreground color, 0 = background) instead
1231 of XCopyArea, which means that the bits in the pixmap are actual
1232 pixel values, instead of symbolic of fg/bg. */
1233 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
1235 XCopyArea (dpy, IMAGE_INSTANCE_X_PIXMAP (p), x_win, gc, 0,
1236 pixmap_offset, width,
1241 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP (p), x_win, gc, 0,
1254 XSetClipMask (dpy, gc, None);
1255 XSetClipOrigin (dpy, gc, 0, 0);
1260 x_output_pixmap (struct window *w, struct display_line *dl,
1261 Lisp_Object image_instance, int xpos, int xoffset,
1262 int start_pixpos, int width, face_index findex,
1263 int cursor_start, int cursor_width, int cursor_height)
1265 struct frame *f = XFRAME (w->frame);
1266 struct device *d = XDEVICE (f->device);
1267 struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1270 Display *dpy = DEVICE_X_DISPLAY (d);
1271 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1272 int lheight = dl->ascent + dl->descent - dl->clip;
1273 int pheight = ((int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > lheight ? lheight :
1274 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
1275 int pwidth = min (width + xoffset, (int) IMAGE_INSTANCE_PIXMAP_WIDTH (p));
1276 int clip_x, clip_y, clip_width, clip_height;
1278 /* The pixmap_offset is used to center the pixmap on lines which are
1279 shorter than it is. This results in odd effects when scrolling
1280 pixmaps off of the bottom. Let's try not using it. */
1282 int pixmap_offset = (int) (IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - lheight) / 2;
1284 int pixmap_offset = 0;
1287 XSETWINDOW (window, w);
1289 if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
1291 if (start_pixpos > xpos && start_pixpos > xpos + width)
1296 if (start_pixpos > xpos)
1298 clip_x += (start_pixpos - xpos);
1299 clip_width -= (start_pixpos - xpos);
1308 /* Place markers for possible future functionality (clipping the top
1309 half instead of the bottom half; think pixel scrolling). */
1311 clip_height = pheight;
1313 /* Clear the area the pixmap is going into. The pixmap itself will
1314 always take care of the full width. We don't want to clear where
1315 it is going to go in order to avoid flicker. So, all we have to
1316 take care of is any area above or below the pixmap. */
1317 /* #### We take a shortcut for now. We know that since we have
1318 pixmap_offset hardwired to 0 that the pixmap is against the top
1319 edge so all we have to worry about is below it. */
1320 /* #### Unless the pixmap has a mask in which case we have to clear
1321 the whole damn thing since we can't yet clear just the area not
1322 included in the mask. */
1323 if (((int) (dl->ypos - dl->ascent + pheight) <
1324 (int) (dl->ypos + dl->descent - dl->clip))
1325 || IMAGE_INSTANCE_X_MASK (p))
1327 int clear_x, clear_y, clear_width, clear_height;
1329 if (IMAGE_INSTANCE_X_MASK (p))
1331 clear_y = dl->ypos - dl->ascent;
1332 clear_height = lheight;
1336 clear_y = dl->ypos - dl->ascent + pheight;
1337 clear_height = lheight - pheight;
1340 if (start_pixpos >= 0 && start_pixpos > xpos)
1342 clear_x = start_pixpos;
1343 clear_width = xpos + width - start_pixpos;
1348 clear_width = width;
1351 redisplay_clear_region (window, findex, clear_x, clear_y,
1352 clear_width, clear_height);
1355 /* Output the pixmap. */
1357 Lisp_Object tmp_pixel;
1358 XColor tmp_bcolor, tmp_fcolor;
1360 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1361 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1362 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1363 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1365 x_output_x_pixmap (f, p, xpos - xoffset, dl->ypos - dl->ascent, clip_x,
1366 clip_y, clip_width, clip_height,
1367 pwidth, pheight, pixmap_offset,
1368 tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
1371 /* Draw a cursor over top of the pixmap. */
1372 if (cursor_width && cursor_height && (cursor_start >= xpos)
1373 && !NILP (w->text_cursor_visible_p)
1374 && (cursor_start < xpos + pwidth))
1377 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1378 int y = dl->ypos - dl->ascent;
1379 struct face_cachel *cursor_cachel =
1380 WINDOW_FACE_CACHEL (w,
1381 get_builtin_face_cache_index
1382 (w, Vtext_cursor_face));
1384 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1386 if (cursor_width > xpos + pwidth - cursor_start)
1387 cursor_width = xpos + pwidth - cursor_start;
1391 XFillRectangle (dpy, x_win, gc, cursor_start, y, cursor_width,
1396 XDrawRectangle (dpy, x_win, gc, cursor_start, y, cursor_width,
1402 /*****************************************************************************
1403 x_output_vertical_divider
1405 Draw a vertical divider down the right side of the given window.
1406 ****************************************************************************/
1408 x_output_vertical_divider (struct window *w, int clear)
1410 struct frame *f = XFRAME (w->frame);
1411 struct device *d = XDEVICE (f->device);
1413 Display *dpy = DEVICE_X_DISPLAY (d);
1414 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1415 Lisp_Object tmp_pixel;
1421 int x, y1, y2, width, shadow_thickness, spacing, line_width;
1422 face_index div_face = get_builtin_face_cache_index (w, Vvertical_divider_face);
1424 width = window_divider_width (w);
1425 shadow_thickness = XINT (w->vertical_divider_shadow_thickness);
1426 spacing = XINT (w->vertical_divider_spacing);
1427 line_width = XINT (w->vertical_divider_line_width);
1428 x = WINDOW_RIGHT (w) - width;
1429 y1 = WINDOW_TOP (w) + FRAME_TOP_GUTTER_BOUNDS (f);
1430 y2 = WINDOW_BOTTOM (w) + FRAME_BOTTOM_GUTTER_BOUNDS (f);
1432 memset (&gcv, ~0, sizeof (XGCValues));
1434 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1435 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1437 /* First, get the GC's. */
1438 gcv.background = tmp_color.pixel;
1439 gcv.foreground = tmp_color.pixel;
1440 gcv.graphics_exposures = False;
1441 mask = GCForeground | GCBackground | GCGraphicsExposures;
1442 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1444 /* Clear the divider area first. This needs to be done when a
1445 window split occurs. */
1447 XClearArea (dpy, x_win, x, y1, width, y2 - y1, False);
1449 /* Draw the divider line. */
1450 XFillRectangle (dpy, x_win, background_gc,
1451 x + spacing + shadow_thickness, y1,
1452 line_width, y2 - y1);
1454 /* Draw the shadows around the divider line */
1455 x_bevel_area (w, div_face, x + spacing, y1,
1456 width - 2 * spacing, y2 - y1,
1460 /*****************************************************************************
1463 Output a blank by clearing the area it covers in the foreground color
1465 ****************************************************************************/
1467 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
1468 int start_pixpos, int cursor_start, int cursor_width)
1470 struct frame *f = XFRAME (w->frame);
1471 struct device *d = XDEVICE (f->device);
1473 Display *dpy = DEVICE_X_DISPLAY (d);
1474 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1476 struct face_cachel *cursor_cachel =
1477 WINDOW_FACE_CACHEL (w,
1478 get_builtin_face_cache_index
1479 (w, Vtext_cursor_face));
1480 Lisp_Object bg_pmap;
1481 Lisp_Object buffer = WINDOW_BUFFER (w);
1482 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1486 int y = dl->ypos - dl->ascent;
1487 int width = rb->width;
1488 int height = dl->ascent + dl->descent - dl->clip;
1490 if (start_pixpos > x)
1492 if (start_pixpos >= (x + width))
1496 width -= (start_pixpos - x);
1501 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
1502 if (!IMAGE_INSTANCEP (bg_pmap)
1503 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
1507 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1510 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1511 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
1514 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1516 /* If this rune is marked as having the cursor, then it is actually
1517 representing a tab. */
1518 if (!NILP (w->text_cursor_visible_p)
1519 && (rb->cursor_type == CURSOR_ON
1521 && (cursor_start + cursor_width > x)
1522 && cursor_start < (x + width))))
1524 int cursor_height, cursor_y;
1525 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1526 struct Lisp_Font_Instance *fi;
1528 fi = XFONT_INSTANCE (FACE_CACHEL_FONT
1529 (WINDOW_FACE_CACHEL (w, rb->findex),
1532 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1534 cursor_y = dl->ypos - fi->ascent;
1535 cursor_height = fi->height;
1536 if (cursor_y + cursor_height > y + height)
1537 cursor_height = y + height - cursor_y;
1541 if (NILP (bar_cursor_value))
1543 XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1544 fi->width, cursor_height);
1548 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1550 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1551 make_int (bar_width));
1552 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
1553 cursor_y, cursor_start + bar_width - 1,
1554 cursor_y + cursor_height - 1);
1557 else if (NILP (bar_cursor_value))
1559 XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1560 fi->width - 1, cursor_height - 1);
1565 /*****************************************************************************
1568 Output a horizontal line in the foreground of its face.
1569 ****************************************************************************/
1571 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
1573 struct frame *f = XFRAME (w->frame);
1574 struct device *d = XDEVICE (f->device);
1576 Display *dpy = DEVICE_X_DISPLAY (d);
1577 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1581 int width = rb->width;
1582 int height = dl->ascent + dl->descent - dl->clip;
1583 int ypos1, ypos2, ypos3, ypos4;
1585 ypos1 = dl->ypos - dl->ascent;
1586 ypos2 = ypos1 + rb->object.hline.yoffset;
1587 ypos3 = ypos2 + rb->object.hline.thickness;
1588 ypos4 = dl->ypos + dl->descent - dl->clip;
1590 /* First clear the area not covered by the line. */
1591 if (height - rb->object.hline.thickness > 0)
1593 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1596 if (ypos2 - ypos1 > 0)
1597 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1598 if (ypos4 - ypos3 > 0)
1599 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1602 /* Now draw the line. */
1603 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1611 if (ypos3 - ypos2 > 0)
1612 XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1615 /*****************************************************************************
1618 Draw a shadow around the given area using the given GC's. It is the
1619 callers responsibility to set the GC's appropriately.
1620 ****************************************************************************/
1622 x_output_shadows (struct frame *f, int x, int y, int width, int height,
1623 GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
1624 int shadow_thickness)
1626 struct device *d = XDEVICE (f->device);
1628 Display *dpy = DEVICE_X_DISPLAY (d);
1629 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1631 XSegment top_shadow[20], bottom_shadow[20];
1634 if (shadow_thickness > 10)
1635 shadow_thickness = 10;
1636 else if (shadow_thickness < 0)
1637 shadow_thickness = 0;
1638 if (shadow_thickness > (width / 2))
1639 shadow_thickness = width / 2;
1640 if (shadow_thickness > (height / 2))
1641 shadow_thickness = height / 2;
1643 for (elt = 0; elt < shadow_thickness; elt++)
1646 int seg2 = elt + shadow_thickness;
1648 top_shadow[seg1].x1 = x;
1649 top_shadow[seg1].x2 = x + width - elt - 1;
1650 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
1652 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
1653 top_shadow[seg2].y1 = y + shadow_thickness;
1654 top_shadow[seg2].y2 = y + height - elt - 1;
1656 bottom_shadow[seg1].x1 = x + elt + 1;
1657 bottom_shadow[seg1].x2 = x + width - 1;
1658 bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
1660 bottom_shadow[seg2].x1 = bottom_shadow[seg2].x2 = x + width - elt - 1;
1661 bottom_shadow[seg2].y1 = y + elt + 1;
1662 bottom_shadow[seg2].y2 = y + height - shadow_thickness;
1665 XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow, shadow_thickness * 2);
1666 XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
1667 shadow_thickness * 2);
1670 /*****************************************************************************
1671 x_generate_shadow_pixels
1673 Given three pixels (top shadow, bottom shadow, background) massage
1674 the top and bottom shadow colors to guarantee that they differ. The
1675 background pixels are not allowed to be modified.
1677 This function modifies its parameters.
1679 This code is modified from code blatantly stolen from lwlib/xlwmenu.c
1680 ****************************************************************************/
1681 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
1682 ? ((unsigned long) (x)) : ((unsigned long) (y)))
1685 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
1686 unsigned long *bottom_shadow,
1687 unsigned long background,
1688 unsigned long core_background)
1690 struct device *d = XDEVICE (f->device);
1691 Display *dpy = DEVICE_X_DISPLAY (d);
1692 Colormap cmap = DEVICE_X_COLORMAP (d);
1693 Visual *visual = DEVICE_X_VISUAL (d);
1696 int top_frobbed = 0, bottom_frobbed = 0;
1698 /* If the top shadow is the same color as the background, try to
1700 if (*top_shadow == background)
1702 topc.pixel = background;
1703 XQueryColor (dpy, cmap, &topc);
1704 /* don't overflow/wrap! */
1705 topc.red = MINL (65535, (unsigned long) topc.red * 6 / 5);
1706 topc.green = MINL (65535, (unsigned long) topc.green * 6 / 5);
1707 topc.blue = MINL (65535, (unsigned long) topc.blue * 6 / 5);
1708 if (allocate_nearest_color (dpy, cmap, visual, &topc))
1710 *top_shadow = topc.pixel;
1715 /* If the bottom shadow is the same color as the background, try to
1717 if (*bottom_shadow == background)
1719 botc.pixel = background;
1720 XQueryColor (dpy, cmap, &botc);
1721 botc.red = (unsigned short) ((unsigned long) botc.red * 3 / 5);
1722 botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5);
1723 botc.blue = (unsigned short) ((unsigned long) botc.blue * 3 / 5);
1724 if (allocate_nearest_color (dpy, cmap, visual, &botc))
1726 *bottom_shadow = botc.pixel;
1731 /* If we had to adjust both shadows, then we have to do some
1733 if (top_frobbed && bottom_frobbed)
1735 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
1736 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
1737 if (bot_avg > top_avg)
1739 Pixel tmp = *top_shadow;
1741 *top_shadow = *bottom_shadow;
1742 *bottom_shadow = tmp;
1744 else if (topc.pixel == botc.pixel)
1746 if (botc.pixel == background)
1747 *top_shadow = core_background;
1749 *bottom_shadow = background;
1754 /*****************************************************************************
1755 x_redraw_exposed_window
1757 Given a bounding box for an area that needs to be redrawn, determine
1758 what parts of what lines are contained within and re-output their
1760 ****************************************************************************/
1762 x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
1764 struct frame *f = XFRAME (w->frame);
1766 int start_x, start_y, end_x, end_y;
1767 int orig_windows_structure_changed;
1769 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1771 if (!NILP (w->vchild))
1773 x_redraw_exposed_windows (w->vchild, x, y, width, height);
1776 else if (!NILP (w->hchild))
1778 x_redraw_exposed_windows (w->hchild, x, y, width, height);
1782 /* If the window doesn't intersect the exposed region, we're done here. */
1783 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w)
1784 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w))
1790 start_x = max (WINDOW_LEFT (w), x);
1791 end_x = min (WINDOW_RIGHT (w), (x + width));
1792 start_y = max (WINDOW_TOP (w), y);
1793 end_y = min (WINDOW_BOTTOM (w), y + height);
1795 /* We do this to make sure that the 3D modelines get redrawn if
1796 they are in the exposed region. */
1797 orig_windows_structure_changed = f->windows_structure_changed;
1798 f->windows_structure_changed = 1;
1801 if (window_needs_vertical_divider (w))
1803 x_output_vertical_divider (w, 0);
1806 for (line = 0; line < Dynarr_length (cdla); line++)
1808 struct display_line *cdl = Dynarr_atp (cdla, line);
1809 int top_y = cdl->ypos - cdl->ascent;
1810 int bottom_y = cdl->ypos + cdl->descent;
1812 if (bottom_y >= start_y)
1823 output_display_line (w, 0, cdla, line, start_x, end_x);
1828 f->windows_structure_changed = orig_windows_structure_changed;
1830 /* If there have never been any face cache_elements created, then this
1831 expose event doesn't actually have anything to do. */
1832 if (Dynarr_largest (w->face_cachels))
1833 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
1836 /*****************************************************************************
1837 x_redraw_exposed_windows
1839 For each window beneath the given window in the window hierarchy,
1840 ensure that it is redrawn if necessary after an Expose event.
1841 ****************************************************************************/
1843 x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
1846 for (; !NILP (window); window = XWINDOW (window)->next)
1847 x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
1850 /*****************************************************************************
1851 x_redraw_exposed_area
1853 For each window on the given frame, ensure that any area in the
1854 Exposed area is redrawn.
1855 ****************************************************************************/
1857 x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
1859 /* If any window on the frame has had its face cache reset then the
1860 redisplay structures are effectively invalid. If we attempt to
1861 use them we'll blow up. We mark the frame as changed to ensure
1862 that redisplay will do a full update. This probably isn't
1863 necessary but it can't hurt. */
1865 #ifdef HAVE_TOOLBARS
1866 /* #### We would rather put these off as well but there is currently
1867 no combination of flags which will force an unchanged toolbar to
1869 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
1871 redraw_exposed_gutters (f, x, y, width, height);
1873 if (!f->window_face_cache_reset)
1875 x_redraw_exposed_windows (f->root_window, x, y, width, height);
1877 XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
1880 MARK_FRAME_CHANGED (f);
1883 /****************************************************************************
1886 Clear the area in the box defined by the given parameters using the
1888 ****************************************************************************/
1890 x_clear_region (Lisp_Object locale, struct device* d, struct frame* f, face_index findex,
1892 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1893 Lisp_Object background_pixmap)
1899 dpy = DEVICE_X_DISPLAY (d);
1900 x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1902 if (!UNBOUNDP (background_pixmap))
1904 gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
1908 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1910 XClearArea (dpy, x_win, x, y, width, height, False);
1913 /*****************************************************************************
1916 Draw a cursor at the end of a line. The end-of-line cursor is
1917 narrower than the normal cursor.
1918 ****************************************************************************/
1920 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos,
1923 struct frame *f = XFRAME (w->frame);
1924 struct device *d = XDEVICE (f->device);
1927 Display *dpy = DEVICE_X_DISPLAY (d);
1928 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1930 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
1931 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
1933 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1934 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1938 int y = dl->ypos - dl->ascent;
1939 int width = EOL_CURSOR_WIDTH;
1940 int height = dl->ascent + dl->descent - dl->clip;
1941 int cursor_height, cursor_y;
1942 int defheight, defascent;
1944 XSETWINDOW (window, w);
1945 redisplay_clear_region (window, findex, x, y, width, height);
1947 if (NILP (w->text_cursor_visible_p))
1950 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1952 default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
1954 /* make sure the cursor is entirely contained between y and y+height */
1955 cursor_height = min (defheight, height);
1956 cursor_y = max (y, min (y + height - cursor_height,
1957 dl->ypos - defascent));
1962 XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2);
1963 #endif /* HAVE_XIM */
1965 if (NILP (bar_cursor_value))
1967 XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
1971 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1973 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1974 make_int (bar_width));
1975 XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
1976 x + bar_width - 1, cursor_y + cursor_height - 1);
1979 else if (NILP (bar_cursor_value))
1981 XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
1987 x_clear_frame_window (Lisp_Object window)
1989 struct window *w = XWINDOW (window);
1991 if (!NILP (w->vchild))
1993 x_clear_frame_windows (w->vchild);
1997 if (!NILP (w->hchild))
1999 x_clear_frame_windows (w->hchild);
2003 redisplay_clear_to_window_end (w, WINDOW_TEXT_TOP (w),
2004 WINDOW_TEXT_BOTTOM (w));
2008 x_clear_frame_windows (Lisp_Object window)
2010 for (; !NILP (window); window = XWINDOW (window)->next)
2011 x_clear_frame_window (window);
2015 x_clear_frame (struct frame *f)
2017 struct device *d = XDEVICE (f->device);
2018 Display *dpy = DEVICE_X_DISPLAY (d);
2019 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2020 int x, y, width, height;
2023 x = FRAME_LEFT_BORDER_START (f);
2024 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
2025 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
2026 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) -
2027 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f));
2028 /* #### This adjustment by 1 should be being done in the macros.
2029 There is some small differences between when the menubar is on
2030 and off that we still need to deal with. */
2031 y = FRAME_TOP_BORDER_START (f) - 1;
2032 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
2033 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
2034 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) -
2035 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1;
2037 XClearArea (dpy, x_win, x, y, width, height, False);
2039 XSETFRAME (frame, f);
2041 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
2042 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
2043 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
2045 x_clear_frame_windows (f->root_window);
2048 XFlush (DEVICE_X_DISPLAY (d));
2051 /* briefly swap the foreground and background colors.
2055 x_flash (struct device *d)
2061 XColor tmp_fcolor, tmp_bcolor;
2062 Lisp_Object tmp_pixel, frame;
2063 struct frame *f = device_selected_frame (d);
2064 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f));
2065 Widget shell = FRAME_X_SHELL_WIDGET (f);
2067 XSETFRAME (frame, f);
2069 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
2070 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
2071 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
2072 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
2074 dpy = XtDisplay (shell);
2075 win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2076 memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
2077 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
2078 gcv.function = GXxor;
2079 gcv.graphics_exposures = False;
2080 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
2081 (GCForeground | GCFunction | GCGraphicsExposures));
2082 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2083 w->pixel_width, w->pixel_height);
2090 tv.tv_sec = usecs / 1000000L;
2091 tv.tv_usec = usecs % 1000000L;
2092 /* I'm sure someone is going to complain about this... */
2093 select (0, 0, 0, 0, &tv);
2098 #else /* !HAVE_POLL */
2100 #endif /* HAVE_POLL */
2101 #endif /* HAVE_SELECT */
2103 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2104 w->pixel_width, w->pixel_height);
2110 /* Make audible bell. */
2113 x_ring_bell (struct device *d, int volume, int pitch, int duration)
2115 Display *display = DEVICE_X_DISPLAY (d);
2117 if (volume < 0) volume = 0;
2118 else if (volume > 100) volume = 100;
2119 if (pitch < 0 && duration < 0)
2121 XBell (display, (volume * 2) - 100);
2126 XKeyboardState state;
2127 XKeyboardControl ctl;
2129 /* #### grab server? */
2130 XGetKeyboardControl (display, &state);
2132 ctl.bell_pitch = (pitch >= 0 ? pitch : state.bell_pitch);
2133 ctl.bell_duration = (duration >= 0 ? duration : state.bell_duration);
2134 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2136 XBell (display, (volume * 2) - 100);
2138 ctl.bell_pitch = state.bell_pitch;
2139 ctl.bell_duration = state.bell_duration;
2140 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2142 /* #### ungrab server? */
2148 /************************************************************************/
2149 /* initialization */
2150 /************************************************************************/
2153 console_type_create_redisplay_x (void)
2155 /* redisplay methods */
2156 CONSOLE_HAS_METHOD (x, text_width);
2157 CONSOLE_HAS_METHOD (x, output_display_block);
2158 CONSOLE_HAS_METHOD (x, divider_height);
2159 CONSOLE_HAS_METHOD (x, eol_cursor_width);
2160 CONSOLE_HAS_METHOD (x, output_vertical_divider);
2161 CONSOLE_HAS_METHOD (x, clear_region);
2162 CONSOLE_HAS_METHOD (x, clear_frame);
2163 CONSOLE_HAS_METHOD (x, output_begin);
2164 CONSOLE_HAS_METHOD (x, output_end);
2165 CONSOLE_HAS_METHOD (x, flash);
2166 CONSOLE_HAS_METHOD (x, ring_bell);
2167 CONSOLE_HAS_METHOD (x, bevel_area);