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 if ((!NILP (ccl_prog))
169 && (setup_ccl_program (&char_converter, ccl_prog) >= 0))
170 need_ccl_conversion = 1;
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 /*****************************************************************************
289 x_window_output_begin
291 Perform any necessary initialization prior to an update.
292 ****************************************************************************/
294 x_window_output_begin (struct window *w)
298 /*****************************************************************************
301 Perform any necessary flushing of queues when an update has completed.
302 ****************************************************************************/
304 x_window_output_end (struct window *w)
306 XFlush (DEVICE_X_DISPLAY (WINDOW_XDEVICE (w)));
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;
443 redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset,
444 rb->object.dglyph.yoffset, start_pixpos,
445 rb->width, &dbox, &dga);
447 XSETWINDOW (window, w);
448 instance = glyph_image_instance (rb->object.dglyph.glyph,
449 window, ERROR_ME_NOT, 1);
452 if (IMAGE_INSTANCEP (instance))
454 switch (XIMAGE_INSTANCE_TYPE (instance))
456 case IMAGE_MONO_PIXMAP:
457 case IMAGE_COLOR_PIXMAP:
458 redisplay_output_pixmap (w, instance, &dbox, &dga, findex,
459 cursor_start, cursor_width,
464 if (EQ (XIMAGE_INSTANCE_WIDGET_TYPE (instance),
467 redisplay_output_layout (window, instance, &dbox, &dga, findex,
468 cursor_start, cursor_width,
472 case IMAGE_SUBWINDOW:
473 redisplay_output_subwindow (w, instance, &dbox, &dga, findex,
474 cursor_start, cursor_width,
479 /* nothing is as nothing does */
487 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
488 (XIMAGE_INSTANCE (instance)) = 0;
499 if (Dynarr_length (buf))
500 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
501 0, cursor_start, cursor_width, cursor_height);
503 /* #### This is really conditionalized well for optimized
506 && !EQ (Qzero, w->modeline_shadow_thickness)
508 || f->windows_structure_changed
509 || w->shadow_thickness_changed))
510 bevel_modeline (w, dl);
515 /*****************************************************************************
518 Draw shadows for the given area in the given face.
519 ****************************************************************************/
521 x_bevel_area (struct window *w, face_index findex,
522 int x, int y, int width, int height,
523 int shadow_thickness, int edges, enum edge_style style)
525 struct frame *f = XFRAME (w->frame);
526 struct device *d = XDEVICE (f->device);
528 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
529 Display *dpy = DEVICE_X_DISPLAY (d);
530 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
531 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
532 Lisp_Object tmp_pixel;
535 GC top_shadow_gc, bottom_shadow_gc, background_gc;
541 assert (shadow_thickness >=0);
542 memset (&gcv, ~0, sizeof (XGCValues));
544 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
545 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
547 /* First, get the GC's. */
548 top_shadow_pixel = tmp_color.pixel;
549 bottom_shadow_pixel = tmp_color.pixel;
550 background_pixel = tmp_color.pixel;
552 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
553 background_pixel, ef->core.background_pixel);
555 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
556 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
557 gcv.background = tmp_color.pixel;
558 gcv.graphics_exposures = False;
559 mask = GCForeground | GCBackground | GCGraphicsExposures;
561 /* If we can't distinguish one of the shadows (the color is the same as the
562 background), it's better to use a pixmap to generate a dithered gray. */
563 if (top_shadow_pixel == background_pixel ||
564 bottom_shadow_pixel == background_pixel)
569 if (DEVICE_X_GRAY_PIXMAP (d) == None)
571 DEVICE_X_GRAY_PIXMAP (d) =
572 XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
573 gray_width, gray_height, 1, 0, 1);
576 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
577 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
578 gcv.foreground = tmp_color.pixel;
579 /* this is needed because the GC draws with a pixmap here */
580 gcv.fill_style = FillOpaqueStippled;
581 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
582 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
583 (mask | GCStipple | GCFillStyle));
585 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
586 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
587 bottom_shadow_pixel = tmp_color.pixel;
589 flip_gcs = (bottom_shadow_pixel ==
590 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
594 gcv.foreground = top_shadow_pixel;
595 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
598 gcv.foreground = bottom_shadow_pixel;
599 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
601 if (use_pixmap && flip_gcs)
603 GC tmp_gc = bottom_shadow_gc;
604 bottom_shadow_gc = top_shadow_gc;
605 top_shadow_gc = tmp_gc;
608 gcv.foreground = background_pixel;
609 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
611 /* possibly revert the GC's This will give a depressed look to the
613 if (style == EDGE_ETCHED_IN || style == EDGE_BEVEL_IN)
617 temp = top_shadow_gc;
618 top_shadow_gc = bottom_shadow_gc;
619 bottom_shadow_gc = temp;
622 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
623 shadow_thickness /= 2;
625 /* Draw the shadows around the divider line */
626 x_output_shadows (f, x, y, width, height,
627 top_shadow_gc, bottom_shadow_gc,
628 background_gc, shadow_thickness, edges);
630 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
632 /* Draw the shadows around the divider line */
633 x_output_shadows (f, x + shadow_thickness, y + shadow_thickness,
634 width - 2*shadow_thickness, height - 2*shadow_thickness,
635 bottom_shadow_gc, top_shadow_gc,
636 background_gc, shadow_thickness, edges);
640 /*****************************************************************************
643 Given a number of parameters return a GC with those properties.
644 ****************************************************************************/
646 x_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
647 Lisp_Object bg_pmap, Lisp_Object lwidth)
652 memset (&gcv, ~0, sizeof (XGCValues));
653 gcv.graphics_exposures = False;
654 /* Make absolutely sure that we don't pick up a clipping region in
655 the GC returned by this function. */
656 gcv.clip_mask = None;
657 gcv.clip_x_origin = 0;
658 gcv.clip_y_origin = 0;
659 gcv.fill_style = FillSolid;
660 mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
665 gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
670 if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg))
672 /* #### I fixed once case where this was getting it. It was a
673 bad macro expansion (compiler bug). */
674 stderr_out ("Help! x_get_gc got a bogus fg value! fg = ");
681 if (COLOR_INSTANCEP (fg))
682 gcv.foreground = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (fg)).pixel;
684 gcv.foreground = XINT (fg);
685 mask |= GCForeground;
690 if (COLOR_INSTANCEP (bg))
691 gcv.background = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (bg)).pixel;
693 gcv.background = XINT (bg);
694 mask |= GCBackground;
697 /* This special case comes from a request to draw text with a face which has
698 the dim property. We'll use a stippled foreground GC. */
699 if (EQ (bg_pmap, Qdim))
701 assert (DEVICE_X_GRAY_PIXMAP (d) != None);
703 gcv.fill_style = FillStippled;
704 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
705 mask |= (GCFillStyle | GCStipple);
707 else if (IMAGE_INSTANCEP (bg_pmap)
708 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
710 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
712 gcv.fill_style = FillOpaqueStippled;
713 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
714 mask |= (GCStipple | GCFillStyle);
718 gcv.fill_style = FillTiled;
719 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
720 mask |= (GCTile | GCFillStyle);
726 gcv.line_width = XINT (lwidth);
730 return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
733 /*****************************************************************************
736 Given a string and a starting position, output that string in the
737 given face. If cursor is true, draw a cursor around the string.
738 Correctly handles multiple charsets in the string.
740 The meaning of the parameters is something like this:
742 W Window that the text is to be displayed in.
743 DL Display line that this text is on. The values in the
744 structure are used to determine the vertical position and
745 clipping range of the text.
746 BUF Dynamic array of Emchars specifying what is actually to be
748 XPOS X position in pixels where the text should start being drawn.
749 XOFFSET Number of pixels to be chopped off the left side of the
750 text. The effect is as if the text were shifted to the
751 left this many pixels and clipped at XPOS.
752 CLIP_START Clip everything left of this X position.
753 WIDTH Clip everything right of XPOS + WIDTH.
754 FINDEX Index for the face cache element describing how to display
756 CURSOR #### I don't understand this. There's something
757 strange and overcomplexified with this variable.
758 Chuck, explain please?
759 CURSOR_START Starting X position of cursor.
760 CURSOR_WIDTH Width of cursor in pixels.
761 CURSOR_HEIGHT Height of cursor in pixels.
763 Starting Y position of cursor is the top of the text line.
764 The cursor is drawn sometimes whether or not CURSOR is set. ???
765 ****************************************************************************/
767 x_output_string (struct window *w, struct display_line *dl,
768 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
769 int width, face_index findex, int cursor,
770 int cursor_start, int cursor_width, int cursor_height)
772 /* General variables */
773 struct frame *f = XFRAME (w->frame);
774 struct device *d = XDEVICE (f->device);
777 Display *dpy = DEVICE_X_DISPLAY (d);
778 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
782 /* Cursor-related variables */
783 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
785 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
787 struct face_cachel *cursor_cachel = 0;
789 /* Text-related variables */
793 int len = Dynarr_length (buf);
794 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
795 struct textual_run *runs = alloca_array (struct textual_run, len);
798 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
800 XSETDEVICE (device, d);
801 XSETWINDOW (window, w);
804 width = x_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
805 height = DISPLAY_LINE_HEIGHT (dl);
807 /* Regularize the variables passed in. */
809 if (clip_start < xpos)
811 clip_end = xpos + width;
812 if (clip_start >= clip_end)
813 /* It's all clipped out. */
818 /* make sure the area we are about to display is subwindow free. */
819 redisplay_unmap_subwindows_maybe (f, clip_start, DISPLAY_LINE_YPOS (dl),
820 clip_end - clip_start, DISPLAY_LINE_HEIGHT (dl));
822 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
823 Dynarr_length (buf));
825 cursor_clip = (cursor_start >= clip_start &&
826 cursor_start < clip_end);
828 /* This cursor code is really a mess. */
829 if (!NILP (w->text_cursor_visible_p)
833 && (cursor_start + cursor_width >= clip_start)
834 && !NILP (bar_cursor_value))))
836 /* These have to be in separate statements in order to avoid a
838 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face);
839 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks);
841 /* We have to reset this since any call to WINDOW_FACE_CACHEL
842 may cause the cache to resize and any pointers to it to
844 cachel = WINDOW_FACE_CACHEL (w, findex);
848 if (cursor && focus && (cursor_start == clip_start) && cursor_height)
849 XIM_SetSpotLocation (f, xpos - 2, dl->ypos + dl->descent - 2);
850 #endif /* HAVE_XIM */
852 bg_pmap = cachel->background_pixmap;
853 if (!IMAGE_INSTANCEP (bg_pmap)
854 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
857 if ((cursor && focus && NILP (bar_cursor_value)
858 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap))
861 bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
865 XFillRectangle (dpy, x_win, bgc, clip_start,
866 DISPLAY_LINE_YPOS (dl), clip_end - clip_start,
869 for (i = 0; i < nruns; i++)
871 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
872 Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
876 if (EQ (font, Vthe_null_font_instance))
879 this_width = x_text_width_single_run (cachel, runs + i);
880 need_clipping = (dl->clip || clip_start > xpos ||
881 clip_end < xpos + this_width);
883 /* XDrawImageString only clears the area equal to the height of
884 the given font. It is possible that a font is being displayed
885 on a line taller than it is, so this would cause us to fail to
887 if ((int) fi->height < (int) (height + dl->clip + dl->top_clip))
889 int clear_start = max (xpos, clip_start);
890 int clear_end = min (xpos + this_width, clip_end);
894 int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
896 ypos1_string = dl->ypos - fi->ascent;
897 ypos2_string = dl->ypos + fi->descent;
898 ypos1_line = DISPLAY_LINE_YPOS (dl);
899 ypos2_line = ypos1_line + DISPLAY_LINE_HEIGHT (dl);
901 /* Make sure we don't clear below the real bottom of the
903 if (ypos1_string > ypos2_line)
904 ypos1_string = ypos2_line;
905 if (ypos2_string > ypos2_line)
906 ypos2_string = ypos2_line;
908 if (ypos1_line < ypos1_string)
910 redisplay_clear_region (window, findex, clear_start, ypos1_line,
911 clear_end - clear_start,
912 ypos1_string - ypos1_line);
915 if (ypos2_line > ypos2_string)
917 redisplay_clear_region (window, findex, clear_start, ypos2_string,
918 clear_end - clear_start,
919 ypos2_line - ypos2_string);
924 redisplay_clear_region (window, findex, clear_start,
925 DISPLAY_LINE_YPOS (dl), clear_end - clear_start,
930 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value))
931 gc = x_get_gc (d, font, cursor_cachel->foreground,
932 cursor_cachel->background, Qnil, Qnil);
933 else if (cachel->dim)
935 /* Ensure the gray bitmap exists */
936 if (DEVICE_X_GRAY_PIXMAP (d) == None)
937 DEVICE_X_GRAY_PIXMAP (d) =
938 XCreateBitmapFromData (dpy, x_win, (char *)gray_bits,
939 gray_width, gray_height);
941 /* Request a GC with the gray stipple pixmap to draw dimmed text */
942 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
946 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
951 XRectangle clip_box[1];
955 clip_box[0].width = clip_end - clip_start;
956 clip_box[0].height = height;
958 XSetClipRectangles (dpy, gc, clip_start, DISPLAY_LINE_YPOS (dl),
959 clip_box, 1, Unsorted);
962 if (runs[i].dimension == 1)
963 (bgc ? XDrawString : XDrawImageString) (dpy, x_win, gc, xpos,
964 dl->ypos, (char *) runs[i].ptr,
967 (bgc ? XDrawString16 : XDrawImageString16) (dpy, x_win, gc, xpos,
969 (XChar2b *) runs[i].ptr,
972 /* We draw underlines in the same color as the text. */
973 if (cachel->underline)
976 unsigned long uthick;
979 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
980 if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos))
981 upos = dl->descent / 2;
982 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
985 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
987 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
988 uthick = dl->descent - dl->clip - upos;
992 XDrawLine (dpy, x_win, gc, xpos, dl->ypos + upos,
993 xpos + this_width, dl->ypos + upos);
997 XFillRectangle (dpy, x_win, gc, xpos,
998 dl->ypos + upos, this_width, uthick);
1003 if (cachel->strikethru) {
1004 unsigned long ascent,descent,upos, uthick;
1007 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
1009 if (!XGetFontProperty (xfont, XA_STRIKEOUT_ASCENT, &ascent))
1010 ascent = xfont->ascent;
1011 if (!XGetFontProperty (xfont, XA_STRIKEOUT_DESCENT, &descent))
1012 descent = xfont->descent;
1013 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
1016 upos = ascent - ((ascent + descent) / 2) + 1;
1018 /* Generally, upos will be positive (above the baseline),so subtract */
1019 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip)
1021 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip)
1022 uthick = dl->descent - dl->clip + upos;
1026 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos,
1027 xpos + this_width, dl->ypos - upos);
1029 else if (uthick > 1)
1031 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos,
1032 this_width, uthick);
1037 /* Restore the GC */
1040 XSetClipMask (dpy, gc, None);
1041 XSetClipOrigin (dpy, gc, 0, 0);
1044 /* If we are actually superimposing the cursor then redraw with just
1045 the appropriate section highlighted. */
1046 if (cursor_clip && !cursor && focus && cursor_cachel)
1049 XRectangle clip_box[1];
1051 cgc = x_get_gc (d, font, cursor_cachel->foreground,
1052 cursor_cachel->background, Qnil, Qnil);
1056 clip_box[0].width = cursor_width;
1057 clip_box[0].height = height;
1059 XSetClipRectangles (dpy, cgc, cursor_start, DISPLAY_LINE_YPOS (dl),
1060 clip_box, 1, Unsorted);
1062 if (runs[i].dimension == 1)
1063 XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
1064 (char *) runs[i].ptr, runs[i].len);
1066 XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
1067 (XChar2b *) runs[i].ptr, runs[i].len);
1069 XSetClipMask (dpy, cgc, None);
1070 XSetClipOrigin (dpy, cgc, 0, 0);
1076 /* Draw the non-focus box or bar-cursor as needed. */
1077 /* Can't this logic be simplified? */
1079 && ((cursor && !focus && NILP (bar_cursor_value))
1081 && (cursor_start + cursor_width >= clip_start)
1082 && !NILP (bar_cursor_value))))
1084 int tmp_height, tmp_y;
1085 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1086 int need_clipping = (cursor_start < clip_start
1087 || clip_end < cursor_start + cursor_width);
1089 /* #### This value is correct (as far as I know) because
1090 all of the times we need to draw this cursor, we will
1091 be called with exactly one character, so we know we
1092 can always use runs[0].
1094 This is bogus as all hell, however. The cursor handling in
1095 this function is way bogus and desperately needs to be
1096 cleaned up. (In particular, the drawing of the cursor should
1097 really really be separated out of this function. This may be
1098 a bit tricky now because this function itself does way too
1099 much stuff, a lot of which needs to be moved into
1100 redisplay.c) This is the only way to be able to easily add
1101 new cursor types or (e.g.) make the bar cursor be able to
1102 span two characters instead of overlaying just one. */
1103 int bogusly_obtained_ascent_value =
1104 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent;
1106 if (!NILP (bar_cursor_value))
1108 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1109 make_int (bar_width));
1113 gc = x_get_gc (d, Qnil, cursor_cachel->background,
1117 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1118 tmp_height = cursor_height;
1119 if (tmp_y + tmp_height > (int) (DISPLAY_LINE_YPOS(dl) + height))
1121 tmp_y = DISPLAY_LINE_YPOS (dl) + height - tmp_height;
1122 if (tmp_y < (int) DISPLAY_LINE_YPOS (dl))
1123 tmp_y = DISPLAY_LINE_YPOS (dl);
1124 tmp_height = DISPLAY_LINE_YPOS (dl) + height - tmp_y;
1129 XRectangle clip_box[1];
1132 clip_box[0].width = clip_end - clip_start;
1133 clip_box[0].height = tmp_height;
1134 XSetClipRectangles (dpy, gc, clip_start, tmp_y,
1135 clip_box, 1, Unsorted);
1138 if (!focus && NILP (bar_cursor_value))
1140 XDrawRectangle (dpy, x_win, gc, cursor_start, tmp_y,
1141 cursor_width - 1, tmp_height - 1);
1143 else if (focus && !NILP (bar_cursor_value))
1145 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1, tmp_y,
1146 cursor_start + bar_width - 1, tmp_y + tmp_height - 1);
1149 /* Restore the GC */
1152 XSetClipMask (dpy, gc, None);
1153 XSetClipOrigin (dpy, gc, 0, 0);
1159 x_output_x_pixmap (struct frame *f, Lisp_Image_Instance *p, int x,
1160 int y, int xoffset, int yoffset,
1161 int width, int height, unsigned long fg, unsigned long bg,
1164 struct device *d = XDEVICE (f->device);
1165 Display *dpy = DEVICE_X_DISPLAY (d);
1166 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1170 unsigned long pixmap_mask;
1174 memset (&gcv, ~0, sizeof (XGCValues));
1175 gcv.graphics_exposures = False;
1176 gcv.foreground = fg;
1177 gcv.background = bg;
1178 pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
1180 if (IMAGE_INSTANCE_X_MASK (p))
1182 gcv.function = GXcopy;
1183 gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
1184 gcv.clip_x_origin = x - xoffset;
1185 gcv.clip_y_origin = y - yoffset;
1186 pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
1188 /* Can't set a clip rectangle because we already have a mask.
1189 Is it possible to get an equivalent effect by changing the
1190 args to XCopyArea below rather than messing with a clip box?
1191 - dkindred@cs.cmu.edu
1192 Yes. We don't clip at all now - andy@xemacs.org
1196 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
1201 /* override_gc might have a mask already--we don't want to nuke it.
1202 Maybe we can insist that override_gc have no mask, or use
1203 one of the suggestions above. */
1206 /* depth of 0 means it's a bitmap, not a pixmap, and we should use
1207 XCopyPlane (1 = current foreground color, 0 = background) instead
1208 of XCopyArea, which means that the bits in the pixmap are actual
1209 pixel values, instead of symbolic of fg/bg. */
1210 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
1213 IMAGE_INSTANCE_X_PIXMAP_SLICE
1214 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc, xoffset,
1220 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP_SLICE
1221 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc,
1222 xoffset, yoffset, width, height, x, y, 1L);
1227 x_output_pixmap (struct window *w, Lisp_Object image_instance,
1228 struct display_box *db, struct display_glyph_area *dga,
1229 face_index findex, int cursor_start, int cursor_width,
1230 int cursor_height, int bg_pixmap)
1232 struct frame *f = XFRAME (w->frame);
1233 struct device *d = XDEVICE (f->device);
1234 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1236 Display *dpy = DEVICE_X_DISPLAY (d);
1237 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1239 /* Output the pixmap. */
1241 Lisp_Object tmp_pixel;
1242 XColor tmp_bcolor, tmp_fcolor;
1244 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1245 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1246 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1247 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1249 x_output_x_pixmap (f, p, db->xpos, db->ypos,
1250 dga->xoffset, dga->yoffset,
1251 dga->width, dga->height,
1252 tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
1255 /* Draw a cursor over top of the pixmap. */
1256 if (cursor_width && cursor_height && (cursor_start >= db->xpos)
1257 && !NILP (w->text_cursor_visible_p)
1258 && (cursor_start < db->xpos + dga->width))
1261 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1262 struct face_cachel *cursor_cachel =
1263 WINDOW_FACE_CACHEL (w,
1264 get_builtin_face_cache_index
1265 (w, Vtext_cursor_face));
1267 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1269 if (cursor_width > db->xpos + dga->width - cursor_start)
1270 cursor_width = db->xpos + dga->width - cursor_start;
1274 XFillRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1279 XDrawRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1285 /*****************************************************************************
1286 x_output_vertical_divider
1288 Draw a vertical divider down the right side of the given window.
1289 ****************************************************************************/
1291 x_output_vertical_divider (struct window *w, int clear)
1293 struct frame *f = XFRAME (w->frame);
1294 struct device *d = XDEVICE (f->device);
1296 Display *dpy = DEVICE_X_DISPLAY (d);
1297 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1298 Lisp_Object tmp_pixel;
1302 enum edge_style style;
1305 int x, y1, y2, width, shadow_thickness, spacing, line_width;
1306 face_index div_face = get_builtin_face_cache_index (w, Vvertical_divider_face);
1308 width = window_divider_width (w);
1309 shadow_thickness = XINT (w->vertical_divider_shadow_thickness);
1310 spacing = XINT (w->vertical_divider_spacing);
1311 line_width = XINT (w->vertical_divider_line_width);
1312 x = WINDOW_RIGHT (w) - width;
1313 y1 = WINDOW_TOP (w);
1314 y2 = WINDOW_BOTTOM (w);
1316 memset (&gcv, ~0, sizeof (XGCValues));
1318 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1319 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1321 /* First, get the GC's. */
1322 gcv.background = tmp_color.pixel;
1323 gcv.foreground = tmp_color.pixel;
1324 gcv.graphics_exposures = False;
1325 mask = GCForeground | GCBackground | GCGraphicsExposures;
1326 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1328 /* Clear the divider area first. This needs to be done when a
1329 window split occurs. */
1331 XClearArea (dpy, x_win, x, y1, width, y2 - y1, False);
1333 /* Draw the divider line. */
1334 XFillRectangle (dpy, x_win, background_gc,
1335 x + spacing + shadow_thickness, y1,
1336 line_width, y2 - y1);
1338 if (shadow_thickness < 0)
1340 shadow_thickness = -shadow_thickness;
1341 style = EDGE_BEVEL_IN;
1345 style = EDGE_BEVEL_OUT;
1348 /* Draw the shadows around the divider line */
1349 x_bevel_area (w, div_face, x + spacing, y1,
1350 width - 2 * spacing, y2 - y1,
1351 shadow_thickness, EDGE_ALL, style);
1354 /*****************************************************************************
1357 Output a blank by clearing the area it covers in the foreground color
1359 ****************************************************************************/
1361 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
1362 int start_pixpos, int cursor_start, int cursor_width)
1364 struct frame *f = XFRAME (w->frame);
1365 struct device *d = XDEVICE (f->device);
1367 Display *dpy = DEVICE_X_DISPLAY (d);
1368 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1370 struct face_cachel *cursor_cachel =
1371 WINDOW_FACE_CACHEL (w,
1372 get_builtin_face_cache_index
1373 (w, Vtext_cursor_face));
1374 Lisp_Object bg_pmap;
1375 Lisp_Object buffer = WINDOW_BUFFER (w);
1376 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1380 int y = DISPLAY_LINE_YPOS (dl);
1381 int width = rb->width;
1382 int height = DISPLAY_LINE_HEIGHT (dl);
1384 /* Unmap all subwindows in the area we are going to blank. */
1385 redisplay_unmap_subwindows_maybe (f, x, y, width, height);
1387 if (start_pixpos > x)
1389 if (start_pixpos >= (x + width))
1393 width -= (start_pixpos - x);
1398 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
1399 if (!IMAGE_INSTANCEP (bg_pmap)
1400 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
1404 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1407 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1408 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
1411 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1413 /* If this rune is marked as having the cursor, then it is actually
1414 representing a tab. */
1415 if (!NILP (w->text_cursor_visible_p)
1416 && (rb->cursor_type == CURSOR_ON
1418 && (cursor_start + cursor_width > x)
1419 && cursor_start < (x + width))))
1421 int cursor_height, cursor_y;
1422 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1423 Lisp_Font_Instance *fi;
1425 fi = XFONT_INSTANCE (FACE_CACHEL_FONT
1426 (WINDOW_FACE_CACHEL (w, rb->findex),
1429 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1431 cursor_y = dl->ypos - fi->ascent;
1432 cursor_height = fi->height;
1433 if (cursor_y + cursor_height > y + height)
1434 cursor_height = y + height - cursor_y;
1438 if (NILP (bar_cursor_value))
1440 XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1441 fi->width, cursor_height);
1445 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1447 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1448 make_int (bar_width));
1449 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
1450 cursor_y, cursor_start + bar_width - 1,
1451 cursor_y + cursor_height - 1);
1454 else if (NILP (bar_cursor_value))
1456 XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1457 fi->width - 1, cursor_height - 1);
1462 /*****************************************************************************
1465 Output a horizontal line in the foreground of its face.
1466 ****************************************************************************/
1468 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
1470 struct frame *f = XFRAME (w->frame);
1471 struct device *d = XDEVICE (f->device);
1473 Display *dpy = DEVICE_X_DISPLAY (d);
1474 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1478 int width = rb->width;
1479 int height = DISPLAY_LINE_HEIGHT (dl);
1480 int ypos1, ypos2, ypos3, ypos4;
1482 ypos1 = DISPLAY_LINE_YPOS (dl);
1483 ypos2 = ypos1 + rb->object.hline.yoffset;
1484 ypos3 = ypos2 + rb->object.hline.thickness;
1485 ypos4 = dl->ypos + dl->descent - dl->clip;
1487 /* First clear the area not covered by the line. */
1488 if (height - rb->object.hline.thickness > 0)
1490 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1493 if (ypos2 - ypos1 > 0)
1494 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1495 if (ypos4 - ypos3 > 0)
1496 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1499 /* Now draw the line. */
1500 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1508 if (ypos3 - ypos2 > 0)
1509 XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1512 /*****************************************************************************
1515 Draw a shadow around the given area using the given GC's. It is the
1516 callers responsibility to set the GC's appropriately.
1517 ****************************************************************************/
1519 x_output_shadows (struct frame *f, int x, int y, int width, int height,
1520 GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
1521 int shadow_thickness, int edges)
1523 struct device *d = XDEVICE (f->device);
1525 Display *dpy = DEVICE_X_DISPLAY (d);
1526 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1528 XSegment top_shadow[20], bottom_shadow[20];
1531 if (shadow_thickness > 10)
1532 shadow_thickness = 10;
1533 else if (shadow_thickness < 0)
1534 shadow_thickness = 0;
1535 if (shadow_thickness > (width / 2))
1536 shadow_thickness = width / 2;
1537 if (shadow_thickness > (height / 2))
1538 shadow_thickness = height / 2;
1540 for (elt = 0; elt < shadow_thickness; elt++)
1543 int seg2 = (edges & EDGE_TOP) ? elt + shadow_thickness : elt;
1544 int bot_seg2 = (edges & EDGE_BOTTOM) ? elt + shadow_thickness : elt;
1546 if (edges & EDGE_TOP)
1548 top_shadow[seg1].x1 = x + elt;
1549 top_shadow[seg1].x2 = x + width - elt - 1;
1550 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
1552 if (edges & EDGE_LEFT)
1554 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
1555 top_shadow[seg2].y1 = y + elt;
1556 top_shadow[seg2].y2 = y + height - elt - 1;
1558 if (edges & EDGE_BOTTOM)
1560 bottom_shadow[seg1].x1 = x + elt;
1561 bottom_shadow[seg1].x2 = x + width - elt - 1;
1562 bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
1564 if (edges & EDGE_RIGHT)
1566 bottom_shadow[bot_seg2].x1 = bottom_shadow[bot_seg2].x2 = x + width - elt - 1;
1567 bottom_shadow[bot_seg2].y1 = y + elt;
1568 bottom_shadow[bot_seg2].y2 = y + height - elt - 1;
1572 XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow,
1573 ((edges & EDGE_TOP) ? shadow_thickness : 0)
1574 + ((edges & EDGE_LEFT) ? shadow_thickness : 0));
1575 XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
1576 ((edges & EDGE_BOTTOM) ? shadow_thickness : 0)
1577 + ((edges & EDGE_RIGHT) ? shadow_thickness : 0));
1580 /*****************************************************************************
1581 x_generate_shadow_pixels
1583 Given three pixels (top shadow, bottom shadow, background) massage
1584 the top and bottom shadow colors to guarantee that they differ. The
1585 background pixels are not allowed to be modified.
1587 This function modifies its parameters.
1589 This code is modified from code blatantly stolen from lwlib/xlwmenu.c
1590 ****************************************************************************/
1591 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
1592 ? ((unsigned long) (x)) : ((unsigned long) (y)))
1595 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
1596 unsigned long *bottom_shadow,
1597 unsigned long background,
1598 unsigned long core_background)
1600 struct device *d = XDEVICE (f->device);
1601 Display *dpy = DEVICE_X_DISPLAY (d);
1602 Colormap cmap = DEVICE_X_COLORMAP (d);
1603 Visual *visual = DEVICE_X_VISUAL (d);
1606 int top_frobbed = 0, bottom_frobbed = 0;
1608 /* If the top shadow is the same color as the background, try to
1610 if (*top_shadow == background)
1612 topc.pixel = background;
1613 XQueryColor (dpy, cmap, &topc);
1614 /* don't overflow/wrap! */
1615 topc.red = MINL (65535, (unsigned long) topc.red * 6 / 5);
1616 topc.green = MINL (65535, (unsigned long) topc.green * 6 / 5);
1617 topc.blue = MINL (65535, (unsigned long) topc.blue * 6 / 5);
1618 if (allocate_nearest_color (dpy, cmap, visual, &topc))
1620 *top_shadow = topc.pixel;
1625 /* If the bottom shadow is the same color as the background, try to
1627 if (*bottom_shadow == background)
1629 botc.pixel = background;
1630 XQueryColor (dpy, cmap, &botc);
1631 botc.red = (unsigned short) ((unsigned long) botc.red * 3 / 5);
1632 botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5);
1633 botc.blue = (unsigned short) ((unsigned long) botc.blue * 3 / 5);
1634 if (allocate_nearest_color (dpy, cmap, visual, &botc))
1636 *bottom_shadow = botc.pixel;
1641 /* If we had to adjust both shadows, then we have to do some
1643 if (top_frobbed && bottom_frobbed)
1645 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
1646 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
1647 if (bot_avg > top_avg)
1649 Pixel tmp = *top_shadow;
1651 *top_shadow = *bottom_shadow;
1652 *bottom_shadow = tmp;
1654 else if (topc.pixel == botc.pixel)
1656 if (botc.pixel == background)
1657 *top_shadow = core_background;
1659 *bottom_shadow = background;
1664 /*****************************************************************************
1665 x_redraw_exposed_window
1667 Given a bounding box for an area that needs to be redrawn, determine
1668 what parts of what lines are contained within and re-output their
1670 ****************************************************************************/
1672 x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
1674 struct frame *f = XFRAME (w->frame);
1676 int start_x, start_y, end_x, end_y;
1677 int orig_windows_structure_changed;
1679 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1681 if (!NILP (w->vchild))
1683 x_redraw_exposed_windows (w->vchild, x, y, width, height);
1686 else if (!NILP (w->hchild))
1688 x_redraw_exposed_windows (w->hchild, x, y, width, height);
1692 /* If the window doesn't intersect the exposed region, we're done here. */
1693 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w)
1694 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w))
1700 start_x = max (WINDOW_LEFT (w), x);
1701 end_x = min (WINDOW_RIGHT (w), (x + width));
1702 start_y = max (WINDOW_TOP (w), y);
1703 end_y = min (WINDOW_BOTTOM (w), y + height);
1705 /* We do this to make sure that the 3D modelines get redrawn if
1706 they are in the exposed region. */
1707 orig_windows_structure_changed = f->windows_structure_changed;
1708 f->windows_structure_changed = 1;
1711 redisplay_clear_top_of_window (w);
1712 if (window_needs_vertical_divider (w))
1714 x_output_vertical_divider (w, 0);
1717 for (line = 0; line < Dynarr_length (cdla); line++)
1719 struct display_line *cdl = Dynarr_atp (cdla, line);
1720 int top_y = cdl->ypos - cdl->ascent;
1721 int bottom_y = cdl->ypos + cdl->descent;
1723 if (bottom_y >= start_y)
1734 output_display_line (w, 0, cdla, line, start_x, end_x);
1739 f->windows_structure_changed = orig_windows_structure_changed;
1741 /* If there have never been any face cache_elements created, then this
1742 expose event doesn't actually have anything to do. */
1743 if (Dynarr_largest (w->face_cachels))
1744 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
1747 /*****************************************************************************
1748 x_redraw_exposed_windows
1750 For each window beneath the given window in the window hierarchy,
1751 ensure that it is redrawn if necessary after an Expose event.
1752 ****************************************************************************/
1754 x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
1757 for (; !NILP (window); window = XWINDOW (window)->next)
1758 x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
1761 /*****************************************************************************
1762 x_redraw_exposed_area
1764 For each window on the given frame, ensure that any area in the
1765 Exposed area is redrawn.
1766 ****************************************************************************/
1768 x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
1770 /* If any window on the frame has had its face cache reset then the
1771 redisplay structures are effectively invalid. If we attempt to
1772 use them we'll blow up. We mark the frame as changed to ensure
1773 that redisplay will do a full update. This probably isn't
1774 necessary but it can't hurt. */
1776 #ifdef HAVE_TOOLBARS
1777 /* #### We would rather put these off as well but there is currently
1778 no combination of flags which will force an unchanged toolbar to
1780 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
1782 redraw_exposed_gutters (f, x, y, width, height);
1784 if (!f->window_face_cache_reset)
1786 x_redraw_exposed_windows (f->root_window, x, y, width, height);
1788 XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
1791 MARK_FRAME_CHANGED (f);
1794 /****************************************************************************
1797 Clear the area in the box defined by the given parameters using the
1799 ****************************************************************************/
1801 x_clear_region (Lisp_Object locale, struct device* d, struct frame* f, face_index findex,
1803 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1804 Lisp_Object background_pixmap)
1810 dpy = DEVICE_X_DISPLAY (d);
1811 x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1813 if (!UNBOUNDP (background_pixmap))
1815 gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
1819 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1821 XClearArea (dpy, x_win, x, y, width, height, False);
1824 /*****************************************************************************
1827 Draw a cursor at the end of a line. The end-of-line cursor is
1828 narrower than the normal cursor.
1829 ****************************************************************************/
1831 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos,
1834 struct frame *f = XFRAME (w->frame);
1835 struct device *d = XDEVICE (f->device);
1838 Display *dpy = DEVICE_X_DISPLAY (d);
1839 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1841 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
1842 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
1844 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1845 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1849 int y = DISPLAY_LINE_YPOS (dl);
1850 int width = EOL_CURSOR_WIDTH;
1851 int height = DISPLAY_LINE_HEIGHT (dl);
1852 int cursor_height, cursor_y;
1853 int defheight, defascent;
1855 XSETWINDOW (window, w);
1856 redisplay_clear_region (window, findex, x, y, width, height);
1858 if (NILP (w->text_cursor_visible_p))
1861 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1863 default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
1865 /* make sure the cursor is entirely contained between y and y+height */
1866 cursor_height = min (defheight, height);
1867 cursor_y = max (y, min (y + height - cursor_height,
1868 dl->ypos - defascent));
1873 XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2);
1874 #endif /* HAVE_XIM */
1876 if (NILP (bar_cursor_value))
1878 XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
1882 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1884 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1885 make_int (bar_width));
1886 XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
1887 x + bar_width - 1, cursor_y + cursor_height - 1);
1890 else if (NILP (bar_cursor_value))
1892 XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
1898 x_clear_frame_window (Lisp_Object window)
1900 struct window *w = XWINDOW (window);
1902 if (!NILP (w->vchild))
1904 x_clear_frame_windows (w->vchild);
1908 if (!NILP (w->hchild))
1910 x_clear_frame_windows (w->hchild);
1914 redisplay_clear_to_window_end (w, WINDOW_TEXT_TOP (w),
1915 WINDOW_TEXT_BOTTOM (w));
1919 x_clear_frame_windows (Lisp_Object window)
1921 for (; !NILP (window); window = XWINDOW (window)->next)
1922 x_clear_frame_window (window);
1926 x_clear_frame (struct frame *f)
1928 struct device *d = XDEVICE (f->device);
1929 Display *dpy = DEVICE_X_DISPLAY (d);
1930 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1931 int x, y, width, height;
1934 x = FRAME_LEFT_BORDER_START (f);
1935 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
1936 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
1937 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) -
1938 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f));
1939 /* #### This adjustment by 1 should be being done in the macros.
1940 There is some small differences between when the menubar is on
1941 and off that we still need to deal with. */
1942 y = FRAME_TOP_BORDER_START (f) - 1;
1943 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
1944 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
1945 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) -
1946 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1;
1948 XClearArea (dpy, x_win, x, y, width, height, False);
1950 XSETFRAME (frame, f);
1952 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
1953 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
1954 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
1956 x_clear_frame_windows (f->root_window);
1959 XFlush (DEVICE_X_DISPLAY (d));
1962 /* briefly swap the foreground and background colors.
1966 x_flash (struct device *d)
1972 XColor tmp_fcolor, tmp_bcolor;
1973 Lisp_Object tmp_pixel, frame;
1974 struct frame *f = device_selected_frame (d);
1975 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f));
1976 Widget shell = FRAME_X_SHELL_WIDGET (f);
1979 XSETFRAME (frame, f);
1981 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
1982 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1983 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
1984 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1986 dpy = XtDisplay (shell);
1987 win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1988 memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
1989 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
1990 gcv.function = GXxor;
1991 gcv.graphics_exposures = False;
1992 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
1993 (GCForeground | GCFunction | GCGraphicsExposures));
1994 default_face_height_and_width (frame, &flash_height, 0);
1996 /* If window is tall, flash top and bottom line. */
1997 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
1999 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2000 w->pixel_width, flash_height);
2001 XFillRectangle (dpy, win, gc, w->pixel_left,
2002 w->pixel_top + w->pixel_height - flash_height,
2003 w->pixel_width, flash_height);
2006 /* If it is short, flash it all. */
2007 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2008 w->pixel_width, w->pixel_height);
2016 tv.tv_sec = usecs / 1000000L;
2017 tv.tv_usec = usecs % 1000000L;
2018 /* I'm sure someone is going to complain about this... */
2019 select (0, 0, 0, 0, &tv);
2024 #else /* !HAVE_POLL */
2026 #endif /* HAVE_POLL */
2027 #endif /* HAVE_SELECT */
2029 /* If window is tall, flash top and bottom line. */
2030 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
2032 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2033 w->pixel_width, flash_height);
2034 XFillRectangle (dpy, win, gc, w->pixel_left,
2035 w->pixel_top + w->pixel_height - flash_height,
2036 w->pixel_width, flash_height);
2039 /* If it is short, flash it all. */
2040 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2041 w->pixel_width, w->pixel_height);
2048 /* Make audible bell. */
2051 x_ring_bell (struct device *d, int volume, int pitch, int duration)
2053 Display *display = DEVICE_X_DISPLAY (d);
2055 if (volume < 0) volume = 0;
2056 else if (volume > 100) volume = 100;
2057 if (pitch < 0 && duration < 0)
2059 XBell (display, (volume * 2) - 100);
2064 XKeyboardState state;
2065 XKeyboardControl ctl;
2067 /* #### grab server? */
2068 XGetKeyboardControl (display, &state);
2070 ctl.bell_pitch = (pitch >= 0 ? pitch : (int) state.bell_pitch);
2071 ctl.bell_duration = (duration >= 0 ? duration : (int) state.bell_duration);
2072 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2074 XBell (display, (volume * 2) - 100);
2076 ctl.bell_pitch = state.bell_pitch;
2077 ctl.bell_duration = state.bell_duration;
2078 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2080 /* #### ungrab server? */
2086 /************************************************************************/
2087 /* initialization */
2088 /************************************************************************/
2091 console_type_create_redisplay_x (void)
2093 /* redisplay methods */
2094 CONSOLE_HAS_METHOD (x, text_width);
2095 CONSOLE_HAS_METHOD (x, output_display_block);
2096 CONSOLE_HAS_METHOD (x, divider_height);
2097 CONSOLE_HAS_METHOD (x, eol_cursor_width);
2098 CONSOLE_HAS_METHOD (x, output_vertical_divider);
2099 CONSOLE_HAS_METHOD (x, clear_region);
2100 CONSOLE_HAS_METHOD (x, clear_frame);
2101 CONSOLE_HAS_METHOD (x, window_output_begin);
2102 CONSOLE_HAS_METHOD (x, window_output_end);
2103 CONSOLE_HAS_METHOD (x, flash);
2104 CONSOLE_HAS_METHOD (x, ring_bell);
2105 CONSOLE_HAS_METHOD (x, bevel_area);
2106 CONSOLE_HAS_METHOD (x, output_string);
2107 CONSOLE_HAS_METHOD (x, output_pixmap);