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 Charc *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++)
141 Lisp_Object charset = CHARC_CHARSET (cc);
142 int code_point = CHARC_CODE_POINT (cc);
147 dimension = XCHARSET_DIMENSION (charset);
148 graphic = XCHARSET_GRAPHIC (charset);
156 byte1 = code_point >> 8;
157 byte2 = code_point & 0xFF;
159 if (!EQ (charset, prev_charset))
161 run_storage[runs_so_far].ptr = text_storage;
162 run_storage[runs_so_far].charset = charset;
163 run_storage[runs_so_far].dimension = dimension;
167 run_storage[runs_so_far - 1].len =
168 text_storage - run_storage[runs_so_far - 1].ptr;
169 if (run_storage[runs_so_far - 1].dimension == 2)
170 run_storage[runs_so_far - 1].len >>= 1;
173 prev_charset = charset;
176 Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset);
177 if ((!NILP (ccl_prog))
178 && (setup_ccl_program (&char_converter, ccl_prog) >= 0))
179 need_ccl_conversion = 1;
189 else if (graphic == 1)
195 if (need_ccl_conversion)
197 char_converter.reg[0] = XCHARSET_ID (charset);
198 char_converter.reg[1] = byte1;
199 char_converter.reg[2] = byte2;
200 ccl_driver (&char_converter, 0, 0, 0, 0, CCL_MODE_ENCODING);
201 byte1 = char_converter.reg[1];
202 byte2 = char_converter.reg[2];
205 *text_storage++ = (unsigned char) byte1;
207 *text_storage++ = (unsigned char) byte2;
212 run_storage[runs_so_far - 1].len =
213 text_storage - run_storage[runs_so_far - 1].ptr;
214 if (run_storage[runs_so_far - 1].dimension == 2)
215 run_storage[runs_so_far - 1].len >>= 1;
221 /****************************************************************************/
223 /* X output routines */
225 /****************************************************************************/
228 x_text_width_single_run (struct face_cachel *cachel, struct textual_run *run)
230 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
231 Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
232 if (!fi->proportional_p)
233 return fi->width * run->len;
236 if (run->dimension == 2)
237 return XTextWidth16 (FONT_INSTANCE_X_FONT (fi),
238 (XChar2b *) run->ptr, run->len);
240 return XTextWidth (FONT_INSTANCE_X_FONT (fi),
241 (char *) run->ptr, run->len);
248 Given a string and a face, return the string's length in pixels when
249 displayed in the font associated with the face.
253 x_text_width (struct frame *f, struct face_cachel *cachel, const Charc *str,
256 int width_so_far = 0;
257 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
258 struct textual_run *runs = alloca_array (struct textual_run, len);
262 nruns = separate_textual_runs (text_storage, runs, str, len);
264 for (i = 0; i < nruns; i++)
265 width_so_far += x_text_width_single_run (cachel, runs + i);
270 /*****************************************************************************
273 Return the height of the horizontal divider. This is a function because
274 divider_height is a device method.
276 #### If we add etched horizontal divider lines this will have to get
278 ****************************************************************************/
280 x_divider_height (void)
285 /*****************************************************************************
288 Return the width of the end-of-line cursor. This is a function
289 because eol_cursor_width is a device method.
290 ****************************************************************************/
292 x_eol_cursor_width (void)
294 return EOL_CURSOR_WIDTH;
297 /*****************************************************************************
298 x_window_output_begin
300 Perform any necessary initialization prior to an update.
301 ****************************************************************************/
303 x_window_output_begin (struct window *w)
307 /*****************************************************************************
310 Perform any necessary flushing of queues when an update has completed.
311 ****************************************************************************/
313 x_window_output_end (struct window *w)
315 XFlush (DEVICE_X_DISPLAY (WINDOW_XDEVICE (w)));
318 /*****************************************************************************
319 x_output_display_block
321 Given a display line, a block number for that start line, output all
322 runes between start and end in the specified display block.
323 ****************************************************************************/
325 x_output_display_block (struct window *w, struct display_line *dl, int block,
326 int start, int end, int start_pixpos, int cursor_start,
327 int cursor_width, int cursor_height)
329 struct frame *f = XFRAME (w->frame);
330 Charc_dynarr *buf = Dynarr_new (Charc);
333 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
334 rune_dynarr *rba = db->runes;
340 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
341 MULE is not defined */
343 XSETWINDOW (window, w);
344 rb = Dynarr_atp (rba, start);
347 /* Nothing to do so don't do anything. */
352 if (rb->type == RUNE_CHAR)
353 charset = CHARC_CHARSET (rb->object.cglyph);
356 end = Dynarr_length (rba);
361 rb = Dynarr_atp (rba, elt);
363 if (rb->findex == findex && rb->type == RUNE_CHAR
364 && (!CHARC_ASCII_EQ (rb->object.cglyph, '\n'))
365 && rb->cursor_type != CURSOR_ON
366 && EQ (charset, CHARC_CHARSET (rb->object.cglyph)))
368 Dynarr_add (buf, rb->object.cglyph);
374 if (Dynarr_length (buf))
376 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
377 findex, 0, cursor_start, cursor_width,
385 if (rb->type == RUNE_CHAR)
389 charset = CHARC_CHARSET (rb->object.cglyph);
391 if (rb->cursor_type == CURSOR_ON)
393 if (CHARC_ASCII_EQ (rb->object.cglyph, '\n'))
395 x_output_eol_cursor (w, dl, xpos, findex);
399 Dynarr_add (buf, rb->object.cglyph);
400 x_output_string (w, dl, buf, xpos, 0, start_pixpos,
401 rb->width, findex, 1,
402 cursor_start, cursor_width,
410 else if (CHARC_ASCII_EQ (rb->object.cglyph, '\n'))
412 /* Clear in case a cursor was formerly here. */
413 redisplay_clear_region (window, findex, xpos,
414 DISPLAY_LINE_YPOS (dl),
416 DISPLAY_LINE_HEIGHT (dl));
420 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
422 if (rb->type == RUNE_BLANK)
423 x_output_blank (w, dl, rb, start_pixpos, cursor_start,
427 /* #### Our flagging of when we need to redraw the
428 modeline shadows sucks. Since RUNE_HLINE is only used
429 by the modeline at the moment it is a good bet
430 that if it gets redrawn then we should also
431 redraw the shadows. This won't be true forever.
432 We borrow the shadow_thickness_changed flag for
434 w->shadow_thickness_changed = 1;
435 x_output_hline (w, dl, rb);
441 rb = Dynarr_atp (rba, elt);
447 else if (rb->type == RUNE_DGLYPH)
449 Lisp_Object instance;
450 struct display_box dbox;
451 struct display_glyph_area dga;
452 redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset,
453 start_pixpos, rb->width,
456 XSETWINDOW (window, w);
457 instance = glyph_image_instance (rb->object.dglyph.glyph,
458 window, ERROR_ME_NOT, 1);
461 if (IMAGE_INSTANCEP (instance))
463 switch (XIMAGE_INSTANCE_TYPE (instance))
465 case IMAGE_MONO_PIXMAP:
466 case IMAGE_COLOR_PIXMAP:
467 redisplay_output_pixmap (w, instance, &dbox, &dga, findex,
468 cursor_start, cursor_width,
473 if (EQ (XIMAGE_INSTANCE_WIDGET_TYPE (instance),
476 redisplay_output_layout (window, instance, &dbox, &dga, findex,
477 cursor_start, cursor_width,
481 case IMAGE_SUBWINDOW:
482 redisplay_output_subwindow (w, instance, &dbox, &dga, findex,
483 cursor_start, cursor_width,
488 /* nothing is as nothing does */
496 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
497 (XIMAGE_INSTANCE (instance)) = 0;
508 if (Dynarr_length (buf))
509 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
510 0, cursor_start, cursor_width, cursor_height);
512 /* #### This is really conditionalized well for optimized
515 && !EQ (Qzero, w->modeline_shadow_thickness)
517 || f->windows_structure_changed
518 || w->shadow_thickness_changed))
519 bevel_modeline (w, dl);
524 /*****************************************************************************
527 Draw a shadows for the given area in the given face.
528 ****************************************************************************/
530 x_bevel_area (struct window *w, face_index findex,
531 int x, int y, int width, int height,
532 int shadow_thickness, int edges, enum edge_style style)
534 struct frame *f = XFRAME (w->frame);
535 struct device *d = XDEVICE (f->device);
537 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
538 Display *dpy = DEVICE_X_DISPLAY (d);
539 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
540 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
541 Lisp_Object tmp_pixel;
544 GC top_shadow_gc, bottom_shadow_gc, background_gc;
550 assert (shadow_thickness >=0);
551 memset (&gcv, ~0, sizeof (XGCValues));
553 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
554 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
556 /* First, get the GC's. */
557 top_shadow_pixel = tmp_color.pixel;
558 bottom_shadow_pixel = tmp_color.pixel;
559 background_pixel = tmp_color.pixel;
561 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
562 background_pixel, ef->core.background_pixel);
564 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
565 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
566 gcv.background = tmp_color.pixel;
567 gcv.graphics_exposures = False;
568 mask = GCForeground | GCBackground | GCGraphicsExposures;
570 /* If we can't distinguish one of the shadows (the color is the same as the
571 background), it's better to use a pixmap to generate a dithered gray. */
572 if (top_shadow_pixel == background_pixel ||
573 bottom_shadow_pixel == background_pixel)
578 if (DEVICE_X_GRAY_PIXMAP (d) == None)
580 DEVICE_X_GRAY_PIXMAP (d) =
581 XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
582 gray_width, gray_height, 1, 0, 1);
585 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
586 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
587 gcv.foreground = tmp_color.pixel;
588 /* this is needed because the GC draws with a pixmap here */
589 gcv.fill_style = FillOpaqueStippled;
590 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
591 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
592 (mask | GCStipple | GCFillStyle));
594 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
595 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
596 bottom_shadow_pixel = tmp_color.pixel;
598 flip_gcs = (bottom_shadow_pixel ==
599 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
603 gcv.foreground = top_shadow_pixel;
604 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
607 gcv.foreground = bottom_shadow_pixel;
608 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
610 if (use_pixmap && flip_gcs)
612 GC tmp_gc = bottom_shadow_gc;
613 bottom_shadow_gc = top_shadow_gc;
614 top_shadow_gc = tmp_gc;
617 gcv.foreground = background_pixel;
618 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
620 /* possibly revert the GC's This will give a depressed look to the
622 if (style == EDGE_ETCHED_IN || style == EDGE_BEVEL_IN)
626 temp = top_shadow_gc;
627 top_shadow_gc = bottom_shadow_gc;
628 bottom_shadow_gc = temp;
631 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
632 shadow_thickness /= 2;
634 /* Draw the shadows around the divider line */
635 x_output_shadows (f, x, y, width, height,
636 top_shadow_gc, bottom_shadow_gc,
637 background_gc, shadow_thickness, edges);
639 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
641 /* Draw the shadows around the divider line */
642 x_output_shadows (f, x + shadow_thickness, y + shadow_thickness,
643 width - 2*shadow_thickness, height - 2*shadow_thickness,
644 bottom_shadow_gc, top_shadow_gc,
645 background_gc, shadow_thickness, edges);
649 /*****************************************************************************
652 Given a number of parameters return a GC with those properties.
653 ****************************************************************************/
655 x_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
656 Lisp_Object bg_pmap, Lisp_Object lwidth)
661 memset (&gcv, ~0, sizeof (XGCValues));
662 gcv.graphics_exposures = False;
663 /* Make absolutely sure that we don't pick up a clipping region in
664 the GC returned by this function. */
665 gcv.clip_mask = None;
666 gcv.clip_x_origin = 0;
667 gcv.clip_y_origin = 0;
668 gcv.fill_style = FillSolid;
669 mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
674 gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
679 if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg))
681 /* #### I fixed once case where this was getting it. It was a
682 bad macro expansion (compiler bug). */
683 stderr_out ("Help! x_get_gc got a bogus fg value! fg = ");
690 if (COLOR_INSTANCEP (fg))
691 gcv.foreground = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (fg)).pixel;
693 gcv.foreground = XINT (fg);
694 mask |= GCForeground;
699 if (COLOR_INSTANCEP (bg))
700 gcv.background = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (bg)).pixel;
702 gcv.background = XINT (bg);
703 mask |= GCBackground;
706 /* This special case comes from a request to draw text with a face which has
707 the dim property. We'll use a stippled foreground GC. */
708 if (EQ (bg_pmap, Qdim))
710 assert (DEVICE_X_GRAY_PIXMAP (d) != None);
712 gcv.fill_style = FillStippled;
713 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
714 mask |= (GCFillStyle | GCStipple);
716 else if (IMAGE_INSTANCEP (bg_pmap)
717 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
719 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
721 gcv.fill_style = FillOpaqueStippled;
722 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
723 mask |= (GCStipple | GCFillStyle);
727 gcv.fill_style = FillTiled;
728 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
729 mask |= (GCTile | GCFillStyle);
735 gcv.line_width = XINT (lwidth);
739 return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
742 /*****************************************************************************
745 Given a string and a starting position, output that string in the
746 given face. If cursor is true, draw a cursor around the string.
747 Correctly handles multiple charsets in the string.
749 The meaning of the parameters is something like this:
751 W Window that the text is to be displayed in.
752 DL Display line that this text is on. The values in the
753 structure are used to determine the vertical position and
754 clipping range of the text.
755 BUF Dynamic array of Emchars specifying what is actually to be
757 XPOS X position in pixels where the text should start being drawn.
758 XOFFSET Number of pixels to be chopped off the left side of the
759 text. The effect is as if the text were shifted to the
760 left this many pixels and clipped at XPOS.
761 CLIP_START Clip everything left of this X position.
762 WIDTH Clip everything right of XPOS + WIDTH.
763 FINDEX Index for the face cache element describing how to display
765 CURSOR #### I don't understand this. There's something
766 strange and overcomplexified with this variable.
767 Chuck, explain please?
768 CURSOR_START Starting X position of cursor.
769 CURSOR_WIDTH Width of cursor in pixels.
770 CURSOR_HEIGHT Height of cursor in pixels.
772 Starting Y position of cursor is the top of the text line.
773 The cursor is drawn sometimes whether or not CURSOR is set. ???
774 ****************************************************************************/
776 x_output_string (struct window *w, struct display_line *dl,
777 Charc_dynarr *buf, int xpos, int xoffset, int clip_start,
778 int width, face_index findex, int cursor,
779 int cursor_start, int cursor_width, int cursor_height)
781 /* General variables */
782 struct frame *f = XFRAME (w->frame);
783 struct device *d = XDEVICE (f->device);
786 Display *dpy = DEVICE_X_DISPLAY (d);
787 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
791 /* Cursor-related variables */
792 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
794 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
796 struct face_cachel *cursor_cachel = 0;
798 /* Text-related variables */
802 int len = Dynarr_length (buf);
803 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
804 struct textual_run *runs = alloca_array (struct textual_run, len);
807 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
809 XSETDEVICE (device, d);
810 XSETWINDOW (window, w);
813 width = x_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
814 height = DISPLAY_LINE_HEIGHT (dl);
816 /* Regularize the variables passed in. */
818 if (clip_start < xpos)
820 clip_end = xpos + width;
821 if (clip_start >= clip_end)
822 /* It's all clipped out. */
827 /* make sure the area we are about to display is subwindow free. */
828 redisplay_unmap_subwindows_maybe (f, clip_start, DISPLAY_LINE_YPOS (dl),
829 clip_end - clip_start, DISPLAY_LINE_HEIGHT (dl));
831 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
832 Dynarr_length (buf));
834 cursor_clip = (cursor_start >= clip_start &&
835 cursor_start < clip_end);
837 /* This cursor code is really a mess. */
838 if (!NILP (w->text_cursor_visible_p)
842 && (cursor_start + cursor_width >= clip_start)
843 && !NILP (bar_cursor_value))))
845 /* These have to be in separate statements in order to avoid a
847 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face);
848 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks);
850 /* We have to reset this since any call to WINDOW_FACE_CACHEL
851 may cause the cache to resize and any pointers to it to
853 cachel = WINDOW_FACE_CACHEL (w, findex);
857 if (cursor && focus && (cursor_start == clip_start) && cursor_height)
858 XIM_SetSpotLocation (f, xpos - 2, dl->ypos + dl->descent - 2);
859 #endif /* HAVE_XIM */
861 bg_pmap = cachel->background_pixmap;
862 if (!IMAGE_INSTANCEP (bg_pmap)
863 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
866 if ((cursor && focus && NILP (bar_cursor_value)
867 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap))
870 bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
874 XFillRectangle (dpy, x_win, bgc, clip_start,
875 DISPLAY_LINE_YPOS (dl), clip_end - clip_start,
878 for (i = 0; i < nruns; i++)
880 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
881 Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
885 if (EQ (font, Vthe_null_font_instance))
888 this_width = x_text_width_single_run (cachel, runs + i);
889 need_clipping = (dl->clip || clip_start > xpos ||
890 clip_end < xpos + this_width);
892 /* XDrawImageString only clears the area equal to the height of
893 the given font. It is possible that a font is being displayed
894 on a line taller than it is, so this would cause us to fail to
896 if ((int) fi->height < (int) (height + dl->clip + dl->top_clip))
898 int clear_start = max (xpos, clip_start);
899 int clear_end = min (xpos + this_width, clip_end);
903 int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
905 ypos1_string = dl->ypos - fi->ascent;
906 ypos2_string = dl->ypos + fi->descent;
907 ypos1_line = DISPLAY_LINE_YPOS (dl);
908 ypos2_line = ypos1_line + DISPLAY_LINE_HEIGHT (dl);
910 /* Make sure we don't clear below the real bottom of the
912 if (ypos1_string > ypos2_line)
913 ypos1_string = ypos2_line;
914 if (ypos2_string > ypos2_line)
915 ypos2_string = ypos2_line;
917 if (ypos1_line < ypos1_string)
919 redisplay_clear_region (window, findex, clear_start, ypos1_line,
920 clear_end - clear_start,
921 ypos1_string - ypos1_line);
924 if (ypos2_line > ypos2_string)
926 redisplay_clear_region (window, findex, clear_start, ypos2_string,
927 clear_end - clear_start,
928 ypos2_line - ypos2_string);
933 redisplay_clear_region (window, findex, clear_start,
934 DISPLAY_LINE_YPOS (dl), clear_end - clear_start,
939 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value))
940 gc = x_get_gc (d, font, cursor_cachel->foreground,
941 cursor_cachel->background, Qnil, Qnil);
942 else if (cachel->dim)
944 /* Ensure the gray bitmap exists */
945 if (DEVICE_X_GRAY_PIXMAP (d) == None)
946 DEVICE_X_GRAY_PIXMAP (d) =
947 XCreateBitmapFromData (dpy, x_win, (char *)gray_bits,
948 gray_width, gray_height);
950 /* Request a GC with the gray stipple pixmap to draw dimmed text */
951 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
955 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
960 XRectangle clip_box[1];
964 clip_box[0].width = clip_end - clip_start;
965 clip_box[0].height = height;
967 XSetClipRectangles (dpy, gc, clip_start, DISPLAY_LINE_YPOS (dl),
968 clip_box, 1, Unsorted);
971 if (runs[i].dimension == 1)
972 (bgc ? XDrawString : XDrawImageString) (dpy, x_win, gc, xpos,
973 dl->ypos, (char *) runs[i].ptr,
976 (bgc ? XDrawString16 : XDrawImageString16) (dpy, x_win, gc, xpos,
978 (XChar2b *) runs[i].ptr,
981 /* We draw underlines in the same color as the text. */
982 if (cachel->underline)
984 unsigned long upos, uthick;
987 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
988 if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos))
989 upos = dl->descent / 2;
990 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
993 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
995 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
996 uthick = dl->descent - dl->clip - upos;
1000 XDrawLine (dpy, x_win, gc, xpos, dl->ypos + upos,
1001 xpos + this_width, dl->ypos + upos);
1003 else if (uthick > 1)
1005 XFillRectangle (dpy, x_win, gc, xpos,
1006 dl->ypos + upos, this_width, uthick);
1011 if (cachel->strikethru) {
1012 unsigned long ascent,descent,upos, uthick;
1015 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
1017 if (!XGetFontProperty (xfont, XA_STRIKEOUT_ASCENT, &ascent))
1018 ascent = xfont->ascent;
1019 if (!XGetFontProperty (xfont, XA_STRIKEOUT_DESCENT, &descent))
1020 descent = xfont->descent;
1021 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
1024 upos = ascent - ((ascent + descent) / 2) + 1;
1026 /* Generally, upos will be positive (above the baseline),so subtract */
1027 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip)
1029 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip)
1030 uthick = dl->descent - dl->clip + upos;
1034 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos,
1035 xpos + this_width, dl->ypos - upos);
1037 else if (uthick > 1)
1039 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos,
1040 this_width, uthick);
1045 /* Restore the GC */
1048 XSetClipMask (dpy, gc, None);
1049 XSetClipOrigin (dpy, gc, 0, 0);
1052 /* If we are actually superimposing the cursor then redraw with just
1053 the appropriate section highlighted. */
1054 if (cursor_clip && !cursor && focus && cursor_cachel)
1057 XRectangle clip_box[1];
1059 cgc = x_get_gc (d, font, cursor_cachel->foreground,
1060 cursor_cachel->background, Qnil, Qnil);
1064 clip_box[0].width = cursor_width;
1065 clip_box[0].height = height;
1067 XSetClipRectangles (dpy, cgc, cursor_start, DISPLAY_LINE_YPOS (dl),
1068 clip_box, 1, Unsorted);
1070 if (runs[i].dimension == 1)
1071 XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
1072 (char *) runs[i].ptr, runs[i].len);
1074 XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
1075 (XChar2b *) runs[i].ptr, runs[i].len);
1077 XSetClipMask (dpy, cgc, None);
1078 XSetClipOrigin (dpy, cgc, 0, 0);
1084 /* Draw the non-focus box or bar-cursor as needed. */
1085 /* Can't this logic be simplified? */
1087 && ((cursor && !focus && NILP (bar_cursor_value))
1089 && (cursor_start + cursor_width >= clip_start)
1090 && !NILP (bar_cursor_value))))
1092 int tmp_height, tmp_y;
1093 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1094 int need_clipping = (cursor_start < clip_start
1095 || clip_end < cursor_start + cursor_width);
1097 /* #### This value is correct (as far as I know) because
1098 all of the times we need to draw this cursor, we will
1099 be called with exactly one character, so we know we
1100 can always use runs[0].
1102 This is bogus as all hell, however. The cursor handling in
1103 this function is way bogus and desperately needs to be
1104 cleaned up. (In particular, the drawing of the cursor should
1105 really really be separated out of this function. This may be
1106 a bit tricky now because this function itself does way too
1107 much stuff, a lot of which needs to be moved into
1108 redisplay.c) This is the only way to be able to easily add
1109 new cursor types or (e.g.) make the bar cursor be able to
1110 span two characters instead of overlaying just one. */
1111 int bogusly_obtained_ascent_value =
1112 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent;
1114 if (!NILP (bar_cursor_value))
1116 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1117 make_int (bar_width));
1121 gc = x_get_gc (d, Qnil, cursor_cachel->background,
1125 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1126 tmp_height = cursor_height;
1127 if (tmp_y + tmp_height > (int) (DISPLAY_LINE_YPOS(dl) + height))
1129 tmp_y = DISPLAY_LINE_YPOS (dl) + height - tmp_height;
1130 if (tmp_y < (int) DISPLAY_LINE_YPOS (dl))
1131 tmp_y = DISPLAY_LINE_YPOS (dl);
1132 tmp_height = DISPLAY_LINE_YPOS (dl) + height - tmp_y;
1137 XRectangle clip_box[1];
1140 clip_box[0].width = clip_end - clip_start;
1141 clip_box[0].height = tmp_height;
1142 XSetClipRectangles (dpy, gc, clip_start, tmp_y,
1143 clip_box, 1, Unsorted);
1146 if (!focus && NILP (bar_cursor_value))
1148 XDrawRectangle (dpy, x_win, gc, cursor_start, tmp_y,
1149 cursor_width - 1, tmp_height - 1);
1151 else if (focus && !NILP (bar_cursor_value))
1153 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1, tmp_y,
1154 cursor_start + bar_width - 1, tmp_y + tmp_height - 1);
1157 /* Restore the GC */
1160 XSetClipMask (dpy, gc, None);
1161 XSetClipOrigin (dpy, gc, 0, 0);
1167 x_output_x_pixmap (struct frame *f, Lisp_Image_Instance *p, int x,
1168 int y, int xoffset, int yoffset,
1169 int width, int height, unsigned long fg, unsigned long bg,
1172 struct device *d = XDEVICE (f->device);
1173 Display *dpy = DEVICE_X_DISPLAY (d);
1174 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1178 unsigned long pixmap_mask;
1182 memset (&gcv, ~0, sizeof (XGCValues));
1183 gcv.graphics_exposures = False;
1184 gcv.foreground = fg;
1185 gcv.background = bg;
1186 pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
1188 if (IMAGE_INSTANCE_X_MASK (p))
1190 gcv.function = GXcopy;
1191 gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
1192 gcv.clip_x_origin = x - xoffset;
1193 gcv.clip_y_origin = y - yoffset;
1194 pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
1196 /* Can't set a clip rectangle because we already have a mask.
1197 Is it possible to get an equivalent effect by changing the
1198 args to XCopyArea below rather than messing with a clip box?
1199 - dkindred@cs.cmu.edu
1200 Yes. We don't clip at all now - andy@xemacs.org
1204 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
1209 /* override_gc might have a mask already--we don't want to nuke it.
1210 Maybe we can insist that override_gc have no mask, or use
1211 one of the suggestions above. */
1214 /* depth of 0 means it's a bitmap, not a pixmap, and we should use
1215 XCopyPlane (1 = current foreground color, 0 = background) instead
1216 of XCopyArea, which means that the bits in the pixmap are actual
1217 pixel values, instead of symbolic of fg/bg. */
1218 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
1221 IMAGE_INSTANCE_X_PIXMAP_SLICE
1222 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc, xoffset,
1228 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP_SLICE
1229 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc,
1230 xoffset, yoffset, width, height, x, y, 1L);
1235 x_output_pixmap (struct window *w, Lisp_Object image_instance,
1236 struct display_box *db, struct display_glyph_area *dga,
1237 face_index findex, int cursor_start, int cursor_width,
1238 int cursor_height, int bg_pixmap)
1240 struct frame *f = XFRAME (w->frame);
1241 struct device *d = XDEVICE (f->device);
1242 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1244 Display *dpy = DEVICE_X_DISPLAY (d);
1245 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1247 /* Output the pixmap. */
1249 Lisp_Object tmp_pixel;
1250 XColor tmp_bcolor, tmp_fcolor;
1252 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1253 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1254 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1255 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1257 x_output_x_pixmap (f, p, db->xpos, db->ypos,
1258 dga->xoffset, dga->yoffset,
1259 dga->width, dga->height,
1260 tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
1263 /* Draw a cursor over top of the pixmap. */
1264 if (cursor_width && cursor_height && (cursor_start >= db->xpos)
1265 && !NILP (w->text_cursor_visible_p)
1266 && (cursor_start < db->xpos + dga->width))
1269 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1270 struct face_cachel *cursor_cachel =
1271 WINDOW_FACE_CACHEL (w,
1272 get_builtin_face_cache_index
1273 (w, Vtext_cursor_face));
1275 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1277 if (cursor_width > db->xpos + dga->width - cursor_start)
1278 cursor_width = db->xpos + dga->width - cursor_start;
1282 XFillRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1287 XDrawRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1293 /*****************************************************************************
1294 x_output_vertical_divider
1296 Draw a vertical divider down the right side of the given window.
1297 ****************************************************************************/
1299 x_output_vertical_divider (struct window *w, int clear)
1301 struct frame *f = XFRAME (w->frame);
1302 struct device *d = XDEVICE (f->device);
1304 Display *dpy = DEVICE_X_DISPLAY (d);
1305 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1306 Lisp_Object tmp_pixel;
1310 enum edge_style style;
1313 int x, y1, y2, width, shadow_thickness, spacing, line_width;
1314 face_index div_face = get_builtin_face_cache_index (w, Vvertical_divider_face);
1316 width = window_divider_width (w);
1317 shadow_thickness = XINT (w->vertical_divider_shadow_thickness);
1318 spacing = XINT (w->vertical_divider_spacing);
1319 line_width = XINT (w->vertical_divider_line_width);
1320 x = WINDOW_RIGHT (w) - width;
1321 y1 = WINDOW_TOP (w);
1322 y2 = WINDOW_BOTTOM (w);
1324 memset (&gcv, ~0, sizeof (XGCValues));
1326 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1327 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1329 /* First, get the GC's. */
1330 gcv.background = tmp_color.pixel;
1331 gcv.foreground = tmp_color.pixel;
1332 gcv.graphics_exposures = False;
1333 mask = GCForeground | GCBackground | GCGraphicsExposures;
1334 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1336 /* Clear the divider area first. This needs to be done when a
1337 window split occurs. */
1339 XClearArea (dpy, x_win, x, y1, width, y2 - y1, False);
1341 /* Draw the divider line. */
1342 XFillRectangle (dpy, x_win, background_gc,
1343 x + spacing + shadow_thickness, y1,
1344 line_width, y2 - y1);
1346 if (shadow_thickness < 0)
1348 shadow_thickness = -shadow_thickness;
1349 style = EDGE_BEVEL_IN;
1353 style = EDGE_BEVEL_OUT;
1356 /* Draw the shadows around the divider line */
1357 x_bevel_area (w, div_face, x + spacing, y1,
1358 width - 2 * spacing, y2 - y1,
1359 shadow_thickness, EDGE_ALL, style);
1362 /*****************************************************************************
1365 Output a blank by clearing the area it covers in the foreground color
1367 ****************************************************************************/
1369 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
1370 int start_pixpos, int cursor_start, int cursor_width)
1372 struct frame *f = XFRAME (w->frame);
1373 struct device *d = XDEVICE (f->device);
1375 Display *dpy = DEVICE_X_DISPLAY (d);
1376 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1378 struct face_cachel *cursor_cachel =
1379 WINDOW_FACE_CACHEL (w,
1380 get_builtin_face_cache_index
1381 (w, Vtext_cursor_face));
1382 Lisp_Object bg_pmap;
1383 Lisp_Object buffer = WINDOW_BUFFER (w);
1384 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1388 int y = DISPLAY_LINE_YPOS (dl);
1389 int width = rb->width;
1390 int height = DISPLAY_LINE_HEIGHT (dl);
1392 /* Unmap all subwindows in the area we are going to blank. */
1393 redisplay_unmap_subwindows_maybe (f, x, y, width, height);
1395 if (start_pixpos > x)
1397 if (start_pixpos >= (x + width))
1401 width -= (start_pixpos - x);
1406 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
1407 if (!IMAGE_INSTANCEP (bg_pmap)
1408 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
1412 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1415 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1416 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
1419 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1421 /* If this rune is marked as having the cursor, then it is actually
1422 representing a tab. */
1423 if (!NILP (w->text_cursor_visible_p)
1424 && (rb->cursor_type == CURSOR_ON
1426 && (cursor_start + cursor_width > x)
1427 && cursor_start < (x + width))))
1429 int cursor_height, cursor_y;
1430 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1431 Lisp_Font_Instance *fi;
1433 fi = XFONT_INSTANCE (FACE_CACHEL_FONT
1434 (WINDOW_FACE_CACHEL (w, rb->findex),
1437 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1439 cursor_y = dl->ypos - fi->ascent;
1440 cursor_height = fi->height;
1441 if (cursor_y + cursor_height > y + height)
1442 cursor_height = y + height - cursor_y;
1446 if (NILP (bar_cursor_value))
1448 XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1449 fi->width, cursor_height);
1453 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1455 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1456 make_int (bar_width));
1457 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
1458 cursor_y, cursor_start + bar_width - 1,
1459 cursor_y + cursor_height - 1);
1462 else if (NILP (bar_cursor_value))
1464 XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1465 fi->width - 1, cursor_height - 1);
1470 /*****************************************************************************
1473 Output a horizontal line in the foreground of its face.
1474 ****************************************************************************/
1476 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
1478 struct frame *f = XFRAME (w->frame);
1479 struct device *d = XDEVICE (f->device);
1481 Display *dpy = DEVICE_X_DISPLAY (d);
1482 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1486 int width = rb->width;
1487 int height = DISPLAY_LINE_HEIGHT (dl);
1488 int ypos1, ypos2, ypos3, ypos4;
1490 ypos1 = DISPLAY_LINE_YPOS (dl);
1491 ypos2 = ypos1 + rb->object.hline.yoffset;
1492 ypos3 = ypos2 + rb->object.hline.thickness;
1493 ypos4 = dl->ypos + dl->descent - dl->clip;
1495 /* First clear the area not covered by the line. */
1496 if (height - rb->object.hline.thickness > 0)
1498 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1501 if (ypos2 - ypos1 > 0)
1502 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1503 if (ypos4 - ypos3 > 0)
1504 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1507 /* Now draw the line. */
1508 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1516 if (ypos3 - ypos2 > 0)
1517 XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1520 /*****************************************************************************
1523 Draw a shadow around the given area using the given GC's. It is the
1524 callers responsibility to set the GC's appropriately.
1525 ****************************************************************************/
1527 x_output_shadows (struct frame *f, int x, int y, int width, int height,
1528 GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
1529 int shadow_thickness, int edges)
1531 struct device *d = XDEVICE (f->device);
1533 Display *dpy = DEVICE_X_DISPLAY (d);
1534 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1536 XSegment top_shadow[20], bottom_shadow[20];
1539 if (shadow_thickness > 10)
1540 shadow_thickness = 10;
1541 else if (shadow_thickness < 0)
1542 shadow_thickness = 0;
1543 if (shadow_thickness > (width / 2))
1544 shadow_thickness = width / 2;
1545 if (shadow_thickness > (height / 2))
1546 shadow_thickness = height / 2;
1548 for (elt = 0; elt < shadow_thickness; elt++)
1551 int seg2 = (edges & EDGE_TOP) ? elt + shadow_thickness : elt;
1552 int bot_seg2 = (edges & EDGE_BOTTOM) ? elt + shadow_thickness : elt;
1554 if (edges & EDGE_TOP)
1556 top_shadow[seg1].x1 = x + elt;
1557 top_shadow[seg1].x2 = x + width - elt - 1;
1558 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
1560 if (edges & EDGE_LEFT)
1562 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
1563 top_shadow[seg2].y1 = y + elt;
1564 top_shadow[seg2].y2 = y + height - elt - 1;
1566 if (edges & EDGE_BOTTOM)
1568 bottom_shadow[seg1].x1 = x + elt;
1569 bottom_shadow[seg1].x2 = x + width - elt - 1;
1570 bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
1572 if (edges & EDGE_RIGHT)
1574 bottom_shadow[bot_seg2].x1 = bottom_shadow[bot_seg2].x2 = x + width - elt - 1;
1575 bottom_shadow[bot_seg2].y1 = y + elt;
1576 bottom_shadow[bot_seg2].y2 = y + height - elt - 1;
1580 XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow,
1581 ((edges & EDGE_TOP) ? shadow_thickness : 0)
1582 + ((edges & EDGE_LEFT) ? shadow_thickness : 0));
1583 XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
1584 ((edges & EDGE_BOTTOM) ? shadow_thickness : 0)
1585 + ((edges & EDGE_RIGHT) ? shadow_thickness : 0));
1588 /*****************************************************************************
1589 x_generate_shadow_pixels
1591 Given three pixels (top shadow, bottom shadow, background) massage
1592 the top and bottom shadow colors to guarantee that they differ. The
1593 background pixels are not allowed to be modified.
1595 This function modifies its parameters.
1597 This code is modified from code blatantly stolen from lwlib/xlwmenu.c
1598 ****************************************************************************/
1599 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
1600 ? ((unsigned long) (x)) : ((unsigned long) (y)))
1603 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
1604 unsigned long *bottom_shadow,
1605 unsigned long background,
1606 unsigned long core_background)
1608 struct device *d = XDEVICE (f->device);
1609 Display *dpy = DEVICE_X_DISPLAY (d);
1610 Colormap cmap = DEVICE_X_COLORMAP (d);
1611 Visual *visual = DEVICE_X_VISUAL (d);
1614 int top_frobbed = 0, bottom_frobbed = 0;
1616 /* If the top shadow is the same color as the background, try to
1618 if (*top_shadow == background)
1620 topc.pixel = background;
1621 XQueryColor (dpy, cmap, &topc);
1622 /* don't overflow/wrap! */
1623 topc.red = MINL (65535, (unsigned long) topc.red * 6 / 5);
1624 topc.green = MINL (65535, (unsigned long) topc.green * 6 / 5);
1625 topc.blue = MINL (65535, (unsigned long) topc.blue * 6 / 5);
1626 if (allocate_nearest_color (dpy, cmap, visual, &topc))
1628 *top_shadow = topc.pixel;
1633 /* If the bottom shadow is the same color as the background, try to
1635 if (*bottom_shadow == background)
1637 botc.pixel = background;
1638 XQueryColor (dpy, cmap, &botc);
1639 botc.red = (unsigned short) ((unsigned long) botc.red * 3 / 5);
1640 botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5);
1641 botc.blue = (unsigned short) ((unsigned long) botc.blue * 3 / 5);
1642 if (allocate_nearest_color (dpy, cmap, visual, &botc))
1644 *bottom_shadow = botc.pixel;
1649 /* If we had to adjust both shadows, then we have to do some
1651 if (top_frobbed && bottom_frobbed)
1653 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
1654 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
1655 if (bot_avg > top_avg)
1657 Pixel tmp = *top_shadow;
1659 *top_shadow = *bottom_shadow;
1660 *bottom_shadow = tmp;
1662 else if (topc.pixel == botc.pixel)
1664 if (botc.pixel == background)
1665 *top_shadow = core_background;
1667 *bottom_shadow = background;
1672 /*****************************************************************************
1673 x_redraw_exposed_window
1675 Given a bounding box for an area that needs to be redrawn, determine
1676 what parts of what lines are contained within and re-output their
1678 ****************************************************************************/
1680 x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
1682 struct frame *f = XFRAME (w->frame);
1684 int start_x, start_y, end_x, end_y;
1685 int orig_windows_structure_changed;
1687 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1689 if (!NILP (w->vchild))
1691 x_redraw_exposed_windows (w->vchild, x, y, width, height);
1694 else if (!NILP (w->hchild))
1696 x_redraw_exposed_windows (w->hchild, x, y, width, height);
1700 /* If the window doesn't intersect the exposed region, we're done here. */
1701 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w)
1702 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w))
1708 start_x = max (WINDOW_LEFT (w), x);
1709 end_x = min (WINDOW_RIGHT (w), (x + width));
1710 start_y = max (WINDOW_TOP (w), y);
1711 end_y = min (WINDOW_BOTTOM (w), y + height);
1713 /* We do this to make sure that the 3D modelines get redrawn if
1714 they are in the exposed region. */
1715 orig_windows_structure_changed = f->windows_structure_changed;
1716 f->windows_structure_changed = 1;
1719 if (window_needs_vertical_divider (w))
1721 x_output_vertical_divider (w, 0);
1724 for (line = 0; line < Dynarr_length (cdla); line++)
1726 struct display_line *cdl = Dynarr_atp (cdla, line);
1727 int top_y = cdl->ypos - cdl->ascent;
1728 int bottom_y = cdl->ypos + cdl->descent;
1730 if (bottom_y >= start_y)
1741 output_display_line (w, 0, cdla, line, start_x, end_x);
1746 f->windows_structure_changed = orig_windows_structure_changed;
1748 /* If there have never been any face cache_elements created, then this
1749 expose event doesn't actually have anything to do. */
1750 if (Dynarr_largest (w->face_cachels))
1751 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
1754 /*****************************************************************************
1755 x_redraw_exposed_windows
1757 For each window beneath the given window in the window hierarchy,
1758 ensure that it is redrawn if necessary after an Expose event.
1759 ****************************************************************************/
1761 x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
1764 for (; !NILP (window); window = XWINDOW (window)->next)
1765 x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
1768 /*****************************************************************************
1769 x_redraw_exposed_area
1771 For each window on the given frame, ensure that any area in the
1772 Exposed area is redrawn.
1773 ****************************************************************************/
1775 x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
1777 /* If any window on the frame has had its face cache reset then the
1778 redisplay structures are effectively invalid. If we attempt to
1779 use them we'll blow up. We mark the frame as changed to ensure
1780 that redisplay will do a full update. This probably isn't
1781 necessary but it can't hurt. */
1783 #ifdef HAVE_TOOLBARS
1784 /* #### We would rather put these off as well but there is currently
1785 no combination of flags which will force an unchanged toolbar to
1787 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
1789 redraw_exposed_gutters (f, x, y, width, height);
1791 if (!f->window_face_cache_reset)
1793 x_redraw_exposed_windows (f->root_window, x, y, width, height);
1795 XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
1798 MARK_FRAME_CHANGED (f);
1801 /****************************************************************************
1804 Clear the area in the box defined by the given parameters using the
1806 ****************************************************************************/
1808 x_clear_region (Lisp_Object locale, struct device* d, struct frame* f, face_index findex,
1810 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1811 Lisp_Object background_pixmap)
1817 dpy = DEVICE_X_DISPLAY (d);
1818 x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1820 if (!UNBOUNDP (background_pixmap))
1822 gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
1826 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1828 XClearArea (dpy, x_win, x, y, width, height, False);
1831 /*****************************************************************************
1834 Draw a cursor at the end of a line. The end-of-line cursor is
1835 narrower than the normal cursor.
1836 ****************************************************************************/
1838 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos,
1841 struct frame *f = XFRAME (w->frame);
1842 struct device *d = XDEVICE (f->device);
1845 Display *dpy = DEVICE_X_DISPLAY (d);
1846 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1848 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
1849 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
1851 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1852 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1856 int y = DISPLAY_LINE_YPOS (dl);
1857 int width = EOL_CURSOR_WIDTH;
1858 int height = DISPLAY_LINE_HEIGHT (dl);
1859 int cursor_height, cursor_y;
1860 int defheight, defascent;
1862 XSETWINDOW (window, w);
1863 redisplay_clear_region (window, findex, x, y, width, height);
1865 if (NILP (w->text_cursor_visible_p))
1868 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1870 default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
1872 /* make sure the cursor is entirely contained between y and y+height */
1873 cursor_height = min (defheight, height);
1874 cursor_y = max (y, min (y + height - cursor_height,
1875 dl->ypos - defascent));
1880 XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2);
1881 #endif /* HAVE_XIM */
1883 if (NILP (bar_cursor_value))
1885 XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
1889 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1891 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1892 make_int (bar_width));
1893 XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
1894 x + bar_width - 1, cursor_y + cursor_height - 1);
1897 else if (NILP (bar_cursor_value))
1899 XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
1905 x_clear_frame_window (Lisp_Object window)
1907 struct window *w = XWINDOW (window);
1909 if (!NILP (w->vchild))
1911 x_clear_frame_windows (w->vchild);
1915 if (!NILP (w->hchild))
1917 x_clear_frame_windows (w->hchild);
1921 redisplay_clear_to_window_end (w, WINDOW_TEXT_TOP (w),
1922 WINDOW_TEXT_BOTTOM (w));
1926 x_clear_frame_windows (Lisp_Object window)
1928 for (; !NILP (window); window = XWINDOW (window)->next)
1929 x_clear_frame_window (window);
1933 x_clear_frame (struct frame *f)
1935 struct device *d = XDEVICE (f->device);
1936 Display *dpy = DEVICE_X_DISPLAY (d);
1937 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1938 int x, y, width, height;
1941 x = FRAME_LEFT_BORDER_START (f);
1942 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
1943 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
1944 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) -
1945 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f));
1946 /* #### This adjustment by 1 should be being done in the macros.
1947 There is some small differences between when the menubar is on
1948 and off that we still need to deal with. */
1949 y = FRAME_TOP_BORDER_START (f) - 1;
1950 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
1951 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
1952 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) -
1953 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1;
1955 XClearArea (dpy, x_win, x, y, width, height, False);
1957 XSETFRAME (frame, f);
1959 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
1960 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
1961 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
1963 x_clear_frame_windows (f->root_window);
1966 XFlush (DEVICE_X_DISPLAY (d));
1969 /* briefly swap the foreground and background colors.
1973 x_flash (struct device *d)
1979 XColor tmp_fcolor, tmp_bcolor;
1980 Lisp_Object tmp_pixel, frame;
1981 struct frame *f = device_selected_frame (d);
1982 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f));
1983 Widget shell = FRAME_X_SHELL_WIDGET (f);
1986 XSETFRAME (frame, f);
1988 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
1989 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1990 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
1991 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1993 dpy = XtDisplay (shell);
1994 win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1995 memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
1996 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
1997 gcv.function = GXxor;
1998 gcv.graphics_exposures = False;
1999 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
2000 (GCForeground | GCFunction | GCGraphicsExposures));
2001 default_face_height_and_width (frame, &flash_height, 0);
2003 /* If window is tall, flash top and bottom line. */
2004 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
2006 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2007 w->pixel_width, flash_height);
2008 XFillRectangle (dpy, win, gc, w->pixel_left,
2009 w->pixel_top + w->pixel_height - flash_height,
2010 w->pixel_width, flash_height);
2013 /* If it is short, flash it all. */
2014 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2015 w->pixel_width, w->pixel_height);
2023 tv.tv_sec = usecs / 1000000L;
2024 tv.tv_usec = usecs % 1000000L;
2025 /* I'm sure someone is going to complain about this... */
2026 select (0, 0, 0, 0, &tv);
2031 #else /* !HAVE_POLL */
2033 #endif /* HAVE_POLL */
2034 #endif /* HAVE_SELECT */
2036 /* If window is tall, flash top and bottom line. */
2037 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
2039 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2040 w->pixel_width, flash_height);
2041 XFillRectangle (dpy, win, gc, w->pixel_left,
2042 w->pixel_top + w->pixel_height - flash_height,
2043 w->pixel_width, flash_height);
2046 /* If it is short, flash it all. */
2047 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2048 w->pixel_width, w->pixel_height);
2055 /* Make audible bell. */
2058 x_ring_bell (struct device *d, int volume, int pitch, int duration)
2060 Display *display = DEVICE_X_DISPLAY (d);
2062 if (volume < 0) volume = 0;
2063 else if (volume > 100) volume = 100;
2064 if (pitch < 0 && duration < 0)
2066 XBell (display, (volume * 2) - 100);
2071 XKeyboardState state;
2072 XKeyboardControl ctl;
2074 /* #### grab server? */
2075 XGetKeyboardControl (display, &state);
2077 ctl.bell_pitch = (pitch >= 0 ? pitch : state.bell_pitch);
2078 ctl.bell_duration = (duration >= 0 ? duration : state.bell_duration);
2079 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2081 XBell (display, (volume * 2) - 100);
2083 ctl.bell_pitch = state.bell_pitch;
2084 ctl.bell_duration = state.bell_duration;
2085 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2087 /* #### ungrab server? */
2093 /************************************************************************/
2094 /* initialization */
2095 /************************************************************************/
2098 console_type_create_redisplay_x (void)
2100 /* redisplay methods */
2101 CONSOLE_HAS_METHOD (x, text_width);
2102 CONSOLE_HAS_METHOD (x, output_display_block);
2103 CONSOLE_HAS_METHOD (x, divider_height);
2104 CONSOLE_HAS_METHOD (x, eol_cursor_width);
2105 CONSOLE_HAS_METHOD (x, output_vertical_divider);
2106 CONSOLE_HAS_METHOD (x, clear_region);
2107 CONSOLE_HAS_METHOD (x, clear_frame);
2108 CONSOLE_HAS_METHOD (x, window_output_begin);
2109 CONSOLE_HAS_METHOD (x, window_output_end);
2110 CONSOLE_HAS_METHOD (x, flash);
2111 CONSOLE_HAS_METHOD (x, ring_bell);
2112 CONSOLE_HAS_METHOD (x, bevel_area);
2113 CONSOLE_HAS_METHOD (x, output_string);
2114 CONSOLE_HAS_METHOD (x, output_pixmap);