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);
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);
357 buf = Dynarr_new (Charc);
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;
453 redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset,
454 rb->object.dglyph.yoffset, start_pixpos,
455 rb->width, &dbox, &dga);
457 XSETWINDOW (window, w);
458 instance = glyph_image_instance (rb->object.dglyph.glyph,
459 window, ERROR_ME_NOT, 1);
462 if (IMAGE_INSTANCEP (instance))
464 switch (XIMAGE_INSTANCE_TYPE (instance))
466 case IMAGE_MONO_PIXMAP:
467 case IMAGE_COLOR_PIXMAP:
468 redisplay_output_pixmap (w, instance, &dbox, &dga, findex,
469 cursor_start, cursor_width,
474 if (EQ (XIMAGE_INSTANCE_WIDGET_TYPE (instance),
477 redisplay_output_layout (window, instance, &dbox, &dga, findex,
478 cursor_start, cursor_width,
482 case IMAGE_SUBWINDOW:
483 redisplay_output_subwindow (w, instance, &dbox, &dga, findex,
484 cursor_start, cursor_width,
489 /* nothing is as nothing does */
497 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
498 (XIMAGE_INSTANCE (instance)) = 0;
509 if (Dynarr_length (buf))
510 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
511 0, cursor_start, cursor_width, cursor_height);
513 /* #### This is really conditionalized well for optimized
516 && !EQ (Qzero, w->modeline_shadow_thickness)
518 || f->windows_structure_changed
519 || w->shadow_thickness_changed))
520 bevel_modeline (w, dl);
525 /*****************************************************************************
528 Draw shadows for the given area in the given face.
529 ****************************************************************************/
531 x_bevel_area (struct window *w, face_index findex,
532 int x, int y, int width, int height,
533 int shadow_thickness, int edges, enum edge_style style)
535 struct frame *f = XFRAME (w->frame);
536 struct device *d = XDEVICE (f->device);
538 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
539 Display *dpy = DEVICE_X_DISPLAY (d);
540 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
541 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
542 Lisp_Object tmp_pixel;
545 GC top_shadow_gc, bottom_shadow_gc, background_gc;
551 assert (shadow_thickness >=0);
552 memset (&gcv, ~0, sizeof (XGCValues));
554 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
555 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
557 /* First, get the GC's. */
558 top_shadow_pixel = tmp_color.pixel;
559 bottom_shadow_pixel = tmp_color.pixel;
560 background_pixel = tmp_color.pixel;
562 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
563 background_pixel, ef->core.background_pixel);
565 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
566 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
567 gcv.background = tmp_color.pixel;
568 gcv.graphics_exposures = False;
569 mask = GCForeground | GCBackground | GCGraphicsExposures;
571 /* If we can't distinguish one of the shadows (the color is the same as the
572 background), it's better to use a pixmap to generate a dithered gray. */
573 if (top_shadow_pixel == background_pixel ||
574 bottom_shadow_pixel == background_pixel)
579 if (DEVICE_X_GRAY_PIXMAP (d) == None)
581 DEVICE_X_GRAY_PIXMAP (d) =
582 XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
583 gray_width, gray_height, 1, 0, 1);
586 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
587 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
588 gcv.foreground = tmp_color.pixel;
589 /* this is needed because the GC draws with a pixmap here */
590 gcv.fill_style = FillOpaqueStippled;
591 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
592 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
593 (mask | GCStipple | GCFillStyle));
595 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
596 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
597 bottom_shadow_pixel = tmp_color.pixel;
599 flip_gcs = (bottom_shadow_pixel ==
600 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
604 gcv.foreground = top_shadow_pixel;
605 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
608 gcv.foreground = bottom_shadow_pixel;
609 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
611 if (use_pixmap && flip_gcs)
613 GC tmp_gc = bottom_shadow_gc;
614 bottom_shadow_gc = top_shadow_gc;
615 top_shadow_gc = tmp_gc;
618 gcv.foreground = background_pixel;
619 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
621 /* possibly revert the GC's This will give a depressed look to the
623 if (style == EDGE_ETCHED_IN || style == EDGE_BEVEL_IN)
627 temp = top_shadow_gc;
628 top_shadow_gc = bottom_shadow_gc;
629 bottom_shadow_gc = temp;
632 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
633 shadow_thickness /= 2;
635 /* Draw the shadows around the divider line */
636 x_output_shadows (f, x, y, width, height,
637 top_shadow_gc, bottom_shadow_gc,
638 background_gc, shadow_thickness, edges);
640 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
642 /* Draw the shadows around the divider line */
643 x_output_shadows (f, x + shadow_thickness, y + shadow_thickness,
644 width - 2*shadow_thickness, height - 2*shadow_thickness,
645 bottom_shadow_gc, top_shadow_gc,
646 background_gc, shadow_thickness, edges);
650 /*****************************************************************************
653 Given a number of parameters return a GC with those properties.
654 ****************************************************************************/
656 x_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
657 Lisp_Object bg_pmap, Lisp_Object lwidth)
662 memset (&gcv, ~0, sizeof (XGCValues));
663 gcv.graphics_exposures = False;
664 /* Make absolutely sure that we don't pick up a clipping region in
665 the GC returned by this function. */
666 gcv.clip_mask = None;
667 gcv.clip_x_origin = 0;
668 gcv.clip_y_origin = 0;
669 gcv.fill_style = FillSolid;
670 mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
675 gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
680 if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg))
682 /* #### I fixed once case where this was getting it. It was a
683 bad macro expansion (compiler bug). */
684 stderr_out ("Help! x_get_gc got a bogus fg value! fg = ");
691 if (COLOR_INSTANCEP (fg))
692 gcv.foreground = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (fg)).pixel;
694 gcv.foreground = XINT (fg);
695 mask |= GCForeground;
700 if (COLOR_INSTANCEP (bg))
701 gcv.background = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (bg)).pixel;
703 gcv.background = XINT (bg);
704 mask |= GCBackground;
707 /* This special case comes from a request to draw text with a face which has
708 the dim property. We'll use a stippled foreground GC. */
709 if (EQ (bg_pmap, Qdim))
711 assert (DEVICE_X_GRAY_PIXMAP (d) != None);
713 gcv.fill_style = FillStippled;
714 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
715 mask |= (GCFillStyle | GCStipple);
717 else if (IMAGE_INSTANCEP (bg_pmap)
718 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
720 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
722 gcv.fill_style = FillOpaqueStippled;
723 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
724 mask |= (GCStipple | GCFillStyle);
728 gcv.fill_style = FillTiled;
729 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
730 mask |= (GCTile | GCFillStyle);
736 gcv.line_width = XINT (lwidth);
740 return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
743 /*****************************************************************************
746 Given a string and a starting position, output that string in the
747 given face. If cursor is true, draw a cursor around the string.
748 Correctly handles multiple charsets in the string.
750 The meaning of the parameters is something like this:
752 W Window that the text is to be displayed in.
753 DL Display line that this text is on. The values in the
754 structure are used to determine the vertical position and
755 clipping range of the text.
756 BUF Dynamic array of Emchars specifying what is actually to be
758 XPOS X position in pixels where the text should start being drawn.
759 XOFFSET Number of pixels to be chopped off the left side of the
760 text. The effect is as if the text were shifted to the
761 left this many pixels and clipped at XPOS.
762 CLIP_START Clip everything left of this X position.
763 WIDTH Clip everything right of XPOS + WIDTH.
764 FINDEX Index for the face cache element describing how to display
766 CURSOR #### I don't understand this. There's something
767 strange and overcomplexified with this variable.
768 Chuck, explain please?
769 CURSOR_START Starting X position of cursor.
770 CURSOR_WIDTH Width of cursor in pixels.
771 CURSOR_HEIGHT Height of cursor in pixels.
773 Starting Y position of cursor is the top of the text line.
774 The cursor is drawn sometimes whether or not CURSOR is set. ???
775 ****************************************************************************/
777 x_output_string (struct window *w, struct display_line *dl,
778 Charc_dynarr *buf, int xpos, int xoffset, int clip_start,
779 int width, face_index findex, int cursor,
780 int cursor_start, int cursor_width, int cursor_height)
782 /* General variables */
783 struct frame *f = XFRAME (w->frame);
784 struct device *d = XDEVICE (f->device);
787 Display *dpy = DEVICE_X_DISPLAY (d);
788 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
792 /* Cursor-related variables */
793 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
795 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
797 struct face_cachel *cursor_cachel = 0;
799 /* Text-related variables */
803 int len = Dynarr_length (buf);
804 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
805 struct textual_run *runs = alloca_array (struct textual_run, len);
808 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
810 XSETDEVICE (device, d);
811 XSETWINDOW (window, w);
814 width = x_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
815 height = DISPLAY_LINE_HEIGHT (dl);
817 /* Regularize the variables passed in. */
819 if (clip_start < xpos)
821 clip_end = xpos + width;
822 if (clip_start >= clip_end)
823 /* It's all clipped out. */
828 /* make sure the area we are about to display is subwindow free. */
829 redisplay_unmap_subwindows_maybe (f, clip_start, DISPLAY_LINE_YPOS (dl),
830 clip_end - clip_start, DISPLAY_LINE_HEIGHT (dl));
832 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
833 Dynarr_length (buf));
835 cursor_clip = (cursor_start >= clip_start &&
836 cursor_start < clip_end);
838 /* This cursor code is really a mess. */
839 if (!NILP (w->text_cursor_visible_p)
843 && (cursor_start + cursor_width >= clip_start)
844 && !NILP (bar_cursor_value))))
846 /* These have to be in separate statements in order to avoid a
848 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face);
849 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks);
851 /* We have to reset this since any call to WINDOW_FACE_CACHEL
852 may cause the cache to resize and any pointers to it to
854 cachel = WINDOW_FACE_CACHEL (w, findex);
858 if (cursor && focus && (cursor_start == clip_start) && cursor_height)
859 XIM_SetSpotLocation (f, xpos - 2, dl->ypos + dl->descent - 2);
860 #endif /* HAVE_XIM */
862 bg_pmap = cachel->background_pixmap;
863 if (!IMAGE_INSTANCEP (bg_pmap)
864 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
867 if ((cursor && focus && NILP (bar_cursor_value)
868 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap))
871 bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
875 XFillRectangle (dpy, x_win, bgc, clip_start,
876 DISPLAY_LINE_YPOS (dl), clip_end - clip_start,
879 for (i = 0; i < nruns; i++)
881 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
882 Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
886 if (EQ (font, Vthe_null_font_instance))
889 this_width = x_text_width_single_run (cachel, runs + i);
890 need_clipping = (dl->clip || clip_start > xpos ||
891 clip_end < xpos + this_width);
893 /* XDrawImageString only clears the area equal to the height of
894 the given font. It is possible that a font is being displayed
895 on a line taller than it is, so this would cause us to fail to
897 if ((int) fi->height < (int) (height + dl->clip + dl->top_clip))
899 int clear_start = max (xpos, clip_start);
900 int clear_end = min (xpos + this_width, clip_end);
904 int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
906 ypos1_string = dl->ypos - fi->ascent;
907 ypos2_string = dl->ypos + fi->descent;
908 ypos1_line = DISPLAY_LINE_YPOS (dl);
909 ypos2_line = ypos1_line + DISPLAY_LINE_HEIGHT (dl);
911 /* Make sure we don't clear below the real bottom of the
913 if (ypos1_string > ypos2_line)
914 ypos1_string = ypos2_line;
915 if (ypos2_string > ypos2_line)
916 ypos2_string = ypos2_line;
918 if (ypos1_line < ypos1_string)
920 redisplay_clear_region (window, findex, clear_start, ypos1_line,
921 clear_end - clear_start,
922 ypos1_string - ypos1_line);
925 if (ypos2_line > ypos2_string)
927 redisplay_clear_region (window, findex, clear_start, ypos2_string,
928 clear_end - clear_start,
929 ypos2_line - ypos2_string);
934 redisplay_clear_region (window, findex, clear_start,
935 DISPLAY_LINE_YPOS (dl), clear_end - clear_start,
940 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value))
941 gc = x_get_gc (d, font, cursor_cachel->foreground,
942 cursor_cachel->background, Qnil, Qnil);
943 else if (cachel->dim)
945 /* Ensure the gray bitmap exists */
946 if (DEVICE_X_GRAY_PIXMAP (d) == None)
947 DEVICE_X_GRAY_PIXMAP (d) =
948 XCreateBitmapFromData (dpy, x_win, (char *)gray_bits,
949 gray_width, gray_height);
951 /* Request a GC with the gray stipple pixmap to draw dimmed text */
952 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
956 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
961 XRectangle clip_box[1];
965 clip_box[0].width = clip_end - clip_start;
966 clip_box[0].height = height;
968 XSetClipRectangles (dpy, gc, clip_start, DISPLAY_LINE_YPOS (dl),
969 clip_box, 1, Unsorted);
972 if (runs[i].dimension == 1)
973 (bgc ? XDrawString : XDrawImageString) (dpy, x_win, gc, xpos,
974 dl->ypos, (char *) runs[i].ptr,
977 (bgc ? XDrawString16 : XDrawImageString16) (dpy, x_win, gc, xpos,
979 (XChar2b *) runs[i].ptr,
982 /* We draw underlines in the same color as the text. */
983 if (cachel->underline)
985 /* upos is naturally signed, why would anyone think otherwise?
986 uthick is signed to avoid unsigned propagation. */
990 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
991 if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos))
992 upos = dl->descent / 2;
993 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
996 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
998 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
999 uthick = dl->descent - dl->clip - upos;
1003 XDrawLine (dpy, x_win, gc, xpos, dl->ypos + upos,
1004 xpos + this_width, dl->ypos + upos);
1006 else if (uthick > 1)
1008 XFillRectangle (dpy, x_win, gc, xpos,
1009 dl->ypos + upos, this_width, uthick);
1014 if (cachel->strikethru) {
1015 /* ascent, descent, and upos are naturally signed; why would anyone
1016 think otherwise? uthick is signed to avoid unsigned propagation. */
1017 long ascent, descent, upos, uthick;
1020 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
1022 if (!XGetFontProperty (xfont, XA_STRIKEOUT_ASCENT, &ascent))
1023 ascent = xfont->ascent;
1024 if (!XGetFontProperty (xfont, XA_STRIKEOUT_DESCENT, &descent))
1025 descent = xfont->descent;
1026 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
1029 upos = ascent - ((ascent + descent) / 2) + 1;
1031 /* Generally, upos will be positive (above the baseline),so subtract */
1032 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip)
1034 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip)
1035 uthick = dl->descent - dl->clip + upos;
1039 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos,
1040 xpos + this_width, dl->ypos - upos);
1042 else if (uthick > 1)
1044 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos,
1045 this_width, uthick);
1050 /* Restore the GC */
1053 XSetClipMask (dpy, gc, None);
1054 XSetClipOrigin (dpy, gc, 0, 0);
1057 /* If we are actually superimposing the cursor then redraw with just
1058 the appropriate section highlighted. */
1059 if (cursor_clip && !cursor && focus && cursor_cachel)
1062 XRectangle clip_box[1];
1064 cgc = x_get_gc (d, font, cursor_cachel->foreground,
1065 cursor_cachel->background, Qnil, Qnil);
1069 clip_box[0].width = cursor_width;
1070 clip_box[0].height = height;
1072 XSetClipRectangles (dpy, cgc, cursor_start, DISPLAY_LINE_YPOS (dl),
1073 clip_box, 1, Unsorted);
1075 if (runs[i].dimension == 1)
1076 XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
1077 (char *) runs[i].ptr, runs[i].len);
1079 XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
1080 (XChar2b *) runs[i].ptr, runs[i].len);
1082 XSetClipMask (dpy, cgc, None);
1083 XSetClipOrigin (dpy, cgc, 0, 0);
1089 /* Draw the non-focus box or bar-cursor as needed. */
1090 /* Can't this logic be simplified? */
1092 && ((cursor && !focus && NILP (bar_cursor_value))
1094 && (cursor_start + cursor_width >= clip_start)
1095 && !NILP (bar_cursor_value))))
1097 int tmp_height, tmp_y;
1098 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1099 int need_clipping = (cursor_start < clip_start
1100 || clip_end < cursor_start + cursor_width);
1102 /* #### This value is correct (as far as I know) because
1103 all of the times we need to draw this cursor, we will
1104 be called with exactly one character, so we know we
1105 can always use runs[0].
1107 This is bogus as all hell, however. The cursor handling in
1108 this function is way bogus and desperately needs to be
1109 cleaned up. (In particular, the drawing of the cursor should
1110 really really be separated out of this function. This may be
1111 a bit tricky now because this function itself does way too
1112 much stuff, a lot of which needs to be moved into
1113 redisplay.c) This is the only way to be able to easily add
1114 new cursor types or (e.g.) make the bar cursor be able to
1115 span two characters instead of overlaying just one. */
1116 int bogusly_obtained_ascent_value =
1117 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent;
1119 if (!NILP (bar_cursor_value))
1121 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1122 make_int (bar_width));
1126 gc = x_get_gc (d, Qnil, cursor_cachel->background,
1130 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1131 tmp_height = cursor_height;
1132 if (tmp_y + tmp_height > (int) (DISPLAY_LINE_YPOS(dl) + height))
1134 tmp_y = DISPLAY_LINE_YPOS (dl) + height - tmp_height;
1135 if (tmp_y < (int) DISPLAY_LINE_YPOS (dl))
1136 tmp_y = DISPLAY_LINE_YPOS (dl);
1137 tmp_height = DISPLAY_LINE_YPOS (dl) + height - tmp_y;
1142 XRectangle clip_box[1];
1145 clip_box[0].width = clip_end - clip_start;
1146 clip_box[0].height = tmp_height;
1147 XSetClipRectangles (dpy, gc, clip_start, tmp_y,
1148 clip_box, 1, Unsorted);
1151 if (!focus && NILP (bar_cursor_value))
1153 XDrawRectangle (dpy, x_win, gc, cursor_start, tmp_y,
1154 cursor_width - 1, tmp_height - 1);
1156 else if (focus && !NILP (bar_cursor_value))
1158 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1, tmp_y,
1159 cursor_start + bar_width - 1, tmp_y + tmp_height - 1);
1162 /* Restore the GC */
1165 XSetClipMask (dpy, gc, None);
1166 XSetClipOrigin (dpy, gc, 0, 0);
1172 x_output_x_pixmap (struct frame *f, Lisp_Image_Instance *p, int x,
1173 int y, int xoffset, int yoffset,
1174 int width, int height, unsigned long fg, unsigned long bg,
1177 struct device *d = XDEVICE (f->device);
1178 Display *dpy = DEVICE_X_DISPLAY (d);
1179 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1183 unsigned long pixmap_mask;
1187 memset (&gcv, ~0, sizeof (XGCValues));
1188 gcv.graphics_exposures = False;
1189 gcv.foreground = fg;
1190 gcv.background = bg;
1191 pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
1193 if (IMAGE_INSTANCE_X_MASK (p))
1195 gcv.function = GXcopy;
1196 gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
1197 gcv.clip_x_origin = x - xoffset;
1198 gcv.clip_y_origin = y - yoffset;
1199 pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
1201 /* Can't set a clip rectangle because we already have a mask.
1202 Is it possible to get an equivalent effect by changing the
1203 args to XCopyArea below rather than messing with a clip box?
1204 - dkindred@cs.cmu.edu
1205 Yes. We don't clip at all now - andy@xemacs.org
1209 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
1214 /* override_gc might have a mask already--we don't want to nuke it.
1215 Maybe we can insist that override_gc have no mask, or use
1216 one of the suggestions above. */
1219 /* depth of 0 means it's a bitmap, not a pixmap, and we should use
1220 XCopyPlane (1 = current foreground color, 0 = background) instead
1221 of XCopyArea, which means that the bits in the pixmap are actual
1222 pixel values, instead of symbolic of fg/bg. */
1223 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
1226 IMAGE_INSTANCE_X_PIXMAP_SLICE
1227 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc, xoffset,
1233 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP_SLICE
1234 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc,
1235 xoffset, yoffset, width, height, x, y, 1L);
1240 x_output_pixmap (struct window *w, Lisp_Object image_instance,
1241 struct display_box *db, struct display_glyph_area *dga,
1242 face_index findex, int cursor_start, int cursor_width,
1243 int cursor_height, int bg_pixmap)
1245 struct frame *f = XFRAME (w->frame);
1246 struct device *d = XDEVICE (f->device);
1247 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1249 Display *dpy = DEVICE_X_DISPLAY (d);
1250 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1252 /* Output the pixmap. */
1254 Lisp_Object tmp_pixel;
1255 XColor tmp_bcolor, tmp_fcolor;
1257 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1258 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1259 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1260 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1262 x_output_x_pixmap (f, p, db->xpos, db->ypos,
1263 dga->xoffset, dga->yoffset,
1264 dga->width, dga->height,
1265 tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
1268 /* Draw a cursor over top of the pixmap. */
1269 if (cursor_width && cursor_height && (cursor_start >= db->xpos)
1270 && !NILP (w->text_cursor_visible_p)
1271 && (cursor_start < db->xpos + dga->width))
1274 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1275 struct face_cachel *cursor_cachel =
1276 WINDOW_FACE_CACHEL (w,
1277 get_builtin_face_cache_index
1278 (w, Vtext_cursor_face));
1280 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1282 if (cursor_width > db->xpos + dga->width - cursor_start)
1283 cursor_width = db->xpos + dga->width - cursor_start;
1287 XFillRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1292 XDrawRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1298 /*****************************************************************************
1299 x_output_vertical_divider
1301 Draw a vertical divider down the right side of the given window.
1302 ****************************************************************************/
1304 x_output_vertical_divider (struct window *w, int clear)
1306 struct frame *f = XFRAME (w->frame);
1307 struct device *d = XDEVICE (f->device);
1309 Display *dpy = DEVICE_X_DISPLAY (d);
1310 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1311 Lisp_Object tmp_pixel;
1315 enum edge_style style;
1318 int x, y1, y2, width, shadow_thickness, spacing, line_width;
1319 face_index div_face = get_builtin_face_cache_index (w, Vvertical_divider_face);
1321 width = window_divider_width (w);
1322 shadow_thickness = XINT (w->vertical_divider_shadow_thickness);
1323 spacing = XINT (w->vertical_divider_spacing);
1324 line_width = XINT (w->vertical_divider_line_width);
1325 x = WINDOW_RIGHT (w) - width;
1326 y1 = WINDOW_TOP (w);
1327 y2 = WINDOW_BOTTOM (w);
1329 memset (&gcv, ~0, sizeof (XGCValues));
1331 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1332 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1334 /* First, get the GC's. */
1335 gcv.background = tmp_color.pixel;
1336 gcv.foreground = tmp_color.pixel;
1337 gcv.graphics_exposures = False;
1338 mask = GCForeground | GCBackground | GCGraphicsExposures;
1339 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1341 /* Clear the divider area first. This needs to be done when a
1342 window split occurs. */
1344 XClearArea (dpy, x_win, x, y1, width, y2 - y1, False);
1346 /* Draw the divider line. */
1347 XFillRectangle (dpy, x_win, background_gc,
1348 x + spacing + shadow_thickness, y1,
1349 line_width, y2 - y1);
1351 if (shadow_thickness < 0)
1353 shadow_thickness = -shadow_thickness;
1354 style = EDGE_BEVEL_IN;
1358 style = EDGE_BEVEL_OUT;
1361 /* Draw the shadows around the divider line */
1362 x_bevel_area (w, div_face, x + spacing, y1,
1363 width - 2 * spacing, y2 - y1,
1364 shadow_thickness, EDGE_ALL, style);
1367 /*****************************************************************************
1370 Output a blank by clearing the area it covers in the foreground color
1372 ****************************************************************************/
1374 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
1375 int start_pixpos, int cursor_start, int cursor_width)
1377 struct frame *f = XFRAME (w->frame);
1378 struct device *d = XDEVICE (f->device);
1380 Display *dpy = DEVICE_X_DISPLAY (d);
1381 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1383 struct face_cachel *cursor_cachel =
1384 WINDOW_FACE_CACHEL (w,
1385 get_builtin_face_cache_index
1386 (w, Vtext_cursor_face));
1387 Lisp_Object bg_pmap;
1388 Lisp_Object buffer = WINDOW_BUFFER (w);
1389 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1393 int y = DISPLAY_LINE_YPOS (dl);
1394 int width = rb->width;
1395 int height = DISPLAY_LINE_HEIGHT (dl);
1397 /* Unmap all subwindows in the area we are going to blank. */
1398 redisplay_unmap_subwindows_maybe (f, x, y, width, height);
1400 if (start_pixpos > x)
1402 if (start_pixpos >= (x + width))
1406 width -= (start_pixpos - x);
1411 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
1412 if (!IMAGE_INSTANCEP (bg_pmap)
1413 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
1417 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1420 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1421 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
1424 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1426 /* If this rune is marked as having the cursor, then it is actually
1427 representing a tab. */
1428 if (!NILP (w->text_cursor_visible_p)
1429 && (rb->cursor_type == CURSOR_ON
1431 && (cursor_start + cursor_width > x)
1432 && cursor_start < (x + width))))
1434 int cursor_height, cursor_y;
1435 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1436 Lisp_Font_Instance *fi;
1438 fi = XFONT_INSTANCE (FACE_CACHEL_FONT
1439 (WINDOW_FACE_CACHEL (w, rb->findex),
1442 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1444 cursor_y = dl->ypos - fi->ascent;
1445 cursor_height = fi->height;
1446 if (cursor_y + cursor_height > y + height)
1447 cursor_height = y + height - cursor_y;
1451 if (NILP (bar_cursor_value))
1453 XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1454 fi->width, cursor_height);
1458 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1460 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1461 make_int (bar_width));
1462 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
1463 cursor_y, cursor_start + bar_width - 1,
1464 cursor_y + cursor_height - 1);
1467 else if (NILP (bar_cursor_value))
1469 XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1470 fi->width - 1, cursor_height - 1);
1475 /*****************************************************************************
1478 Output a horizontal line in the foreground of its face.
1479 ****************************************************************************/
1481 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
1483 struct frame *f = XFRAME (w->frame);
1484 struct device *d = XDEVICE (f->device);
1486 Display *dpy = DEVICE_X_DISPLAY (d);
1487 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1491 int width = rb->width;
1492 int height = DISPLAY_LINE_HEIGHT (dl);
1493 int ypos1, ypos2, ypos3, ypos4;
1495 ypos1 = DISPLAY_LINE_YPOS (dl);
1496 ypos2 = ypos1 + rb->object.hline.yoffset;
1497 ypos3 = ypos2 + rb->object.hline.thickness;
1498 ypos4 = dl->ypos + dl->descent - dl->clip;
1500 /* First clear the area not covered by the line. */
1501 if (height - rb->object.hline.thickness > 0)
1503 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1506 if (ypos2 - ypos1 > 0)
1507 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1508 if (ypos4 - ypos3 > 0)
1509 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1512 /* Now draw the line. */
1513 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1521 if (ypos3 - ypos2 > 0)
1522 XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1525 /*****************************************************************************
1528 Draw a shadow around the given area using the given GC's. It is the
1529 callers responsibility to set the GC's appropriately.
1530 ****************************************************************************/
1532 x_output_shadows (struct frame *f, int x, int y, int width, int height,
1533 GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
1534 int shadow_thickness, int edges)
1536 struct device *d = XDEVICE (f->device);
1538 Display *dpy = DEVICE_X_DISPLAY (d);
1539 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1541 XSegment top_shadow[20], bottom_shadow[20];
1544 if (shadow_thickness > 10)
1545 shadow_thickness = 10;
1546 else if (shadow_thickness < 0)
1547 shadow_thickness = 0;
1548 if (shadow_thickness > (width / 2))
1549 shadow_thickness = width / 2;
1550 if (shadow_thickness > (height / 2))
1551 shadow_thickness = height / 2;
1553 for (elt = 0; elt < shadow_thickness; elt++)
1556 int seg2 = (edges & EDGE_TOP) ? elt + shadow_thickness : elt;
1557 int bot_seg2 = (edges & EDGE_BOTTOM) ? elt + shadow_thickness : elt;
1559 if (edges & EDGE_TOP)
1561 top_shadow[seg1].x1 = x + elt;
1562 top_shadow[seg1].x2 = x + width - elt - 1;
1563 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
1565 if (edges & EDGE_LEFT)
1567 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
1568 top_shadow[seg2].y1 = y + elt;
1569 top_shadow[seg2].y2 = y + height - elt - 1;
1571 if (edges & EDGE_BOTTOM)
1573 bottom_shadow[seg1].x1 = x + elt;
1574 bottom_shadow[seg1].x2 = x + width - elt - 1;
1575 bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
1577 if (edges & EDGE_RIGHT)
1579 bottom_shadow[bot_seg2].x1 = bottom_shadow[bot_seg2].x2 = x + width - elt - 1;
1580 bottom_shadow[bot_seg2].y1 = y + elt;
1581 bottom_shadow[bot_seg2].y2 = y + height - elt - 1;
1585 XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow,
1586 ((edges & EDGE_TOP) ? shadow_thickness : 0)
1587 + ((edges & EDGE_LEFT) ? shadow_thickness : 0));
1588 XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
1589 ((edges & EDGE_BOTTOM) ? shadow_thickness : 0)
1590 + ((edges & EDGE_RIGHT) ? shadow_thickness : 0));
1593 /*****************************************************************************
1594 x_generate_shadow_pixels
1596 Given three pixels (top shadow, bottom shadow, background) massage
1597 the top and bottom shadow colors to guarantee that they differ. The
1598 background pixels are not allowed to be modified.
1600 This function modifies its parameters.
1602 This code is modified from code blatantly stolen from lwlib/xlwmenu.c
1603 ****************************************************************************/
1604 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
1605 ? ((unsigned long) (x)) : ((unsigned long) (y)))
1608 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
1609 unsigned long *bottom_shadow,
1610 unsigned long background,
1611 unsigned long core_background)
1613 struct device *d = XDEVICE (f->device);
1614 Display *dpy = DEVICE_X_DISPLAY (d);
1615 Colormap cmap = DEVICE_X_COLORMAP (d);
1616 Visual *visual = DEVICE_X_VISUAL (d);
1619 int top_frobbed = 0, bottom_frobbed = 0;
1621 /* If the top shadow is the same color as the background, try to
1623 if (*top_shadow == background)
1625 topc.pixel = background;
1626 XQueryColor (dpy, cmap, &topc);
1627 /* don't overflow/wrap! */
1628 topc.red = MINL (65535, (unsigned long) topc.red * 6 / 5);
1629 topc.green = MINL (65535, (unsigned long) topc.green * 6 / 5);
1630 topc.blue = MINL (65535, (unsigned long) topc.blue * 6 / 5);
1631 if (allocate_nearest_color (dpy, cmap, visual, &topc))
1633 *top_shadow = topc.pixel;
1638 /* If the bottom shadow is the same color as the background, try to
1640 if (*bottom_shadow == background)
1642 botc.pixel = background;
1643 XQueryColor (dpy, cmap, &botc);
1644 botc.red = (unsigned short) ((unsigned long) botc.red * 3 / 5);
1645 botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5);
1646 botc.blue = (unsigned short) ((unsigned long) botc.blue * 3 / 5);
1647 if (allocate_nearest_color (dpy, cmap, visual, &botc))
1649 *bottom_shadow = botc.pixel;
1654 /* If we had to adjust both shadows, then we have to do some
1656 if (top_frobbed && bottom_frobbed)
1658 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
1659 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
1660 if (bot_avg > top_avg)
1662 Pixel tmp = *top_shadow;
1664 *top_shadow = *bottom_shadow;
1665 *bottom_shadow = tmp;
1667 else if (topc.pixel == botc.pixel)
1669 if (botc.pixel == background)
1670 *top_shadow = core_background;
1672 *bottom_shadow = background;
1677 /*****************************************************************************
1678 x_redraw_exposed_window
1680 Given a bounding box for an area that needs to be redrawn, determine
1681 what parts of what lines are contained within and re-output their
1683 ****************************************************************************/
1685 x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
1687 struct frame *f = XFRAME (w->frame);
1689 int start_x, start_y, end_x, end_y;
1690 int orig_windows_structure_changed;
1692 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1694 if (!NILP (w->vchild))
1696 x_redraw_exposed_windows (w->vchild, x, y, width, height);
1699 else if (!NILP (w->hchild))
1701 x_redraw_exposed_windows (w->hchild, x, y, width, height);
1705 /* If the window doesn't intersect the exposed region, we're done here. */
1706 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w)
1707 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w))
1713 start_x = max (WINDOW_LEFT (w), x);
1714 end_x = min (WINDOW_RIGHT (w), (x + width));
1715 start_y = max (WINDOW_TOP (w), y);
1716 end_y = min (WINDOW_BOTTOM (w), y + height);
1718 /* We do this to make sure that the 3D modelines get redrawn if
1719 they are in the exposed region. */
1720 orig_windows_structure_changed = f->windows_structure_changed;
1721 f->windows_structure_changed = 1;
1724 redisplay_clear_top_of_window (w);
1725 if (window_needs_vertical_divider (w))
1727 x_output_vertical_divider (w, 0);
1730 for (line = 0; line < Dynarr_length (cdla); line++)
1732 struct display_line *cdl = Dynarr_atp (cdla, line);
1733 int top_y = cdl->ypos - cdl->ascent;
1734 int bottom_y = cdl->ypos + cdl->descent;
1736 if (bottom_y >= start_y)
1747 output_display_line (w, 0, cdla, line, start_x, end_x);
1752 f->windows_structure_changed = orig_windows_structure_changed;
1754 /* If there have never been any face cache_elements created, then this
1755 expose event doesn't actually have anything to do. */
1756 if (Dynarr_largest (w->face_cachels))
1757 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
1760 /*****************************************************************************
1761 x_redraw_exposed_windows
1763 For each window beneath the given window in the window hierarchy,
1764 ensure that it is redrawn if necessary after an Expose event.
1765 ****************************************************************************/
1767 x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
1770 for (; !NILP (window); window = XWINDOW (window)->next)
1771 x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
1774 /*****************************************************************************
1775 x_redraw_exposed_area
1777 For each window on the given frame, ensure that any area in the
1778 Exposed area is redrawn.
1779 ****************************************************************************/
1781 x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
1783 /* If any window on the frame has had its face cache reset then the
1784 redisplay structures are effectively invalid. If we attempt to
1785 use them we'll blow up. We mark the frame as changed to ensure
1786 that redisplay will do a full update. This probably isn't
1787 necessary but it can't hurt. */
1789 #ifdef HAVE_TOOLBARS
1790 /* #### We would rather put these off as well but there is currently
1791 no combination of flags which will force an unchanged toolbar to
1793 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
1795 redraw_exposed_gutters (f, x, y, width, height);
1797 if (!f->window_face_cache_reset)
1799 x_redraw_exposed_windows (f->root_window, x, y, width, height);
1801 XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
1804 MARK_FRAME_CHANGED (f);
1807 /****************************************************************************
1810 Clear the area in the box defined by the given parameters using the
1812 ****************************************************************************/
1814 x_clear_region (Lisp_Object locale, struct device* d, struct frame* f, face_index findex,
1816 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1817 Lisp_Object background_pixmap)
1823 dpy = DEVICE_X_DISPLAY (d);
1824 x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1826 if (!UNBOUNDP (background_pixmap))
1828 gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
1832 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1834 XClearArea (dpy, x_win, x, y, width, height, False);
1837 /*****************************************************************************
1840 Draw a cursor at the end of a line. The end-of-line cursor is
1841 narrower than the normal cursor.
1842 ****************************************************************************/
1844 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos,
1847 struct frame *f = XFRAME (w->frame);
1848 struct device *d = XDEVICE (f->device);
1851 Display *dpy = DEVICE_X_DISPLAY (d);
1852 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1854 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
1855 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
1857 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1858 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1862 int y = DISPLAY_LINE_YPOS (dl);
1863 int width = EOL_CURSOR_WIDTH;
1864 int height = DISPLAY_LINE_HEIGHT (dl);
1865 int cursor_height, cursor_y;
1866 int defheight, defascent;
1868 XSETWINDOW (window, w);
1869 redisplay_clear_region (window, findex, x, y, width, height);
1871 if (NILP (w->text_cursor_visible_p))
1874 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1876 default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
1878 /* make sure the cursor is entirely contained between y and y+height */
1879 cursor_height = min (defheight, height);
1880 cursor_y = max (y, min (y + height - cursor_height,
1881 dl->ypos - defascent));
1886 XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2);
1887 #endif /* HAVE_XIM */
1889 if (NILP (bar_cursor_value))
1891 XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
1895 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1897 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1898 make_int (bar_width));
1899 XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
1900 x + bar_width - 1, cursor_y + cursor_height - 1);
1903 else if (NILP (bar_cursor_value))
1905 XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
1911 x_clear_frame_window (Lisp_Object window)
1913 struct window *w = XWINDOW (window);
1915 if (!NILP (w->vchild))
1917 x_clear_frame_windows (w->vchild);
1921 if (!NILP (w->hchild))
1923 x_clear_frame_windows (w->hchild);
1927 redisplay_clear_to_window_end (w, WINDOW_TEXT_TOP (w),
1928 WINDOW_TEXT_BOTTOM (w));
1932 x_clear_frame_windows (Lisp_Object window)
1934 for (; !NILP (window); window = XWINDOW (window)->next)
1935 x_clear_frame_window (window);
1939 x_clear_frame (struct frame *f)
1941 struct device *d = XDEVICE (f->device);
1942 Display *dpy = DEVICE_X_DISPLAY (d);
1943 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1944 int x, y, width, height;
1947 x = FRAME_LEFT_BORDER_START (f);
1948 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
1949 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
1950 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) -
1951 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f));
1952 /* #### This adjustment by 1 should be being done in the macros.
1953 There is some small differences between when the menubar is on
1954 and off that we still need to deal with. */
1955 y = FRAME_TOP_BORDER_START (f) - 1;
1956 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
1957 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
1958 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) -
1959 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1;
1961 XClearArea (dpy, x_win, x, y, width, height, False);
1963 XSETFRAME (frame, f);
1965 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
1966 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
1967 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
1969 x_clear_frame_windows (f->root_window);
1972 XFlush (DEVICE_X_DISPLAY (d));
1975 /* briefly swap the foreground and background colors.
1979 x_flash (struct device *d)
1985 XColor tmp_fcolor, tmp_bcolor;
1986 Lisp_Object tmp_pixel, frame;
1987 struct frame *f = device_selected_frame (d);
1988 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f));
1989 Widget shell = FRAME_X_SHELL_WIDGET (f);
1992 XSETFRAME (frame, f);
1994 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
1995 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1996 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
1997 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1999 dpy = XtDisplay (shell);
2000 win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2001 memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
2002 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
2003 gcv.function = GXxor;
2004 gcv.graphics_exposures = False;
2005 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
2006 (GCForeground | GCFunction | GCGraphicsExposures));
2007 default_face_height_and_width (frame, &flash_height, 0);
2009 /* If window is tall, flash top and bottom line. */
2010 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
2012 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2013 w->pixel_width, flash_height);
2014 XFillRectangle (dpy, win, gc, w->pixel_left,
2015 w->pixel_top + w->pixel_height - flash_height,
2016 w->pixel_width, flash_height);
2019 /* If it is short, flash it all. */
2020 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2021 w->pixel_width, w->pixel_height);
2029 tv.tv_sec = usecs / 1000000L;
2030 tv.tv_usec = usecs % 1000000L;
2031 /* I'm sure someone is going to complain about this... */
2032 select (0, 0, 0, 0, &tv);
2037 #else /* !HAVE_POLL */
2039 #endif /* HAVE_POLL */
2040 #endif /* HAVE_SELECT */
2042 /* If window is tall, flash top and bottom line. */
2043 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
2045 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2046 w->pixel_width, flash_height);
2047 XFillRectangle (dpy, win, gc, w->pixel_left,
2048 w->pixel_top + w->pixel_height - flash_height,
2049 w->pixel_width, flash_height);
2052 /* If it is short, flash it all. */
2053 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2054 w->pixel_width, w->pixel_height);
2061 /* Make audible bell. */
2064 x_ring_bell (struct device *d, int volume, int pitch, int duration)
2066 Display *display = DEVICE_X_DISPLAY (d);
2068 if (volume < 0) volume = 0;
2069 else if (volume > 100) volume = 100;
2070 if (pitch < 0 && duration < 0)
2072 XBell (display, (volume * 2) - 100);
2077 XKeyboardState state;
2078 XKeyboardControl ctl;
2080 /* #### grab server? */
2081 XGetKeyboardControl (display, &state);
2083 ctl.bell_pitch = (pitch >= 0 ? pitch : (int) state.bell_pitch);
2084 ctl.bell_duration = (duration >= 0 ? duration : (int) state.bell_duration);
2085 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2087 XBell (display, (volume * 2) - 100);
2089 ctl.bell_pitch = state.bell_pitch;
2090 ctl.bell_duration = state.bell_duration;
2091 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2093 /* #### ungrab server? */
2099 /************************************************************************/
2100 /* initialization */
2101 /************************************************************************/
2104 console_type_create_redisplay_x (void)
2106 /* redisplay methods */
2107 CONSOLE_HAS_METHOD (x, text_width);
2108 CONSOLE_HAS_METHOD (x, output_display_block);
2109 CONSOLE_HAS_METHOD (x, divider_height);
2110 CONSOLE_HAS_METHOD (x, eol_cursor_width);
2111 CONSOLE_HAS_METHOD (x, output_vertical_divider);
2112 CONSOLE_HAS_METHOD (x, clear_region);
2113 CONSOLE_HAS_METHOD (x, clear_frame);
2114 CONSOLE_HAS_METHOD (x, window_output_begin);
2115 CONSOLE_HAS_METHOD (x, window_output_end);
2116 CONSOLE_HAS_METHOD (x, flash);
2117 CONSOLE_HAS_METHOD (x, ring_bell);
2118 CONSOLE_HAS_METHOD (x, bevel_area);
2119 CONSOLE_HAS_METHOD (x, output_string);
2120 CONSOLE_HAS_METHOD (x, output_pixmap);