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 need_ccl_conversion = !NILP (ccl_prog);
169 if (need_ccl_conversion)
170 setup_ccl_program (&char_converter, ccl_prog);
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;
442 redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset,
443 start_pixpos, rb->width,
446 XSETWINDOW (window, w);
447 instance = glyph_image_instance (rb->object.dglyph.glyph,
448 window, ERROR_ME_NOT, 1);
451 if (IMAGE_INSTANCEP (instance))
453 switch (XIMAGE_INSTANCE_TYPE (instance))
455 case IMAGE_MONO_PIXMAP:
456 case IMAGE_COLOR_PIXMAP:
457 redisplay_output_pixmap (w, instance, &dbox, &dga, findex,
458 cursor_start, cursor_width,
463 if (EQ (XIMAGE_INSTANCE_WIDGET_TYPE (instance),
466 redisplay_output_layout (window, instance, &dbox, &dga, findex,
467 cursor_start, cursor_width,
471 case IMAGE_SUBWINDOW:
472 redisplay_output_subwindow (w, instance, &dbox, &dga, findex,
473 cursor_start, cursor_width,
478 /* nothing is as nothing does */
486 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
487 (XIMAGE_INSTANCE (instance)) = 0;
498 if (Dynarr_length (buf))
499 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
500 0, cursor_start, cursor_width, cursor_height);
502 /* #### This is really conditionalized well for optimized
505 && !EQ (Qzero, w->modeline_shadow_thickness)
507 || f->windows_structure_changed
508 || w->shadow_thickness_changed))
509 bevel_modeline (w, dl);
514 /*****************************************************************************
517 Draw a shadows for the given area in the given face.
518 ****************************************************************************/
520 x_bevel_area (struct window *w, face_index findex,
521 int x, int y, int width, int height,
522 int shadow_thickness, int edges, enum edge_style style)
524 struct frame *f = XFRAME (w->frame);
525 struct device *d = XDEVICE (f->device);
527 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
528 Display *dpy = DEVICE_X_DISPLAY (d);
529 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
530 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
531 Lisp_Object tmp_pixel;
534 GC top_shadow_gc, bottom_shadow_gc, background_gc;
540 assert (shadow_thickness >=0);
541 memset (&gcv, ~0, sizeof (XGCValues));
543 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
544 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
546 /* First, get the GC's. */
547 top_shadow_pixel = tmp_color.pixel;
548 bottom_shadow_pixel = tmp_color.pixel;
549 background_pixel = tmp_color.pixel;
551 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
552 background_pixel, ef->core.background_pixel);
554 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
555 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
556 gcv.background = tmp_color.pixel;
557 gcv.graphics_exposures = False;
558 mask = GCForeground | GCBackground | GCGraphicsExposures;
560 /* If we can't distinguish one of the shadows (the color is the same as the
561 background), it's better to use a pixmap to generate a dithered gray. */
562 if (top_shadow_pixel == background_pixel ||
563 bottom_shadow_pixel == background_pixel)
568 if (DEVICE_X_GRAY_PIXMAP (d) == None)
570 DEVICE_X_GRAY_PIXMAP (d) =
571 XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
572 gray_width, gray_height, 1, 0, 1);
575 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
576 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
577 gcv.foreground = tmp_color.pixel;
578 /* this is needed because the GC draws with a pixmap here */
579 gcv.fill_style = FillOpaqueStippled;
580 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
581 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
582 (mask | GCStipple | GCFillStyle));
584 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
585 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
586 bottom_shadow_pixel = tmp_color.pixel;
588 flip_gcs = (bottom_shadow_pixel ==
589 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
593 gcv.foreground = top_shadow_pixel;
594 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
597 gcv.foreground = bottom_shadow_pixel;
598 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
600 if (use_pixmap && flip_gcs)
602 GC tmp_gc = bottom_shadow_gc;
603 bottom_shadow_gc = top_shadow_gc;
604 top_shadow_gc = tmp_gc;
607 gcv.foreground = background_pixel;
608 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
610 /* possibly revert the GC's This will give a depressed look to the
612 if (style == EDGE_ETCHED_IN || style == EDGE_BEVEL_IN)
616 temp = top_shadow_gc;
617 top_shadow_gc = bottom_shadow_gc;
618 bottom_shadow_gc = temp;
621 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
622 shadow_thickness /= 2;
624 /* Draw the shadows around the divider line */
625 x_output_shadows (f, x, y, width, height,
626 top_shadow_gc, bottom_shadow_gc,
627 background_gc, shadow_thickness, edges);
629 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
631 /* Draw the shadows around the divider line */
632 x_output_shadows (f, x + shadow_thickness, y + shadow_thickness,
633 width - 2*shadow_thickness, height - 2*shadow_thickness,
634 bottom_shadow_gc, top_shadow_gc,
635 background_gc, shadow_thickness, edges);
639 /*****************************************************************************
642 Given a number of parameters return a GC with those properties.
643 ****************************************************************************/
645 x_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
646 Lisp_Object bg_pmap, Lisp_Object lwidth)
651 memset (&gcv, ~0, sizeof (XGCValues));
652 gcv.graphics_exposures = False;
653 /* Make absolutely sure that we don't pick up a clipping region in
654 the GC returned by this function. */
655 gcv.clip_mask = None;
656 gcv.clip_x_origin = 0;
657 gcv.clip_y_origin = 0;
658 gcv.fill_style = FillSolid;
659 mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
664 gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
669 if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg))
671 /* #### I fixed once case where this was getting it. It was a
672 bad macro expansion (compiler bug). */
673 stderr_out ("Help! x_get_gc got a bogus fg value! fg = ");
680 if (COLOR_INSTANCEP (fg))
681 gcv.foreground = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (fg)).pixel;
683 gcv.foreground = XINT (fg);
684 mask |= GCForeground;
689 if (COLOR_INSTANCEP (bg))
690 gcv.background = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (bg)).pixel;
692 gcv.background = XINT (bg);
693 mask |= GCBackground;
696 /* This special case comes from a request to draw text with a face which has
697 the dim property. We'll use a stippled foreground GC. */
698 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);
706 else if (IMAGE_INSTANCEP (bg_pmap)
707 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
709 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
711 gcv.fill_style = FillOpaqueStippled;
712 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
713 mask |= (GCStipple | GCFillStyle);
717 gcv.fill_style = FillTiled;
718 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
719 mask |= (GCTile | GCFillStyle);
725 gcv.line_width = XINT (lwidth);
729 return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
732 /*****************************************************************************
735 Given a string and a starting position, output that string in the
736 given face. If cursor is true, draw a cursor around the string.
737 Correctly handles multiple charsets in the string.
739 The meaning of the parameters is something like this:
741 W Window that the text is to be displayed in.
742 DL Display line that this text is on. The values in the
743 structure are used to determine the vertical position and
744 clipping range of the text.
745 BUF Dynamic array of Emchars specifying what is actually to be
747 XPOS X position in pixels where the text should start being drawn.
748 XOFFSET Number of pixels to be chopped off the left side of the
749 text. The effect is as if the text were shifted to the
750 left this many pixels and clipped at XPOS.
751 CLIP_START Clip everything left of this X position.
752 WIDTH Clip everything right of XPOS + WIDTH.
753 FINDEX Index for the face cache element describing how to display
755 CURSOR #### I don't understand this. There's something
756 strange and overcomplexified with this variable.
757 Chuck, explain please?
758 CURSOR_START Starting X position of cursor.
759 CURSOR_WIDTH Width of cursor in pixels.
760 CURSOR_HEIGHT Height of cursor in pixels.
762 Starting Y position of cursor is the top of the text line.
763 The cursor is drawn sometimes whether or not CURSOR is set. ???
764 ****************************************************************************/
766 x_output_string (struct window *w, struct display_line *dl,
767 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
768 int width, face_index findex, int cursor,
769 int cursor_start, int cursor_width, int cursor_height)
771 /* General variables */
772 struct frame *f = XFRAME (w->frame);
773 struct device *d = XDEVICE (f->device);
776 Display *dpy = DEVICE_X_DISPLAY (d);
777 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
781 /* Cursor-related variables */
782 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
784 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
786 struct face_cachel *cursor_cachel = 0;
788 /* Text-related variables */
792 int len = Dynarr_length (buf);
793 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
794 struct textual_run *runs = alloca_array (struct textual_run, len);
797 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
799 XSETDEVICE (device, d);
800 XSETWINDOW (window, w);
803 width = x_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
804 height = DISPLAY_LINE_HEIGHT (dl);
806 /* Regularize the variables passed in. */
808 if (clip_start < xpos)
810 clip_end = xpos + width;
811 if (clip_start >= clip_end)
812 /* It's all clipped out. */
817 /* make sure the area we are about to display is subwindow free. */
818 redisplay_unmap_subwindows_maybe (f, clip_start, DISPLAY_LINE_YPOS (dl),
819 clip_end - clip_start, DISPLAY_LINE_HEIGHT (dl));
821 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
822 Dynarr_length (buf));
824 cursor_clip = (cursor_start >= clip_start &&
825 cursor_start < clip_end);
827 /* This cursor code is really a mess. */
828 if (!NILP (w->text_cursor_visible_p)
832 && (cursor_start + cursor_width >= clip_start)
833 && !NILP (bar_cursor_value))))
835 /* These have to be in separate statements in order to avoid a
837 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face);
838 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks);
840 /* We have to reset this since any call to WINDOW_FACE_CACHEL
841 may cause the cache to resize and any pointers to it to
843 cachel = WINDOW_FACE_CACHEL (w, findex);
847 if (cursor && focus && (cursor_start == clip_start) && cursor_height)
848 XIM_SetSpotLocation (f, xpos - 2, dl->ypos + dl->descent - 2);
849 #endif /* HAVE_XIM */
851 bg_pmap = cachel->background_pixmap;
852 if (!IMAGE_INSTANCEP (bg_pmap)
853 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
856 if ((cursor && focus && NILP (bar_cursor_value)
857 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap))
860 bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
864 XFillRectangle (dpy, x_win, bgc, clip_start,
865 DISPLAY_LINE_YPOS (dl), clip_end - clip_start,
868 for (i = 0; i < nruns; i++)
870 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
871 Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
875 if (EQ (font, Vthe_null_font_instance))
878 this_width = x_text_width_single_run (cachel, runs + i);
879 need_clipping = (dl->clip || clip_start > xpos ||
880 clip_end < xpos + this_width);
882 /* XDrawImageString only clears the area equal to the height of
883 the given font. It is possible that a font is being displayed
884 on a line taller than it is, so this would cause us to fail to
886 if ((int) fi->height < (int) (height + dl->clip + dl->top_clip))
888 int clear_start = max (xpos, clip_start);
889 int clear_end = min (xpos + this_width, clip_end);
893 int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
895 ypos1_string = dl->ypos - fi->ascent;
896 ypos2_string = dl->ypos + fi->descent;
897 ypos1_line = DISPLAY_LINE_YPOS (dl);
898 ypos2_line = ypos1_line + DISPLAY_LINE_HEIGHT (dl);
900 /* Make sure we don't clear below the real bottom of the
902 if (ypos1_string > ypos2_line)
903 ypos1_string = ypos2_line;
904 if (ypos2_string > ypos2_line)
905 ypos2_string = ypos2_line;
907 if (ypos1_line < ypos1_string)
909 redisplay_clear_region (window, findex, clear_start, ypos1_line,
910 clear_end - clear_start,
911 ypos1_string - ypos1_line);
914 if (ypos2_line > ypos2_string)
916 redisplay_clear_region (window, findex, clear_start, ypos2_string,
917 clear_end - clear_start,
918 ypos2_line - ypos2_string);
923 redisplay_clear_region (window, findex, clear_start,
924 DISPLAY_LINE_YPOS (dl), clear_end - clear_start,
929 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value))
930 gc = x_get_gc (d, font, cursor_cachel->foreground,
931 cursor_cachel->background, Qnil, Qnil);
932 else if (cachel->dim)
934 /* Ensure the gray bitmap exists */
935 if (DEVICE_X_GRAY_PIXMAP (d) == None)
936 DEVICE_X_GRAY_PIXMAP (d) =
937 XCreateBitmapFromData (dpy, x_win, (char *)gray_bits,
938 gray_width, gray_height);
940 /* Request a GC with the gray stipple pixmap to draw dimmed text */
941 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
945 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
950 XRectangle clip_box[1];
954 clip_box[0].width = clip_end - clip_start;
955 clip_box[0].height = height;
957 XSetClipRectangles (dpy, gc, clip_start, DISPLAY_LINE_YPOS (dl),
958 clip_box, 1, Unsorted);
961 if (runs[i].dimension == 1)
962 (bgc ? XDrawString : XDrawImageString) (dpy, x_win, gc, xpos,
963 dl->ypos, (char *) runs[i].ptr,
966 (bgc ? XDrawString16 : XDrawImageString16) (dpy, x_win, gc, xpos,
968 (XChar2b *) runs[i].ptr,
971 /* We draw underlines in the same color as the text. */
972 if (cachel->underline)
974 unsigned long upos, uthick;
977 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
978 if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos))
979 upos = dl->descent / 2;
980 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
983 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
985 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
986 uthick = dl->descent - dl->clip - upos;
990 XDrawLine (dpy, x_win, gc, xpos, dl->ypos + upos,
991 xpos + this_width, dl->ypos + upos);
995 XFillRectangle (dpy, x_win, gc, xpos,
996 dl->ypos + upos, this_width, uthick);
1001 if (cachel->strikethru) {
1002 unsigned long ascent,descent,upos, uthick;
1005 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
1007 if (!XGetFontProperty (xfont, XA_STRIKEOUT_ASCENT, &ascent))
1008 ascent = xfont->ascent;
1009 if (!XGetFontProperty (xfont, XA_STRIKEOUT_DESCENT, &descent))
1010 descent = xfont->descent;
1011 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
1014 upos = ascent - ((ascent + descent) / 2) + 1;
1016 /* Generally, upos will be positive (above the baseline),so subtract */
1017 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip)
1019 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip)
1020 uthick = dl->descent - dl->clip + upos;
1024 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos,
1025 xpos + this_width, dl->ypos - upos);
1027 else if (uthick > 1)
1029 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos,
1030 this_width, uthick);
1035 /* Restore the GC */
1038 XSetClipMask (dpy, gc, None);
1039 XSetClipOrigin (dpy, gc, 0, 0);
1042 /* If we are actually superimposing the cursor then redraw with just
1043 the appropriate section highlighted. */
1044 if (cursor_clip && !cursor && focus && cursor_cachel)
1047 XRectangle clip_box[1];
1049 cgc = x_get_gc (d, font, cursor_cachel->foreground,
1050 cursor_cachel->background, Qnil, Qnil);
1054 clip_box[0].width = cursor_width;
1055 clip_box[0].height = height;
1057 XSetClipRectangles (dpy, cgc, cursor_start, DISPLAY_LINE_YPOS (dl),
1058 clip_box, 1, Unsorted);
1060 if (runs[i].dimension == 1)
1061 XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
1062 (char *) runs[i].ptr, runs[i].len);
1064 XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
1065 (XChar2b *) runs[i].ptr, runs[i].len);
1067 XSetClipMask (dpy, cgc, None);
1068 XSetClipOrigin (dpy, cgc, 0, 0);
1074 /* Draw the non-focus box or bar-cursor as needed. */
1075 /* Can't this logic be simplified? */
1077 && ((cursor && !focus && NILP (bar_cursor_value))
1079 && (cursor_start + cursor_width >= clip_start)
1080 && !NILP (bar_cursor_value))))
1082 int tmp_height, tmp_y;
1083 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1084 int need_clipping = (cursor_start < clip_start
1085 || clip_end < cursor_start + cursor_width);
1087 /* #### This value is correct (as far as I know) because
1088 all of the times we need to draw this cursor, we will
1089 be called with exactly one character, so we know we
1090 can always use runs[0].
1092 This is bogus as all hell, however. The cursor handling in
1093 this function is way bogus and desperately needs to be
1094 cleaned up. (In particular, the drawing of the cursor should
1095 really really be separated out of this function. This may be
1096 a bit tricky now because this function itself does way too
1097 much stuff, a lot of which needs to be moved into
1098 redisplay.c) This is the only way to be able to easily add
1099 new cursor types or (e.g.) make the bar cursor be able to
1100 span two characters instead of overlaying just one. */
1101 int bogusly_obtained_ascent_value =
1102 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent;
1104 if (!NILP (bar_cursor_value))
1106 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1107 make_int (bar_width));
1111 gc = x_get_gc (d, Qnil, cursor_cachel->background,
1115 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1116 tmp_height = cursor_height;
1117 if (tmp_y + tmp_height > (int) (DISPLAY_LINE_YPOS(dl) + height))
1119 tmp_y = DISPLAY_LINE_YPOS (dl) + height - tmp_height;
1120 if (tmp_y < (int) DISPLAY_LINE_YPOS (dl))
1121 tmp_y = DISPLAY_LINE_YPOS (dl);
1122 tmp_height = DISPLAY_LINE_YPOS (dl) + height - tmp_y;
1127 XRectangle clip_box[1];
1130 clip_box[0].width = clip_end - clip_start;
1131 clip_box[0].height = tmp_height;
1132 XSetClipRectangles (dpy, gc, clip_start, tmp_y,
1133 clip_box, 1, Unsorted);
1136 if (!focus && NILP (bar_cursor_value))
1138 XDrawRectangle (dpy, x_win, gc, cursor_start, tmp_y,
1139 cursor_width - 1, tmp_height - 1);
1141 else if (focus && !NILP (bar_cursor_value))
1143 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1, tmp_y,
1144 cursor_start + bar_width - 1, tmp_y + tmp_height - 1);
1147 /* Restore the GC */
1150 XSetClipMask (dpy, gc, None);
1151 XSetClipOrigin (dpy, gc, 0, 0);
1157 x_output_x_pixmap (struct frame *f, Lisp_Image_Instance *p, int x,
1158 int y, int xoffset, int yoffset,
1159 int width, int height, unsigned long fg, unsigned long bg,
1162 struct device *d = XDEVICE (f->device);
1163 Display *dpy = DEVICE_X_DISPLAY (d);
1164 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1168 unsigned long pixmap_mask;
1172 memset (&gcv, ~0, sizeof (XGCValues));
1173 gcv.graphics_exposures = False;
1174 gcv.foreground = fg;
1175 gcv.background = bg;
1176 pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
1178 if (IMAGE_INSTANCE_X_MASK (p))
1180 gcv.function = GXcopy;
1181 gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
1182 gcv.clip_x_origin = x - xoffset;
1183 gcv.clip_y_origin = y - yoffset;
1184 pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
1186 /* Can't set a clip rectangle because we already have a mask.
1187 Is it possible to get an equivalent effect by changing the
1188 args to XCopyArea below rather than messing with a clip box?
1189 - dkindred@cs.cmu.edu
1190 Yes. We don't clip at all now - andy@xemacs.org
1194 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
1199 /* override_gc might have a mask already--we don't want to nuke it.
1200 Maybe we can insist that override_gc have no mask, or use
1201 one of the suggestions above. */
1204 /* depth of 0 means it's a bitmap, not a pixmap, and we should use
1205 XCopyPlane (1 = current foreground color, 0 = background) instead
1206 of XCopyArea, which means that the bits in the pixmap are actual
1207 pixel values, instead of symbolic of fg/bg. */
1208 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
1211 IMAGE_INSTANCE_X_PIXMAP_SLICE
1212 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc, xoffset,
1218 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP_SLICE
1219 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc,
1220 xoffset, yoffset, width, height, x, y, 1L);
1225 x_output_pixmap (struct window *w, Lisp_Object image_instance,
1226 struct display_box *db, struct display_glyph_area *dga,
1227 face_index findex, int cursor_start, int cursor_width,
1228 int cursor_height, int bg_pixmap)
1230 struct frame *f = XFRAME (w->frame);
1231 struct device *d = XDEVICE (f->device);
1232 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1234 Display *dpy = DEVICE_X_DISPLAY (d);
1235 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1237 /* Output the pixmap. */
1239 Lisp_Object tmp_pixel;
1240 XColor tmp_bcolor, tmp_fcolor;
1242 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1243 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1244 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1245 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1247 x_output_x_pixmap (f, p, db->xpos, db->ypos,
1248 dga->xoffset, dga->yoffset,
1249 dga->width, dga->height,
1250 tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
1253 /* Draw a cursor over top of the pixmap. */
1254 if (cursor_width && cursor_height && (cursor_start >= db->xpos)
1255 && !NILP (w->text_cursor_visible_p)
1256 && (cursor_start < db->xpos + dga->width))
1259 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1260 struct face_cachel *cursor_cachel =
1261 WINDOW_FACE_CACHEL (w,
1262 get_builtin_face_cache_index
1263 (w, Vtext_cursor_face));
1265 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1267 if (cursor_width > db->xpos + dga->width - cursor_start)
1268 cursor_width = db->xpos + dga->width - cursor_start;
1272 XFillRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1277 XDrawRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1283 /*****************************************************************************
1284 x_output_vertical_divider
1286 Draw a vertical divider down the right side of the given window.
1287 ****************************************************************************/
1289 x_output_vertical_divider (struct window *w, int clear)
1291 struct frame *f = XFRAME (w->frame);
1292 struct device *d = XDEVICE (f->device);
1294 Display *dpy = DEVICE_X_DISPLAY (d);
1295 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1296 Lisp_Object tmp_pixel;
1300 enum edge_style style;
1303 int x, y1, y2, width, shadow_thickness, spacing, line_width;
1304 face_index div_face = get_builtin_face_cache_index (w, Vvertical_divider_face);
1306 width = window_divider_width (w);
1307 shadow_thickness = XINT (w->vertical_divider_shadow_thickness);
1308 spacing = XINT (w->vertical_divider_spacing);
1309 line_width = XINT (w->vertical_divider_line_width);
1310 x = WINDOW_RIGHT (w) - width;
1311 y1 = WINDOW_TOP (w);
1312 y2 = WINDOW_BOTTOM (w);
1314 memset (&gcv, ~0, sizeof (XGCValues));
1316 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1317 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1319 /* First, get the GC's. */
1320 gcv.background = tmp_color.pixel;
1321 gcv.foreground = tmp_color.pixel;
1322 gcv.graphics_exposures = False;
1323 mask = GCForeground | GCBackground | GCGraphicsExposures;
1324 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1326 /* Clear the divider area first. This needs to be done when a
1327 window split occurs. */
1329 XClearArea (dpy, x_win, x, y1, width, y2 - y1, False);
1331 /* Draw the divider line. */
1332 XFillRectangle (dpy, x_win, background_gc,
1333 x + spacing + shadow_thickness, y1,
1334 line_width, y2 - y1);
1336 if (shadow_thickness < 0)
1338 shadow_thickness = -shadow_thickness;
1339 style = EDGE_BEVEL_IN;
1343 style = EDGE_BEVEL_OUT;
1346 /* Draw the shadows around the divider line */
1347 x_bevel_area (w, div_face, x + spacing, y1,
1348 width - 2 * spacing, y2 - y1,
1349 shadow_thickness, EDGE_ALL, style);
1352 /*****************************************************************************
1355 Output a blank by clearing the area it covers in the foreground color
1357 ****************************************************************************/
1359 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
1360 int start_pixpos, int cursor_start, int cursor_width)
1362 struct frame *f = XFRAME (w->frame);
1363 struct device *d = XDEVICE (f->device);
1365 Display *dpy = DEVICE_X_DISPLAY (d);
1366 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1368 struct face_cachel *cursor_cachel =
1369 WINDOW_FACE_CACHEL (w,
1370 get_builtin_face_cache_index
1371 (w, Vtext_cursor_face));
1372 Lisp_Object bg_pmap;
1373 Lisp_Object buffer = WINDOW_BUFFER (w);
1374 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1378 int y = DISPLAY_LINE_YPOS (dl);
1379 int width = rb->width;
1380 int height = DISPLAY_LINE_HEIGHT (dl);
1382 /* Unmap all subwindows in the area we are going to blank. */
1383 redisplay_unmap_subwindows_maybe (f, x, y, width, height);
1385 if (start_pixpos > x)
1387 if (start_pixpos >= (x + width))
1391 width -= (start_pixpos - x);
1396 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
1397 if (!IMAGE_INSTANCEP (bg_pmap)
1398 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
1402 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1405 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1406 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
1409 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1411 /* If this rune is marked as having the cursor, then it is actually
1412 representing a tab. */
1413 if (!NILP (w->text_cursor_visible_p)
1414 && (rb->cursor_type == CURSOR_ON
1416 && (cursor_start + cursor_width > x)
1417 && cursor_start < (x + width))))
1419 int cursor_height, cursor_y;
1420 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1421 Lisp_Font_Instance *fi;
1423 fi = XFONT_INSTANCE (FACE_CACHEL_FONT
1424 (WINDOW_FACE_CACHEL (w, rb->findex),
1427 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1429 cursor_y = dl->ypos - fi->ascent;
1430 cursor_height = fi->height;
1431 if (cursor_y + cursor_height > y + height)
1432 cursor_height = y + height - cursor_y;
1436 if (NILP (bar_cursor_value))
1438 XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1439 fi->width, cursor_height);
1443 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1445 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1446 make_int (bar_width));
1447 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
1448 cursor_y, cursor_start + bar_width - 1,
1449 cursor_y + cursor_height - 1);
1452 else if (NILP (bar_cursor_value))
1454 XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1455 fi->width - 1, cursor_height - 1);
1460 /*****************************************************************************
1463 Output a horizontal line in the foreground of its face.
1464 ****************************************************************************/
1466 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
1468 struct frame *f = XFRAME (w->frame);
1469 struct device *d = XDEVICE (f->device);
1471 Display *dpy = DEVICE_X_DISPLAY (d);
1472 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1476 int width = rb->width;
1477 int height = DISPLAY_LINE_HEIGHT (dl);
1478 int ypos1, ypos2, ypos3, ypos4;
1480 ypos1 = DISPLAY_LINE_YPOS (dl);
1481 ypos2 = ypos1 + rb->object.hline.yoffset;
1482 ypos3 = ypos2 + rb->object.hline.thickness;
1483 ypos4 = dl->ypos + dl->descent - dl->clip;
1485 /* First clear the area not covered by the line. */
1486 if (height - rb->object.hline.thickness > 0)
1488 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1491 if (ypos2 - ypos1 > 0)
1492 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1493 if (ypos4 - ypos3 > 0)
1494 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1497 /* Now draw the line. */
1498 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1506 if (ypos3 - ypos2 > 0)
1507 XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1510 /*****************************************************************************
1513 Draw a shadow around the given area using the given GC's. It is the
1514 callers responsibility to set the GC's appropriately.
1515 ****************************************************************************/
1517 x_output_shadows (struct frame *f, int x, int y, int width, int height,
1518 GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
1519 int shadow_thickness, int edges)
1521 struct device *d = XDEVICE (f->device);
1523 Display *dpy = DEVICE_X_DISPLAY (d);
1524 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1526 XSegment top_shadow[20], bottom_shadow[20];
1529 if (shadow_thickness > 10)
1530 shadow_thickness = 10;
1531 else if (shadow_thickness < 0)
1532 shadow_thickness = 0;
1533 if (shadow_thickness > (width / 2))
1534 shadow_thickness = width / 2;
1535 if (shadow_thickness > (height / 2))
1536 shadow_thickness = height / 2;
1538 for (elt = 0; elt < shadow_thickness; elt++)
1541 int seg2 = (edges & EDGE_TOP) ? elt + shadow_thickness : elt;
1542 int bot_seg2 = (edges & EDGE_BOTTOM) ? elt + shadow_thickness : elt;
1544 if (edges & EDGE_TOP)
1546 top_shadow[seg1].x1 = x + elt;
1547 top_shadow[seg1].x2 = x + width - elt - 1;
1548 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
1550 if (edges & EDGE_LEFT)
1552 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
1553 top_shadow[seg2].y1 = y + elt;
1554 top_shadow[seg2].y2 = y + height - elt - 1;
1556 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 = y + height - elt - 1;
1562 if (edges & EDGE_RIGHT)
1564 bottom_shadow[bot_seg2].x1 = bottom_shadow[bot_seg2].x2 = x + width - elt - 1;
1565 bottom_shadow[bot_seg2].y1 = y + elt;
1566 bottom_shadow[bot_seg2].y2 = y + height - elt - 1;
1570 XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow,
1571 ((edges & EDGE_TOP) ? shadow_thickness : 0)
1572 + ((edges & EDGE_LEFT) ? shadow_thickness : 0));
1573 XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
1574 ((edges & EDGE_BOTTOM) ? shadow_thickness : 0)
1575 + ((edges & EDGE_RIGHT) ? shadow_thickness : 0));
1578 /*****************************************************************************
1579 x_generate_shadow_pixels
1581 Given three pixels (top shadow, bottom shadow, background) massage
1582 the top and bottom shadow colors to guarantee that they differ. The
1583 background pixels are not allowed to be modified.
1585 This function modifies its parameters.
1587 This code is modified from code blatantly stolen from lwlib/xlwmenu.c
1588 ****************************************************************************/
1589 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
1590 ? ((unsigned long) (x)) : ((unsigned long) (y)))
1593 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
1594 unsigned long *bottom_shadow,
1595 unsigned long background,
1596 unsigned long core_background)
1598 struct device *d = XDEVICE (f->device);
1599 Display *dpy = DEVICE_X_DISPLAY (d);
1600 Colormap cmap = DEVICE_X_COLORMAP (d);
1601 Visual *visual = DEVICE_X_VISUAL (d);
1604 int top_frobbed = 0, bottom_frobbed = 0;
1606 /* If the top shadow is the same color as the background, try to
1608 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))
1618 *top_shadow = topc.pixel;
1623 /* If the bottom shadow is the same color as the background, try to
1625 if (*bottom_shadow == background)
1627 botc.pixel = background;
1628 XQueryColor (dpy, cmap, &botc);
1629 botc.red = (unsigned short) ((unsigned long) botc.red * 3 / 5);
1630 botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5);
1631 botc.blue = (unsigned short) ((unsigned long) botc.blue * 3 / 5);
1632 if (allocate_nearest_color (dpy, cmap, visual, &botc))
1634 *bottom_shadow = botc.pixel;
1639 /* If we had to adjust both shadows, then we have to do some
1641 if (top_frobbed && bottom_frobbed)
1643 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
1644 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
1645 if (bot_avg > top_avg)
1647 Pixel tmp = *top_shadow;
1649 *top_shadow = *bottom_shadow;
1650 *bottom_shadow = tmp;
1652 else if (topc.pixel == botc.pixel)
1654 if (botc.pixel == background)
1655 *top_shadow = core_background;
1657 *bottom_shadow = background;
1662 /*****************************************************************************
1663 x_redraw_exposed_window
1665 Given a bounding box for an area that needs to be redrawn, determine
1666 what parts of what lines are contained within and re-output their
1668 ****************************************************************************/
1670 x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
1672 struct frame *f = XFRAME (w->frame);
1674 int start_x, start_y, end_x, end_y;
1675 int orig_windows_structure_changed;
1677 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1679 if (!NILP (w->vchild))
1681 x_redraw_exposed_windows (w->vchild, x, y, width, height);
1684 else if (!NILP (w->hchild))
1686 x_redraw_exposed_windows (w->hchild, x, y, width, height);
1690 /* If the window doesn't intersect the exposed region, we're done here. */
1691 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w)
1692 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w))
1698 start_x = max (WINDOW_LEFT (w), x);
1699 end_x = min (WINDOW_RIGHT (w), (x + width));
1700 start_y = max (WINDOW_TOP (w), y);
1701 end_y = min (WINDOW_BOTTOM (w), y + height);
1703 /* We do this to make sure that the 3D modelines get redrawn if
1704 they are in the exposed region. */
1705 orig_windows_structure_changed = f->windows_structure_changed;
1706 f->windows_structure_changed = 1;
1709 if (window_needs_vertical_divider (w))
1711 x_output_vertical_divider (w, 0);
1714 for (line = 0; line < Dynarr_length (cdla); line++)
1716 struct display_line *cdl = Dynarr_atp (cdla, line);
1717 int top_y = cdl->ypos - cdl->ascent;
1718 int bottom_y = cdl->ypos + cdl->descent;
1720 if (bottom_y >= start_y)
1731 output_display_line (w, 0, cdla, line, start_x, end_x);
1736 f->windows_structure_changed = orig_windows_structure_changed;
1738 /* If there have never been any face cache_elements created, then this
1739 expose event doesn't actually have anything to do. */
1740 if (Dynarr_largest (w->face_cachels))
1741 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
1744 /*****************************************************************************
1745 x_redraw_exposed_windows
1747 For each window beneath the given window in the window hierarchy,
1748 ensure that it is redrawn if necessary after an Expose event.
1749 ****************************************************************************/
1751 x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
1754 for (; !NILP (window); window = XWINDOW (window)->next)
1755 x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
1758 /*****************************************************************************
1759 x_redraw_exposed_area
1761 For each window on the given frame, ensure that any area in the
1762 Exposed area is redrawn.
1763 ****************************************************************************/
1765 x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
1767 /* If any window on the frame has had its face cache reset then the
1768 redisplay structures are effectively invalid. If we attempt to
1769 use them we'll blow up. We mark the frame as changed to ensure
1770 that redisplay will do a full update. This probably isn't
1771 necessary but it can't hurt. */
1773 #ifdef HAVE_TOOLBARS
1774 /* #### We would rather put these off as well but there is currently
1775 no combination of flags which will force an unchanged toolbar to
1777 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
1779 redraw_exposed_gutters (f, x, y, width, height);
1781 if (!f->window_face_cache_reset)
1783 x_redraw_exposed_windows (f->root_window, x, y, width, height);
1785 XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
1788 MARK_FRAME_CHANGED (f);
1791 /****************************************************************************
1794 Clear the area in the box defined by the given parameters using the
1796 ****************************************************************************/
1798 x_clear_region (Lisp_Object locale, struct device* d, struct frame* f, face_index findex,
1800 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1801 Lisp_Object background_pixmap)
1807 dpy = DEVICE_X_DISPLAY (d);
1808 x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1810 if (!UNBOUNDP (background_pixmap))
1812 gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
1816 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1818 XClearArea (dpy, x_win, x, y, width, height, False);
1821 /*****************************************************************************
1824 Draw a cursor at the end of a line. The end-of-line cursor is
1825 narrower than the normal cursor.
1826 ****************************************************************************/
1828 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos,
1831 struct frame *f = XFRAME (w->frame);
1832 struct device *d = XDEVICE (f->device);
1835 Display *dpy = DEVICE_X_DISPLAY (d);
1836 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1838 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
1839 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
1841 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1842 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1846 int y = DISPLAY_LINE_YPOS (dl);
1847 int width = EOL_CURSOR_WIDTH;
1848 int height = DISPLAY_LINE_HEIGHT (dl);
1849 int cursor_height, cursor_y;
1850 int defheight, defascent;
1852 XSETWINDOW (window, w);
1853 redisplay_clear_region (window, findex, x, y, width, height);
1855 if (NILP (w->text_cursor_visible_p))
1858 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1860 default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
1862 /* make sure the cursor is entirely contained between y and y+height */
1863 cursor_height = min (defheight, height);
1864 cursor_y = max (y, min (y + height - cursor_height,
1865 dl->ypos - defascent));
1870 XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2);
1871 #endif /* HAVE_XIM */
1873 if (NILP (bar_cursor_value))
1875 XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
1879 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1881 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1882 make_int (bar_width));
1883 XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
1884 x + bar_width - 1, cursor_y + cursor_height - 1);
1887 else if (NILP (bar_cursor_value))
1889 XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
1895 x_clear_frame_window (Lisp_Object window)
1897 struct window *w = XWINDOW (window);
1899 if (!NILP (w->vchild))
1901 x_clear_frame_windows (w->vchild);
1905 if (!NILP (w->hchild))
1907 x_clear_frame_windows (w->hchild);
1911 redisplay_clear_to_window_end (w, WINDOW_TEXT_TOP (w),
1912 WINDOW_TEXT_BOTTOM (w));
1916 x_clear_frame_windows (Lisp_Object window)
1918 for (; !NILP (window); window = XWINDOW (window)->next)
1919 x_clear_frame_window (window);
1923 x_clear_frame (struct frame *f)
1925 struct device *d = XDEVICE (f->device);
1926 Display *dpy = DEVICE_X_DISPLAY (d);
1927 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1928 int x, y, width, height;
1931 x = FRAME_LEFT_BORDER_START (f);
1932 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
1933 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
1934 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) -
1935 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f));
1936 /* #### This adjustment by 1 should be being done in the macros.
1937 There is some small differences between when the menubar is on
1938 and off that we still need to deal with. */
1939 y = FRAME_TOP_BORDER_START (f) - 1;
1940 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
1941 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
1942 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) -
1943 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1;
1945 XClearArea (dpy, x_win, x, y, width, height, False);
1947 XSETFRAME (frame, f);
1949 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
1950 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
1951 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
1953 x_clear_frame_windows (f->root_window);
1956 XFlush (DEVICE_X_DISPLAY (d));
1959 /* briefly swap the foreground and background colors.
1963 x_flash (struct device *d)
1969 XColor tmp_fcolor, tmp_bcolor;
1970 Lisp_Object tmp_pixel, frame;
1971 struct frame *f = device_selected_frame (d);
1972 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f));
1973 Widget shell = FRAME_X_SHELL_WIDGET (f);
1976 XSETFRAME (frame, f);
1978 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
1979 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1980 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
1981 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1983 dpy = XtDisplay (shell);
1984 win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1985 memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
1986 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
1987 gcv.function = GXxor;
1988 gcv.graphics_exposures = False;
1989 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
1990 (GCForeground | GCFunction | GCGraphicsExposures));
1991 default_face_height_and_width (frame, &flash_height, 0);
1993 /* If window is tall, flash top and bottom line. */
1994 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
1996 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
1997 w->pixel_width, flash_height);
1998 XFillRectangle (dpy, win, gc, w->pixel_left,
1999 w->pixel_top + w->pixel_height - flash_height,
2000 w->pixel_width, flash_height);
2003 /* If it is short, flash it all. */
2004 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2005 w->pixel_width, w->pixel_height);
2013 tv.tv_sec = usecs / 1000000L;
2014 tv.tv_usec = usecs % 1000000L;
2015 /* I'm sure someone is going to complain about this... */
2016 select (0, 0, 0, 0, &tv);
2021 #else /* !HAVE_POLL */
2023 #endif /* HAVE_POLL */
2024 #endif /* HAVE_SELECT */
2026 /* If window is tall, flash top and bottom line. */
2027 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
2029 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2030 w->pixel_width, flash_height);
2031 XFillRectangle (dpy, win, gc, w->pixel_left,
2032 w->pixel_top + w->pixel_height - flash_height,
2033 w->pixel_width, flash_height);
2036 /* If it is short, flash it all. */
2037 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2038 w->pixel_width, w->pixel_height);
2045 /* Make audible bell. */
2048 x_ring_bell (struct device *d, int volume, int pitch, int duration)
2050 Display *display = DEVICE_X_DISPLAY (d);
2052 if (volume < 0) volume = 0;
2053 else if (volume > 100) volume = 100;
2054 if (pitch < 0 && duration < 0)
2056 XBell (display, (volume * 2) - 100);
2061 XKeyboardState state;
2062 XKeyboardControl ctl;
2064 /* #### grab server? */
2065 XGetKeyboardControl (display, &state);
2067 ctl.bell_pitch = (pitch >= 0 ? pitch : state.bell_pitch);
2068 ctl.bell_duration = (duration >= 0 ? duration : state.bell_duration);
2069 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2071 XBell (display, (volume * 2) - 100);
2073 ctl.bell_pitch = state.bell_pitch;
2074 ctl.bell_duration = state.bell_duration;
2075 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2077 /* #### ungrab server? */
2083 /************************************************************************/
2084 /* initialization */
2085 /************************************************************************/
2088 console_type_create_redisplay_x (void)
2090 /* redisplay methods */
2091 CONSOLE_HAS_METHOD (x, text_width);
2092 CONSOLE_HAS_METHOD (x, output_display_block);
2093 CONSOLE_HAS_METHOD (x, divider_height);
2094 CONSOLE_HAS_METHOD (x, eol_cursor_width);
2095 CONSOLE_HAS_METHOD (x, output_vertical_divider);
2096 CONSOLE_HAS_METHOD (x, clear_region);
2097 CONSOLE_HAS_METHOD (x, clear_frame);
2098 CONSOLE_HAS_METHOD (x, window_output_begin);
2099 CONSOLE_HAS_METHOD (x, window_output_end);
2100 CONSOLE_HAS_METHOD (x, flash);
2101 CONSOLE_HAS_METHOD (x, ring_bell);
2102 CONSOLE_HAS_METHOD (x, bevel_area);
2103 CONSOLE_HAS_METHOD (x, output_string);
2104 CONSOLE_HAS_METHOD (x, output_pixmap);