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 int x_interline_space; /* #### implement me */
59 #define EOL_CURSOR_WIDTH 5
61 static void x_output_vertical_divider (struct window *w, int clear);
62 static void x_output_blank (struct window *w, struct display_line *dl,
63 struct rune *rb, int start_pixpos,
64 int cursor_start, int cursor_width);
65 static void x_output_hline (struct window *w, struct display_line *dl,
67 static void x_redraw_exposed_window (struct window *w, int x, int y,
68 int width, int height);
69 static void x_redraw_exposed_windows (Lisp_Object window, int x, int y,
70 int width, int height);
71 static void x_output_eol_cursor (struct window *w, struct display_line *dl,
72 int xpos, face_index findex);
73 static void x_clear_frame (struct frame *f);
74 static void x_clear_frame_windows (Lisp_Object window);
77 /* Note: We do not use the Xmb*() functions and XFontSets.
78 Those functions are generally losing for a number of reasons:
80 1) They only support one locale (e.g. you could display
81 Japanese and ASCII text, but not mixed Japanese/Chinese
82 text). You could maybe call setlocale() frequently
83 to try to deal with this, but that would generally
84 fail because an XFontSet is tied to one locale and
85 won't have the other character sets in it.
86 2) Not all (or even very many) OS's support the useful
87 locales. For example, as far as I know SunOS and
88 Solaris only support the Japanese locale if you get the
89 special Asian-language version of the OS. Yuck yuck
90 yuck. Linux doesn't support the Japanese locale at
92 3) The locale support in X only exists in R5, not in R4.
93 (Not sure how big of a problem this is: how many
95 4) Who knows if the multi-byte text format (which is locale-
96 specific) is even the same for the same locale on
97 different OS's? It's not even documented anywhere that
98 I can find what the multi-byte text format for the
99 Japanese locale under SunOS and Solaris is, but I assume
111 /* Separate out the text in DYN into a series of textual runs of a
112 particular charset. Also convert the characters as necessary into
113 the format needed by XDrawImageString(), XDrawImageString16(), et
114 al. (This means converting to one or two byte format, possibly
115 tweaking the high bits, and possibly running a CCL program.) You
116 must pre-allocate the space used and pass it in. (This is done so
117 you can alloca() the space.) You need to allocate (2 * len) bytes
118 of TEXT_STORAGE and (len * sizeof (struct textual_run)) bytes of
119 RUN_STORAGE, where LEN is the length of the dynarr.
121 Returns the number of runs actually used. */
124 separate_textual_runs (unsigned char *text_storage,
125 struct textual_run *run_storage,
126 const Emchar *str, Charcount len)
128 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a
129 possible valid charset when
130 MULE is not defined */
134 struct ccl_program char_converter;
135 int need_ccl_conversion = 0;
138 for (i = 0; i < len; i++)
146 BREAKUP_CHAR (ch, charset, byte1, byte2);
147 dimension = XCHARSET_DIMENSION (charset);
148 graphic = XCHARSET_GRAPHIC (charset);
150 if (!EQ (charset, prev_charset))
152 run_storage[runs_so_far].ptr = text_storage;
153 run_storage[runs_so_far].charset = charset;
154 run_storage[runs_so_far].dimension = dimension;
158 run_storage[runs_so_far - 1].len =
159 text_storage - run_storage[runs_so_far - 1].ptr;
160 if (run_storage[runs_so_far - 1].dimension == 2)
161 run_storage[runs_so_far - 1].len >>= 1;
164 prev_charset = charset;
167 Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset);
168 if ((!NILP (ccl_prog))
169 && (setup_ccl_program (&char_converter, ccl_prog) >= 0))
170 need_ccl_conversion = 1;
180 else if (graphic == 1)
186 if (need_ccl_conversion)
188 char_converter.reg[0] = XCHARSET_ID (charset);
189 char_converter.reg[1] = byte1;
190 char_converter.reg[2] = byte2;
191 ccl_driver (&char_converter, 0, 0, 0, 0, CCL_MODE_ENCODING);
192 byte1 = char_converter.reg[1];
193 byte2 = char_converter.reg[2];
196 *text_storage++ = (unsigned char) byte1;
198 *text_storage++ = (unsigned char) byte2;
203 run_storage[runs_so_far - 1].len =
204 text_storage - run_storage[runs_so_far - 1].ptr;
205 if (run_storage[runs_so_far - 1].dimension == 2)
206 run_storage[runs_so_far - 1].len >>= 1;
212 /****************************************************************************/
214 /* X output routines */
216 /****************************************************************************/
219 x_text_width_single_run (struct face_cachel *cachel, struct textual_run *run)
221 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
222 Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
223 if (!fi->proportional_p)
224 return fi->width * run->len;
227 if (run->dimension == 2)
228 return XTextWidth16 (FONT_INSTANCE_X_FONT (fi),
229 (XChar2b *) run->ptr, run->len);
231 return XTextWidth (FONT_INSTANCE_X_FONT (fi),
232 (char *) run->ptr, run->len);
239 Given a string and a face, return the string's length in pixels when
240 displayed in the font associated with the face.
244 x_text_width (struct frame *f, struct face_cachel *cachel, const Emchar *str,
247 int width_so_far = 0;
248 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
249 struct textual_run *runs = alloca_array (struct textual_run, len);
253 nruns = separate_textual_runs (text_storage, runs, str, len);
255 for (i = 0; i < nruns; i++)
256 width_so_far += x_text_width_single_run (cachel, runs + i);
261 /*****************************************************************************
264 Return the height of the horizontal divider. This is a function because
265 divider_height is a device method.
267 #### If we add etched horizontal divider lines this will have to get
269 ****************************************************************************/
271 x_divider_height (void)
276 /*****************************************************************************
279 Return the width of the end-of-line cursor. This is a function
280 because eol_cursor_width is a device method.
281 ****************************************************************************/
283 x_eol_cursor_width (void)
285 return EOL_CURSOR_WIDTH;
288 /*****************************************************************************
289 x_window_output_begin
291 Perform any necessary initialization prior to an update.
292 ****************************************************************************/
294 x_window_output_begin (struct window *w)
298 /*****************************************************************************
301 Perform any necessary flushing of queues when an update has completed.
302 ****************************************************************************/
304 x_window_output_end (struct window *w)
306 XFlush (DEVICE_X_DISPLAY (WINDOW_XDEVICE (w)));
309 /*****************************************************************************
310 x_output_display_block
312 Given a display line, a block number for that start line, output all
313 runes between start and end in the specified display block.
314 ****************************************************************************/
316 x_output_display_block (struct window *w, struct display_line *dl, int block,
317 int start, int end, int start_pixpos, int cursor_start,
318 int cursor_width, int cursor_height)
320 struct frame *f = XFRAME (w->frame);
321 Emchar_dynarr *buf = Dynarr_new (Emchar);
324 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
325 rune_dynarr *rba = db->runes;
331 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
332 MULE is not defined */
334 XSETWINDOW (window, w);
335 rb = Dynarr_atp (rba, start);
338 /* Nothing to do so don't do anything. */
343 if (rb->type == RUNE_CHAR)
344 charset = CHAR_CHARSET (rb->object.chr.ch);
347 end = Dynarr_length (rba);
352 rb = Dynarr_atp (rba, elt);
354 if (rb->findex == findex && rb->type == RUNE_CHAR
355 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
356 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
358 Dynarr_add (buf, rb->object.chr.ch);
364 if (Dynarr_length (buf))
366 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
367 findex, 0, cursor_start, cursor_width,
375 if (rb->type == RUNE_CHAR)
379 charset = CHAR_CHARSET (rb->object.chr.ch);
381 if (rb->cursor_type == CURSOR_ON)
383 if (rb->object.chr.ch == '\n')
385 x_output_eol_cursor (w, dl, xpos, findex);
389 Dynarr_add (buf, rb->object.chr.ch);
390 x_output_string (w, dl, buf, xpos, 0, start_pixpos,
391 rb->width, findex, 1,
392 cursor_start, cursor_width,
400 else if (rb->object.chr.ch == '\n')
402 /* Clear in case a cursor was formerly here. */
403 redisplay_clear_region (window, findex, xpos,
404 DISPLAY_LINE_YPOS (dl),
406 DISPLAY_LINE_HEIGHT (dl));
410 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
412 if (rb->type == RUNE_BLANK)
413 x_output_blank (w, dl, rb, start_pixpos, cursor_start,
417 /* #### Our flagging of when we need to redraw the
418 modeline shadows sucks. Since RUNE_HLINE is only used
419 by the modeline at the moment it is a good bet
420 that if it gets redrawn then we should also
421 redraw the shadows. This won't be true forever.
422 We borrow the shadow_thickness_changed flag for
424 w->shadow_thickness_changed = 1;
425 x_output_hline (w, dl, rb);
431 rb = Dynarr_atp (rba, elt);
437 else if (rb->type == RUNE_DGLYPH)
439 Lisp_Object instance;
440 struct display_box dbox;
441 struct display_glyph_area dga;
443 redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset,
444 rb->object.dglyph.yoffset, start_pixpos,
445 rb->width, &dbox, &dga);
447 XSETWINDOW (window, w);
448 instance = glyph_image_instance (rb->object.dglyph.glyph,
449 window, ERROR_ME_NOT, 1);
452 if (IMAGE_INSTANCEP (instance))
454 switch (XIMAGE_INSTANCE_TYPE (instance))
456 case IMAGE_MONO_PIXMAP:
457 case IMAGE_COLOR_PIXMAP:
458 redisplay_output_pixmap (w, instance, &dbox, &dga, findex,
459 cursor_start, cursor_width,
464 if (EQ (XIMAGE_INSTANCE_WIDGET_TYPE (instance),
467 redisplay_output_layout (window, instance, &dbox, &dga, findex,
468 cursor_start, cursor_width,
472 case IMAGE_SUBWINDOW:
473 redisplay_output_subwindow (w, instance, &dbox, &dga, findex,
474 cursor_start, cursor_width,
479 /* nothing is as nothing does */
487 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
488 (XIMAGE_INSTANCE (instance)) = 0;
499 if (Dynarr_length (buf))
500 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
501 0, cursor_start, cursor_width, cursor_height);
503 /* #### This is really conditionalized well for optimized
506 && !EQ (Qzero, w->modeline_shadow_thickness)
508 || f->windows_structure_changed
509 || w->shadow_thickness_changed))
510 bevel_modeline (w, dl);
515 /*****************************************************************************
518 Draw shadows for the given area in the given face.
519 ****************************************************************************/
521 x_bevel_area (struct window *w, face_index findex,
522 int x, int y, int width, int height,
523 int shadow_thickness, int edges, enum edge_style style)
525 struct frame *f = XFRAME (w->frame);
526 struct device *d = XDEVICE (f->device);
528 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
529 Display *dpy = DEVICE_X_DISPLAY (d);
530 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
531 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
532 Lisp_Object tmp_pixel;
535 GC top_shadow_gc, bottom_shadow_gc, background_gc;
541 assert (shadow_thickness >=0);
542 memset (&gcv, ~0, sizeof (XGCValues));
544 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
545 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
547 /* First, get the GC's. */
548 top_shadow_pixel = tmp_color.pixel;
549 bottom_shadow_pixel = tmp_color.pixel;
550 background_pixel = tmp_color.pixel;
552 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
553 background_pixel, ef->core.background_pixel);
555 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
556 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
557 gcv.background = tmp_color.pixel;
558 gcv.graphics_exposures = False;
559 mask = GCForeground | GCBackground | GCGraphicsExposures;
561 /* If we can't distinguish one of the shadows (the color is the same as the
562 background), it's better to use a pixmap to generate a dithered gray. */
563 if (top_shadow_pixel == background_pixel ||
564 bottom_shadow_pixel == background_pixel)
569 if (DEVICE_X_GRAY_PIXMAP (d) == None)
571 DEVICE_X_GRAY_PIXMAP (d) =
572 XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
573 gray_width, gray_height, 1, 0, 1);
576 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
577 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
578 gcv.foreground = tmp_color.pixel;
579 /* this is needed because the GC draws with a pixmap here */
580 gcv.fill_style = FillOpaqueStippled;
581 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
582 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
583 (mask | GCStipple | GCFillStyle));
585 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
586 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
587 bottom_shadow_pixel = tmp_color.pixel;
589 flip_gcs = (bottom_shadow_pixel ==
590 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
594 gcv.foreground = top_shadow_pixel;
595 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
598 gcv.foreground = bottom_shadow_pixel;
599 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
601 if (use_pixmap && flip_gcs)
603 GC tmp_gc = bottom_shadow_gc;
604 bottom_shadow_gc = top_shadow_gc;
605 top_shadow_gc = tmp_gc;
608 gcv.foreground = background_pixel;
609 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
611 /* possibly revert the GC's This will give a depressed look to the
613 if (style == EDGE_ETCHED_IN || style == EDGE_BEVEL_IN)
617 temp = top_shadow_gc;
618 top_shadow_gc = bottom_shadow_gc;
619 bottom_shadow_gc = temp;
622 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
623 shadow_thickness /= 2;
625 /* Draw the shadows around the divider line */
626 x_output_shadows (f, x, y, width, height,
627 top_shadow_gc, bottom_shadow_gc,
628 background_gc, shadow_thickness, edges);
630 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
632 /* Draw the shadows around the divider line */
633 x_output_shadows (f, x + shadow_thickness, y + shadow_thickness,
634 width - 2*shadow_thickness, height - 2*shadow_thickness,
635 bottom_shadow_gc, top_shadow_gc,
636 background_gc, shadow_thickness, edges);
640 /*****************************************************************************
643 Given a number of parameters return a GC with those properties.
644 ****************************************************************************/
646 x_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
647 Lisp_Object bg_pmap, Lisp_Object lwidth)
652 memset (&gcv, ~0, sizeof (XGCValues));
653 gcv.graphics_exposures = False;
654 /* Make absolutely sure that we don't pick up a clipping region in
655 the GC returned by this function. */
656 gcv.clip_mask = None;
657 gcv.clip_x_origin = 0;
658 gcv.clip_y_origin = 0;
659 gcv.fill_style = FillSolid;
660 mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
665 gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
670 if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg))
672 /* #### I fixed once case where this was getting it. It was a
673 bad macro expansion (compiler bug). */
674 stderr_out ("Help! x_get_gc got a bogus fg value! fg = ");
681 if (COLOR_INSTANCEP (fg))
682 gcv.foreground = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (fg)).pixel;
684 gcv.foreground = XINT (fg);
685 mask |= GCForeground;
690 if (COLOR_INSTANCEP (bg))
691 gcv.background = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (bg)).pixel;
693 gcv.background = XINT (bg);
694 mask |= GCBackground;
697 /* This special case comes from a request to draw text with a face which has
698 the dim property. We'll use a stippled foreground GC. */
699 if (EQ (bg_pmap, Qdim))
701 assert (DEVICE_X_GRAY_PIXMAP (d) != None);
703 gcv.fill_style = FillStippled;
704 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
705 mask |= (GCFillStyle | GCStipple);
707 else if (IMAGE_INSTANCEP (bg_pmap)
708 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
710 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
712 gcv.fill_style = FillOpaqueStippled;
713 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
714 mask |= (GCStipple | GCFillStyle);
718 gcv.fill_style = FillTiled;
719 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
720 mask |= (GCTile | GCFillStyle);
726 gcv.line_width = XINT (lwidth);
730 return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
733 /*****************************************************************************
736 Given a string and a starting position, output that string in the
737 given face. If cursor is true, draw a cursor around the string.
738 Correctly handles multiple charsets in the string.
740 The meaning of the parameters is something like this:
742 W Window that the text is to be displayed in.
743 DL Display line that this text is on. The values in the
744 structure are used to determine the vertical position and
745 clipping range of the text.
746 BUF Dynamic array of Emchars specifying what is actually to be
748 XPOS X position in pixels where the text should start being drawn.
749 XOFFSET Number of pixels to be chopped off the left side of the
750 text. The effect is as if the text were shifted to the
751 left this many pixels and clipped at XPOS.
752 CLIP_START Clip everything left of this X position.
753 WIDTH Clip everything right of XPOS + WIDTH.
754 FINDEX Index for the face cache element describing how to display
756 CURSOR #### I don't understand this. There's something
757 strange and overcomplexified with this variable.
758 Chuck, explain please?
759 CURSOR_START Starting X position of cursor.
760 CURSOR_WIDTH Width of cursor in pixels.
761 CURSOR_HEIGHT Height of cursor in pixels.
763 Starting Y position of cursor is the top of the text line.
764 The cursor is drawn sometimes whether or not CURSOR is set. ???
765 ****************************************************************************/
767 x_output_string (struct window *w, struct display_line *dl,
768 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
769 int width, face_index findex, int cursor,
770 int cursor_start, int cursor_width, int cursor_height)
772 /* General variables */
773 struct frame *f = XFRAME (w->frame);
774 struct device *d = XDEVICE (f->device);
777 Display *dpy = DEVICE_X_DISPLAY (d);
778 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
782 /* Cursor-related variables */
783 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
785 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
787 struct face_cachel *cursor_cachel = 0;
789 /* Text-related variables */
793 int len = Dynarr_length (buf);
794 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
795 struct textual_run *runs = alloca_array (struct textual_run, len);
798 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
800 XSETDEVICE (device, d);
801 XSETWINDOW (window, w);
804 width = x_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
805 height = DISPLAY_LINE_HEIGHT (dl);
807 /* Regularize the variables passed in. */
809 if (clip_start < xpos)
811 clip_end = xpos + width;
812 if (clip_start >= clip_end)
813 /* It's all clipped out. */
818 /* make sure the area we are about to display is subwindow free. */
819 redisplay_unmap_subwindows_maybe (f, clip_start, DISPLAY_LINE_YPOS (dl),
820 clip_end - clip_start, DISPLAY_LINE_HEIGHT (dl));
822 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
823 Dynarr_length (buf));
825 cursor_clip = (cursor_start >= clip_start &&
826 cursor_start < clip_end);
828 /* This cursor code is really a mess. */
829 if (!NILP (w->text_cursor_visible_p)
833 && (cursor_start + cursor_width >= clip_start)
834 && !NILP (bar_cursor_value))))
836 /* These have to be in separate statements in order to avoid a
838 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face);
839 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks);
841 /* We have to reset this since any call to WINDOW_FACE_CACHEL
842 may cause the cache to resize and any pointers to it to
844 cachel = WINDOW_FACE_CACHEL (w, findex);
848 if (cursor && focus && (cursor_start == clip_start) && cursor_height)
849 XIM_SetSpotLocation (f, xpos - 2, dl->ypos + dl->descent - 2);
850 #endif /* HAVE_XIM */
852 bg_pmap = cachel->background_pixmap;
853 if (!IMAGE_INSTANCEP (bg_pmap)
854 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
857 if ((cursor && focus && NILP (bar_cursor_value)
858 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap))
861 bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
865 XFillRectangle (dpy, x_win, bgc, clip_start,
866 DISPLAY_LINE_YPOS (dl), clip_end - clip_start,
869 for (i = 0; i < nruns; i++)
871 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
872 Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
876 if (EQ (font, Vthe_null_font_instance))
879 this_width = x_text_width_single_run (cachel, runs + i);
880 need_clipping = (dl->clip || clip_start > xpos ||
881 clip_end < xpos + this_width);
883 /* XDrawImageString only clears the area equal to the height of
884 the given font. It is possible that a font is being displayed
885 on a line taller than it is, so this would cause us to fail to
887 if ((int) fi->height < (int) (height + dl->clip + dl->top_clip))
889 int clear_start = max (xpos, clip_start);
890 int clear_end = min (xpos + this_width, clip_end);
894 int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
896 ypos1_string = dl->ypos - fi->ascent;
897 ypos2_string = dl->ypos + fi->descent;
898 ypos1_line = DISPLAY_LINE_YPOS (dl);
899 ypos2_line = ypos1_line + DISPLAY_LINE_HEIGHT (dl);
901 /* Make sure we don't clear below the real bottom of the
903 if (ypos1_string > ypos2_line)
904 ypos1_string = ypos2_line;
905 if (ypos2_string > ypos2_line)
906 ypos2_string = ypos2_line;
908 if (ypos1_line < ypos1_string)
910 redisplay_clear_region (window, findex, clear_start, ypos1_line,
911 clear_end - clear_start,
912 ypos1_string - ypos1_line);
915 if (ypos2_line > ypos2_string)
917 redisplay_clear_region (window, findex, clear_start, ypos2_string,
918 clear_end - clear_start,
919 ypos2_line - ypos2_string);
924 redisplay_clear_region (window, findex, clear_start,
925 DISPLAY_LINE_YPOS (dl), clear_end - clear_start,
930 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value))
931 gc = x_get_gc (d, font, cursor_cachel->foreground,
932 cursor_cachel->background, Qnil, Qnil);
933 else if (cachel->dim)
935 /* Ensure the gray bitmap exists */
936 if (DEVICE_X_GRAY_PIXMAP (d) == None)
937 DEVICE_X_GRAY_PIXMAP (d) =
938 XCreateBitmapFromData (dpy, x_win, (char *)gray_bits,
939 gray_width, gray_height);
941 /* Request a GC with the gray stipple pixmap to draw dimmed text */
942 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
946 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
951 XRectangle clip_box[1];
955 clip_box[0].width = clip_end - clip_start;
956 clip_box[0].height = height;
958 XSetClipRectangles (dpy, gc, clip_start, DISPLAY_LINE_YPOS (dl),
959 clip_box, 1, Unsorted);
962 if (runs[i].dimension == 1)
963 (bgc ? XDrawString : XDrawImageString) (dpy, x_win, gc, xpos,
964 dl->ypos, (char *) runs[i].ptr,
967 (bgc ? XDrawString16 : XDrawImageString16) (dpy, x_win, gc, xpos,
969 (XChar2b *) runs[i].ptr,
972 /* We draw underlines in the same color as the text. */
973 if (cachel->underline)
975 /* upos is naturally signed, why would anyone think otherwise?
976 uthick is signed to avoid unsigned propagation. */
980 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
981 if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos))
982 upos = dl->descent / 2;
983 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
986 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
988 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
989 uthick = dl->descent - dl->clip - upos;
993 XDrawLine (dpy, x_win, gc, xpos, dl->ypos + upos,
994 xpos + this_width, dl->ypos + upos);
998 XFillRectangle (dpy, x_win, gc, xpos,
999 dl->ypos + upos, this_width, uthick);
1004 if (cachel->strikethru) {
1005 /* ascent, descent, and upos are naturally signed; why would anyone
1006 think otherwise? uthick is signed to avoid unsigned propagation. */
1007 long ascent, descent, upos, uthick;
1010 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
1012 if (!XGetFontProperty (xfont, XA_STRIKEOUT_ASCENT, &ascent))
1013 ascent = xfont->ascent;
1014 if (!XGetFontProperty (xfont, XA_STRIKEOUT_DESCENT, &descent))
1015 descent = xfont->descent;
1016 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
1019 upos = ascent - ((ascent + descent) / 2) + 1;
1021 /* Generally, upos will be positive (above the baseline),so subtract */
1022 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip)
1024 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip)
1025 uthick = dl->descent - dl->clip + upos;
1029 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos,
1030 xpos + this_width, dl->ypos - upos);
1032 else if (uthick > 1)
1034 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos,
1035 this_width, uthick);
1040 /* Restore the GC */
1043 XSetClipMask (dpy, gc, None);
1044 XSetClipOrigin (dpy, gc, 0, 0);
1047 /* If we are actually superimposing the cursor then redraw with just
1048 the appropriate section highlighted. */
1049 if (cursor_clip && !cursor && focus && cursor_cachel)
1052 XRectangle clip_box[1];
1054 cgc = x_get_gc (d, font, cursor_cachel->foreground,
1055 cursor_cachel->background, Qnil, Qnil);
1059 clip_box[0].width = cursor_width;
1060 clip_box[0].height = height;
1062 XSetClipRectangles (dpy, cgc, cursor_start, DISPLAY_LINE_YPOS (dl),
1063 clip_box, 1, Unsorted);
1065 if (runs[i].dimension == 1)
1066 XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
1067 (char *) runs[i].ptr, runs[i].len);
1069 XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
1070 (XChar2b *) runs[i].ptr, runs[i].len);
1072 XSetClipMask (dpy, cgc, None);
1073 XSetClipOrigin (dpy, cgc, 0, 0);
1079 /* Draw the non-focus box or bar-cursor as needed. */
1080 /* Can't this logic be simplified? */
1082 && ((cursor && !focus && NILP (bar_cursor_value))
1084 && (cursor_start + cursor_width >= clip_start)
1085 && !NILP (bar_cursor_value))))
1087 int tmp_height, tmp_y;
1088 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1089 int need_clipping = (cursor_start < clip_start
1090 || clip_end < cursor_start + cursor_width);
1092 /* #### This value is correct (as far as I know) because
1093 all of the times we need to draw this cursor, we will
1094 be called with exactly one character, so we know we
1095 can always use runs[0].
1097 This is bogus as all hell, however. The cursor handling in
1098 this function is way bogus and desperately needs to be
1099 cleaned up. (In particular, the drawing of the cursor should
1100 really really be separated out of this function. This may be
1101 a bit tricky now because this function itself does way too
1102 much stuff, a lot of which needs to be moved into
1103 redisplay.c) This is the only way to be able to easily add
1104 new cursor types or (e.g.) make the bar cursor be able to
1105 span two characters instead of overlaying just one. */
1106 int bogusly_obtained_ascent_value =
1107 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent;
1109 if (!NILP (bar_cursor_value))
1111 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1112 make_int (bar_width));
1116 gc = x_get_gc (d, Qnil, cursor_cachel->background,
1120 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1121 tmp_height = cursor_height;
1122 if (tmp_y + tmp_height > (int) (DISPLAY_LINE_YPOS(dl) + height))
1124 tmp_y = DISPLAY_LINE_YPOS (dl) + height - tmp_height;
1125 if (tmp_y < (int) DISPLAY_LINE_YPOS (dl))
1126 tmp_y = DISPLAY_LINE_YPOS (dl);
1127 tmp_height = DISPLAY_LINE_YPOS (dl) + height - tmp_y;
1132 XRectangle clip_box[1];
1135 clip_box[0].width = clip_end - clip_start;
1136 clip_box[0].height = tmp_height;
1137 XSetClipRectangles (dpy, gc, clip_start, tmp_y,
1138 clip_box, 1, Unsorted);
1141 if (!focus && NILP (bar_cursor_value))
1143 XDrawRectangle (dpy, x_win, gc, cursor_start, tmp_y,
1144 cursor_width - 1, tmp_height - 1);
1146 else if (focus && !NILP (bar_cursor_value))
1148 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1, tmp_y,
1149 cursor_start + bar_width - 1, tmp_y + tmp_height - 1);
1152 /* Restore the GC */
1155 XSetClipMask (dpy, gc, None);
1156 XSetClipOrigin (dpy, gc, 0, 0);
1162 x_output_x_pixmap (struct frame *f, Lisp_Image_Instance *p, int x,
1163 int y, int xoffset, int yoffset,
1164 int width, int height, unsigned long fg, unsigned long bg,
1167 struct device *d = XDEVICE (f->device);
1168 Display *dpy = DEVICE_X_DISPLAY (d);
1169 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1173 unsigned long pixmap_mask;
1177 memset (&gcv, ~0, sizeof (XGCValues));
1178 gcv.graphics_exposures = False;
1179 gcv.foreground = fg;
1180 gcv.background = bg;
1181 pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
1183 if (IMAGE_INSTANCE_X_MASK (p))
1185 gcv.function = GXcopy;
1186 gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
1187 gcv.clip_x_origin = x - xoffset;
1188 gcv.clip_y_origin = y - yoffset;
1189 pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
1191 /* Can't set a clip rectangle because we already have a mask.
1192 Is it possible to get an equivalent effect by changing the
1193 args to XCopyArea below rather than messing with a clip box?
1194 - dkindred@cs.cmu.edu
1195 Yes. We don't clip at all now - andy@xemacs.org
1199 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
1204 /* override_gc might have a mask already--we don't want to nuke it.
1205 Maybe we can insist that override_gc have no mask, or use
1206 one of the suggestions above. */
1209 /* depth of 0 means it's a bitmap, not a pixmap, and we should use
1210 XCopyPlane (1 = current foreground color, 0 = background) instead
1211 of XCopyArea, which means that the bits in the pixmap are actual
1212 pixel values, instead of symbolic of fg/bg. */
1213 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
1216 IMAGE_INSTANCE_X_PIXMAP_SLICE
1217 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc, xoffset,
1223 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP_SLICE
1224 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc,
1225 xoffset, yoffset, width, height, x, y, 1L);
1230 x_output_pixmap (struct window *w, Lisp_Object image_instance,
1231 struct display_box *db, struct display_glyph_area *dga,
1232 face_index findex, int cursor_start, int cursor_width,
1233 int cursor_height, int bg_pixmap)
1235 struct frame *f = XFRAME (w->frame);
1236 struct device *d = XDEVICE (f->device);
1237 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1239 Display *dpy = DEVICE_X_DISPLAY (d);
1240 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1242 /* Output the pixmap. */
1244 Lisp_Object tmp_pixel;
1245 XColor tmp_bcolor, tmp_fcolor;
1247 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1248 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1249 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1250 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1252 x_output_x_pixmap (f, p, db->xpos, db->ypos,
1253 dga->xoffset, dga->yoffset,
1254 dga->width, dga->height,
1255 tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
1258 /* Draw a cursor over top of the pixmap. */
1259 if (cursor_width && cursor_height && (cursor_start >= db->xpos)
1260 && !NILP (w->text_cursor_visible_p)
1261 && (cursor_start < db->xpos + dga->width))
1264 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1265 struct face_cachel *cursor_cachel =
1266 WINDOW_FACE_CACHEL (w,
1267 get_builtin_face_cache_index
1268 (w, Vtext_cursor_face));
1270 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1272 if (cursor_width > db->xpos + dga->width - cursor_start)
1273 cursor_width = db->xpos + dga->width - cursor_start;
1277 XFillRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1282 XDrawRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1288 /*****************************************************************************
1289 x_output_vertical_divider
1291 Draw a vertical divider down the right side of the given window.
1292 ****************************************************************************/
1294 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, y1, y2, width, shadow_thickness, spacing, line_width;
1309 face_index div_face = get_builtin_face_cache_index (w, Vvertical_divider_face);
1311 width = window_divider_width (w);
1312 shadow_thickness = XINT (w->vertical_divider_shadow_thickness);
1313 spacing = XINT (w->vertical_divider_spacing);
1314 line_width = XINT (w->vertical_divider_line_width);
1315 x = WINDOW_RIGHT (w) - width;
1316 y1 = WINDOW_TOP (w);
1317 y2 = WINDOW_BOTTOM (w);
1319 memset (&gcv, ~0, sizeof (XGCValues));
1321 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1322 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1324 /* First, get the GC's. */
1325 gcv.background = tmp_color.pixel;
1326 gcv.foreground = tmp_color.pixel;
1327 gcv.graphics_exposures = False;
1328 mask = GCForeground | GCBackground | GCGraphicsExposures;
1329 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1331 /* Clear the divider area first. This needs to be done when a
1332 window split occurs. */
1334 XClearArea (dpy, x_win, x, y1, width, y2 - y1, False);
1336 /* Draw the divider line. */
1337 XFillRectangle (dpy, x_win, background_gc,
1338 x + spacing + shadow_thickness, y1,
1339 line_width, y2 - y1);
1341 if (shadow_thickness < 0)
1343 shadow_thickness = -shadow_thickness;
1344 style = EDGE_BEVEL_IN;
1348 style = EDGE_BEVEL_OUT;
1351 /* Draw the shadows around the divider line */
1352 x_bevel_area (w, div_face, x + spacing, y1,
1353 width - 2 * spacing, y2 - y1,
1354 shadow_thickness, EDGE_ALL, style);
1357 /*****************************************************************************
1360 Output a blank by clearing the area it covers in the foreground color
1362 ****************************************************************************/
1364 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
1365 int start_pixpos, int cursor_start, int cursor_width)
1367 struct frame *f = XFRAME (w->frame);
1368 struct device *d = XDEVICE (f->device);
1370 Display *dpy = DEVICE_X_DISPLAY (d);
1371 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1373 struct face_cachel *cursor_cachel =
1374 WINDOW_FACE_CACHEL (w,
1375 get_builtin_face_cache_index
1376 (w, Vtext_cursor_face));
1377 Lisp_Object bg_pmap;
1378 Lisp_Object buffer = WINDOW_BUFFER (w);
1379 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1383 int y = DISPLAY_LINE_YPOS (dl);
1384 int width = rb->width;
1385 int height = DISPLAY_LINE_HEIGHT (dl);
1387 /* Unmap all subwindows in the area we are going to blank. */
1388 redisplay_unmap_subwindows_maybe (f, x, y, width, height);
1390 if (start_pixpos > x)
1392 if (start_pixpos >= (x + width))
1396 width -= (start_pixpos - x);
1401 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
1402 if (!IMAGE_INSTANCEP (bg_pmap)
1403 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
1407 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1410 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1411 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
1414 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1416 /* If this rune is marked as having the cursor, then it is actually
1417 representing a tab. */
1418 if (!NILP (w->text_cursor_visible_p)
1419 && (rb->cursor_type == CURSOR_ON
1421 && (cursor_start + cursor_width > x)
1422 && cursor_start < (x + width))))
1424 int cursor_height, cursor_y;
1425 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1426 Lisp_Font_Instance *fi;
1428 fi = XFONT_INSTANCE (FACE_CACHEL_FONT
1429 (WINDOW_FACE_CACHEL (w, rb->findex),
1432 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1434 cursor_y = dl->ypos - fi->ascent;
1435 cursor_height = fi->height;
1436 if (cursor_y + cursor_height > y + height)
1437 cursor_height = y + height - cursor_y;
1441 if (NILP (bar_cursor_value))
1443 XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1444 fi->width, cursor_height);
1448 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1450 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1451 make_int (bar_width));
1452 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
1453 cursor_y, cursor_start + bar_width - 1,
1454 cursor_y + cursor_height - 1);
1457 else if (NILP (bar_cursor_value))
1459 XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1460 fi->width - 1, cursor_height - 1);
1465 /*****************************************************************************
1468 Output a horizontal line in the foreground of its face.
1469 ****************************************************************************/
1471 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
1473 struct frame *f = XFRAME (w->frame);
1474 struct device *d = XDEVICE (f->device);
1476 Display *dpy = DEVICE_X_DISPLAY (d);
1477 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1481 int width = rb->width;
1482 int height = DISPLAY_LINE_HEIGHT (dl);
1483 int ypos1, ypos2, ypos3, ypos4;
1485 ypos1 = DISPLAY_LINE_YPOS (dl);
1486 ypos2 = ypos1 + rb->object.hline.yoffset;
1487 ypos3 = ypos2 + rb->object.hline.thickness;
1488 ypos4 = dl->ypos + dl->descent - dl->clip;
1490 /* First clear the area not covered by the line. */
1491 if (height - rb->object.hline.thickness > 0)
1493 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1496 if (ypos2 - ypos1 > 0)
1497 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1498 if (ypos4 - ypos3 > 0)
1499 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1502 /* Now draw the line. */
1503 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1511 if (ypos3 - ypos2 > 0)
1512 XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1515 /*****************************************************************************
1518 Draw a shadow around the given area using the given GC's. It is the
1519 callers responsibility to set the GC's appropriately.
1520 ****************************************************************************/
1522 x_output_shadows (struct frame *f, int x, int y, int width, int height,
1523 GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
1524 int shadow_thickness, int edges)
1526 struct device *d = XDEVICE (f->device);
1528 Display *dpy = DEVICE_X_DISPLAY (d);
1529 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1531 XSegment top_shadow[20], bottom_shadow[20];
1534 if (shadow_thickness > 10)
1535 shadow_thickness = 10;
1536 else if (shadow_thickness < 0)
1537 shadow_thickness = 0;
1538 if (shadow_thickness > (width / 2))
1539 shadow_thickness = width / 2;
1540 if (shadow_thickness > (height / 2))
1541 shadow_thickness = height / 2;
1543 for (elt = 0; elt < shadow_thickness; elt++)
1546 int seg2 = (edges & EDGE_TOP) ? elt + shadow_thickness : elt;
1547 int bot_seg2 = (edges & EDGE_BOTTOM) ? elt + shadow_thickness : elt;
1549 if (edges & EDGE_TOP)
1551 top_shadow[seg1].x1 = x + elt;
1552 top_shadow[seg1].x2 = x + width - elt - 1;
1553 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
1555 if (edges & EDGE_LEFT)
1557 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
1558 top_shadow[seg2].y1 = y + elt;
1559 top_shadow[seg2].y2 = y + height - elt - 1;
1561 if (edges & EDGE_BOTTOM)
1563 bottom_shadow[seg1].x1 = x + elt;
1564 bottom_shadow[seg1].x2 = x + width - elt - 1;
1565 bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
1567 if (edges & EDGE_RIGHT)
1569 bottom_shadow[bot_seg2].x1 = bottom_shadow[bot_seg2].x2 = x + width - elt - 1;
1570 bottom_shadow[bot_seg2].y1 = y + elt;
1571 bottom_shadow[bot_seg2].y2 = y + height - elt - 1;
1575 XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow,
1576 ((edges & EDGE_TOP) ? shadow_thickness : 0)
1577 + ((edges & EDGE_LEFT) ? shadow_thickness : 0));
1578 XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
1579 ((edges & EDGE_BOTTOM) ? shadow_thickness : 0)
1580 + ((edges & EDGE_RIGHT) ? shadow_thickness : 0));
1583 /*****************************************************************************
1584 x_generate_shadow_pixels
1586 Given three pixels (top shadow, bottom shadow, background) massage
1587 the top and bottom shadow colors to guarantee that they differ. The
1588 background pixels are not allowed to be modified.
1590 This function modifies its parameters.
1592 This code is modified from code blatantly stolen from lwlib/xlwmenu.c
1593 ****************************************************************************/
1594 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
1595 ? ((unsigned long) (x)) : ((unsigned long) (y)))
1598 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
1599 unsigned long *bottom_shadow,
1600 unsigned long background,
1601 unsigned long core_background)
1603 struct device *d = XDEVICE (f->device);
1604 Display *dpy = DEVICE_X_DISPLAY (d);
1605 Colormap cmap = DEVICE_X_COLORMAP (d);
1606 Visual *visual = DEVICE_X_VISUAL (d);
1609 int top_frobbed = 0, bottom_frobbed = 0;
1611 /* If the top shadow is the same color as the background, try to
1613 if (*top_shadow == background)
1615 topc.pixel = background;
1616 XQueryColor (dpy, cmap, &topc);
1617 /* don't overflow/wrap! */
1618 topc.red = MINL (65535, (unsigned long) topc.red * 6 / 5);
1619 topc.green = MINL (65535, (unsigned long) topc.green * 6 / 5);
1620 topc.blue = MINL (65535, (unsigned long) topc.blue * 6 / 5);
1621 if (allocate_nearest_color (dpy, cmap, visual, &topc))
1623 *top_shadow = topc.pixel;
1628 /* If the bottom shadow is the same color as the background, try to
1630 if (*bottom_shadow == background)
1632 botc.pixel = background;
1633 XQueryColor (dpy, cmap, &botc);
1634 botc.red = (unsigned short) ((unsigned long) botc.red * 3 / 5);
1635 botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5);
1636 botc.blue = (unsigned short) ((unsigned long) botc.blue * 3 / 5);
1637 if (allocate_nearest_color (dpy, cmap, visual, &botc))
1639 *bottom_shadow = botc.pixel;
1644 /* If we had to adjust both shadows, then we have to do some
1646 if (top_frobbed && bottom_frobbed)
1648 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
1649 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
1650 if (bot_avg > top_avg)
1652 Pixel tmp = *top_shadow;
1654 *top_shadow = *bottom_shadow;
1655 *bottom_shadow = tmp;
1657 else if (topc.pixel == botc.pixel)
1659 if (botc.pixel == background)
1660 *top_shadow = core_background;
1662 *bottom_shadow = background;
1667 /*****************************************************************************
1668 x_redraw_exposed_window
1670 Given a bounding box for an area that needs to be redrawn, determine
1671 what parts of what lines are contained within and re-output their
1673 ****************************************************************************/
1675 x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
1677 struct frame *f = XFRAME (w->frame);
1679 int start_x, start_y, end_x, end_y;
1680 int orig_windows_structure_changed;
1682 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1684 if (!NILP (w->vchild))
1686 x_redraw_exposed_windows (w->vchild, x, y, width, height);
1689 else if (!NILP (w->hchild))
1691 x_redraw_exposed_windows (w->hchild, x, y, width, height);
1695 /* If the window doesn't intersect the exposed region, we're done here. */
1696 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w)
1697 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w))
1703 start_x = max (WINDOW_LEFT (w), x);
1704 end_x = min (WINDOW_RIGHT (w), (x + width));
1705 start_y = max (WINDOW_TOP (w), y);
1706 end_y = min (WINDOW_BOTTOM (w), y + height);
1708 /* We do this to make sure that the 3D modelines get redrawn if
1709 they are in the exposed region. */
1710 orig_windows_structure_changed = f->windows_structure_changed;
1711 f->windows_structure_changed = 1;
1714 redisplay_clear_top_of_window (w);
1715 if (window_needs_vertical_divider (w))
1717 x_output_vertical_divider (w, 0);
1720 for (line = 0; line < Dynarr_length (cdla); line++)
1722 struct display_line *cdl = Dynarr_atp (cdla, line);
1723 int top_y = cdl->ypos - cdl->ascent;
1724 int bottom_y = cdl->ypos + cdl->descent;
1726 if (bottom_y >= start_y)
1737 output_display_line (w, 0, cdla, line, start_x, end_x);
1742 f->windows_structure_changed = orig_windows_structure_changed;
1744 /* If there have never been any face cache_elements created, then this
1745 expose event doesn't actually have anything to do. */
1746 if (Dynarr_largest (w->face_cachels))
1747 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
1750 /*****************************************************************************
1751 x_redraw_exposed_windows
1753 For each window beneath the given window in the window hierarchy,
1754 ensure that it is redrawn if necessary after an Expose event.
1755 ****************************************************************************/
1757 x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
1760 for (; !NILP (window); window = XWINDOW (window)->next)
1761 x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
1764 /*****************************************************************************
1765 x_redraw_exposed_area
1767 For each window on the given frame, ensure that any area in the
1768 Exposed area is redrawn.
1769 ****************************************************************************/
1771 x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
1773 /* If any window on the frame has had its face cache reset then the
1774 redisplay structures are effectively invalid. If we attempt to
1775 use them we'll blow up. We mark the frame as changed to ensure
1776 that redisplay will do a full update. This probably isn't
1777 necessary but it can't hurt. */
1779 #ifdef HAVE_TOOLBARS
1780 /* #### We would rather put these off as well but there is currently
1781 no combination of flags which will force an unchanged toolbar to
1783 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
1785 redraw_exposed_gutters (f, x, y, width, height);
1787 if (!f->window_face_cache_reset)
1789 x_redraw_exposed_windows (f->root_window, x, y, width, height);
1791 XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
1794 MARK_FRAME_CHANGED (f);
1797 /****************************************************************************
1800 Clear the area in the box defined by the given parameters using the
1802 ****************************************************************************/
1804 x_clear_region (Lisp_Object locale, struct device* d, struct frame* f, face_index findex,
1806 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1807 Lisp_Object background_pixmap)
1813 dpy = DEVICE_X_DISPLAY (d);
1814 x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1816 if (!UNBOUNDP (background_pixmap))
1818 gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
1822 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1824 XClearArea (dpy, x_win, x, y, width, height, False);
1827 /*****************************************************************************
1830 Draw a cursor at the end of a line. The end-of-line cursor is
1831 narrower than the normal cursor.
1832 ****************************************************************************/
1834 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos,
1837 struct frame *f = XFRAME (w->frame);
1838 struct device *d = XDEVICE (f->device);
1841 Display *dpy = DEVICE_X_DISPLAY (d);
1842 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1844 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
1845 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
1847 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1848 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1852 int y = DISPLAY_LINE_YPOS (dl);
1853 int width = EOL_CURSOR_WIDTH;
1854 int height = DISPLAY_LINE_HEIGHT (dl);
1855 int cursor_height, cursor_y;
1856 int defheight, defascent;
1858 XSETWINDOW (window, w);
1859 redisplay_clear_region (window, findex, x, y, width, height);
1861 if (NILP (w->text_cursor_visible_p))
1864 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1866 default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
1868 /* make sure the cursor is entirely contained between y and y+height */
1869 cursor_height = min (defheight, height);
1870 cursor_y = max (y, min (y + height - cursor_height,
1871 dl->ypos - defascent));
1876 XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2);
1877 #endif /* HAVE_XIM */
1879 if (NILP (bar_cursor_value))
1881 XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
1885 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1887 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1888 make_int (bar_width));
1889 XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
1890 x + bar_width - 1, cursor_y + cursor_height - 1);
1893 else if (NILP (bar_cursor_value))
1895 XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
1901 x_clear_frame_window (Lisp_Object window)
1903 struct window *w = XWINDOW (window);
1905 if (!NILP (w->vchild))
1907 x_clear_frame_windows (w->vchild);
1911 if (!NILP (w->hchild))
1913 x_clear_frame_windows (w->hchild);
1917 redisplay_clear_to_window_end (w, WINDOW_TEXT_TOP (w),
1918 WINDOW_TEXT_BOTTOM (w));
1922 x_clear_frame_windows (Lisp_Object window)
1924 for (; !NILP (window); window = XWINDOW (window)->next)
1925 x_clear_frame_window (window);
1929 x_clear_frame (struct frame *f)
1931 struct device *d = XDEVICE (f->device);
1932 Display *dpy = DEVICE_X_DISPLAY (d);
1933 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1934 int x, y, width, height;
1937 x = FRAME_LEFT_BORDER_START (f);
1938 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
1939 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
1940 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) -
1941 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f));
1942 /* #### This adjustment by 1 should be being done in the macros.
1943 There is some small differences between when the menubar is on
1944 and off that we still need to deal with. */
1945 y = FRAME_TOP_BORDER_START (f) - 1;
1946 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
1947 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
1948 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) -
1949 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1;
1951 XClearArea (dpy, x_win, x, y, width, height, False);
1953 XSETFRAME (frame, f);
1955 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
1956 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
1957 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
1959 x_clear_frame_windows (f->root_window);
1962 XFlush (DEVICE_X_DISPLAY (d));
1965 /* briefly swap the foreground and background colors.
1969 x_flash (struct device *d)
1975 XColor tmp_fcolor, tmp_bcolor;
1976 Lisp_Object tmp_pixel, frame;
1977 struct frame *f = device_selected_frame (d);
1978 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f));
1979 Widget shell = FRAME_X_SHELL_WIDGET (f);
1982 XSETFRAME (frame, f);
1984 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
1985 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1986 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
1987 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1989 dpy = XtDisplay (shell);
1990 win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1991 memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
1992 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
1993 gcv.function = GXxor;
1994 gcv.graphics_exposures = False;
1995 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
1996 (GCForeground | GCFunction | GCGraphicsExposures));
1997 default_face_height_and_width (frame, &flash_height, 0);
1999 /* If window is tall, flash top and bottom line. */
2000 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
2002 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2003 w->pixel_width, flash_height);
2004 XFillRectangle (dpy, win, gc, w->pixel_left,
2005 w->pixel_top + w->pixel_height - flash_height,
2006 w->pixel_width, flash_height);
2009 /* If it is short, flash it all. */
2010 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2011 w->pixel_width, w->pixel_height);
2019 tv.tv_sec = usecs / 1000000L;
2020 tv.tv_usec = usecs % 1000000L;
2021 /* I'm sure someone is going to complain about this... */
2022 select (0, 0, 0, 0, &tv);
2027 #else /* !HAVE_POLL */
2029 #endif /* HAVE_POLL */
2030 #endif /* HAVE_SELECT */
2032 /* If window is tall, flash top and bottom line. */
2033 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
2035 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2036 w->pixel_width, flash_height);
2037 XFillRectangle (dpy, win, gc, w->pixel_left,
2038 w->pixel_top + w->pixel_height - flash_height,
2039 w->pixel_width, flash_height);
2042 /* If it is short, flash it all. */
2043 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2044 w->pixel_width, w->pixel_height);
2051 /* Make audible bell. */
2054 x_ring_bell (struct device *d, int volume, int pitch, int duration)
2056 Display *display = DEVICE_X_DISPLAY (d);
2058 if (volume < 0) volume = 0;
2059 else if (volume > 100) volume = 100;
2060 if (pitch < 0 && duration < 0)
2062 XBell (display, (volume * 2) - 100);
2067 XKeyboardState state;
2068 XKeyboardControl ctl;
2070 /* #### grab server? */
2071 XGetKeyboardControl (display, &state);
2073 ctl.bell_pitch = (pitch >= 0 ? pitch : (int) state.bell_pitch);
2074 ctl.bell_duration = (duration >= 0 ? duration : (int) state.bell_duration);
2075 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2077 XBell (display, (volume * 2) - 100);
2079 ctl.bell_pitch = state.bell_pitch;
2080 ctl.bell_duration = state.bell_duration;
2081 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2083 /* #### ungrab server? */
2089 /************************************************************************/
2090 /* initialization */
2091 /************************************************************************/
2094 console_type_create_redisplay_x (void)
2096 /* redisplay methods */
2097 CONSOLE_HAS_METHOD (x, text_width);
2098 CONSOLE_HAS_METHOD (x, output_display_block);
2099 CONSOLE_HAS_METHOD (x, divider_height);
2100 CONSOLE_HAS_METHOD (x, eol_cursor_width);
2101 CONSOLE_HAS_METHOD (x, output_vertical_divider);
2102 CONSOLE_HAS_METHOD (x, clear_region);
2103 CONSOLE_HAS_METHOD (x, clear_frame);
2104 CONSOLE_HAS_METHOD (x, window_output_begin);
2105 CONSOLE_HAS_METHOD (x, window_output_end);
2106 CONSOLE_HAS_METHOD (x, flash);
2107 CONSOLE_HAS_METHOD (x, ring_bell);
2108 CONSOLE_HAS_METHOD (x, bevel_area);
2109 CONSOLE_HAS_METHOD (x, output_string);
2110 CONSOLE_HAS_METHOD (x, output_pixmap);