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;
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)
989 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
990 if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos))
991 upos = dl->descent / 2;
992 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
995 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
997 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
998 uthick = dl->descent - dl->clip - upos;
1002 XDrawLine (dpy, x_win, gc, xpos, dl->ypos + upos,
1003 xpos + this_width, dl->ypos + upos);
1005 else if (uthick > 1)
1007 XFillRectangle (dpy, x_win, gc, xpos,
1008 dl->ypos + upos, this_width, uthick);
1013 if (cachel->strikethru) {
1014 unsigned long ascent,descent,upos, uthick;
1017 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
1019 if (!XGetFontProperty (xfont, XA_STRIKEOUT_ASCENT, &ascent))
1020 ascent = xfont->ascent;
1021 if (!XGetFontProperty (xfont, XA_STRIKEOUT_DESCENT, &descent))
1022 descent = xfont->descent;
1023 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
1026 upos = ascent - ((ascent + descent) / 2) + 1;
1028 /* Generally, upos will be positive (above the baseline),so subtract */
1029 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip)
1031 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip)
1032 uthick = dl->descent - dl->clip + upos;
1036 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos,
1037 xpos + this_width, dl->ypos - upos);
1039 else if (uthick > 1)
1041 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos,
1042 this_width, uthick);
1047 /* Restore the GC */
1050 XSetClipMask (dpy, gc, None);
1051 XSetClipOrigin (dpy, gc, 0, 0);
1054 /* If we are actually superimposing the cursor then redraw with just
1055 the appropriate section highlighted. */
1056 if (cursor_clip && !cursor && focus && cursor_cachel)
1059 XRectangle clip_box[1];
1061 cgc = x_get_gc (d, font, cursor_cachel->foreground,
1062 cursor_cachel->background, Qnil, Qnil);
1066 clip_box[0].width = cursor_width;
1067 clip_box[0].height = height;
1069 XSetClipRectangles (dpy, cgc, cursor_start, DISPLAY_LINE_YPOS (dl),
1070 clip_box, 1, Unsorted);
1072 if (runs[i].dimension == 1)
1073 XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
1074 (char *) runs[i].ptr, runs[i].len);
1076 XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
1077 (XChar2b *) runs[i].ptr, runs[i].len);
1079 XSetClipMask (dpy, cgc, None);
1080 XSetClipOrigin (dpy, cgc, 0, 0);
1086 /* Draw the non-focus box or bar-cursor as needed. */
1087 /* Can't this logic be simplified? */
1089 && ((cursor && !focus && NILP (bar_cursor_value))
1091 && (cursor_start + cursor_width >= clip_start)
1092 && !NILP (bar_cursor_value))))
1094 int tmp_height, tmp_y;
1095 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1096 int need_clipping = (cursor_start < clip_start
1097 || clip_end < cursor_start + cursor_width);
1099 /* #### This value is correct (as far as I know) because
1100 all of the times we need to draw this cursor, we will
1101 be called with exactly one character, so we know we
1102 can always use runs[0].
1104 This is bogus as all hell, however. The cursor handling in
1105 this function is way bogus and desperately needs to be
1106 cleaned up. (In particular, the drawing of the cursor should
1107 really really be separated out of this function. This may be
1108 a bit tricky now because this function itself does way too
1109 much stuff, a lot of which needs to be moved into
1110 redisplay.c) This is the only way to be able to easily add
1111 new cursor types or (e.g.) make the bar cursor be able to
1112 span two characters instead of overlaying just one. */
1113 int bogusly_obtained_ascent_value =
1114 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent;
1116 if (!NILP (bar_cursor_value))
1118 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1119 make_int (bar_width));
1123 gc = x_get_gc (d, Qnil, cursor_cachel->background,
1127 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1128 tmp_height = cursor_height;
1129 if (tmp_y + tmp_height > (int) (DISPLAY_LINE_YPOS(dl) + height))
1131 tmp_y = DISPLAY_LINE_YPOS (dl) + height - tmp_height;
1132 if (tmp_y < (int) DISPLAY_LINE_YPOS (dl))
1133 tmp_y = DISPLAY_LINE_YPOS (dl);
1134 tmp_height = DISPLAY_LINE_YPOS (dl) + height - tmp_y;
1139 XRectangle clip_box[1];
1142 clip_box[0].width = clip_end - clip_start;
1143 clip_box[0].height = tmp_height;
1144 XSetClipRectangles (dpy, gc, clip_start, tmp_y,
1145 clip_box, 1, Unsorted);
1148 if (!focus && NILP (bar_cursor_value))
1150 XDrawRectangle (dpy, x_win, gc, cursor_start, tmp_y,
1151 cursor_width - 1, tmp_height - 1);
1153 else if (focus && !NILP (bar_cursor_value))
1155 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1, tmp_y,
1156 cursor_start + bar_width - 1, tmp_y + tmp_height - 1);
1159 /* Restore the GC */
1162 XSetClipMask (dpy, gc, None);
1163 XSetClipOrigin (dpy, gc, 0, 0);
1169 x_output_x_pixmap (struct frame *f, Lisp_Image_Instance *p, int x,
1170 int y, int xoffset, int yoffset,
1171 int width, int height, unsigned long fg, unsigned long bg,
1174 struct device *d = XDEVICE (f->device);
1175 Display *dpy = DEVICE_X_DISPLAY (d);
1176 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1180 unsigned long pixmap_mask;
1184 memset (&gcv, ~0, sizeof (XGCValues));
1185 gcv.graphics_exposures = False;
1186 gcv.foreground = fg;
1187 gcv.background = bg;
1188 pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
1190 if (IMAGE_INSTANCE_X_MASK (p))
1192 gcv.function = GXcopy;
1193 gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
1194 gcv.clip_x_origin = x - xoffset;
1195 gcv.clip_y_origin = y - yoffset;
1196 pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
1198 /* Can't set a clip rectangle because we already have a mask.
1199 Is it possible to get an equivalent effect by changing the
1200 args to XCopyArea below rather than messing with a clip box?
1201 - dkindred@cs.cmu.edu
1202 Yes. We don't clip at all now - andy@xemacs.org
1206 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
1211 /* override_gc might have a mask already--we don't want to nuke it.
1212 Maybe we can insist that override_gc have no mask, or use
1213 one of the suggestions above. */
1216 /* depth of 0 means it's a bitmap, not a pixmap, and we should use
1217 XCopyPlane (1 = current foreground color, 0 = background) instead
1218 of XCopyArea, which means that the bits in the pixmap are actual
1219 pixel values, instead of symbolic of fg/bg. */
1220 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
1223 IMAGE_INSTANCE_X_PIXMAP_SLICE
1224 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc, xoffset,
1230 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP_SLICE
1231 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc,
1232 xoffset, yoffset, width, height, x, y, 1L);
1237 x_output_pixmap (struct window *w, Lisp_Object image_instance,
1238 struct display_box *db, struct display_glyph_area *dga,
1239 face_index findex, int cursor_start, int cursor_width,
1240 int cursor_height, int bg_pixmap)
1242 struct frame *f = XFRAME (w->frame);
1243 struct device *d = XDEVICE (f->device);
1244 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1246 Display *dpy = DEVICE_X_DISPLAY (d);
1247 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1249 /* Output the pixmap. */
1251 Lisp_Object tmp_pixel;
1252 XColor tmp_bcolor, tmp_fcolor;
1254 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1255 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1256 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1257 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1259 x_output_x_pixmap (f, p, db->xpos, db->ypos,
1260 dga->xoffset, dga->yoffset,
1261 dga->width, dga->height,
1262 tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
1265 /* Draw a cursor over top of the pixmap. */
1266 if (cursor_width && cursor_height && (cursor_start >= db->xpos)
1267 && !NILP (w->text_cursor_visible_p)
1268 && (cursor_start < db->xpos + dga->width))
1271 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1272 struct face_cachel *cursor_cachel =
1273 WINDOW_FACE_CACHEL (w,
1274 get_builtin_face_cache_index
1275 (w, Vtext_cursor_face));
1277 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1279 if (cursor_width > db->xpos + dga->width - cursor_start)
1280 cursor_width = db->xpos + dga->width - cursor_start;
1284 XFillRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1289 XDrawRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1295 /*****************************************************************************
1296 x_output_vertical_divider
1298 Draw a vertical divider down the right side of the given window.
1299 ****************************************************************************/
1301 x_output_vertical_divider (struct window *w, int clear)
1303 struct frame *f = XFRAME (w->frame);
1304 struct device *d = XDEVICE (f->device);
1306 Display *dpy = DEVICE_X_DISPLAY (d);
1307 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1308 Lisp_Object tmp_pixel;
1312 enum edge_style style;
1315 int x, y1, y2, width, shadow_thickness, spacing, line_width;
1316 face_index div_face = get_builtin_face_cache_index (w, Vvertical_divider_face);
1318 width = window_divider_width (w);
1319 shadow_thickness = XINT (w->vertical_divider_shadow_thickness);
1320 spacing = XINT (w->vertical_divider_spacing);
1321 line_width = XINT (w->vertical_divider_line_width);
1322 x = WINDOW_RIGHT (w) - width;
1323 y1 = WINDOW_TOP (w);
1324 y2 = WINDOW_BOTTOM (w);
1326 memset (&gcv, ~0, sizeof (XGCValues));
1328 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1329 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1331 /* First, get the GC's. */
1332 gcv.background = tmp_color.pixel;
1333 gcv.foreground = tmp_color.pixel;
1334 gcv.graphics_exposures = False;
1335 mask = GCForeground | GCBackground | GCGraphicsExposures;
1336 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1338 /* Clear the divider area first. This needs to be done when a
1339 window split occurs. */
1341 XClearArea (dpy, x_win, x, y1, width, y2 - y1, False);
1343 /* Draw the divider line. */
1344 XFillRectangle (dpy, x_win, background_gc,
1345 x + spacing + shadow_thickness, y1,
1346 line_width, y2 - y1);
1348 if (shadow_thickness < 0)
1350 shadow_thickness = -shadow_thickness;
1351 style = EDGE_BEVEL_IN;
1355 style = EDGE_BEVEL_OUT;
1358 /* Draw the shadows around the divider line */
1359 x_bevel_area (w, div_face, x + spacing, y1,
1360 width - 2 * spacing, y2 - y1,
1361 shadow_thickness, EDGE_ALL, style);
1364 /*****************************************************************************
1367 Output a blank by clearing the area it covers in the foreground color
1369 ****************************************************************************/
1371 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
1372 int start_pixpos, int cursor_start, int cursor_width)
1374 struct frame *f = XFRAME (w->frame);
1375 struct device *d = XDEVICE (f->device);
1377 Display *dpy = DEVICE_X_DISPLAY (d);
1378 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1380 struct face_cachel *cursor_cachel =
1381 WINDOW_FACE_CACHEL (w,
1382 get_builtin_face_cache_index
1383 (w, Vtext_cursor_face));
1384 Lisp_Object bg_pmap;
1385 Lisp_Object buffer = WINDOW_BUFFER (w);
1386 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1390 int y = DISPLAY_LINE_YPOS (dl);
1391 int width = rb->width;
1392 int height = DISPLAY_LINE_HEIGHT (dl);
1394 /* Unmap all subwindows in the area we are going to blank. */
1395 redisplay_unmap_subwindows_maybe (f, x, y, width, height);
1397 if (start_pixpos > x)
1399 if (start_pixpos >= (x + width))
1403 width -= (start_pixpos - x);
1408 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
1409 if (!IMAGE_INSTANCEP (bg_pmap)
1410 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
1414 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1417 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1418 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
1421 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1423 /* If this rune is marked as having the cursor, then it is actually
1424 representing a tab. */
1425 if (!NILP (w->text_cursor_visible_p)
1426 && (rb->cursor_type == CURSOR_ON
1428 && (cursor_start + cursor_width > x)
1429 && cursor_start < (x + width))))
1431 int cursor_height, cursor_y;
1432 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1433 Lisp_Font_Instance *fi;
1435 fi = XFONT_INSTANCE (FACE_CACHEL_FONT
1436 (WINDOW_FACE_CACHEL (w, rb->findex),
1439 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1441 cursor_y = dl->ypos - fi->ascent;
1442 cursor_height = fi->height;
1443 if (cursor_y + cursor_height > y + height)
1444 cursor_height = y + height - cursor_y;
1448 if (NILP (bar_cursor_value))
1450 XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1451 fi->width, cursor_height);
1455 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1457 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1458 make_int (bar_width));
1459 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
1460 cursor_y, cursor_start + bar_width - 1,
1461 cursor_y + cursor_height - 1);
1464 else if (NILP (bar_cursor_value))
1466 XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1467 fi->width - 1, cursor_height - 1);
1472 /*****************************************************************************
1475 Output a horizontal line in the foreground of its face.
1476 ****************************************************************************/
1478 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
1480 struct frame *f = XFRAME (w->frame);
1481 struct device *d = XDEVICE (f->device);
1483 Display *dpy = DEVICE_X_DISPLAY (d);
1484 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1488 int width = rb->width;
1489 int height = DISPLAY_LINE_HEIGHT (dl);
1490 int ypos1, ypos2, ypos3, ypos4;
1492 ypos1 = DISPLAY_LINE_YPOS (dl);
1493 ypos2 = ypos1 + rb->object.hline.yoffset;
1494 ypos3 = ypos2 + rb->object.hline.thickness;
1495 ypos4 = dl->ypos + dl->descent - dl->clip;
1497 /* First clear the area not covered by the line. */
1498 if (height - rb->object.hline.thickness > 0)
1500 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1503 if (ypos2 - ypos1 > 0)
1504 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1505 if (ypos4 - ypos3 > 0)
1506 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1509 /* Now draw the line. */
1510 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1518 if (ypos3 - ypos2 > 0)
1519 XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1522 /*****************************************************************************
1525 Draw a shadow around the given area using the given GC's. It is the
1526 callers responsibility to set the GC's appropriately.
1527 ****************************************************************************/
1529 x_output_shadows (struct frame *f, int x, int y, int width, int height,
1530 GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
1531 int shadow_thickness, int edges)
1533 struct device *d = XDEVICE (f->device);
1535 Display *dpy = DEVICE_X_DISPLAY (d);
1536 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1538 XSegment top_shadow[20], bottom_shadow[20];
1541 if (shadow_thickness > 10)
1542 shadow_thickness = 10;
1543 else if (shadow_thickness < 0)
1544 shadow_thickness = 0;
1545 if (shadow_thickness > (width / 2))
1546 shadow_thickness = width / 2;
1547 if (shadow_thickness > (height / 2))
1548 shadow_thickness = height / 2;
1550 for (elt = 0; elt < shadow_thickness; elt++)
1553 int seg2 = (edges & EDGE_TOP) ? elt + shadow_thickness : elt;
1554 int bot_seg2 = (edges & EDGE_BOTTOM) ? elt + shadow_thickness : elt;
1556 if (edges & EDGE_TOP)
1558 top_shadow[seg1].x1 = x + elt;
1559 top_shadow[seg1].x2 = x + width - elt - 1;
1560 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
1562 if (edges & EDGE_LEFT)
1564 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
1565 top_shadow[seg2].y1 = y + elt;
1566 top_shadow[seg2].y2 = y + height - elt - 1;
1568 if (edges & EDGE_BOTTOM)
1570 bottom_shadow[seg1].x1 = x + elt;
1571 bottom_shadow[seg1].x2 = x + width - elt - 1;
1572 bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
1574 if (edges & EDGE_RIGHT)
1576 bottom_shadow[bot_seg2].x1 = bottom_shadow[bot_seg2].x2 = x + width - elt - 1;
1577 bottom_shadow[bot_seg2].y1 = y + elt;
1578 bottom_shadow[bot_seg2].y2 = y + height - elt - 1;
1582 XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow,
1583 ((edges & EDGE_TOP) ? shadow_thickness : 0)
1584 + ((edges & EDGE_LEFT) ? shadow_thickness : 0));
1585 XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
1586 ((edges & EDGE_BOTTOM) ? shadow_thickness : 0)
1587 + ((edges & EDGE_RIGHT) ? shadow_thickness : 0));
1590 /*****************************************************************************
1591 x_generate_shadow_pixels
1593 Given three pixels (top shadow, bottom shadow, background) massage
1594 the top and bottom shadow colors to guarantee that they differ. The
1595 background pixels are not allowed to be modified.
1597 This function modifies its parameters.
1599 This code is modified from code blatantly stolen from lwlib/xlwmenu.c
1600 ****************************************************************************/
1601 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
1602 ? ((unsigned long) (x)) : ((unsigned long) (y)))
1605 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
1606 unsigned long *bottom_shadow,
1607 unsigned long background,
1608 unsigned long core_background)
1610 struct device *d = XDEVICE (f->device);
1611 Display *dpy = DEVICE_X_DISPLAY (d);
1612 Colormap cmap = DEVICE_X_COLORMAP (d);
1613 Visual *visual = DEVICE_X_VISUAL (d);
1616 int top_frobbed = 0, bottom_frobbed = 0;
1618 /* If the top shadow is the same color as the background, try to
1620 if (*top_shadow == background)
1622 topc.pixel = background;
1623 XQueryColor (dpy, cmap, &topc);
1624 /* don't overflow/wrap! */
1625 topc.red = MINL (65535, (unsigned long) topc.red * 6 / 5);
1626 topc.green = MINL (65535, (unsigned long) topc.green * 6 / 5);
1627 topc.blue = MINL (65535, (unsigned long) topc.blue * 6 / 5);
1628 if (allocate_nearest_color (dpy, cmap, visual, &topc))
1630 *top_shadow = topc.pixel;
1635 /* If the bottom shadow is the same color as the background, try to
1637 if (*bottom_shadow == background)
1639 botc.pixel = background;
1640 XQueryColor (dpy, cmap, &botc);
1641 botc.red = (unsigned short) ((unsigned long) botc.red * 3 / 5);
1642 botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5);
1643 botc.blue = (unsigned short) ((unsigned long) botc.blue * 3 / 5);
1644 if (allocate_nearest_color (dpy, cmap, visual, &botc))
1646 *bottom_shadow = botc.pixel;
1651 /* If we had to adjust both shadows, then we have to do some
1653 if (top_frobbed && bottom_frobbed)
1655 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
1656 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
1657 if (bot_avg > top_avg)
1659 Pixel tmp = *top_shadow;
1661 *top_shadow = *bottom_shadow;
1662 *bottom_shadow = tmp;
1664 else if (topc.pixel == botc.pixel)
1666 if (botc.pixel == background)
1667 *top_shadow = core_background;
1669 *bottom_shadow = background;
1674 /*****************************************************************************
1675 x_redraw_exposed_window
1677 Given a bounding box for an area that needs to be redrawn, determine
1678 what parts of what lines are contained within and re-output their
1680 ****************************************************************************/
1682 x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
1684 struct frame *f = XFRAME (w->frame);
1686 int start_x, start_y, end_x, end_y;
1687 int orig_windows_structure_changed;
1689 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1691 if (!NILP (w->vchild))
1693 x_redraw_exposed_windows (w->vchild, x, y, width, height);
1696 else if (!NILP (w->hchild))
1698 x_redraw_exposed_windows (w->hchild, x, y, width, height);
1702 /* If the window doesn't intersect the exposed region, we're done here. */
1703 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w)
1704 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w))
1710 start_x = max (WINDOW_LEFT (w), x);
1711 end_x = min (WINDOW_RIGHT (w), (x + width));
1712 start_y = max (WINDOW_TOP (w), y);
1713 end_y = min (WINDOW_BOTTOM (w), y + height);
1715 /* We do this to make sure that the 3D modelines get redrawn if
1716 they are in the exposed region. */
1717 orig_windows_structure_changed = f->windows_structure_changed;
1718 f->windows_structure_changed = 1;
1721 redisplay_clear_top_of_window (w);
1722 if (window_needs_vertical_divider (w))
1724 x_output_vertical_divider (w, 0);
1727 for (line = 0; line < Dynarr_length (cdla); line++)
1729 struct display_line *cdl = Dynarr_atp (cdla, line);
1730 int top_y = cdl->ypos - cdl->ascent;
1731 int bottom_y = cdl->ypos + cdl->descent;
1733 if (bottom_y >= start_y)
1744 output_display_line (w, 0, cdla, line, start_x, end_x);
1749 f->windows_structure_changed = orig_windows_structure_changed;
1751 /* If there have never been any face cache_elements created, then this
1752 expose event doesn't actually have anything to do. */
1753 if (Dynarr_largest (w->face_cachels))
1754 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
1757 /*****************************************************************************
1758 x_redraw_exposed_windows
1760 For each window beneath the given window in the window hierarchy,
1761 ensure that it is redrawn if necessary after an Expose event.
1762 ****************************************************************************/
1764 x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
1767 for (; !NILP (window); window = XWINDOW (window)->next)
1768 x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
1771 /*****************************************************************************
1772 x_redraw_exposed_area
1774 For each window on the given frame, ensure that any area in the
1775 Exposed area is redrawn.
1776 ****************************************************************************/
1778 x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
1780 /* If any window on the frame has had its face cache reset then the
1781 redisplay structures are effectively invalid. If we attempt to
1782 use them we'll blow up. We mark the frame as changed to ensure
1783 that redisplay will do a full update. This probably isn't
1784 necessary but it can't hurt. */
1786 #ifdef HAVE_TOOLBARS
1787 /* #### We would rather put these off as well but there is currently
1788 no combination of flags which will force an unchanged toolbar to
1790 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
1792 redraw_exposed_gutters (f, x, y, width, height);
1794 if (!f->window_face_cache_reset)
1796 x_redraw_exposed_windows (f->root_window, x, y, width, height);
1798 XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
1801 MARK_FRAME_CHANGED (f);
1804 /****************************************************************************
1807 Clear the area in the box defined by the given parameters using the
1809 ****************************************************************************/
1811 x_clear_region (Lisp_Object locale, struct device* d, struct frame* f, face_index findex,
1813 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1814 Lisp_Object background_pixmap)
1820 dpy = DEVICE_X_DISPLAY (d);
1821 x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1823 if (!UNBOUNDP (background_pixmap))
1825 gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
1829 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1831 XClearArea (dpy, x_win, x, y, width, height, False);
1834 /*****************************************************************************
1837 Draw a cursor at the end of a line. The end-of-line cursor is
1838 narrower than the normal cursor.
1839 ****************************************************************************/
1841 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos,
1844 struct frame *f = XFRAME (w->frame);
1845 struct device *d = XDEVICE (f->device);
1848 Display *dpy = DEVICE_X_DISPLAY (d);
1849 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1851 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
1852 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
1854 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1855 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1859 int y = DISPLAY_LINE_YPOS (dl);
1860 int width = EOL_CURSOR_WIDTH;
1861 int height = DISPLAY_LINE_HEIGHT (dl);
1862 int cursor_height, cursor_y;
1863 int defheight, defascent;
1865 XSETWINDOW (window, w);
1866 redisplay_clear_region (window, findex, x, y, width, height);
1868 if (NILP (w->text_cursor_visible_p))
1871 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1873 default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
1875 /* make sure the cursor is entirely contained between y and y+height */
1876 cursor_height = min (defheight, height);
1877 cursor_y = max (y, min (y + height - cursor_height,
1878 dl->ypos - defascent));
1883 XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2);
1884 #endif /* HAVE_XIM */
1886 if (NILP (bar_cursor_value))
1888 XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
1892 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1894 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1895 make_int (bar_width));
1896 XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
1897 x + bar_width - 1, cursor_y + cursor_height - 1);
1900 else if (NILP (bar_cursor_value))
1902 XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
1908 x_clear_frame_window (Lisp_Object window)
1910 struct window *w = XWINDOW (window);
1912 if (!NILP (w->vchild))
1914 x_clear_frame_windows (w->vchild);
1918 if (!NILP (w->hchild))
1920 x_clear_frame_windows (w->hchild);
1924 redisplay_clear_to_window_end (w, WINDOW_TEXT_TOP (w),
1925 WINDOW_TEXT_BOTTOM (w));
1929 x_clear_frame_windows (Lisp_Object window)
1931 for (; !NILP (window); window = XWINDOW (window)->next)
1932 x_clear_frame_window (window);
1936 x_clear_frame (struct frame *f)
1938 struct device *d = XDEVICE (f->device);
1939 Display *dpy = DEVICE_X_DISPLAY (d);
1940 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1941 int x, y, width, height;
1944 x = FRAME_LEFT_BORDER_START (f);
1945 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
1946 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
1947 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) -
1948 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f));
1949 /* #### This adjustment by 1 should be being done in the macros.
1950 There is some small differences between when the menubar is on
1951 and off that we still need to deal with. */
1952 y = FRAME_TOP_BORDER_START (f) - 1;
1953 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
1954 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
1955 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) -
1956 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1;
1958 XClearArea (dpy, x_win, x, y, width, height, False);
1960 XSETFRAME (frame, f);
1962 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
1963 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
1964 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
1966 x_clear_frame_windows (f->root_window);
1969 XFlush (DEVICE_X_DISPLAY (d));
1972 /* briefly swap the foreground and background colors.
1976 x_flash (struct device *d)
1982 XColor tmp_fcolor, tmp_bcolor;
1983 Lisp_Object tmp_pixel, frame;
1984 struct frame *f = device_selected_frame (d);
1985 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f));
1986 Widget shell = FRAME_X_SHELL_WIDGET (f);
1989 XSETFRAME (frame, f);
1991 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
1992 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1993 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
1994 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1996 dpy = XtDisplay (shell);
1997 win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1998 memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
1999 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
2000 gcv.function = GXxor;
2001 gcv.graphics_exposures = False;
2002 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
2003 (GCForeground | GCFunction | GCGraphicsExposures));
2004 default_face_height_and_width (frame, &flash_height, 0);
2006 /* If window is tall, flash top and bottom line. */
2007 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
2009 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2010 w->pixel_width, flash_height);
2011 XFillRectangle (dpy, win, gc, w->pixel_left,
2012 w->pixel_top + w->pixel_height - flash_height,
2013 w->pixel_width, flash_height);
2016 /* If it is short, flash it all. */
2017 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2018 w->pixel_width, w->pixel_height);
2026 tv.tv_sec = usecs / 1000000L;
2027 tv.tv_usec = usecs % 1000000L;
2028 /* I'm sure someone is going to complain about this... */
2029 select (0, 0, 0, 0, &tv);
2034 #else /* !HAVE_POLL */
2036 #endif /* HAVE_POLL */
2037 #endif /* HAVE_SELECT */
2039 /* If window is tall, flash top and bottom line. */
2040 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
2042 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2043 w->pixel_width, flash_height);
2044 XFillRectangle (dpy, win, gc, w->pixel_left,
2045 w->pixel_top + w->pixel_height - flash_height,
2046 w->pixel_width, flash_height);
2049 /* If it is short, flash it all. */
2050 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2051 w->pixel_width, w->pixel_height);
2058 /* Make audible bell. */
2061 x_ring_bell (struct device *d, int volume, int pitch, int duration)
2063 Display *display = DEVICE_X_DISPLAY (d);
2065 if (volume < 0) volume = 0;
2066 else if (volume > 100) volume = 100;
2067 if (pitch < 0 && duration < 0)
2069 XBell (display, (volume * 2) - 100);
2074 XKeyboardState state;
2075 XKeyboardControl ctl;
2077 /* #### grab server? */
2078 XGetKeyboardControl (display, &state);
2080 ctl.bell_pitch = (pitch >= 0 ? pitch : (int) state.bell_pitch);
2081 ctl.bell_duration = (duration >= 0 ? duration : (int) state.bell_duration);
2082 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2084 XBell (display, (volume * 2) - 100);
2086 ctl.bell_pitch = state.bell_pitch;
2087 ctl.bell_duration = state.bell_duration;
2088 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2090 /* #### ungrab server? */
2096 /************************************************************************/
2097 /* initialization */
2098 /************************************************************************/
2101 console_type_create_redisplay_x (void)
2103 /* redisplay methods */
2104 CONSOLE_HAS_METHOD (x, text_width);
2105 CONSOLE_HAS_METHOD (x, output_display_block);
2106 CONSOLE_HAS_METHOD (x, divider_height);
2107 CONSOLE_HAS_METHOD (x, eol_cursor_width);
2108 CONSOLE_HAS_METHOD (x, output_vertical_divider);
2109 CONSOLE_HAS_METHOD (x, clear_region);
2110 CONSOLE_HAS_METHOD (x, clear_frame);
2111 CONSOLE_HAS_METHOD (x, window_output_begin);
2112 CONSOLE_HAS_METHOD (x, window_output_end);
2113 CONSOLE_HAS_METHOD (x, flash);
2114 CONSOLE_HAS_METHOD (x, ring_bell);
2115 CONSOLE_HAS_METHOD (x, bevel_area);
2116 CONSOLE_HAS_METHOD (x, output_string);
2117 CONSOLE_HAS_METHOD (x, output_pixmap);