1 /* X output and frame manipulation routines.
2 Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3 Copyright (C) 1994 Lucid, Inc.
4 Copyright (C) 1995 Sun Microsystems, Inc.
6 This file is part of XEmacs.
8 XEmacs is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
13 XEmacs is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License
19 along with XEmacs; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
23 /* Synched up with: Not in FSF. */
25 /* Author: Chuck Thompson */
27 /* Lots of work done by Ben Wing for Mule */
32 #include "console-x.h"
33 #include "EmacsFrame.h"
34 #include "EmacsFrameP.h"
37 #include "objects-x.h"
44 #include "redisplay.h"
47 #include <X11/bitmaps/gray>
49 #include "sysproc.h" /* for select() */
53 #include "file-coding.h" /* for CCL conversion */
56 /* Number of pixels below each line. */
57 int x_interline_space; /* #### implement me */
59 #define EOL_CURSOR_WIDTH 5
61 static void x_output_vertical_divider (struct window *w, int clear);
62 static void x_output_blank (struct window *w, struct display_line *dl,
63 struct rune *rb, int start_pixpos,
64 int cursor_start, int cursor_width);
65 static void x_output_hline (struct window *w, struct display_line *dl,
67 static void x_redraw_exposed_window (struct window *w, int x, int y,
68 int width, int height);
69 static void x_redraw_exposed_windows (Lisp_Object window, int x, int y,
70 int width, int height);
71 static void x_output_eol_cursor (struct window *w, struct display_line *dl,
72 int xpos, face_index findex);
73 static void x_clear_frame (struct frame *f);
74 static void x_clear_frame_windows (Lisp_Object window);
77 /* Note: We do not use the Xmb*() functions and XFontSets.
78 Those functions are generally losing for a number of reasons:
80 1) They only support one locale (e.g. you could display
81 Japanese and ASCII text, but not mixed Japanese/Chinese
82 text). You could maybe call setlocale() frequently
83 to try to deal with this, but that would generally
84 fail because an XFontSet is tied to one locale and
85 won't have the other character sets in it.
86 2) Not all (or even very many) OS's support the useful
87 locales. For example, as far as I know SunOS and
88 Solaris only support the Japanese locale if you get the
89 special Asian-language version of the OS. Yuck yuck
90 yuck. Linux doesn't support the Japanese locale at
92 3) The locale support in X only exists in R5, not in R4.
93 (Not sure how big of a problem this is: how many
95 4) Who knows if the multi-byte text format (which is locale-
96 specific) is even the same for the same locale on
97 different OS's? It's not even documented anywhere that
98 I can find what the multi-byte text format for the
99 Japanese locale under SunOS and Solaris is, but I assume
111 /* Separate out the text in DYN into a series of textual runs of a
112 particular charset. Also convert the characters as necessary into
113 the format needed by XDrawImageString(), XDrawImageString16(), et
114 al. (This means converting to one or two byte format, possibly
115 tweaking the high bits, and possibly running a CCL program.) You
116 must pre-allocate the space used and pass it in. (This is done so
117 you can alloca() the space.) You need to allocate (2 * len) bytes
118 of TEXT_STORAGE and (len * sizeof (struct textual_run)) bytes of
119 RUN_STORAGE, where LEN is the length of the dynarr.
121 Returns the number of runs actually used. */
124 separate_textual_runs (unsigned char *text_storage,
125 struct textual_run *run_storage,
126 const Emchar *str, Charcount len)
128 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a
129 possible valid charset when
130 MULE is not defined */
134 struct ccl_program char_converter;
135 int need_ccl_conversion = 0;
138 for (i = 0; i < len; i++)
146 BREAKUP_CHAR (ch, charset, byte1, byte2);
147 dimension = XCHARSET_DIMENSION (charset);
148 graphic = XCHARSET_GRAPHIC (charset);
150 if (!EQ (charset, prev_charset))
152 run_storage[runs_so_far].ptr = text_storage;
153 run_storage[runs_so_far].charset = charset;
154 run_storage[runs_so_far].dimension = dimension;
158 run_storage[runs_so_far - 1].len =
159 text_storage - run_storage[runs_so_far - 1].ptr;
160 if (run_storage[runs_so_far - 1].dimension == 2)
161 run_storage[runs_so_far - 1].len >>= 1;
164 prev_charset = charset;
167 Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset);
168 need_ccl_conversion = !NILP (ccl_prog);
169 if (need_ccl_conversion)
170 setup_ccl_program (&char_converter, ccl_prog);
180 else if (graphic == 1)
186 if (need_ccl_conversion)
188 char_converter.reg[0] = XCHARSET_ID (charset);
189 char_converter.reg[1] = byte1;
190 char_converter.reg[2] = byte2;
191 ccl_driver (&char_converter, 0, 0, 0, 0, CCL_MODE_ENCODING);
192 byte1 = char_converter.reg[1];
193 byte2 = char_converter.reg[2];
196 *text_storage++ = (unsigned char) byte1;
198 *text_storage++ = (unsigned char) byte2;
203 run_storage[runs_so_far - 1].len =
204 text_storage - run_storage[runs_so_far - 1].ptr;
205 if (run_storage[runs_so_far - 1].dimension == 2)
206 run_storage[runs_so_far - 1].len >>= 1;
212 /****************************************************************************/
214 /* X output routines */
216 /****************************************************************************/
219 x_text_width_single_run (struct face_cachel *cachel, struct textual_run *run)
221 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
222 Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
223 if (!fi->proportional_p)
224 return fi->width * run->len;
227 if (run->dimension == 2)
228 return XTextWidth16 (FONT_INSTANCE_X_FONT (fi),
229 (XChar2b *) run->ptr, run->len);
231 return XTextWidth (FONT_INSTANCE_X_FONT (fi),
232 (char *) run->ptr, run->len);
239 Given a string and a face, return the string's length in pixels when
240 displayed in the font associated with the face.
244 x_text_width (struct frame *f, struct face_cachel *cachel, const Emchar *str,
247 int width_so_far = 0;
248 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
249 struct textual_run *runs = alloca_array (struct textual_run, len);
253 nruns = separate_textual_runs (text_storage, runs, str, len);
255 for (i = 0; i < nruns; i++)
256 width_so_far += x_text_width_single_run (cachel, runs + i);
261 /*****************************************************************************
264 Return the height of the horizontal divider. This is a function because
265 divider_height is a device method.
267 #### If we add etched horizontal divider lines this will have to get
269 ****************************************************************************/
271 x_divider_height (void)
276 /*****************************************************************************
279 Return the width of the end-of-line cursor. This is a function
280 because eol_cursor_width is a device method.
281 ****************************************************************************/
283 x_eol_cursor_width (void)
285 return EOL_CURSOR_WIDTH;
288 /*****************************************************************************
291 Perform any necessary initialization prior to an update.
292 ****************************************************************************/
294 x_output_begin (struct device *d)
298 /*****************************************************************************
301 Perform any necessary flushing of queues when an update has completed.
302 ****************************************************************************/
304 x_output_end (struct device *d)
306 XFlush (DEVICE_X_DISPLAY (d));
309 /*****************************************************************************
310 x_output_display_block
312 Given a display line, a block number for that start line, output all
313 runes between start and end in the specified display block.
314 ****************************************************************************/
316 x_output_display_block (struct window *w, struct display_line *dl, int block,
317 int start, int end, int start_pixpos, int cursor_start,
318 int cursor_width, int cursor_height)
320 struct frame *f = XFRAME (w->frame);
321 Emchar_dynarr *buf = Dynarr_new (Emchar);
324 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
325 rune_dynarr *rba = db->runes;
331 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
332 MULE is not defined */
334 XSETWINDOW (window, w);
335 rb = Dynarr_atp (rba, start);
338 /* Nothing to do so don't do anything. */
343 if (rb->type == RUNE_CHAR)
344 charset = CHAR_CHARSET (rb->object.chr.ch);
347 end = Dynarr_length (rba);
352 rb = Dynarr_atp (rba, elt);
354 if (rb->findex == findex && rb->type == RUNE_CHAR
355 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
356 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
358 Dynarr_add (buf, rb->object.chr.ch);
364 if (Dynarr_length (buf))
366 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
367 findex, 0, cursor_start, cursor_width,
375 if (rb->type == RUNE_CHAR)
379 charset = CHAR_CHARSET (rb->object.chr.ch);
381 if (rb->cursor_type == CURSOR_ON)
383 if (rb->object.chr.ch == '\n')
385 x_output_eol_cursor (w, dl, xpos, findex);
389 Dynarr_add (buf, rb->object.chr.ch);
390 x_output_string (w, dl, buf, xpos, 0, start_pixpos,
391 rb->width, findex, 1,
392 cursor_start, cursor_width,
400 else if (rb->object.chr.ch == '\n')
402 /* Clear in case a cursor was formerly here. */
403 redisplay_clear_region (window, findex, xpos,
404 DISPLAY_LINE_YPOS (dl),
406 DISPLAY_LINE_HEIGHT (dl));
410 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
412 if (rb->type == RUNE_BLANK)
413 x_output_blank (w, dl, rb, start_pixpos, cursor_start,
417 /* #### Our flagging of when we need to redraw the
418 modeline shadows sucks. Since RUNE_HLINE is only used
419 by the modeline at the moment it is a good bet
420 that if it gets redrawn then we should also
421 redraw the shadows. This won't be true forever.
422 We borrow the shadow_thickness_changed flag for
424 w->shadow_thickness_changed = 1;
425 x_output_hline (w, dl, rb);
431 rb = Dynarr_atp (rba, elt);
437 else if (rb->type == RUNE_DGLYPH)
439 Lisp_Object instance;
440 struct display_box dbox;
441 struct display_glyph_area dga;
442 redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset,
443 start_pixpos, rb->width,
446 XSETWINDOW (window, w);
447 instance = glyph_image_instance (rb->object.dglyph.glyph,
448 window, ERROR_ME_NOT, 1);
451 if (IMAGE_INSTANCEP (instance))
453 switch (XIMAGE_INSTANCE_TYPE (instance))
457 /* #### This is way losing. See the comment in
460 XIMAGE_INSTANCE_TEXT_STRING (instance);
461 convert_bufbyte_string_into_emchar_dynarr
462 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
464 x_output_string (w, dl, buf, xpos,
465 rb->object.dglyph.xoffset,
466 start_pixpos, -1, findex,
467 (rb->cursor_type == CURSOR_ON),
468 cursor_start, cursor_width,
474 case IMAGE_MONO_PIXMAP:
475 case IMAGE_COLOR_PIXMAP:
476 redisplay_output_pixmap (w, instance, &dbox, &dga, findex,
477 cursor_start, cursor_width,
482 case IMAGE_SUBWINDOW:
483 redisplay_output_subwindow (w, instance, &dbox, &dga, findex,
484 cursor_start, cursor_width,
489 redisplay_output_layout (w, instance, &dbox, &dga, findex,
490 cursor_start, cursor_width,
495 /* nothing is as nothing does */
502 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
503 (XIMAGE_INSTANCE (instance)) = 0;
514 if (Dynarr_length (buf))
515 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
516 0, cursor_start, cursor_width, cursor_height);
518 /* #### This is really conditionalized well for optimized
521 && !EQ (Qzero, w->modeline_shadow_thickness)
523 || f->windows_structure_changed
524 || w->shadow_thickness_changed))
525 bevel_modeline (w, dl);
530 /*****************************************************************************
533 Draw a shadows for the given area in the given face.
534 ****************************************************************************/
536 x_bevel_area (struct window *w, face_index findex,
537 int x, int y, int width, int height,
538 int shadow_thickness, int edges, enum edge_style style)
540 struct frame *f = XFRAME (w->frame);
541 struct device *d = XDEVICE (f->device);
543 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
544 Display *dpy = DEVICE_X_DISPLAY (d);
545 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
546 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
547 Lisp_Object tmp_pixel;
550 GC top_shadow_gc, bottom_shadow_gc, background_gc;
556 assert (shadow_thickness >=0);
557 memset (&gcv, ~0, sizeof (XGCValues));
559 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
560 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
562 /* First, get the GC's. */
563 top_shadow_pixel = tmp_color.pixel;
564 bottom_shadow_pixel = tmp_color.pixel;
565 background_pixel = tmp_color.pixel;
567 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
568 background_pixel, ef->core.background_pixel);
570 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
571 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
572 gcv.background = tmp_color.pixel;
573 gcv.graphics_exposures = False;
574 mask = GCForeground | GCBackground | GCGraphicsExposures;
576 /* If we can't distinguish one of the shadows (the color is the same as the
577 background), it's better to use a pixmap to generate a dithered gray. */
578 if (top_shadow_pixel == background_pixel ||
579 bottom_shadow_pixel == background_pixel)
584 if (DEVICE_X_GRAY_PIXMAP (d) == None)
586 DEVICE_X_GRAY_PIXMAP (d) =
587 XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
588 gray_width, gray_height, 1, 0, 1);
591 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
592 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
593 gcv.foreground = tmp_color.pixel;
594 /* this is needed because the GC draws with a pixmap here */
595 gcv.fill_style = FillOpaqueStippled;
596 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
597 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
598 (mask | GCStipple | GCFillStyle));
600 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
601 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
602 bottom_shadow_pixel = tmp_color.pixel;
604 flip_gcs = (bottom_shadow_pixel ==
605 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
609 gcv.foreground = top_shadow_pixel;
610 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
613 gcv.foreground = bottom_shadow_pixel;
614 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
616 if (use_pixmap && flip_gcs)
618 GC tmp_gc = bottom_shadow_gc;
619 bottom_shadow_gc = top_shadow_gc;
620 top_shadow_gc = tmp_gc;
623 gcv.foreground = background_pixel;
624 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
626 /* possibly revert the GC's This will give a depressed look to the
628 if (style == EDGE_ETCHED_IN || style == EDGE_BEVEL_IN)
632 temp = top_shadow_gc;
633 top_shadow_gc = bottom_shadow_gc;
634 bottom_shadow_gc = temp;
637 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
638 shadow_thickness /= 2;
640 /* Draw the shadows around the divider line */
641 x_output_shadows (f, x, y, width, height,
642 top_shadow_gc, bottom_shadow_gc,
643 background_gc, shadow_thickness, edges);
645 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
647 /* Draw the shadows around the divider line */
648 x_output_shadows (f, x + shadow_thickness, y + shadow_thickness,
649 width - 2*shadow_thickness, height - 2*shadow_thickness,
650 bottom_shadow_gc, top_shadow_gc,
651 background_gc, shadow_thickness, edges);
655 /*****************************************************************************
658 Given a number of parameters return a GC with those properties.
659 ****************************************************************************/
661 x_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
662 Lisp_Object bg_pmap, Lisp_Object lwidth)
667 memset (&gcv, ~0, sizeof (XGCValues));
668 gcv.graphics_exposures = False;
669 /* Make absolutely sure that we don't pick up a clipping region in
670 the GC returned by this function. */
671 gcv.clip_mask = None;
672 gcv.clip_x_origin = 0;
673 gcv.clip_y_origin = 0;
674 gcv.fill_style = FillSolid;
675 mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
680 gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
685 if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg))
687 /* #### I fixed once case where this was getting it. It was a
688 bad macro expansion (compiler bug). */
689 stderr_out ("Help! x_get_gc got a bogus fg value! fg = ");
696 if (COLOR_INSTANCEP (fg))
697 gcv.foreground = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (fg)).pixel;
699 gcv.foreground = XINT (fg);
700 mask |= GCForeground;
705 if (COLOR_INSTANCEP (bg))
706 gcv.background = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (bg)).pixel;
708 gcv.background = XINT (bg);
709 mask |= GCBackground;
712 /* This special case comes from a request to draw text with a face which has
713 the dim property. We'll use a stippled foreground GC. */
714 if (EQ (bg_pmap, Qdim))
716 assert (DEVICE_X_GRAY_PIXMAP (d) != None);
718 gcv.fill_style = FillStippled;
719 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
720 mask |= (GCFillStyle | GCStipple);
722 else if (IMAGE_INSTANCEP (bg_pmap)
723 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
725 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
727 gcv.fill_style = FillOpaqueStippled;
728 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
729 mask |= (GCStipple | GCFillStyle);
733 gcv.fill_style = FillTiled;
734 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
735 mask |= (GCTile | GCFillStyle);
741 gcv.line_width = XINT (lwidth);
745 return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
748 /*****************************************************************************
751 Given a string and a starting position, output that string in the
752 given face. If cursor is true, draw a cursor around the string.
753 Correctly handles multiple charsets in the string.
755 The meaning of the parameters is something like this:
757 W Window that the text is to be displayed in.
758 DL Display line that this text is on. The values in the
759 structure are used to determine the vertical position and
760 clipping range of the text.
761 BUF Dynamic array of Emchars specifying what is actually to be
763 XPOS X position in pixels where the text should start being drawn.
764 XOFFSET Number of pixels to be chopped off the left side of the
765 text. The effect is as if the text were shifted to the
766 left this many pixels and clipped at XPOS.
767 CLIP_START Clip everything left of this X position.
768 WIDTH Clip everything right of XPOS + WIDTH.
769 FINDEX Index for the face cache element describing how to display
771 CURSOR #### I don't understand this. There's something
772 strange and overcomplexified with this variable.
773 Chuck, explain please?
774 CURSOR_START Starting X position of cursor.
775 CURSOR_WIDTH Width of cursor in pixels.
776 CURSOR_HEIGHT Height of cursor in pixels.
778 Starting Y position of cursor is the top of the text line.
779 The cursor is drawn sometimes whether or not CURSOR is set. ???
780 ****************************************************************************/
782 x_output_string (struct window *w, struct display_line *dl,
783 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
784 int width, face_index findex, int cursor,
785 int cursor_start, int cursor_width, int cursor_height)
787 /* General variables */
788 struct frame *f = XFRAME (w->frame);
789 struct device *d = XDEVICE (f->device);
792 Display *dpy = DEVICE_X_DISPLAY (d);
793 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
797 /* Cursor-related variables */
798 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
800 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
802 struct face_cachel *cursor_cachel = 0;
804 /* Text-related variables */
808 int len = Dynarr_length (buf);
809 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
810 struct textual_run *runs = alloca_array (struct textual_run, len);
813 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
815 XSETDEVICE (device, d);
816 XSETWINDOW (window, w);
819 width = x_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
820 height = DISPLAY_LINE_HEIGHT (dl);
822 /* Regularize the variables passed in. */
824 if (clip_start < xpos)
826 clip_end = xpos + width;
827 if (clip_start >= clip_end)
828 /* It's all clipped out. */
833 /* make sure the area we are about to display is subwindow free. */
834 redisplay_unmap_subwindows_maybe (f, clip_start, DISPLAY_LINE_YPOS (dl),
835 clip_end - clip_start, DISPLAY_LINE_HEIGHT (dl));
837 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
838 Dynarr_length (buf));
840 cursor_clip = (cursor_start >= clip_start &&
841 cursor_start < clip_end);
843 /* This cursor code is really a mess. */
844 if (!NILP (w->text_cursor_visible_p)
848 && (cursor_start + cursor_width >= clip_start)
849 && !NILP (bar_cursor_value))))
851 /* These have to be in separate statements in order to avoid a
853 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face);
854 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks);
856 /* We have to reset this since any call to WINDOW_FACE_CACHEL
857 may cause the cache to resize and any pointers to it to
859 cachel = WINDOW_FACE_CACHEL (w, findex);
863 if (cursor && focus && (cursor_start == clip_start) && cursor_height)
864 XIM_SetSpotLocation (f, xpos - 2, dl->ypos + dl->descent - 2);
865 #endif /* HAVE_XIM */
867 bg_pmap = cachel->background_pixmap;
868 if (!IMAGE_INSTANCEP (bg_pmap)
869 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
872 if ((cursor && focus && NILP (bar_cursor_value)
873 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap))
876 bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
880 XFillRectangle (dpy, x_win, bgc, clip_start,
881 DISPLAY_LINE_YPOS (dl), clip_end - clip_start,
884 for (i = 0; i < nruns; i++)
886 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
887 Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
891 if (EQ (font, Vthe_null_font_instance))
894 this_width = x_text_width_single_run (cachel, runs + i);
895 need_clipping = (dl->clip || clip_start > xpos ||
896 clip_end < xpos + this_width);
898 /* XDrawImageString only clears the area equal to the height of
899 the given font. It is possible that a font is being displayed
900 on a line taller than it is, so this would cause us to fail to
902 if ((int) fi->height < (int) (height + dl->clip + dl->top_clip))
904 int clear_start = max (xpos, clip_start);
905 int clear_end = min (xpos + this_width, clip_end);
909 int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
911 ypos1_string = dl->ypos - fi->ascent;
912 ypos2_string = dl->ypos + fi->descent;
913 ypos1_line = DISPLAY_LINE_YPOS (dl);
914 ypos2_line = ypos1_line + DISPLAY_LINE_HEIGHT (dl);
916 /* Make sure we don't clear below the real bottom of the
918 if (ypos1_string > ypos2_line)
919 ypos1_string = ypos2_line;
920 if (ypos2_string > ypos2_line)
921 ypos2_string = ypos2_line;
923 if (ypos1_line < ypos1_string)
925 redisplay_clear_region (window, findex, clear_start, ypos1_line,
926 clear_end - clear_start,
927 ypos1_string - ypos1_line);
930 if (ypos2_line > ypos2_string)
932 redisplay_clear_region (window, findex, clear_start, ypos2_string,
933 clear_end - clear_start,
934 ypos2_line - ypos2_string);
939 redisplay_clear_region (window, findex, clear_start,
940 DISPLAY_LINE_YPOS (dl), clear_end - clear_start,
945 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value))
946 gc = x_get_gc (d, font, cursor_cachel->foreground,
947 cursor_cachel->background, Qnil, Qnil);
948 else if (cachel->dim)
950 /* Ensure the gray bitmap exists */
951 if (DEVICE_X_GRAY_PIXMAP (d) == None)
952 DEVICE_X_GRAY_PIXMAP (d) =
953 XCreateBitmapFromData (dpy, x_win, (char *)gray_bits,
954 gray_width, gray_height);
956 /* Request a GC with the gray stipple pixmap to draw dimmed text */
957 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
961 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
966 XRectangle clip_box[1];
970 clip_box[0].width = clip_end - clip_start;
971 clip_box[0].height = height;
973 XSetClipRectangles (dpy, gc, clip_start, DISPLAY_LINE_YPOS (dl),
974 clip_box, 1, Unsorted);
977 if (runs[i].dimension == 1)
978 (bgc ? XDrawString : XDrawImageString) (dpy, x_win, gc, xpos,
979 dl->ypos, (char *) runs[i].ptr,
982 (bgc ? XDrawString16 : XDrawImageString16) (dpy, x_win, gc, xpos,
984 (XChar2b *) runs[i].ptr,
987 /* We draw underlines in the same color as the text. */
988 if (cachel->underline)
990 unsigned long upos, uthick;
993 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
994 if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos))
995 upos = dl->descent / 2;
996 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
999 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
1001 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
1002 uthick = dl->descent - dl->clip - upos;
1006 XDrawLine (dpy, x_win, gc, xpos, dl->ypos + upos,
1007 xpos + this_width, dl->ypos + upos);
1009 else if (uthick > 1)
1011 XFillRectangle (dpy, x_win, gc, xpos,
1012 dl->ypos + upos, this_width, uthick);
1017 if (cachel->strikethru) {
1018 unsigned long ascent,descent,upos, uthick;
1021 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
1023 if (!XGetFontProperty (xfont, XA_STRIKEOUT_ASCENT, &ascent))
1024 ascent = xfont->ascent;
1025 if (!XGetFontProperty (xfont, XA_STRIKEOUT_DESCENT, &descent))
1026 descent = xfont->descent;
1027 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
1030 upos = ascent - ((ascent + descent) / 2) + 1;
1032 /* Generally, upos will be positive (above the baseline),so subtract */
1033 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip)
1035 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip)
1036 uthick = dl->descent - dl->clip + upos;
1040 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos,
1041 xpos + this_width, dl->ypos - upos);
1043 else if (uthick > 1)
1045 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos,
1046 this_width, uthick);
1051 /* Restore the GC */
1054 XSetClipMask (dpy, gc, None);
1055 XSetClipOrigin (dpy, gc, 0, 0);
1058 /* If we are actually superimposing the cursor then redraw with just
1059 the appropriate section highlighted. */
1060 if (cursor_clip && !cursor && focus && cursor_cachel)
1063 XRectangle clip_box[1];
1065 cgc = x_get_gc (d, font, cursor_cachel->foreground,
1066 cursor_cachel->background, Qnil, Qnil);
1070 clip_box[0].width = cursor_width;
1071 clip_box[0].height = height;
1073 XSetClipRectangles (dpy, cgc, cursor_start, DISPLAY_LINE_YPOS (dl),
1074 clip_box, 1, Unsorted);
1076 if (runs[i].dimension == 1)
1077 XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
1078 (char *) runs[i].ptr, runs[i].len);
1080 XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
1081 (XChar2b *) runs[i].ptr, runs[i].len);
1083 XSetClipMask (dpy, cgc, None);
1084 XSetClipOrigin (dpy, cgc, 0, 0);
1090 /* Draw the non-focus box or bar-cursor as needed. */
1091 /* Can't this logic be simplified? */
1093 && ((cursor && !focus && NILP (bar_cursor_value))
1095 && (cursor_start + cursor_width >= clip_start)
1096 && !NILP (bar_cursor_value))))
1098 int tmp_height, tmp_y;
1099 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1100 int need_clipping = (cursor_start < clip_start
1101 || clip_end < cursor_start + cursor_width);
1103 /* #### This value is correct (as far as I know) because
1104 all of the times we need to draw this cursor, we will
1105 be called with exactly one character, so we know we
1106 can always use runs[0].
1108 This is bogus as all hell, however. The cursor handling in
1109 this function is way bogus and desperately needs to be
1110 cleaned up. (In particular, the drawing of the cursor should
1111 really really be separated out of this function. This may be
1112 a bit tricky now because this function itself does way too
1113 much stuff, a lot of which needs to be moved into
1114 redisplay.c) This is the only way to be able to easily add
1115 new cursor types or (e.g.) make the bar cursor be able to
1116 span two characters instead of overlaying just one. */
1117 int bogusly_obtained_ascent_value =
1118 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent;
1120 if (!NILP (bar_cursor_value))
1122 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1123 make_int (bar_width));
1127 gc = x_get_gc (d, Qnil, cursor_cachel->background,
1131 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1132 tmp_height = cursor_height;
1133 if (tmp_y + tmp_height > (int) (DISPLAY_LINE_YPOS(dl) + height))
1135 tmp_y = DISPLAY_LINE_YPOS (dl) + height - tmp_height;
1136 if (tmp_y < (int) DISPLAY_LINE_YPOS (dl))
1137 tmp_y = DISPLAY_LINE_YPOS (dl);
1138 tmp_height = DISPLAY_LINE_YPOS (dl) + height - tmp_y;
1143 XRectangle clip_box[1];
1146 clip_box[0].width = clip_end - clip_start;
1147 clip_box[0].height = tmp_height;
1148 XSetClipRectangles (dpy, gc, clip_start, tmp_y,
1149 clip_box, 1, Unsorted);
1152 if (!focus && NILP (bar_cursor_value))
1154 XDrawRectangle (dpy, x_win, gc, cursor_start, tmp_y,
1155 cursor_width - 1, tmp_height - 1);
1157 else if (focus && !NILP (bar_cursor_value))
1159 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1, tmp_y,
1160 cursor_start + bar_width - 1, tmp_y + tmp_height - 1);
1163 /* Restore the GC */
1166 XSetClipMask (dpy, gc, None);
1167 XSetClipOrigin (dpy, gc, 0, 0);
1173 x_output_x_pixmap (struct frame *f, Lisp_Image_Instance *p, int x,
1174 int y, int xoffset, int yoffset,
1175 int width, int height, unsigned long fg, unsigned long bg,
1178 struct device *d = XDEVICE (f->device);
1179 Display *dpy = DEVICE_X_DISPLAY (d);
1180 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1184 unsigned long pixmap_mask;
1188 memset (&gcv, ~0, sizeof (XGCValues));
1189 gcv.graphics_exposures = False;
1190 gcv.foreground = fg;
1191 gcv.background = bg;
1192 pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
1194 if (IMAGE_INSTANCE_X_MASK (p))
1196 gcv.function = GXcopy;
1197 gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
1198 gcv.clip_x_origin = x - xoffset;
1199 gcv.clip_y_origin = y - yoffset;
1200 pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
1202 /* Can't set a clip rectangle because we already have a mask.
1203 Is it possible to get an equivalent effect by changing the
1204 args to XCopyArea below rather than messing with a clip box?
1205 - dkindred@cs.cmu.edu
1206 Yes. We don't clip at all now - andy@xemacs.org
1210 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
1215 /* override_gc might have a mask already--we don't want to nuke it.
1216 Maybe we can insist that override_gc have no mask, or use
1217 one of the suggestions above. */
1220 /* depth of 0 means it's a bitmap, not a pixmap, and we should use
1221 XCopyPlane (1 = current foreground color, 0 = background) instead
1222 of XCopyArea, which means that the bits in the pixmap are actual
1223 pixel values, instead of symbolic of fg/bg. */
1224 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
1227 IMAGE_INSTANCE_X_PIXMAP_SLICE
1228 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc, xoffset,
1234 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP_SLICE
1235 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc,
1236 xoffset, yoffset, width, height, x, y, 1L);
1241 x_output_pixmap (struct window *w, Lisp_Object image_instance,
1242 struct display_box *db, struct display_glyph_area *dga,
1243 face_index findex, int cursor_start, int cursor_width,
1244 int cursor_height, int bg_pixmap)
1246 struct frame *f = XFRAME (w->frame);
1247 struct device *d = XDEVICE (f->device);
1248 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1250 Display *dpy = DEVICE_X_DISPLAY (d);
1251 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1253 /* Output the pixmap. */
1255 Lisp_Object tmp_pixel;
1256 XColor tmp_bcolor, tmp_fcolor;
1258 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1259 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1260 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1261 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1263 x_output_x_pixmap (f, p, db->xpos, db->ypos,
1264 dga->xoffset, dga->yoffset,
1265 dga->width, dga->height,
1266 tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
1269 /* Draw a cursor over top of the pixmap. */
1270 if (cursor_width && cursor_height && (cursor_start >= db->xpos)
1271 && !NILP (w->text_cursor_visible_p)
1272 && (cursor_start < db->xpos + dga->width))
1275 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1276 struct face_cachel *cursor_cachel =
1277 WINDOW_FACE_CACHEL (w,
1278 get_builtin_face_cache_index
1279 (w, Vtext_cursor_face));
1281 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1283 if (cursor_width > db->xpos + dga->width - cursor_start)
1284 cursor_width = db->xpos + dga->width - cursor_start;
1288 XFillRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1293 XDrawRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1299 /*****************************************************************************
1300 x_output_vertical_divider
1302 Draw a vertical divider down the right side of the given window.
1303 ****************************************************************************/
1305 x_output_vertical_divider (struct window *w, int clear)
1307 struct frame *f = XFRAME (w->frame);
1308 struct device *d = XDEVICE (f->device);
1310 Display *dpy = DEVICE_X_DISPLAY (d);
1311 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1312 Lisp_Object tmp_pixel;
1316 enum edge_style style;
1319 int x, y1, y2, width, shadow_thickness, spacing, line_width;
1320 face_index div_face = get_builtin_face_cache_index (w, Vvertical_divider_face);
1322 width = window_divider_width (w);
1323 shadow_thickness = XINT (w->vertical_divider_shadow_thickness);
1324 spacing = XINT (w->vertical_divider_spacing);
1325 line_width = XINT (w->vertical_divider_line_width);
1326 x = WINDOW_RIGHT (w) - width;
1327 y1 = WINDOW_TOP (w);
1328 y2 = WINDOW_BOTTOM (w);
1330 memset (&gcv, ~0, sizeof (XGCValues));
1332 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1333 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1335 /* First, get the GC's. */
1336 gcv.background = tmp_color.pixel;
1337 gcv.foreground = tmp_color.pixel;
1338 gcv.graphics_exposures = False;
1339 mask = GCForeground | GCBackground | GCGraphicsExposures;
1340 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1342 /* Clear the divider area first. This needs to be done when a
1343 window split occurs. */
1345 XClearArea (dpy, x_win, x, y1, width, y2 - y1, False);
1347 /* Draw the divider line. */
1348 XFillRectangle (dpy, x_win, background_gc,
1349 x + spacing + shadow_thickness, y1,
1350 line_width, y2 - y1);
1352 if (shadow_thickness < 0)
1354 shadow_thickness = -shadow_thickness;
1355 style = EDGE_BEVEL_IN;
1359 style = EDGE_BEVEL_OUT;
1362 /* Draw the shadows around the divider line */
1363 x_bevel_area (w, div_face, x + spacing, y1,
1364 width - 2 * spacing, y2 - y1,
1365 shadow_thickness, EDGE_ALL, style);
1368 /*****************************************************************************
1371 Output a blank by clearing the area it covers in the foreground color
1373 ****************************************************************************/
1375 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
1376 int start_pixpos, int cursor_start, int cursor_width)
1378 struct frame *f = XFRAME (w->frame);
1379 struct device *d = XDEVICE (f->device);
1381 Display *dpy = DEVICE_X_DISPLAY (d);
1382 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1384 struct face_cachel *cursor_cachel =
1385 WINDOW_FACE_CACHEL (w,
1386 get_builtin_face_cache_index
1387 (w, Vtext_cursor_face));
1388 Lisp_Object bg_pmap;
1389 Lisp_Object buffer = WINDOW_BUFFER (w);
1390 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1394 int y = DISPLAY_LINE_YPOS (dl);
1395 int width = rb->width;
1396 int height = DISPLAY_LINE_HEIGHT (dl);
1398 /* Unmap all subwindows in the area we are going to blank. */
1399 redisplay_unmap_subwindows_maybe (f, x, y, width, height);
1401 if (start_pixpos > x)
1403 if (start_pixpos >= (x + width))
1407 width -= (start_pixpos - x);
1412 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
1413 if (!IMAGE_INSTANCEP (bg_pmap)
1414 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
1418 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1421 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1422 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
1425 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1427 /* If this rune is marked as having the cursor, then it is actually
1428 representing a tab. */
1429 if (!NILP (w->text_cursor_visible_p)
1430 && (rb->cursor_type == CURSOR_ON
1432 && (cursor_start + cursor_width > x)
1433 && cursor_start < (x + width))))
1435 int cursor_height, cursor_y;
1436 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1437 Lisp_Font_Instance *fi;
1439 fi = XFONT_INSTANCE (FACE_CACHEL_FONT
1440 (WINDOW_FACE_CACHEL (w, rb->findex),
1443 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1445 cursor_y = dl->ypos - fi->ascent;
1446 cursor_height = fi->height;
1447 if (cursor_y + cursor_height > y + height)
1448 cursor_height = y + height - cursor_y;
1452 if (NILP (bar_cursor_value))
1454 XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1455 fi->width, cursor_height);
1459 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1461 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1462 make_int (bar_width));
1463 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
1464 cursor_y, cursor_start + bar_width - 1,
1465 cursor_y + cursor_height - 1);
1468 else if (NILP (bar_cursor_value))
1470 XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1471 fi->width - 1, cursor_height - 1);
1476 /*****************************************************************************
1479 Output a horizontal line in the foreground of its face.
1480 ****************************************************************************/
1482 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
1484 struct frame *f = XFRAME (w->frame);
1485 struct device *d = XDEVICE (f->device);
1487 Display *dpy = DEVICE_X_DISPLAY (d);
1488 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1492 int width = rb->width;
1493 int height = DISPLAY_LINE_HEIGHT (dl);
1494 int ypos1, ypos2, ypos3, ypos4;
1496 ypos1 = DISPLAY_LINE_YPOS (dl);
1497 ypos2 = ypos1 + rb->object.hline.yoffset;
1498 ypos3 = ypos2 + rb->object.hline.thickness;
1499 ypos4 = dl->ypos + dl->descent - dl->clip;
1501 /* First clear the area not covered by the line. */
1502 if (height - rb->object.hline.thickness > 0)
1504 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1507 if (ypos2 - ypos1 > 0)
1508 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1509 if (ypos4 - ypos3 > 0)
1510 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1513 /* Now draw the line. */
1514 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1522 if (ypos3 - ypos2 > 0)
1523 XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1526 /*****************************************************************************
1529 Draw a shadow around the given area using the given GC's. It is the
1530 callers responsibility to set the GC's appropriately.
1531 ****************************************************************************/
1533 x_output_shadows (struct frame *f, int x, int y, int width, int height,
1534 GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
1535 int shadow_thickness, int edges)
1537 struct device *d = XDEVICE (f->device);
1539 Display *dpy = DEVICE_X_DISPLAY (d);
1540 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1542 XSegment top_shadow[20], bottom_shadow[20];
1545 if (shadow_thickness > 10)
1546 shadow_thickness = 10;
1547 else if (shadow_thickness < 0)
1548 shadow_thickness = 0;
1549 if (shadow_thickness > (width / 2))
1550 shadow_thickness = width / 2;
1551 if (shadow_thickness > (height / 2))
1552 shadow_thickness = height / 2;
1554 for (elt = 0; elt < shadow_thickness; elt++)
1557 int seg2 = (edges & EDGE_TOP) ? elt + shadow_thickness : elt;
1558 int bot_seg2 = (edges & EDGE_BOTTOM) ? elt + shadow_thickness : elt;
1560 if (edges & EDGE_TOP)
1562 top_shadow[seg1].x1 = x + elt;
1563 top_shadow[seg1].x2 = x + width - elt - 1;
1564 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
1566 if (edges & EDGE_LEFT)
1568 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
1569 top_shadow[seg2].y1 = y + elt;
1570 top_shadow[seg2].y2 = y + height - elt - 1;
1572 if (edges & EDGE_BOTTOM)
1574 bottom_shadow[seg1].x1 = x + elt;
1575 bottom_shadow[seg1].x2 = x + width - elt - 1;
1576 bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
1578 if (edges & EDGE_RIGHT)
1580 bottom_shadow[bot_seg2].x1 = bottom_shadow[bot_seg2].x2 = x + width - elt - 1;
1581 bottom_shadow[bot_seg2].y1 = y + elt;
1582 bottom_shadow[bot_seg2].y2 = y + height - elt - 1;
1586 XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow,
1587 ((edges & EDGE_TOP) ? shadow_thickness : 0)
1588 + ((edges & EDGE_LEFT) ? shadow_thickness : 0));
1589 XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
1590 ((edges & EDGE_BOTTOM) ? shadow_thickness : 0)
1591 + ((edges & EDGE_RIGHT) ? shadow_thickness : 0));
1594 /*****************************************************************************
1595 x_generate_shadow_pixels
1597 Given three pixels (top shadow, bottom shadow, background) massage
1598 the top and bottom shadow colors to guarantee that they differ. The
1599 background pixels are not allowed to be modified.
1601 This function modifies its parameters.
1603 This code is modified from code blatantly stolen from lwlib/xlwmenu.c
1604 ****************************************************************************/
1605 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
1606 ? ((unsigned long) (x)) : ((unsigned long) (y)))
1609 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
1610 unsigned long *bottom_shadow,
1611 unsigned long background,
1612 unsigned long core_background)
1614 struct device *d = XDEVICE (f->device);
1615 Display *dpy = DEVICE_X_DISPLAY (d);
1616 Colormap cmap = DEVICE_X_COLORMAP (d);
1617 Visual *visual = DEVICE_X_VISUAL (d);
1620 int top_frobbed = 0, bottom_frobbed = 0;
1622 /* If the top shadow is the same color as the background, try to
1624 if (*top_shadow == background)
1626 topc.pixel = background;
1627 XQueryColor (dpy, cmap, &topc);
1628 /* don't overflow/wrap! */
1629 topc.red = MINL (65535, (unsigned long) topc.red * 6 / 5);
1630 topc.green = MINL (65535, (unsigned long) topc.green * 6 / 5);
1631 topc.blue = MINL (65535, (unsigned long) topc.blue * 6 / 5);
1632 if (allocate_nearest_color (dpy, cmap, visual, &topc))
1634 *top_shadow = topc.pixel;
1639 /* If the bottom shadow is the same color as the background, try to
1641 if (*bottom_shadow == background)
1643 botc.pixel = background;
1644 XQueryColor (dpy, cmap, &botc);
1645 botc.red = (unsigned short) ((unsigned long) botc.red * 3 / 5);
1646 botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5);
1647 botc.blue = (unsigned short) ((unsigned long) botc.blue * 3 / 5);
1648 if (allocate_nearest_color (dpy, cmap, visual, &botc))
1650 *bottom_shadow = botc.pixel;
1655 /* If we had to adjust both shadows, then we have to do some
1657 if (top_frobbed && bottom_frobbed)
1659 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
1660 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
1661 if (bot_avg > top_avg)
1663 Pixel tmp = *top_shadow;
1665 *top_shadow = *bottom_shadow;
1666 *bottom_shadow = tmp;
1668 else if (topc.pixel == botc.pixel)
1670 if (botc.pixel == background)
1671 *top_shadow = core_background;
1673 *bottom_shadow = background;
1678 /*****************************************************************************
1679 x_redraw_exposed_window
1681 Given a bounding box for an area that needs to be redrawn, determine
1682 what parts of what lines are contained within and re-output their
1684 ****************************************************************************/
1686 x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
1688 struct frame *f = XFRAME (w->frame);
1690 int start_x, start_y, end_x, end_y;
1691 int orig_windows_structure_changed;
1693 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1695 if (!NILP (w->vchild))
1697 x_redraw_exposed_windows (w->vchild, x, y, width, height);
1700 else if (!NILP (w->hchild))
1702 x_redraw_exposed_windows (w->hchild, x, y, width, height);
1706 /* If the window doesn't intersect the exposed region, we're done here. */
1707 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w)
1708 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w))
1714 start_x = max (WINDOW_LEFT (w), x);
1715 end_x = min (WINDOW_RIGHT (w), (x + width));
1716 start_y = max (WINDOW_TOP (w), y);
1717 end_y = min (WINDOW_BOTTOM (w), y + height);
1719 /* We do this to make sure that the 3D modelines get redrawn if
1720 they are in the exposed region. */
1721 orig_windows_structure_changed = f->windows_structure_changed;
1722 f->windows_structure_changed = 1;
1725 if (window_needs_vertical_divider (w))
1727 x_output_vertical_divider (w, 0);
1730 for (line = 0; line < Dynarr_length (cdla); line++)
1732 struct display_line *cdl = Dynarr_atp (cdla, line);
1733 int top_y = cdl->ypos - cdl->ascent;
1734 int bottom_y = cdl->ypos + cdl->descent;
1736 if (bottom_y >= start_y)
1747 output_display_line (w, 0, cdla, line, start_x, end_x);
1752 f->windows_structure_changed = orig_windows_structure_changed;
1754 /* If there have never been any face cache_elements created, then this
1755 expose event doesn't actually have anything to do. */
1756 if (Dynarr_largest (w->face_cachels))
1757 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
1760 /*****************************************************************************
1761 x_redraw_exposed_windows
1763 For each window beneath the given window in the window hierarchy,
1764 ensure that it is redrawn if necessary after an Expose event.
1765 ****************************************************************************/
1767 x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
1770 for (; !NILP (window); window = XWINDOW (window)->next)
1771 x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
1774 /*****************************************************************************
1775 x_redraw_exposed_area
1777 For each window on the given frame, ensure that any area in the
1778 Exposed area is redrawn.
1779 ****************************************************************************/
1781 x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
1783 /* If any window on the frame has had its face cache reset then the
1784 redisplay structures are effectively invalid. If we attempt to
1785 use them we'll blow up. We mark the frame as changed to ensure
1786 that redisplay will do a full update. This probably isn't
1787 necessary but it can't hurt. */
1789 #ifdef HAVE_TOOLBARS
1790 /* #### We would rather put these off as well but there is currently
1791 no combination of flags which will force an unchanged toolbar to
1793 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
1795 redraw_exposed_gutters (f, x, y, width, height);
1797 if (!f->window_face_cache_reset)
1799 x_redraw_exposed_windows (f->root_window, x, y, width, height);
1801 XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
1804 MARK_FRAME_CHANGED (f);
1807 /****************************************************************************
1810 Clear the area in the box defined by the given parameters using the
1812 ****************************************************************************/
1814 x_clear_region (Lisp_Object locale, struct device* d, struct frame* f, face_index findex,
1816 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1817 Lisp_Object background_pixmap)
1823 dpy = DEVICE_X_DISPLAY (d);
1824 x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1826 if (!UNBOUNDP (background_pixmap))
1828 gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
1832 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1834 XClearArea (dpy, x_win, x, y, width, height, False);
1837 /*****************************************************************************
1840 Draw a cursor at the end of a line. The end-of-line cursor is
1841 narrower than the normal cursor.
1842 ****************************************************************************/
1844 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos,
1847 struct frame *f = XFRAME (w->frame);
1848 struct device *d = XDEVICE (f->device);
1851 Display *dpy = DEVICE_X_DISPLAY (d);
1852 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1854 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
1855 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
1857 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1858 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1862 int y = DISPLAY_LINE_YPOS (dl);
1863 int width = EOL_CURSOR_WIDTH;
1864 int height = DISPLAY_LINE_HEIGHT (dl);
1865 int cursor_height, cursor_y;
1866 int defheight, defascent;
1868 XSETWINDOW (window, w);
1869 redisplay_clear_region (window, findex, x, y, width, height);
1871 if (NILP (w->text_cursor_visible_p))
1874 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1876 default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
1878 /* make sure the cursor is entirely contained between y and y+height */
1879 cursor_height = min (defheight, height);
1880 cursor_y = max (y, min (y + height - cursor_height,
1881 dl->ypos - defascent));
1886 XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2);
1887 #endif /* HAVE_XIM */
1889 if (NILP (bar_cursor_value))
1891 XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
1895 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1897 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1898 make_int (bar_width));
1899 XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
1900 x + bar_width - 1, cursor_y + cursor_height - 1);
1903 else if (NILP (bar_cursor_value))
1905 XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
1911 x_clear_frame_window (Lisp_Object window)
1913 struct window *w = XWINDOW (window);
1915 if (!NILP (w->vchild))
1917 x_clear_frame_windows (w->vchild);
1921 if (!NILP (w->hchild))
1923 x_clear_frame_windows (w->hchild);
1927 redisplay_clear_to_window_end (w, WINDOW_TEXT_TOP (w),
1928 WINDOW_TEXT_BOTTOM (w));
1932 x_clear_frame_windows (Lisp_Object window)
1934 for (; !NILP (window); window = XWINDOW (window)->next)
1935 x_clear_frame_window (window);
1939 x_clear_frame (struct frame *f)
1941 struct device *d = XDEVICE (f->device);
1942 Display *dpy = DEVICE_X_DISPLAY (d);
1943 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1944 int x, y, width, height;
1947 x = FRAME_LEFT_BORDER_START (f);
1948 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
1949 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
1950 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) -
1951 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f));
1952 /* #### This adjustment by 1 should be being done in the macros.
1953 There is some small differences between when the menubar is on
1954 and off that we still need to deal with. */
1955 y = FRAME_TOP_BORDER_START (f) - 1;
1956 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
1957 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
1958 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) -
1959 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1;
1961 XClearArea (dpy, x_win, x, y, width, height, False);
1963 XSETFRAME (frame, f);
1965 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
1966 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
1967 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
1969 x_clear_frame_windows (f->root_window);
1972 XFlush (DEVICE_X_DISPLAY (d));
1975 /* briefly swap the foreground and background colors.
1979 x_flash (struct device *d)
1985 XColor tmp_fcolor, tmp_bcolor;
1986 Lisp_Object tmp_pixel, frame;
1987 struct frame *f = device_selected_frame (d);
1988 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f));
1989 Widget shell = FRAME_X_SHELL_WIDGET (f);
1992 XSETFRAME (frame, f);
1994 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
1995 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1996 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
1997 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1999 dpy = XtDisplay (shell);
2000 win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2001 memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
2002 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
2003 gcv.function = GXxor;
2004 gcv.graphics_exposures = False;
2005 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
2006 (GCForeground | GCFunction | GCGraphicsExposures));
2007 default_face_height_and_width (frame, &flash_height, 0);
2009 /* If window is tall, flash top and bottom line. */
2010 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
2012 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2013 w->pixel_width, flash_height);
2014 XFillRectangle (dpy, win, gc, w->pixel_left,
2015 w->pixel_top + w->pixel_height - flash_height,
2016 w->pixel_width, flash_height);
2019 /* If it is short, flash it all. */
2020 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2021 w->pixel_width, w->pixel_height);
2029 tv.tv_sec = usecs / 1000000L;
2030 tv.tv_usec = usecs % 1000000L;
2031 /* I'm sure someone is going to complain about this... */
2032 select (0, 0, 0, 0, &tv);
2037 #else /* !HAVE_POLL */
2039 #endif /* HAVE_POLL */
2040 #endif /* HAVE_SELECT */
2042 /* If window is tall, flash top and bottom line. */
2043 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
2045 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2046 w->pixel_width, flash_height);
2047 XFillRectangle (dpy, win, gc, w->pixel_left,
2048 w->pixel_top + w->pixel_height - flash_height,
2049 w->pixel_width, flash_height);
2052 /* If it is short, flash it all. */
2053 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2054 w->pixel_width, w->pixel_height);
2061 /* Make audible bell. */
2064 x_ring_bell (struct device *d, int volume, int pitch, int duration)
2066 Display *display = DEVICE_X_DISPLAY (d);
2068 if (volume < 0) volume = 0;
2069 else if (volume > 100) volume = 100;
2070 if (pitch < 0 && duration < 0)
2072 XBell (display, (volume * 2) - 100);
2077 XKeyboardState state;
2078 XKeyboardControl ctl;
2080 /* #### grab server? */
2081 XGetKeyboardControl (display, &state);
2083 ctl.bell_pitch = (pitch >= 0 ? pitch : state.bell_pitch);
2084 ctl.bell_duration = (duration >= 0 ? duration : state.bell_duration);
2085 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2087 XBell (display, (volume * 2) - 100);
2089 ctl.bell_pitch = state.bell_pitch;
2090 ctl.bell_duration = state.bell_duration;
2091 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2093 /* #### ungrab server? */
2099 /************************************************************************/
2100 /* initialization */
2101 /************************************************************************/
2104 console_type_create_redisplay_x (void)
2106 /* redisplay methods */
2107 CONSOLE_HAS_METHOD (x, text_width);
2108 CONSOLE_HAS_METHOD (x, output_display_block);
2109 CONSOLE_HAS_METHOD (x, divider_height);
2110 CONSOLE_HAS_METHOD (x, eol_cursor_width);
2111 CONSOLE_HAS_METHOD (x, output_vertical_divider);
2112 CONSOLE_HAS_METHOD (x, clear_region);
2113 CONSOLE_HAS_METHOD (x, clear_frame);
2114 CONSOLE_HAS_METHOD (x, output_begin);
2115 CONSOLE_HAS_METHOD (x, output_end);
2116 CONSOLE_HAS_METHOD (x, flash);
2117 CONSOLE_HAS_METHOD (x, ring_bell);
2118 CONSOLE_HAS_METHOD (x, bevel_area);
2119 CONSOLE_HAS_METHOD (x, output_string);
2120 CONSOLE_HAS_METHOD (x, output_pixmap);