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 SXEmacs
8 SXEmacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 SXEmacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 /* Synched up with: Not in FSF. */
24 /* Author: Chuck Thompson */
26 /* Lots of work done by Ben Wing for Mule */
31 #include "console-x.h"
32 #include "EmacsFrame.h"
33 #include "EmacsFrameP.h"
36 #include "objects-x.h"
42 #include "ui/gutter.h"
43 #include "ui/redisplay.h"
45 #include "ui/window.h"
46 #include <X11/bitmaps/gray>
48 #include "sysproc.h" /* for select() */
51 #include "mule/mule-ccl.h"
52 #include "mule/file-coding.h" /* for CCL conversion */
55 /* Number of pixels below each line. */
56 int x_interline_space; /* #### implement me */
58 #define EOL_CURSOR_WIDTH 5
60 static void x_output_vertical_divider(struct window *w, int clear);
61 static void x_output_blank(struct window *w, struct display_line *dl,
62 struct rune *rb, int start_pixpos,
63 int cursor_start, int cursor_width);
64 static void x_output_hline(struct window *w, struct display_line *dl,
66 static void x_redraw_exposed_window(struct window *w, int x, int y,
67 int width, int height);
68 static void x_redraw_exposed_windows(Lisp_Object window, int x, int y,
69 int width, int height);
70 static void x_output_eol_cursor(struct window *w, struct display_line *dl,
71 int xpos, face_index findex);
72 static void x_clear_frame(struct frame *f);
73 static void x_clear_frame_windows(Lisp_Object window);
75 /* Note: We do not use the Xmb*() functions and XFontSets.
76 Those functions are generally losing for a number of reasons:
78 1) They only support one locale (e.g. you could display
79 Japanese and ASCII text, but not mixed Japanese/Chinese
80 text). You could maybe call setlocale() frequently
81 to try to deal with this, but that would generally
82 fail because an XFontSet is tied to one locale and
83 won't have the other character sets in it.
84 2) Not all (or even very many) OS's support the useful
85 locales. For example, as far as I know SunOS and
86 Solaris only support the Japanese locale if you get the
87 special Asian-language version of the OS. Yuck yuck
88 yuck. Linux doesn't support the Japanese locale at
90 3) The locale support in X only exists in R5, not in R4.
91 (Not sure how big of a problem this is: how many
93 4) Who knows if the multi-byte text format (which is locale-
94 specific) is even the same for the same locale on
95 different OS's? It's not even documented anywhere that
96 I can find what the multi-byte text format for the
97 Japanese locale under SunOS and Solaris is, but I assume
108 /* Separate out the text in DYN into a series of textual runs of a
109 particular charset. Also convert the characters as necessary into
110 the format needed by XDrawImageString(), XDrawImageString16(), et
111 al. (This means converting to one or two byte format, possibly
112 tweaking the high bits, and possibly running a CCL program.) You
113 must pre-allocate the space used and pass it in. (This is done so
114 you can alloca() the space.) You need to allocate (2 * len) bytes
115 of TEXT_STORAGE and (len * sizeof (struct textual_run)) bytes of
116 RUN_STORAGE, where LEN is the length of the dynarr.
118 Returns the number of runs actually used. */
121 separate_textual_runs(unsigned char *text_storage,
122 struct textual_run *run_storage,
123 const Emchar * str, Charcount len)
125 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a
126 possible valid charset when
127 MULE is not defined */
131 struct ccl_program char_converter;
132 int need_ccl_conversion = 0;
135 for (i = 0; i < len; i++) {
142 BREAKUP_CHAR(ch, charset, byte1, byte2);
143 dimension = XCHARSET_DIMENSION(charset);
144 graphic = XCHARSET_GRAPHIC(charset);
146 if (!EQ(charset, prev_charset)) {
147 run_storage[runs_so_far].ptr = text_storage;
148 run_storage[runs_so_far].charset = charset;
149 run_storage[runs_so_far].dimension = dimension;
152 run_storage[runs_so_far - 1].len =
153 text_storage - run_storage[runs_so_far -
155 if (run_storage[runs_so_far - 1].dimension == 2)
156 run_storage[runs_so_far - 1].len >>= 1;
159 prev_charset = charset;
162 Lisp_Object ccl_prog =
163 XCHARSET_CCL_PROGRAM(charset);
164 if ((!NILP(ccl_prog))
167 (&char_converter, ccl_prog) >= 0))
168 need_ccl_conversion = 1;
176 } else if (graphic == 1) {
181 if (need_ccl_conversion) {
182 char_converter.reg[0] = XCHARSET_ID(charset);
183 char_converter.reg[1] = byte1;
184 char_converter.reg[2] = byte2;
185 ccl_driver(&char_converter, 0, 0, 0, 0,
187 byte1 = char_converter.reg[1];
188 byte2 = char_converter.reg[2];
191 *text_storage++ = (unsigned char)byte1;
193 *text_storage++ = (unsigned char)byte2;
197 run_storage[runs_so_far - 1].len =
198 text_storage - run_storage[runs_so_far - 1].ptr;
199 if (run_storage[runs_so_far - 1].dimension == 2)
200 run_storage[runs_so_far - 1].len >>= 1;
206 /****************************************************************************/
208 /* X output routines */
210 /****************************************************************************/
213 x_text_width_single_run(struct face_cachel *cachel, struct textual_run *run)
215 Lisp_Object font_inst = FACE_CACHEL_FONT(cachel, run->charset);
216 Lisp_Font_Instance *fi = XFONT_INSTANCE(font_inst);
217 if (!fi->proportional_p)
218 return fi->width * run->len;
220 if (run->dimension == 2)
221 return XTextWidth16(FONT_INSTANCE_X_FONT(fi),
222 (XChar2b *) run->ptr, run->len);
224 return XTextWidth(FONT_INSTANCE_X_FONT(fi),
225 (char *)run->ptr, run->len);
232 Given a string and a face, return the string's length in pixels when
233 displayed in the font associated with the face.
237 x_text_width(struct frame *f, struct face_cachel *cachel, const Emchar * str,
240 int width_so_far = 0;
241 unsigned char *text_storage = (unsigned char *)alloca(2 * len);
242 struct textual_run *runs = alloca_array(struct textual_run, len);
246 nruns = separate_textual_runs(text_storage, runs, str, len);
248 for (i = 0; i < nruns; i++)
249 width_so_far += x_text_width_single_run(cachel, runs + i);
254 /*****************************************************************************
257 Return the height of the horizontal divider. This is a function because
258 divider_height is a device method.
260 #### If we add etched horizontal divider lines this will have to get
262 ****************************************************************************/
263 static int x_divider_height(void)
268 /*****************************************************************************
271 Return the width of the end-of-line cursor. This is a function
272 because eol_cursor_width is a device method.
273 ****************************************************************************/
274 static int x_eol_cursor_width(void)
276 return EOL_CURSOR_WIDTH;
279 /*****************************************************************************
280 x_window_output_begin
282 Perform any necessary initialization prior to an update.
283 ****************************************************************************/
284 static void x_window_output_begin(struct window *w)
288 /*****************************************************************************
291 Perform any necessary flushing of queues when an update has completed.
292 ****************************************************************************/
293 static void x_window_output_end(struct window *w)
295 XFlush(DEVICE_X_DISPLAY(WINDOW_XDEVICE(w)));
298 /*****************************************************************************
299 x_output_display_block
301 Given a display line, a block number for that start line, output all
302 runes between start and end in the specified display block.
303 ****************************************************************************/
305 x_output_display_block(struct window *w, struct display_line *dl, int block,
306 int start, int end, int start_pixpos, int cursor_start,
307 int cursor_width, int cursor_height)
309 struct frame *f = XFRAME(w->frame);
310 Emchar_dynarr *buf = NULL;
313 struct display_block *db = Dynarr_atp(dl->display_blocks, block);
314 rune_dynarr *rba = db->runes;
320 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
321 MULE is not defined */
323 XSETWINDOW(window, w);
324 rb = Dynarr_atp(rba, start);
327 /* Nothing to do so don't do anything. */
332 if (rb->type == RUNE_CHAR)
333 charset = CHAR_CHARSET(rb->object.chr.ch);
336 end = Dynarr_length(rba);
338 buf = Dynarr_new (Emchar);
341 rb = Dynarr_atp(rba, elt);
343 if (rb->findex == findex && rb->type == RUNE_CHAR
344 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
345 && EQ(charset, CHAR_CHARSET(rb->object.chr.ch))) {
346 Dynarr_add(buf, rb->object.chr.ch);
350 if (Dynarr_length(buf)) {
351 x_output_string(w, dl, buf, xpos, 0,
352 start_pixpos, width, findex, 0,
353 cursor_start, cursor_width,
361 if (rb->type == RUNE_CHAR) {
364 charset = CHAR_CHARSET(rb->object.chr.ch);
366 if (rb->cursor_type == CURSOR_ON) {
367 if (rb->object.chr.ch == '\n') {
368 x_output_eol_cursor(w, dl, xpos,
373 x_output_string(w, dl, buf,
386 } else if (rb->object.chr.ch == '\n') {
387 /* Clear in case a cursor was formerly here. */
388 redisplay_clear_region(window, findex,
396 } else if (rb->type == RUNE_BLANK
397 || rb->type == RUNE_HLINE) {
398 if (rb->type == RUNE_BLANK)
399 x_output_blank(w, dl, rb, start_pixpos,
403 /* #### Our flagging of when we need to redraw the
404 modeline shadows sucks. Since RUNE_HLINE is only used
405 by the modeline at the moment it is a good bet
406 that if it gets redrawn then we should also
407 redraw the shadows. This won't be true forever.
408 We borrow the shadow_thickness_changed flag for
410 w->shadow_thickness_changed = 1;
411 x_output_hline(w, dl, rb);
416 rb = Dynarr_atp(rba, elt);
421 } else if (rb->type == RUNE_DGLYPH) {
422 Lisp_Object instance;
423 struct display_box dbox;
424 struct display_glyph_area dga;
426 redisplay_calculate_display_boxes(dl, rb->xpos,
437 XSETWINDOW(window, w);
439 glyph_image_instance(rb->object.dglyph.
444 if (IMAGE_INSTANCEP(instance)) {
445 switch (XIMAGE_INSTANCE_TYPE(instance)) {
446 case IMAGE_MONO_PIXMAP:
447 case IMAGE_COLOR_PIXMAP:
448 redisplay_output_pixmap(w,
461 (XIMAGE_INSTANCE_WIDGET_TYPE
462 (instance), Qlayout)) {
463 redisplay_output_layout
472 case IMAGE_SUBWINDOW:
473 redisplay_output_subwindow(w,
484 /* nothing is as nothing does */
493 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
494 (XIMAGE_INSTANCE(instance)) = 0;
504 if (Dynarr_length(buf))
505 x_output_string(w, dl, buf, xpos, 0, start_pixpos, width,
506 findex, 0, cursor_start, cursor_width,
509 /* #### This is really conditionalized well for optimized
511 if (dl->modeline && !EQ(Qzero, w->modeline_shadow_thickness)
513 || f->windows_structure_changed || w->shadow_thickness_changed))
514 bevel_modeline(w, dl);
519 /*****************************************************************************
522 Draw shadows for the given area in the given face.
523 ****************************************************************************/
525 x_bevel_area(struct window *w, face_index findex,
526 int x, int y, int width, int height,
527 int shadow_thickness, int edges, enum edge_style style)
529 struct frame *f = XFRAME(w->frame);
530 struct device *d = XDEVICE(f->device);
532 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET(f);
533 Display *dpy = DEVICE_X_DISPLAY(d);
534 Window x_win = XtWindow(FRAME_X_TEXT_WIDGET(f));
535 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
536 Lisp_Object tmp_pixel;
539 GC top_shadow_gc, bottom_shadow_gc, background_gc;
545 assert(shadow_thickness >= 0);
546 memset(&gcv, ~0, sizeof(XGCValues));
548 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND(w, findex);
549 tmp_color = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(tmp_pixel));
551 /* First, get the GC's. */
552 top_shadow_pixel = tmp_color.pixel;
553 bottom_shadow_pixel = tmp_color.pixel;
554 background_pixel = tmp_color.pixel;
556 x_generate_shadow_pixels(f, &top_shadow_pixel, &bottom_shadow_pixel,
557 background_pixel, ef->core.background_pixel);
559 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND(w, findex);
560 tmp_color = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(tmp_pixel));
561 gcv.background = tmp_color.pixel;
562 gcv.graphics_exposures = False;
563 mask = GCForeground | GCBackground | GCGraphicsExposures;
565 /* If we can't distinguish one of the shadows (the color is the same as the
566 background), it's better to use a pixmap to generate a dithered gray. */
567 if (top_shadow_pixel == background_pixel ||
568 bottom_shadow_pixel == background_pixel)
572 if (DEVICE_X_GRAY_PIXMAP(d) == None) {
573 DEVICE_X_GRAY_PIXMAP(d) =
574 XCreatePixmapFromBitmapData(dpy, x_win,
576 gray_width, gray_height,
580 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND(w, findex);
581 tmp_color = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(tmp_pixel));
582 gcv.foreground = tmp_color.pixel;
583 /* this is needed because the GC draws with a pixmap here */
584 gcv.fill_style = FillOpaqueStippled;
585 gcv.stipple = DEVICE_X_GRAY_PIXMAP(d);
586 top_shadow_gc = gc_cache_lookup(DEVICE_X_GC_CACHE(d), &gcv,
590 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND(w, findex);
591 tmp_color = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(tmp_pixel));
592 bottom_shadow_pixel = tmp_color.pixel;
594 flip_gcs = (bottom_shadow_pixel ==
595 WhitePixelOfScreen(DefaultScreenOfDisplay(dpy)));
597 gcv.foreground = top_shadow_pixel;
599 gc_cache_lookup(DEVICE_X_GC_CACHE(d), &gcv, mask);
602 gcv.foreground = bottom_shadow_pixel;
603 bottom_shadow_gc = gc_cache_lookup(DEVICE_X_GC_CACHE(d), &gcv, mask);
605 if (use_pixmap && flip_gcs) {
606 GC tmp_gc = bottom_shadow_gc;
607 bottom_shadow_gc = top_shadow_gc;
608 top_shadow_gc = tmp_gc;
611 gcv.foreground = background_pixel;
612 background_gc = gc_cache_lookup(DEVICE_X_GC_CACHE(d), &gcv, mask);
614 /* possibly revert the GC's This will give a depressed look to the
616 if (style == EDGE_ETCHED_IN || style == EDGE_BEVEL_IN) {
619 temp = top_shadow_gc;
620 top_shadow_gc = bottom_shadow_gc;
621 bottom_shadow_gc = temp;
624 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
625 shadow_thickness /= 2;
627 /* Draw the shadows around the divider line */
628 x_output_shadows(f, x, y, width, height,
629 top_shadow_gc, bottom_shadow_gc,
630 background_gc, shadow_thickness, edges);
632 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT) {
633 /* Draw the shadows around the divider line */
634 x_output_shadows(f, x + shadow_thickness, y + shadow_thickness,
635 width - 2 * shadow_thickness,
636 height - 2 * shadow_thickness,
637 bottom_shadow_gc, top_shadow_gc, background_gc,
638 shadow_thickness, edges);
642 /*****************************************************************************
645 Given a number of parameters return a GC with those properties.
646 ****************************************************************************/
648 x_get_gc(struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
649 Lisp_Object bg_pmap, Lisp_Object lwidth)
654 memset(&gcv, ~0, sizeof(XGCValues));
655 gcv.graphics_exposures = False;
656 /* Make absolutely sure that we don't pick up a clipping region in
657 the GC returned by this function. */
658 gcv.clip_mask = None;
659 gcv.clip_x_origin = 0;
660 gcv.clip_y_origin = 0;
661 gcv.fill_style = FillSolid;
662 mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
666 gcv.font = FONT_INSTANCE_X_FONT(XFONT_INSTANCE(font))->fid;
671 if (!NILP(fg) && !COLOR_INSTANCEP(fg) && !INTP(fg)) {
672 /* #### I fixed once case where this was getting it. It was a
673 bad macro expansion (compiler bug). */
674 stderr_out("Help! x_get_gc got a bogus fg value! fg = ");
680 if (COLOR_INSTANCEP(fg))
682 COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(fg)).pixel;
684 gcv.foreground = XINT(fg);
685 mask |= GCForeground;
689 if (COLOR_INSTANCEP(bg))
691 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)) {
700 assert(DEVICE_X_GRAY_PIXMAP(d) != None);
702 gcv.fill_style = FillStippled;
703 gcv.stipple = DEVICE_X_GRAY_PIXMAP(d);
704 mask |= (GCFillStyle | GCStipple);
705 } else if (IMAGE_INSTANCEP(bg_pmap)
706 && IMAGE_INSTANCE_PIXMAP_TYPE_P(XIMAGE_INSTANCE(bg_pmap))) {
707 if (XIMAGE_INSTANCE_PIXMAP_DEPTH(bg_pmap) == 0) {
708 gcv.fill_style = FillOpaqueStippled;
709 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP(bg_pmap);
710 mask |= (GCStipple | GCFillStyle);
712 gcv.fill_style = FillTiled;
713 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP(bg_pmap);
714 mask |= (GCTile | GCFillStyle);
719 gcv.line_width = XINT(lwidth);
723 return gc_cache_lookup(DEVICE_X_GC_CACHE(d), &gcv, mask);
726 /*****************************************************************************
729 Given a string and a starting position, output that string in the
730 given face. If cursor is true, draw a cursor around the string.
731 Correctly handles multiple charsets in the string.
733 The meaning of the parameters is something like this:
735 W Window that the text is to be displayed in.
736 DL Display line that this text is on. The values in the
737 structure are used to determine the vertical position and
738 clipping range of the text.
739 BUF Dynamic array of Emchars specifying what is actually to be
741 XPOS X position in pixels where the text should start being drawn.
742 XOFFSET Number of pixels to be chopped off the left side of the
743 text. The effect is as if the text were shifted to the
744 left this many pixels and clipped at XPOS.
745 CLIP_START Clip everything left of this X position.
746 WIDTH Clip everything right of XPOS + WIDTH.
747 FINDEX Index for the face cache element describing how to display
749 CURSOR #### I don't understand this. There's something
750 strange and overcomplexified with this variable.
751 Chuck, explain please?
752 CURSOR_START Starting X position of cursor.
753 CURSOR_WIDTH Width of cursor in pixels.
754 CURSOR_HEIGHT Height of cursor in pixels.
756 Starting Y position of cursor is the top of the text line.
757 The cursor is drawn sometimes whether or not CURSOR is set. ???
758 ****************************************************************************/
760 x_output_string(struct window *w, struct display_line *dl,
761 Emchar_dynarr * buf, int xpos, int xoffset, int clip_start,
762 int width, face_index findex, int cursor,
763 int cursor_start, int cursor_width, int cursor_height)
765 /* General variables */
766 struct frame *f = XFRAME(w->frame);
767 struct device *d = XDEVICE(f->device);
770 Display *dpy = DEVICE_X_DISPLAY(d);
771 Window x_win = XtWindow(FRAME_X_TEXT_WIDGET(f));
775 /* Cursor-related variables */
776 int focus = EQ(w->frame, DEVICE_FRAME_WITH_FOCUS_REAL(d));
778 Lisp_Object bar_cursor_value = symbol_value_in_buffer(Qbar_cursor,
780 struct face_cachel *cursor_cachel = 0;
782 /* Text-related variables */
786 int len = Dynarr_length(buf);
787 unsigned char *text_storage = (unsigned char *)alloca(2 * len);
788 struct textual_run *runs = alloca_array(struct textual_run, len);
791 struct face_cachel *cachel = WINDOW_FACE_CACHEL(w, findex);
793 XSETDEVICE(device, d);
794 XSETWINDOW(window, w);
798 x_text_width(f, cachel, Dynarr_atp(buf, 0),
800 height = DISPLAY_LINE_HEIGHT(dl);
802 /* Regularize the variables passed in. */
804 if (clip_start < xpos)
806 clip_end = xpos + width;
807 if (clip_start >= clip_end)
808 /* It's all clipped out. */
813 /* make sure the area we are about to display is subwindow free. */
814 redisplay_unmap_subwindows_maybe(f, clip_start, DISPLAY_LINE_YPOS(dl),
815 clip_end - clip_start,
816 DISPLAY_LINE_HEIGHT(dl));
818 nruns = separate_textual_runs(text_storage, runs, Dynarr_atp(buf, 0),
821 cursor_clip = (cursor_start >= clip_start && cursor_start < clip_end);
823 /* This cursor code is really a mess. */
824 if (!NILP(w->text_cursor_visible_p)
827 || (cursor_width && (cursor_start + cursor_width >= clip_start)
828 && !NILP(bar_cursor_value)))) {
829 /* These have to be in separate statements in order to avoid a
832 get_builtin_face_cache_index(w, Vtext_cursor_face);
833 cursor_cachel = WINDOW_FACE_CACHEL(w, sucks);
835 /* We have to reset this since any call to WINDOW_FACE_CACHEL
836 may cause the cache to resize and any pointers to it to
838 cachel = WINDOW_FACE_CACHEL(w, findex);
841 if (cursor && focus && (cursor_start == clip_start) && cursor_height)
842 XIM_SetSpotLocation(f, xpos - 2, dl->ypos + dl->descent - 2);
843 #endif /* HAVE_XIM */
845 bg_pmap = cachel->background_pixmap;
846 if (!IMAGE_INSTANCEP(bg_pmap)
847 || !IMAGE_INSTANCE_PIXMAP_TYPE_P(XIMAGE_INSTANCE(bg_pmap)))
850 if ((cursor && focus && NILP(bar_cursor_value)
851 && !NILP(w->text_cursor_visible_p)) || NILP(bg_pmap))
854 bgc = x_get_gc(d, Qnil, cachel->foreground, cachel->background,
858 XFillRectangle(dpy, x_win, bgc, clip_start,
859 DISPLAY_LINE_YPOS(dl), clip_end - clip_start,
862 for (i = 0; i < nruns; i++) {
863 Lisp_Object font = FACE_CACHEL_FONT(cachel, runs[i].charset);
864 Lisp_Font_Instance *fi = XFONT_INSTANCE(font);
868 if (EQ(font, Vthe_null_font_instance))
871 this_width = x_text_width_single_run(cachel, runs + i);
872 need_clipping = (dl->clip || clip_start > xpos ||
873 clip_end < xpos + this_width);
875 /* XDrawImageString only clears the area equal to the height of
876 the given font. It is possible that a font is being displayed
877 on a line taller than it is, so this would cause us to fail to
879 if ((int)fi->height < (int)(height + dl->clip + dl->top_clip)) {
880 int clear_start = max(xpos, clip_start);
881 int clear_end = min(xpos + this_width, clip_end);
884 int ypos1_line, ypos1_string, ypos2_line,
887 ypos1_string = dl->ypos - fi->ascent;
888 ypos2_string = dl->ypos + fi->descent;
889 ypos1_line = DISPLAY_LINE_YPOS(dl);
891 ypos1_line + DISPLAY_LINE_HEIGHT(dl);
893 /* Make sure we don't clear below the real bottom of the
895 if (ypos1_string > ypos2_line)
896 ypos1_string = ypos2_line;
897 if (ypos2_string > ypos2_line)
898 ypos2_string = ypos2_line;
900 if (ypos1_line < ypos1_string) {
901 redisplay_clear_region(window, findex,
910 if (ypos2_line > ypos2_string) {
911 redisplay_clear_region(window, findex,
920 redisplay_clear_region(window, findex,
922 DISPLAY_LINE_YPOS(dl),
923 clear_end - clear_start,
928 if (cursor && cursor_cachel && focus && NILP(bar_cursor_value))
929 gc = x_get_gc(d, font, cursor_cachel->foreground,
930 cursor_cachel->background, Qnil, Qnil);
931 else if (cachel->dim) {
932 /* Ensure the gray bitmap exists */
933 if (DEVICE_X_GRAY_PIXMAP(d) == None)
934 DEVICE_X_GRAY_PIXMAP(d) =
935 XCreateBitmapFromData(dpy, x_win,
940 /* Request a GC with the gray stipple pixmap to draw dimmed text */
941 gc = x_get_gc(d, font, cachel->foreground,
942 cachel->background, Qdim, Qnil);
944 gc = x_get_gc(d, font, cachel->foreground,
945 cachel->background, Qnil, Qnil);
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,
956 DISPLAY_LINE_YPOS(dl), clip_box, 1,
960 if (runs[i].dimension == 1)
961 (bgc ? XDrawString : XDrawImageString) (dpy, x_win, gc,
967 (bgc ? XDrawString16 : XDrawImageString16) (dpy, x_win,
975 /* We draw underlines in the same color as the text. */
976 if (cachel->underline) {
978 unsigned long upos_ext, uthick_ext;
981 xfont = FONT_INSTANCE_X_FONT(XFONT_INSTANCE(font));
982 if (!XGetFontProperty
983 (xfont, XA_UNDERLINE_POSITION, &upos_ext))
984 upos = dl->descent / 2;
986 upos = (int) upos_ext;
988 if (!XGetFontProperty
989 (xfont, XA_UNDERLINE_THICKNESS, &uthick_ext))
992 uthick = (int) uthick_ext;
994 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip) {
995 if (dl->ypos + upos + uthick >
996 dl->ypos + dl->descent - dl->clip)
997 uthick = dl->descent - dl->clip - upos;
1000 XDrawLine(dpy, x_win, gc, xpos,
1004 } else if (uthick > 1) {
1005 XFillRectangle(dpy, x_win, gc, xpos,
1007 this_width, uthick);
1012 if (cachel->strikethru) {
1013 int ascent, descent, upos, uthick;
1014 unsigned long ascent_ext, descent_ext, uthick_ext;
1017 xfont = FONT_INSTANCE_X_FONT(XFONT_INSTANCE(font));
1019 if (!XGetFontProperty
1020 (xfont, XA_STRIKEOUT_ASCENT, &ascent_ext))
1021 ascent = xfont->ascent;
1023 ascent = (int) ascent_ext;
1025 if (!XGetFontProperty
1026 (xfont, XA_STRIKEOUT_DESCENT, &descent_ext))
1027 descent = xfont->descent;
1029 descent = (int) descent_ext;
1031 if (!XGetFontProperty
1032 (xfont, XA_UNDERLINE_THICKNESS, &uthick_ext))
1035 uthick = (int) uthick_ext;
1037 upos = ascent - ((ascent + descent) / 2) + 1;
1039 /* Generally, upos will be positive (above the baseline),so subtract */
1040 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip) {
1041 if (dl->ypos - upos + uthick >
1042 dl->ypos + dl->descent - dl->clip)
1043 uthick = dl->descent - dl->clip + upos;
1046 XDrawLine(dpy, x_win, gc, xpos,
1050 } else if (uthick > 1) {
1051 XFillRectangle(dpy, x_win, gc, xpos,
1053 this_width, uthick);
1058 /* Restore the GC */
1059 if (need_clipping) {
1060 XSetClipMask(dpy, gc, None);
1061 XSetClipOrigin(dpy, gc, 0, 0);
1064 /* If we are actually superimposing the cursor then redraw with just
1065 the appropriate section highlighted. */
1066 if (cursor_clip && !cursor && focus && cursor_cachel) {
1068 XRectangle clip_box[1];
1070 cgc = x_get_gc(d, font, cursor_cachel->foreground,
1071 cursor_cachel->background, Qnil, Qnil);
1075 clip_box[0].width = cursor_width;
1076 clip_box[0].height = height;
1078 XSetClipRectangles(dpy, cgc, cursor_start,
1079 DISPLAY_LINE_YPOS(dl), clip_box, 1,
1082 if (runs[i].dimension == 1)
1083 XDrawImageString(dpy, x_win, cgc, xpos,
1084 dl->ypos, (char *)runs[i].ptr,
1087 XDrawImageString16(dpy, x_win, cgc, xpos,
1089 (XChar2b *) runs[i].ptr,
1092 XSetClipMask(dpy, cgc, None);
1093 XSetClipOrigin(dpy, cgc, 0, 0);
1099 /* Draw the non-focus box or bar-cursor as needed. */
1100 /* Can't this logic be simplified? */
1101 if (cursor_cachel && ((cursor && !focus && NILP(bar_cursor_value))
1103 && (cursor_start + cursor_width >= clip_start)
1104 && !NILP(bar_cursor_value)))) {
1105 int tmp_height, tmp_y;
1106 int bar_width = EQ(bar_cursor_value, Qt) ? 1 : 2;
1107 int need_clipping = (cursor_start < clip_start
1108 || clip_end < cursor_start + cursor_width);
1110 /* #### This value is correct (as far as I know) because
1111 all of the times we need to draw this cursor, we will
1112 be called with exactly one character, so we know we
1113 can always use runs[0].
1115 This is bogus as all hell, however. The cursor handling in
1116 this function is way bogus and desperately needs to be
1117 cleaned up. (In particular, the drawing of the cursor should
1118 really really be separated out of this function. This may be
1119 a bit tricky now because this function itself does way too
1120 much stuff, a lot of which needs to be moved into
1121 redisplay.c) This is the only way to be able to easily add
1122 new cursor types or (e.g.) make the bar cursor be able to
1123 span two characters instead of overlaying just one. */
1124 int bogusly_obtained_ascent_value =
1125 XFONT_INSTANCE(FACE_CACHEL_FONT(cachel, runs[0].charset))->
1128 if (!NILP(bar_cursor_value)) {
1129 gc = x_get_gc(d, Qnil, cursor_cachel->background, Qnil,
1130 Qnil, make_int(bar_width));
1132 gc = x_get_gc(d, Qnil, cursor_cachel->background,
1136 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1137 tmp_height = cursor_height;
1138 if (tmp_y + tmp_height > (int)(DISPLAY_LINE_YPOS(dl) + height)) {
1139 tmp_y = DISPLAY_LINE_YPOS(dl) + height - tmp_height;
1140 if (tmp_y < (int)DISPLAY_LINE_YPOS(dl))
1141 tmp_y = DISPLAY_LINE_YPOS(dl);
1142 tmp_height = DISPLAY_LINE_YPOS(dl) + height - tmp_y;
1145 if (need_clipping) {
1146 XRectangle clip_box[1];
1149 clip_box[0].width = clip_end - clip_start;
1150 clip_box[0].height = tmp_height;
1151 XSetClipRectangles(dpy, gc, clip_start, tmp_y,
1152 clip_box, 1, Unsorted);
1155 if (!focus && NILP(bar_cursor_value)) {
1156 XDrawRectangle(dpy, x_win, gc, cursor_start, tmp_y,
1157 cursor_width - 1, tmp_height - 1);
1158 } else if (focus && !NILP(bar_cursor_value)) {
1159 XDrawLine(dpy, x_win, gc, cursor_start + bar_width - 1,
1160 tmp_y, cursor_start + bar_width - 1,
1161 tmp_y + tmp_height - 1);
1164 /* Restore the GC */
1165 if (need_clipping) {
1166 XSetClipMask(dpy, gc, None);
1167 XSetClipOrigin(dpy, gc, 0, 0);
1173 x_output_x_pixmap(struct frame *f, Lisp_Image_Instance * p, int x,
1174 int y, int xoffset, int yoffset,
1175 int width, int height, unsigned long fg, unsigned long bg,
1178 struct device *d = XDEVICE(f->device);
1179 Display *dpy = DEVICE_X_DISPLAY(d);
1180 Window x_win = XtWindow(FRAME_X_TEXT_WIDGET(f));
1184 unsigned long pixmap_mask;
1187 memset(&gcv, ~0, sizeof(XGCValues));
1188 gcv.graphics_exposures = False;
1189 gcv.foreground = fg;
1190 gcv.background = bg;
1191 pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
1193 if (IMAGE_INSTANCE_X_MASK(p)) {
1194 gcv.function = GXcopy;
1195 gcv.clip_mask = IMAGE_INSTANCE_X_MASK(p);
1196 gcv.clip_x_origin = x - xoffset;
1197 gcv.clip_y_origin = y - yoffset;
1199 (GCFunction | GCClipMask | GCClipXOrigin |
1201 /* Can't set a clip rectangle because we already have a mask.
1202 Is it possible to get an equivalent effect by changing the
1203 args to XCopyArea below rather than messing with a clip box?
1204 - dkindred@cs.cmu.edu
1205 Yes. We don't clip at all now - andy@xemacs.org
1209 gc = gc_cache_lookup(DEVICE_X_GC_CACHE(d), &gcv, pixmap_mask);
1212 /* override_gc might have a mask already--we don't want to nuke it.
1213 Maybe we can insist that override_gc have no mask, or use
1214 one of the suggestions above. */
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 IMAGE_INSTANCE_X_PIXMAP_SLICE
1224 (p, IMAGE_INSTANCE_PIXMAP_SLICE(p)), x_win, gc,
1225 xoffset, yoffset, width, height, x, y);
1227 XCopyPlane(dpy, IMAGE_INSTANCE_X_PIXMAP_SLICE
1228 (p, IMAGE_INSTANCE_PIXMAP_SLICE(p)), x_win, gc,
1229 xoffset, yoffset, width, height, x, y, 1L);
1234 x_output_pixmap(struct window *w, Lisp_Object image_instance,
1235 struct display_box *db, struct display_glyph_area *dga,
1236 face_index findex, int cursor_start, int cursor_width,
1237 int cursor_height, int bg_pixmap)
1239 struct frame *f = XFRAME(w->frame);
1240 struct device *d = XDEVICE(f->device);
1241 Lisp_Image_Instance *p = XIMAGE_INSTANCE(image_instance);
1243 Display *dpy = DEVICE_X_DISPLAY(d);
1244 Window x_win = XtWindow(FRAME_X_TEXT_WIDGET(f));
1246 /* Output the pixmap. */
1248 Lisp_Object tmp_pixel;
1249 XColor tmp_bcolor, tmp_fcolor;
1251 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND(w, findex);
1252 tmp_fcolor = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(tmp_pixel));
1253 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND(w, findex);
1254 tmp_bcolor = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(tmp_pixel));
1256 x_output_x_pixmap(f, p, db->xpos, db->ypos,
1257 dga->xoffset, dga->yoffset,
1258 dga->width, dga->height,
1259 tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
1262 /* Draw a cursor over top of the pixmap. */
1263 if (cursor_width && cursor_height && (cursor_start >= db->xpos)
1264 && !NILP(w->text_cursor_visible_p)
1265 && (cursor_start < db->xpos + dga->width)) {
1267 int focus = EQ(w->frame, DEVICE_FRAME_WITH_FOCUS_REAL(d));
1268 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL(w,
1269 get_builtin_face_cache_index
1271 Vtext_cursor_face));
1273 gc = x_get_gc(d, Qnil, cursor_cachel->background, Qnil, Qnil,
1276 if (cursor_width > db->xpos + dga->width - cursor_start)
1277 cursor_width = db->xpos + dga->width - cursor_start;
1280 XFillRectangle(dpy, x_win, gc, cursor_start, db->ypos,
1281 cursor_width, cursor_height);
1283 XDrawRectangle(dpy, x_win, gc, cursor_start, db->ypos,
1284 cursor_width, cursor_height);
1289 /*****************************************************************************
1290 x_output_vertical_divider
1292 Draw a vertical divider down the right side of the given window.
1293 ****************************************************************************/
1294 static void x_output_vertical_divider(struct window *w, int clear)
1296 struct frame *f = XFRAME(w->frame);
1297 struct device *d = XDEVICE(f->device);
1299 Display *dpy = DEVICE_X_DISPLAY(d);
1300 Window x_win = XtWindow(FRAME_X_TEXT_WIDGET(f));
1301 Lisp_Object tmp_pixel;
1305 enum edge_style style;
1308 int x, yy1, yy2, width, shadow_thickness, spacing, line_width;
1309 face_index div_face =
1310 get_builtin_face_cache_index(w, Vvertical_divider_face);
1312 width = window_divider_width(w);
1313 shadow_thickness = XINT(w->vertical_divider_shadow_thickness);
1314 spacing = XINT(w->vertical_divider_spacing);
1315 line_width = XINT(w->vertical_divider_line_width);
1316 x = WINDOW_RIGHT(w) - width;
1317 yy1 = WINDOW_TOP(w);
1318 yy2 = WINDOW_BOTTOM(w);
1320 memset(&gcv, ~0, sizeof(XGCValues));
1322 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND(w, div_face);
1323 tmp_color = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(tmp_pixel));
1325 /* First, get the GC's. */
1326 gcv.background = tmp_color.pixel;
1327 gcv.foreground = tmp_color.pixel;
1328 gcv.graphics_exposures = False;
1329 mask = GCForeground | GCBackground | GCGraphicsExposures;
1330 background_gc = gc_cache_lookup(DEVICE_X_GC_CACHE(d), &gcv, mask);
1332 /* Clear the divider area first. This needs to be done when a
1333 window split occurs. */
1335 XClearArea(dpy, x_win, x, yy1, width, yy2 - yy1, False);
1337 /* Draw the divider line. */
1338 XFillRectangle(dpy, x_win, background_gc,
1339 x + spacing + shadow_thickness,
1340 yy1, line_width, yy2 - yy1);
1342 if (shadow_thickness < 0) {
1343 shadow_thickness = -shadow_thickness;
1344 style = EDGE_BEVEL_IN;
1346 style = EDGE_BEVEL_OUT;
1349 /* Draw the shadows around the divider line */
1350 x_bevel_area(w, div_face, x + spacing, yy1,
1351 width - 2 * spacing, yy2 - yy1,
1352 shadow_thickness, EDGE_ALL, style);
1355 /*****************************************************************************
1358 Output a blank by clearing the area it covers in the foreground color
1360 ****************************************************************************/
1362 x_output_blank(struct window *w, struct display_line *dl, struct rune *rb,
1363 int start_pixpos, int cursor_start, int cursor_width)
1365 struct frame *f = XFRAME(w->frame);
1366 struct device *d = XDEVICE(f->device);
1368 Display *dpy = DEVICE_X_DISPLAY(d);
1369 Window x_win = XtWindow(FRAME_X_TEXT_WIDGET(f));
1371 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL(w,
1372 get_builtin_face_cache_index
1374 Vtext_cursor_face));
1375 Lisp_Object bg_pmap;
1376 Lisp_Object buffer = WINDOW_BUFFER(w);
1377 Lisp_Object bar_cursor_value = symbol_value_in_buffer(Qbar_cursor,
1381 int y = DISPLAY_LINE_YPOS(dl);
1382 int width = rb->width;
1383 int height = DISPLAY_LINE_HEIGHT(dl);
1385 /* Unmap all subwindows in the area we are going to blank. */
1386 redisplay_unmap_subwindows_maybe(f, x, y, width, height);
1388 if (start_pixpos > x) {
1389 if (start_pixpos >= (x + width))
1392 width -= (start_pixpos - x);
1397 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP(w, rb->findex);
1398 if (!IMAGE_INSTANCEP(bg_pmap)
1399 || !IMAGE_INSTANCE_PIXMAP_TYPE_P(XIMAGE_INSTANCE(bg_pmap)))
1403 gc = x_get_gc(d, Qnil,
1404 WINDOW_FACE_CACHEL_BACKGROUND(w, rb->findex),
1407 gc = x_get_gc(d, Qnil,
1408 WINDOW_FACE_CACHEL_FOREGROUND(w, rb->findex),
1409 WINDOW_FACE_CACHEL_BACKGROUND(w, rb->findex),
1412 XFillRectangle(dpy, x_win, gc, x, y, width, height);
1414 /* If this rune is marked as having the cursor, then it is actually
1415 representing a tab. */
1416 if (!NILP(w->text_cursor_visible_p)
1417 && (rb->cursor_type == CURSOR_ON
1418 || (cursor_width && (cursor_start + cursor_width > x)
1419 && cursor_start < (x + width)))) {
1420 int cursor_height, cursor_y;
1421 int focus = EQ(w->frame, DEVICE_FRAME_WITH_FOCUS_REAL(d));
1422 Lisp_Font_Instance *fi;
1424 fi = XFONT_INSTANCE(FACE_CACHEL_FONT
1425 (WINDOW_FACE_CACHEL(w, rb->findex),
1428 gc = x_get_gc(d, Qnil, cursor_cachel->background, Qnil, Qnil,
1431 cursor_y = dl->ypos - fi->ascent;
1432 cursor_height = fi->height;
1433 if (cursor_y + cursor_height > y + height)
1434 cursor_height = y + height - cursor_y;
1437 if (NILP(bar_cursor_value)) {
1438 XFillRectangle(dpy, x_win, gc, cursor_start,
1439 cursor_y, fi->width,
1443 EQ(bar_cursor_value, Qt) ? 1 : 2;
1445 gc = x_get_gc(d, Qnil,
1446 cursor_cachel->background, Qnil,
1447 Qnil, make_int(bar_width));
1448 XDrawLine(dpy, x_win, gc,
1449 cursor_start + bar_width - 1,
1451 cursor_start + bar_width - 1,
1452 cursor_y + cursor_height - 1);
1454 } else if (NILP(bar_cursor_value)) {
1455 XDrawRectangle(dpy, x_win, gc, cursor_start, cursor_y,
1456 fi->width - 1, cursor_height - 1);
1461 /*****************************************************************************
1464 Output a horizontal line in the foreground of its face.
1465 ****************************************************************************/
1467 x_output_hline(struct window *w, struct display_line *dl, struct rune *rb)
1469 struct frame *f = XFRAME(w->frame);
1470 struct device *d = XDEVICE(f->device);
1472 Display *dpy = DEVICE_X_DISPLAY(d);
1473 Window x_win = XtWindow(FRAME_X_TEXT_WIDGET(f));
1477 int width = rb->width;
1478 int height = DISPLAY_LINE_HEIGHT(dl);
1479 int ypos1, ypos2, ypos3, ypos4;
1481 ypos1 = DISPLAY_LINE_YPOS(dl);
1482 ypos2 = ypos1 + rb->object.hline.yoffset;
1483 ypos3 = ypos2 + rb->object.hline.thickness;
1484 ypos4 = dl->ypos + dl->descent - dl->clip;
1486 /* First clear the area not covered by the line. */
1487 if (height - rb->object.hline.thickness > 0) {
1488 gc = x_get_gc(d, Qnil,
1489 WINDOW_FACE_CACHEL_FOREGROUND(w, rb->findex),
1492 if (ypos2 - ypos1 > 0)
1493 XFillRectangle(dpy, x_win, gc, x, ypos1, width,
1495 if (ypos4 - ypos3 > 0)
1496 XFillRectangle(dpy, x_win, gc, x, ypos1, width,
1500 /* Now draw the line. */
1501 gc = x_get_gc(d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND(w, rb->findex),
1509 if (ypos3 - ypos2 > 0)
1510 XFillRectangle(dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1513 /*****************************************************************************
1516 Draw a shadow around the given area using the given GC's. It is the
1517 callers responsibility to set the GC's appropriately.
1518 ****************************************************************************/
1520 x_output_shadows(struct frame *f, int x, int y, int width, int height,
1521 GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
1522 int shadow_thickness, int edges)
1524 struct device *d = XDEVICE(f->device);
1526 Display *dpy = DEVICE_X_DISPLAY(d);
1527 Window x_win = XtWindow(FRAME_X_TEXT_WIDGET(f));
1529 XSegment top_shadow[20], bottom_shadow[20];
1532 if (shadow_thickness > 10)
1533 shadow_thickness = 10;
1534 else if (shadow_thickness < 0)
1535 shadow_thickness = 0;
1536 if (shadow_thickness > (width / 2))
1537 shadow_thickness = width / 2;
1538 if (shadow_thickness > (height / 2))
1539 shadow_thickness = height / 2;
1541 for (elt = 0; elt < shadow_thickness; elt++) {
1543 int seg2 = (edges & EDGE_TOP) ? elt + shadow_thickness : elt;
1545 (edges & EDGE_BOTTOM) ? elt + shadow_thickness : elt;
1547 if (edges & EDGE_TOP) {
1548 top_shadow[seg1].x1 = x + elt;
1549 top_shadow[seg1].x2 = x + width - elt - 1;
1550 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
1552 if (edges & EDGE_LEFT) {
1553 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
1554 top_shadow[seg2].y1 = y + elt;
1555 top_shadow[seg2].y2 = y + height - elt - 1;
1557 if (edges & EDGE_BOTTOM) {
1558 bottom_shadow[seg1].x1 = x + elt;
1559 bottom_shadow[seg1].x2 = x + width - elt - 1;
1560 bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 =
1561 y + height - elt - 1;
1563 if (edges & EDGE_RIGHT) {
1564 bottom_shadow[bot_seg2].x1 =
1565 bottom_shadow[bot_seg2].x2 = x + width - elt - 1;
1566 bottom_shadow[bot_seg2].y1 = y + elt;
1567 bottom_shadow[bot_seg2].y2 = y + height - elt - 1;
1571 XDrawSegments(dpy, x_win, top_shadow_gc, top_shadow,
1572 ((edges & EDGE_TOP) ? shadow_thickness : 0)
1573 + ((edges & EDGE_LEFT) ? shadow_thickness : 0));
1574 XDrawSegments(dpy, x_win, bottom_shadow_gc, bottom_shadow,
1575 ((edges & EDGE_BOTTOM) ? shadow_thickness : 0)
1576 + ((edges & EDGE_RIGHT) ? shadow_thickness : 0));
1579 /*****************************************************************************
1580 x_generate_shadow_pixels
1582 Given three pixels (top shadow, bottom shadow, background) massage
1583 the top and bottom shadow colors to guarantee that they differ. The
1584 background pixels are not allowed to be modified.
1586 This function modifies its parameters.
1588 This code is modified from code blatantly stolen from lwlib/xlwmenu.c
1589 ****************************************************************************/
1590 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
1591 ? ((unsigned long) (x)) : ((unsigned long) (y)))
1594 x_generate_shadow_pixels(struct frame *f, unsigned long *top_shadow,
1595 unsigned long *bottom_shadow,
1596 unsigned long background,
1597 unsigned long core_background)
1599 struct device *d = XDEVICE(f->device);
1600 Display *dpy = DEVICE_X_DISPLAY(d);
1601 Colormap cmap = DEVICE_X_COLORMAP(d);
1602 Visual *visual = DEVICE_X_VISUAL(d);
1605 int top_frobbed = 0, bottom_frobbed = 0;
1607 /* If the top shadow is the same color as the background, try to
1609 if (*top_shadow == background) {
1610 topc.pixel = background;
1611 XQueryColor(dpy, cmap, &topc);
1612 /* don't overflow/wrap! */
1613 topc.red = MINL(65535, (unsigned long)topc.red * 6 / 5);
1614 topc.green = MINL(65535, (unsigned long)topc.green * 6 / 5);
1615 topc.blue = MINL(65535, (unsigned long)topc.blue * 6 / 5);
1616 if (allocate_nearest_color(dpy, cmap, visual, &topc)) {
1617 *top_shadow = topc.pixel;
1622 /* If the bottom shadow is the same color as the background, try to
1624 if (*bottom_shadow == background) {
1625 botc.pixel = background;
1626 XQueryColor(dpy, cmap, &botc);
1627 botc.red = (unsigned short)((unsigned long)botc.red * 3 / 5);
1629 (unsigned short)((unsigned long)botc.green * 3 / 5);
1630 botc.blue = (unsigned short)((unsigned long)botc.blue * 3 / 5);
1631 if (allocate_nearest_color(dpy, cmap, visual, &botc)) {
1632 *bottom_shadow = botc.pixel;
1637 /* If we had to adjust both shadows, then we have to do some
1639 if (top_frobbed && bottom_frobbed) {
1641 ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
1643 ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
1644 if (bot_avg > top_avg) {
1645 Pixel tmp = *top_shadow;
1647 *top_shadow = *bottom_shadow;
1648 *bottom_shadow = tmp;
1649 } else if (topc.pixel == botc.pixel) {
1650 if (botc.pixel == background)
1651 *top_shadow = core_background;
1653 *bottom_shadow = background;
1658 /*****************************************************************************
1659 x_redraw_exposed_window
1661 Given a bounding box for an area that needs to be redrawn, determine
1662 what parts of what lines are contained within and re-output their
1664 ****************************************************************************/
1666 x_redraw_exposed_window(struct window *w, int x, int y, int width, int height)
1668 struct frame *f = XFRAME(w->frame);
1670 int start_x, start_y, end_x, end_y;
1671 int orig_windows_structure_changed;
1673 display_line_dynarr *cdla = window_display_lines(w, CURRENT_DISP);
1675 if (!NILP(w->vchild)) {
1676 x_redraw_exposed_windows(w->vchild, x, y, width, height);
1678 } else if (!NILP(w->hchild)) {
1679 x_redraw_exposed_windows(w->hchild, x, y, width, height);
1683 /* If the window doesn't intersect the exposed region, we're done here. */
1684 if (x >= WINDOW_RIGHT(w) || (x + width) <= WINDOW_LEFT(w)
1685 || y >= WINDOW_BOTTOM(w) || (y + height) <= WINDOW_TOP(w)) {
1688 start_x = max(WINDOW_LEFT(w), x);
1689 end_x = min(WINDOW_RIGHT(w), (x + width));
1690 start_y = max(WINDOW_TOP(w), y);
1691 end_y = min(WINDOW_BOTTOM(w), y + height);
1693 /* We do this to make sure that the 3D modelines get redrawn if
1694 they are in the exposed region. */
1695 orig_windows_structure_changed = f->windows_structure_changed;
1696 f->windows_structure_changed = 1;
1699 redisplay_clear_top_of_window(w);
1700 if (window_needs_vertical_divider(w)) {
1701 x_output_vertical_divider(w, 0);
1704 for (line = 0; line < Dynarr_length(cdla); line++) {
1705 struct display_line *cdl = Dynarr_atp(cdla, line);
1706 int top_y = cdl->ypos - cdl->ascent;
1707 int bottom_y = cdl->ypos + cdl->descent;
1709 if (bottom_y >= start_y) {
1710 if (top_y > end_y) {
1716 output_display_line(w, 0, cdla, line, start_x,
1722 f->windows_structure_changed = orig_windows_structure_changed;
1724 /* If there have never been any face cache_elements created, then this
1725 expose event doesn't actually have anything to do. */
1726 if (Dynarr_largest(w->face_cachels))
1727 redisplay_clear_bottom_of_window(w, cdla, start_y, end_y);
1730 /*****************************************************************************
1731 x_redraw_exposed_windows
1733 For each window beneath the given window in the window hierarchy,
1734 ensure that it is redrawn if necessary after an Expose event.
1735 ****************************************************************************/
1737 x_redraw_exposed_windows(Lisp_Object window, int x, int y, int width,
1740 for (; !NILP(window); window = XWINDOW(window)->next)
1741 x_redraw_exposed_window(XWINDOW(window), x, y, width, height);
1744 /*****************************************************************************
1745 x_redraw_exposed_area
1747 For each window on the given frame, ensure that any area in the
1748 Exposed area is redrawn.
1749 ****************************************************************************/
1750 void x_redraw_exposed_area(struct frame *f, int x, int y, int width, int height)
1752 /* If any window on the frame has had its face cache reset then the
1753 redisplay structures are effectively invalid. If we attempt to
1754 use them we'll blow up. We mark the frame as changed to ensure
1755 that redisplay will do a full update. This probably isn't
1756 necessary but it can't hurt. */
1758 #ifdef HAVE_TOOLBARS
1759 /* #### We would rather put these off as well but there is currently
1760 no combination of flags which will force an unchanged toolbar to
1762 MAYBE_FRAMEMETH(f, redraw_exposed_toolbars, (f, x, y, width, height));
1764 redraw_exposed_gutters(f, x, y, width, height);
1766 if (!f->window_face_cache_reset) {
1767 x_redraw_exposed_windows(f->root_window, x, y, width, height);
1769 XFlush(DEVICE_X_DISPLAY(XDEVICE(f->device)));
1771 MARK_FRAME_CHANGED(f);
1774 /****************************************************************************
1777 Clear the area in the box defined by the given parameters using the
1779 ****************************************************************************/
1781 x_clear_region(Lisp_Object locale, struct device *d, struct frame *f,
1782 face_index findex, int x, int y, int width, int height,
1783 Lisp_Object fcolor, Lisp_Object bcolor,
1784 Lisp_Object background_pixmap)
1790 dpy = DEVICE_X_DISPLAY(d);
1791 x_win = XtWindow(FRAME_X_TEXT_WIDGET(f));
1793 if (!UNBOUNDP(background_pixmap)) {
1794 gc = x_get_gc(d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
1798 XFillRectangle(dpy, x_win, gc, x, y, width, height);
1800 XClearArea(dpy, x_win, x, y, width, height, False);
1803 /*****************************************************************************
1806 Draw a cursor at the end of a line. The end-of-line cursor is
1807 narrower than the normal cursor.
1808 ****************************************************************************/
1810 x_output_eol_cursor(struct window *w, struct display_line *dl, int xpos,
1813 struct frame *f = XFRAME(w->frame);
1814 struct device *d = XDEVICE(f->device);
1817 Display *dpy = DEVICE_X_DISPLAY(d);
1818 Window x_win = XtWindow(FRAME_X_TEXT_WIDGET(f));
1820 face_index elt = get_builtin_face_cache_index(w, Vtext_cursor_face);
1821 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL(w, elt);
1823 int focus = EQ(w->frame, DEVICE_FRAME_WITH_FOCUS_REAL(d));
1824 Lisp_Object bar_cursor_value = symbol_value_in_buffer(Qbar_cursor,
1828 int y = DISPLAY_LINE_YPOS(dl);
1829 int width = EOL_CURSOR_WIDTH;
1830 int height = DISPLAY_LINE_HEIGHT(dl);
1831 int cursor_height, cursor_y;
1832 int defheight, defascent;
1834 XSETWINDOW(window, w);
1835 redisplay_clear_region(window, findex, x, y, width, height);
1837 if (NILP(w->text_cursor_visible_p))
1840 gc = x_get_gc(d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1842 default_face_font_info(window, &defascent, 0, &defheight, 0, 0);
1844 /* make sure the cursor is entirely contained between y and y+height */
1845 cursor_height = min(defheight, height);
1846 cursor_y = max(y, min(y + height - cursor_height,
1847 dl->ypos - defascent));
1851 XIM_SetSpotLocation(f, x - 2, cursor_y + cursor_height - 2);
1852 #endif /* HAVE_XIM */
1854 if (NILP(bar_cursor_value)) {
1855 XFillRectangle(dpy, x_win, gc, x, cursor_y, width,
1858 int bar_width = EQ(bar_cursor_value, Qt) ? 1 : 2;
1860 gc = x_get_gc(d, Qnil, cursor_cachel->background, Qnil,
1861 Qnil, make_int(bar_width));
1862 XDrawLine(dpy, x_win, gc, x + bar_width - 1, cursor_y,
1864 cursor_y + cursor_height - 1);
1866 } else if (NILP(bar_cursor_value)) {
1867 XDrawRectangle(dpy, x_win, gc, x, cursor_y, width - 1,
1872 static void x_clear_frame_window(Lisp_Object window)
1874 struct window *w = XWINDOW(window);
1876 if (!NILP(w->vchild)) {
1877 x_clear_frame_windows(w->vchild);
1881 if (!NILP(w->hchild)) {
1882 x_clear_frame_windows(w->hchild);
1886 redisplay_clear_to_window_end(w, WINDOW_TEXT_TOP(w),
1887 WINDOW_TEXT_BOTTOM(w));
1890 static void x_clear_frame_windows(Lisp_Object window)
1892 for (; !NILP(window); window = XWINDOW(window)->next)
1893 x_clear_frame_window(window);
1896 static void x_clear_frame(struct frame *f)
1898 struct device *d = XDEVICE(f->device);
1899 Display *dpy = DEVICE_X_DISPLAY(d);
1900 Window x_win = XtWindow(FRAME_X_TEXT_WIDGET(f));
1901 int x, y, width, height;
1904 x = FRAME_LEFT_BORDER_START(f);
1905 width = (FRAME_PIXWIDTH(f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH(f) -
1906 FRAME_REAL_RIGHT_TOOLBAR_WIDTH(f) -
1907 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH(f) -
1908 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH(f));
1909 /* #### This adjustment by 1 should be being done in the macros.
1910 There is some small differences between when the menubar is on
1911 and off that we still need to deal with. */
1912 y = FRAME_TOP_BORDER_START(f) - 1;
1913 height = (FRAME_PIXHEIGHT(f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT(f) -
1914 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT(f) -
1915 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH(f) -
1916 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH(f)) + 1;
1918 XClearArea(dpy, x_win, x, y, width, height, False);
1920 XSETFRAME(frame, f);
1922 if (!UNBOUNDP(FACE_BACKGROUND_PIXMAP(Vdefault_face, frame))
1923 || !UNBOUNDP(FACE_BACKGROUND_PIXMAP(Vleft_margin_face, frame))
1924 || !UNBOUNDP(FACE_BACKGROUND_PIXMAP(Vright_margin_face, frame))) {
1925 x_clear_frame_windows(f->root_window);
1928 XFlush(DEVICE_X_DISPLAY(d));
1931 /* briefly swap the foreground and background colors.
1934 static int x_flash(struct device *d)
1940 XColor tmp_fcolor, tmp_bcolor;
1941 Lisp_Object tmp_pixel, frame;
1942 struct frame *f = device_selected_frame(d);
1943 struct window *w = XWINDOW(FRAME_ROOT_WINDOW(f));
1944 Widget shell = FRAME_X_SHELL_WIDGET(f);
1947 XSETFRAME(frame, f);
1949 tmp_pixel = FACE_FOREGROUND(Vdefault_face, frame);
1950 tmp_fcolor = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(tmp_pixel));
1951 tmp_pixel = FACE_BACKGROUND(Vdefault_face, frame);
1952 tmp_bcolor = COLOR_INSTANCE_X_COLOR(XCOLOR_INSTANCE(tmp_pixel));
1954 dpy = XtDisplay(shell);
1955 win = XtWindow(FRAME_X_TEXT_WIDGET(f));
1956 memset(&gcv, ~0, sizeof(XGCValues)); /* initialize all slots to ~0 */
1957 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
1958 gcv.function = GXxor;
1959 gcv.graphics_exposures = False;
1960 gc = gc_cache_lookup(DEVICE_X_GC_CACHE(XDEVICE(f->device)), &gcv,
1961 (GCForeground | GCFunction | GCGraphicsExposures));
1962 default_face_height_and_width(frame, &flash_height, 0);
1964 /* If window is tall, flash top and bottom line. */
1965 if (EQ(Vvisible_bell, Qtop_bottom)
1966 && w->pixel_height > 3 * flash_height) {
1967 XFillRectangle(dpy, win, gc, w->pixel_left, w->pixel_top,
1968 w->pixel_width, flash_height);
1969 XFillRectangle(dpy, win, gc, w->pixel_left,
1970 w->pixel_top + w->pixel_height - flash_height,
1971 w->pixel_width, flash_height);
1973 /* If it is short, flash it all. */
1974 XFillRectangle(dpy, win, gc, w->pixel_left, w->pixel_top,
1975 w->pixel_width, w->pixel_height);
1983 tv.tv_sec = usecs / 1000000L;
1984 tv.tv_usec = usecs % 1000000L;
1985 /* I'm sure someone is going to complain about this... */
1986 select(0, 0, 0, 0, &tv);
1991 #else /* !HAVE_POLL */
1993 #endif /* HAVE_POLL */
1994 #endif /* HAVE_SELECT */
1995 /* If window is tall, flash top and bottom line. */
1996 if (EQ(Vvisible_bell, Qtop_bottom)
1997 && w->pixel_height > 3 * flash_height) {
1998 XFillRectangle(dpy, win, gc, w->pixel_left, w->pixel_top,
1999 w->pixel_width, flash_height);
2000 XFillRectangle(dpy, win, gc, w->pixel_left,
2001 w->pixel_top + w->pixel_height - flash_height,
2002 w->pixel_width, flash_height);
2004 /* If it is short, flash it all. */
2005 XFillRectangle(dpy, win, gc, w->pixel_left, w->pixel_top,
2006 w->pixel_width, w->pixel_height);
2013 /* Make audible bell. */
2015 static void x_ring_bell(struct device *d, int volume, int pitch, int duration)
2017 Display *display = DEVICE_X_DISPLAY(d);
2021 else if (volume > 100)
2023 if (pitch < 0 && duration < 0) {
2024 XBell(display, (volume * 2) - 100);
2027 XKeyboardState state;
2028 XKeyboardControl ctl;
2030 /* #### grab server? */
2031 XGetKeyboardControl(display, &state);
2033 ctl.bell_pitch = (pitch >= 0 ? pitch : (int)state.bell_pitch);
2035 (duration >= 0 ? duration : (int)state.bell_duration);
2036 XChangeKeyboardControl(display, KBBellPitch | KBBellDuration,
2039 XBell(display, (volume * 2) - 100);
2041 ctl.bell_pitch = state.bell_pitch;
2042 ctl.bell_duration = state.bell_duration;
2043 XChangeKeyboardControl(display, KBBellPitch | KBBellDuration,
2046 /* #### ungrab server? */
2051 /************************************************************************/
2052 /* initialization */
2053 /************************************************************************/
2055 void console_type_create_redisplay_x(void)
2057 /* redisplay methods */
2058 CONSOLE_HAS_METHOD(x, text_width);
2059 CONSOLE_HAS_METHOD(x, output_display_block);
2060 CONSOLE_HAS_METHOD(x, divider_height);
2061 CONSOLE_HAS_METHOD(x, eol_cursor_width);
2062 CONSOLE_HAS_METHOD(x, output_vertical_divider);
2063 CONSOLE_HAS_METHOD(x, clear_region);
2064 CONSOLE_HAS_METHOD(x, clear_frame);
2065 CONSOLE_HAS_METHOD(x, window_output_begin);
2066 CONSOLE_HAS_METHOD(x, window_output_end);
2067 CONSOLE_HAS_METHOD(x, flash);
2068 CONSOLE_HAS_METHOD(x, ring_bell);
2069 CONSOLE_HAS_METHOD(x, bevel_area);
2070 CONSOLE_HAS_METHOD(x, output_string);
2071 CONSOLE_HAS_METHOD(x, output_pixmap);