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