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))
455 case IMAGE_MONO_PIXMAP:
456 case IMAGE_COLOR_PIXMAP:
457 redisplay_output_pixmap (w, instance, &dbox, &dga, findex,
458 cursor_start, cursor_width,
463 case IMAGE_SUBWINDOW:
464 redisplay_output_subwindow (w, instance, &dbox, &dga, findex,
465 cursor_start, cursor_width,
470 redisplay_output_layout (w, instance, &dbox, &dga, findex,
471 cursor_start, cursor_width,
476 /* nothing is as nothing does */
484 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
485 (XIMAGE_INSTANCE (instance)) = 0;
496 if (Dynarr_length (buf))
497 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
498 0, cursor_start, cursor_width, cursor_height);
500 /* #### This is really conditionalized well for optimized
503 && !EQ (Qzero, w->modeline_shadow_thickness)
505 || f->windows_structure_changed
506 || w->shadow_thickness_changed))
507 bevel_modeline (w, dl);
512 /*****************************************************************************
515 Draw a shadows for the given area in the given face.
516 ****************************************************************************/
518 x_bevel_area (struct window *w, face_index findex,
519 int x, int y, int width, int height,
520 int shadow_thickness, int edges, enum edge_style style)
522 struct frame *f = XFRAME (w->frame);
523 struct device *d = XDEVICE (f->device);
525 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
526 Display *dpy = DEVICE_X_DISPLAY (d);
527 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
528 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
529 Lisp_Object tmp_pixel;
532 GC top_shadow_gc, bottom_shadow_gc, background_gc;
538 assert (shadow_thickness >=0);
539 memset (&gcv, ~0, sizeof (XGCValues));
541 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
542 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
544 /* First, get the GC's. */
545 top_shadow_pixel = tmp_color.pixel;
546 bottom_shadow_pixel = tmp_color.pixel;
547 background_pixel = tmp_color.pixel;
549 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
550 background_pixel, ef->core.background_pixel);
552 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
553 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
554 gcv.background = tmp_color.pixel;
555 gcv.graphics_exposures = False;
556 mask = GCForeground | GCBackground | GCGraphicsExposures;
558 /* If we can't distinguish one of the shadows (the color is the same as the
559 background), it's better to use a pixmap to generate a dithered gray. */
560 if (top_shadow_pixel == background_pixel ||
561 bottom_shadow_pixel == background_pixel)
566 if (DEVICE_X_GRAY_PIXMAP (d) == None)
568 DEVICE_X_GRAY_PIXMAP (d) =
569 XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
570 gray_width, gray_height, 1, 0, 1);
573 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
574 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
575 gcv.foreground = tmp_color.pixel;
576 /* this is needed because the GC draws with a pixmap here */
577 gcv.fill_style = FillOpaqueStippled;
578 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
579 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
580 (mask | GCStipple | GCFillStyle));
582 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
583 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
584 bottom_shadow_pixel = tmp_color.pixel;
586 flip_gcs = (bottom_shadow_pixel ==
587 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
591 gcv.foreground = top_shadow_pixel;
592 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
595 gcv.foreground = bottom_shadow_pixel;
596 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
598 if (use_pixmap && flip_gcs)
600 GC tmp_gc = bottom_shadow_gc;
601 bottom_shadow_gc = top_shadow_gc;
602 top_shadow_gc = tmp_gc;
605 gcv.foreground = background_pixel;
606 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
608 /* possibly revert the GC's This will give a depressed look to the
610 if (style == EDGE_ETCHED_IN || style == EDGE_BEVEL_IN)
614 temp = top_shadow_gc;
615 top_shadow_gc = bottom_shadow_gc;
616 bottom_shadow_gc = temp;
619 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
620 shadow_thickness /= 2;
622 /* Draw the shadows around the divider line */
623 x_output_shadows (f, x, y, width, height,
624 top_shadow_gc, bottom_shadow_gc,
625 background_gc, shadow_thickness, edges);
627 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
629 /* Draw the shadows around the divider line */
630 x_output_shadows (f, x + shadow_thickness, y + shadow_thickness,
631 width - 2*shadow_thickness, height - 2*shadow_thickness,
632 bottom_shadow_gc, top_shadow_gc,
633 background_gc, shadow_thickness, edges);
637 /*****************************************************************************
640 Given a number of parameters return a GC with those properties.
641 ****************************************************************************/
643 x_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
644 Lisp_Object bg_pmap, Lisp_Object lwidth)
649 memset (&gcv, ~0, sizeof (XGCValues));
650 gcv.graphics_exposures = False;
651 /* Make absolutely sure that we don't pick up a clipping region in
652 the GC returned by this function. */
653 gcv.clip_mask = None;
654 gcv.clip_x_origin = 0;
655 gcv.clip_y_origin = 0;
656 gcv.fill_style = FillSolid;
657 mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
662 gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
667 if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg))
669 /* #### I fixed once case where this was getting it. It was a
670 bad macro expansion (compiler bug). */
671 stderr_out ("Help! x_get_gc got a bogus fg value! fg = ");
678 if (COLOR_INSTANCEP (fg))
679 gcv.foreground = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (fg)).pixel;
681 gcv.foreground = XINT (fg);
682 mask |= GCForeground;
687 if (COLOR_INSTANCEP (bg))
688 gcv.background = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (bg)).pixel;
690 gcv.background = XINT (bg);
691 mask |= GCBackground;
694 /* This special case comes from a request to draw text with a face which has
695 the dim property. We'll use a stippled foreground GC. */
696 if (EQ (bg_pmap, Qdim))
698 assert (DEVICE_X_GRAY_PIXMAP (d) != None);
700 gcv.fill_style = FillStippled;
701 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
702 mask |= (GCFillStyle | GCStipple);
704 else if (IMAGE_INSTANCEP (bg_pmap)
705 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
707 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
709 gcv.fill_style = FillOpaqueStippled;
710 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
711 mask |= (GCStipple | GCFillStyle);
715 gcv.fill_style = FillTiled;
716 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
717 mask |= (GCTile | GCFillStyle);
723 gcv.line_width = XINT (lwidth);
727 return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
730 /*****************************************************************************
733 Given a string and a starting position, output that string in the
734 given face. If cursor is true, draw a cursor around the string.
735 Correctly handles multiple charsets in the string.
737 The meaning of the parameters is something like this:
739 W Window that the text is to be displayed in.
740 DL Display line that this text is on. The values in the
741 structure are used to determine the vertical position and
742 clipping range of the text.
743 BUF Dynamic array of Emchars specifying what is actually to be
745 XPOS X position in pixels where the text should start being drawn.
746 XOFFSET Number of pixels to be chopped off the left side of the
747 text. The effect is as if the text were shifted to the
748 left this many pixels and clipped at XPOS.
749 CLIP_START Clip everything left of this X position.
750 WIDTH Clip everything right of XPOS + WIDTH.
751 FINDEX Index for the face cache element describing how to display
753 CURSOR #### I don't understand this. There's something
754 strange and overcomplexified with this variable.
755 Chuck, explain please?
756 CURSOR_START Starting X position of cursor.
757 CURSOR_WIDTH Width of cursor in pixels.
758 CURSOR_HEIGHT Height of cursor in pixels.
760 Starting Y position of cursor is the top of the text line.
761 The cursor is drawn sometimes whether or not CURSOR is set. ???
762 ****************************************************************************/
764 x_output_string (struct window *w, struct display_line *dl,
765 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
766 int width, face_index findex, int cursor,
767 int cursor_start, int cursor_width, int cursor_height)
769 /* General variables */
770 struct frame *f = XFRAME (w->frame);
771 struct device *d = XDEVICE (f->device);
774 Display *dpy = DEVICE_X_DISPLAY (d);
775 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
779 /* Cursor-related variables */
780 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
782 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
784 struct face_cachel *cursor_cachel = 0;
786 /* Text-related variables */
790 int len = Dynarr_length (buf);
791 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
792 struct textual_run *runs = alloca_array (struct textual_run, len);
795 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
797 XSETDEVICE (device, d);
798 XSETWINDOW (window, w);
801 width = x_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
802 height = DISPLAY_LINE_HEIGHT (dl);
804 /* Regularize the variables passed in. */
806 if (clip_start < xpos)
808 clip_end = xpos + width;
809 if (clip_start >= clip_end)
810 /* It's all clipped out. */
815 /* make sure the area we are about to display is subwindow free. */
816 redisplay_unmap_subwindows_maybe (f, clip_start, DISPLAY_LINE_YPOS (dl),
817 clip_end - clip_start, DISPLAY_LINE_HEIGHT (dl));
819 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
820 Dynarr_length (buf));
822 cursor_clip = (cursor_start >= clip_start &&
823 cursor_start < clip_end);
825 /* This cursor code is really a mess. */
826 if (!NILP (w->text_cursor_visible_p)
830 && (cursor_start + cursor_width >= clip_start)
831 && !NILP (bar_cursor_value))))
833 /* These have to be in separate statements in order to avoid a
835 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face);
836 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks);
838 /* We have to reset this since any call to WINDOW_FACE_CACHEL
839 may cause the cache to resize and any pointers to it to
841 cachel = WINDOW_FACE_CACHEL (w, findex);
845 if (cursor && focus && (cursor_start == clip_start) && cursor_height)
846 XIM_SetSpotLocation (f, xpos - 2, dl->ypos + dl->descent - 2);
847 #endif /* HAVE_XIM */
849 bg_pmap = cachel->background_pixmap;
850 if (!IMAGE_INSTANCEP (bg_pmap)
851 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
854 if ((cursor && focus && NILP (bar_cursor_value)
855 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap))
858 bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
862 XFillRectangle (dpy, x_win, bgc, clip_start,
863 DISPLAY_LINE_YPOS (dl), clip_end - clip_start,
866 for (i = 0; i < nruns; i++)
868 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
869 Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
873 if (EQ (font, Vthe_null_font_instance))
876 this_width = x_text_width_single_run (cachel, runs + i);
877 need_clipping = (dl->clip || clip_start > xpos ||
878 clip_end < xpos + this_width);
880 /* XDrawImageString only clears the area equal to the height of
881 the given font. It is possible that a font is being displayed
882 on a line taller than it is, so this would cause us to fail to
884 if ((int) fi->height < (int) (height + dl->clip + dl->top_clip))
886 int clear_start = max (xpos, clip_start);
887 int clear_end = min (xpos + this_width, clip_end);
891 int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
893 ypos1_string = dl->ypos - fi->ascent;
894 ypos2_string = dl->ypos + fi->descent;
895 ypos1_line = DISPLAY_LINE_YPOS (dl);
896 ypos2_line = ypos1_line + DISPLAY_LINE_HEIGHT (dl);
898 /* Make sure we don't clear below the real bottom of the
900 if (ypos1_string > ypos2_line)
901 ypos1_string = ypos2_line;
902 if (ypos2_string > ypos2_line)
903 ypos2_string = ypos2_line;
905 if (ypos1_line < ypos1_string)
907 redisplay_clear_region (window, findex, clear_start, ypos1_line,
908 clear_end - clear_start,
909 ypos1_string - ypos1_line);
912 if (ypos2_line > ypos2_string)
914 redisplay_clear_region (window, findex, clear_start, ypos2_string,
915 clear_end - clear_start,
916 ypos2_line - ypos2_string);
921 redisplay_clear_region (window, findex, clear_start,
922 DISPLAY_LINE_YPOS (dl), clear_end - clear_start,
927 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value))
928 gc = x_get_gc (d, font, cursor_cachel->foreground,
929 cursor_cachel->background, Qnil, Qnil);
930 else if (cachel->dim)
932 /* Ensure the gray bitmap exists */
933 if (DEVICE_X_GRAY_PIXMAP (d) == None)
934 DEVICE_X_GRAY_PIXMAP (d) =
935 XCreateBitmapFromData (dpy, x_win, (char *)gray_bits,
936 gray_width, gray_height);
938 /* Request a GC with the gray stipple pixmap to draw dimmed text */
939 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
943 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
948 XRectangle clip_box[1];
952 clip_box[0].width = clip_end - clip_start;
953 clip_box[0].height = height;
955 XSetClipRectangles (dpy, gc, clip_start, DISPLAY_LINE_YPOS (dl),
956 clip_box, 1, Unsorted);
959 if (runs[i].dimension == 1)
960 (bgc ? XDrawString : XDrawImageString) (dpy, x_win, gc, xpos,
961 dl->ypos, (char *) runs[i].ptr,
964 (bgc ? XDrawString16 : XDrawImageString16) (dpy, x_win, gc, xpos,
966 (XChar2b *) runs[i].ptr,
969 /* We draw underlines in the same color as the text. */
970 if (cachel->underline)
972 unsigned long upos, uthick;
975 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
976 if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos))
977 upos = dl->descent / 2;
978 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
981 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
983 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
984 uthick = dl->descent - dl->clip - upos;
988 XDrawLine (dpy, x_win, gc, xpos, dl->ypos + upos,
989 xpos + this_width, dl->ypos + upos);
993 XFillRectangle (dpy, x_win, gc, xpos,
994 dl->ypos + upos, this_width, uthick);
999 if (cachel->strikethru) {
1000 unsigned long ascent,descent,upos, uthick;
1003 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
1005 if (!XGetFontProperty (xfont, XA_STRIKEOUT_ASCENT, &ascent))
1006 ascent = xfont->ascent;
1007 if (!XGetFontProperty (xfont, XA_STRIKEOUT_DESCENT, &descent))
1008 descent = xfont->descent;
1009 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
1012 upos = ascent - ((ascent + descent) / 2) + 1;
1014 /* Generally, upos will be positive (above the baseline),so subtract */
1015 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip)
1017 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip)
1018 uthick = dl->descent - dl->clip + upos;
1022 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos,
1023 xpos + this_width, dl->ypos - upos);
1025 else if (uthick > 1)
1027 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos,
1028 this_width, uthick);
1033 /* Restore the GC */
1036 XSetClipMask (dpy, gc, None);
1037 XSetClipOrigin (dpy, gc, 0, 0);
1040 /* If we are actually superimposing the cursor then redraw with just
1041 the appropriate section highlighted. */
1042 if (cursor_clip && !cursor && focus && cursor_cachel)
1045 XRectangle clip_box[1];
1047 cgc = x_get_gc (d, font, cursor_cachel->foreground,
1048 cursor_cachel->background, Qnil, Qnil);
1052 clip_box[0].width = cursor_width;
1053 clip_box[0].height = height;
1055 XSetClipRectangles (dpy, cgc, cursor_start, DISPLAY_LINE_YPOS (dl),
1056 clip_box, 1, Unsorted);
1058 if (runs[i].dimension == 1)
1059 XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
1060 (char *) runs[i].ptr, runs[i].len);
1062 XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
1063 (XChar2b *) runs[i].ptr, runs[i].len);
1065 XSetClipMask (dpy, cgc, None);
1066 XSetClipOrigin (dpy, cgc, 0, 0);
1072 /* Draw the non-focus box or bar-cursor as needed. */
1073 /* Can't this logic be simplified? */
1075 && ((cursor && !focus && NILP (bar_cursor_value))
1077 && (cursor_start + cursor_width >= clip_start)
1078 && !NILP (bar_cursor_value))))
1080 int tmp_height, tmp_y;
1081 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1082 int need_clipping = (cursor_start < clip_start
1083 || clip_end < cursor_start + cursor_width);
1085 /* #### This value is correct (as far as I know) because
1086 all of the times we need to draw this cursor, we will
1087 be called with exactly one character, so we know we
1088 can always use runs[0].
1090 This is bogus as all hell, however. The cursor handling in
1091 this function is way bogus and desperately needs to be
1092 cleaned up. (In particular, the drawing of the cursor should
1093 really really be separated out of this function. This may be
1094 a bit tricky now because this function itself does way too
1095 much stuff, a lot of which needs to be moved into
1096 redisplay.c) This is the only way to be able to easily add
1097 new cursor types or (e.g.) make the bar cursor be able to
1098 span two characters instead of overlaying just one. */
1099 int bogusly_obtained_ascent_value =
1100 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent;
1102 if (!NILP (bar_cursor_value))
1104 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1105 make_int (bar_width));
1109 gc = x_get_gc (d, Qnil, cursor_cachel->background,
1113 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1114 tmp_height = cursor_height;
1115 if (tmp_y + tmp_height > (int) (DISPLAY_LINE_YPOS(dl) + height))
1117 tmp_y = DISPLAY_LINE_YPOS (dl) + height - tmp_height;
1118 if (tmp_y < (int) DISPLAY_LINE_YPOS (dl))
1119 tmp_y = DISPLAY_LINE_YPOS (dl);
1120 tmp_height = DISPLAY_LINE_YPOS (dl) + height - tmp_y;
1125 XRectangle clip_box[1];
1128 clip_box[0].width = clip_end - clip_start;
1129 clip_box[0].height = tmp_height;
1130 XSetClipRectangles (dpy, gc, clip_start, tmp_y,
1131 clip_box, 1, Unsorted);
1134 if (!focus && NILP (bar_cursor_value))
1136 XDrawRectangle (dpy, x_win, gc, cursor_start, tmp_y,
1137 cursor_width - 1, tmp_height - 1);
1139 else if (focus && !NILP (bar_cursor_value))
1141 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1, tmp_y,
1142 cursor_start + bar_width - 1, tmp_y + tmp_height - 1);
1145 /* Restore the GC */
1148 XSetClipMask (dpy, gc, None);
1149 XSetClipOrigin (dpy, gc, 0, 0);
1155 x_output_x_pixmap (struct frame *f, Lisp_Image_Instance *p, int x,
1156 int y, int xoffset, int yoffset,
1157 int width, int height, unsigned long fg, unsigned long bg,
1160 struct device *d = XDEVICE (f->device);
1161 Display *dpy = DEVICE_X_DISPLAY (d);
1162 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1166 unsigned long pixmap_mask;
1170 memset (&gcv, ~0, sizeof (XGCValues));
1171 gcv.graphics_exposures = False;
1172 gcv.foreground = fg;
1173 gcv.background = bg;
1174 pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
1176 if (IMAGE_INSTANCE_X_MASK (p))
1178 gcv.function = GXcopy;
1179 gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
1180 gcv.clip_x_origin = x - xoffset;
1181 gcv.clip_y_origin = y - yoffset;
1182 pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
1184 /* Can't set a clip rectangle because we already have a mask.
1185 Is it possible to get an equivalent effect by changing the
1186 args to XCopyArea below rather than messing with a clip box?
1187 - dkindred@cs.cmu.edu
1188 Yes. We don't clip at all now - andy@xemacs.org
1192 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
1197 /* override_gc might have a mask already--we don't want to nuke it.
1198 Maybe we can insist that override_gc have no mask, or use
1199 one of the suggestions above. */
1202 /* depth of 0 means it's a bitmap, not a pixmap, and we should use
1203 XCopyPlane (1 = current foreground color, 0 = background) instead
1204 of XCopyArea, which means that the bits in the pixmap are actual
1205 pixel values, instead of symbolic of fg/bg. */
1206 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
1209 IMAGE_INSTANCE_X_PIXMAP_SLICE
1210 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc, xoffset,
1216 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP_SLICE
1217 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc,
1218 xoffset, yoffset, width, height, x, y, 1L);
1223 x_output_pixmap (struct window *w, Lisp_Object image_instance,
1224 struct display_box *db, struct display_glyph_area *dga,
1225 face_index findex, int cursor_start, int cursor_width,
1226 int cursor_height, int bg_pixmap)
1228 struct frame *f = XFRAME (w->frame);
1229 struct device *d = XDEVICE (f->device);
1230 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1232 Display *dpy = DEVICE_X_DISPLAY (d);
1233 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1235 /* Output the pixmap. */
1237 Lisp_Object tmp_pixel;
1238 XColor tmp_bcolor, tmp_fcolor;
1240 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1241 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1242 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1243 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1245 x_output_x_pixmap (f, p, db->xpos, db->ypos,
1246 dga->xoffset, dga->yoffset,
1247 dga->width, dga->height,
1248 tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
1251 /* Draw a cursor over top of the pixmap. */
1252 if (cursor_width && cursor_height && (cursor_start >= db->xpos)
1253 && !NILP (w->text_cursor_visible_p)
1254 && (cursor_start < db->xpos + dga->width))
1257 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1258 struct face_cachel *cursor_cachel =
1259 WINDOW_FACE_CACHEL (w,
1260 get_builtin_face_cache_index
1261 (w, Vtext_cursor_face));
1263 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1265 if (cursor_width > db->xpos + dga->width - cursor_start)
1266 cursor_width = db->xpos + dga->width - cursor_start;
1270 XFillRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1275 XDrawRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1281 /*****************************************************************************
1282 x_output_vertical_divider
1284 Draw a vertical divider down the right side of the given window.
1285 ****************************************************************************/
1287 x_output_vertical_divider (struct window *w, int clear)
1289 struct frame *f = XFRAME (w->frame);
1290 struct device *d = XDEVICE (f->device);
1292 Display *dpy = DEVICE_X_DISPLAY (d);
1293 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1294 Lisp_Object tmp_pixel;
1298 enum edge_style style;
1301 int x, y1, y2, width, shadow_thickness, spacing, line_width;
1302 face_index div_face = get_builtin_face_cache_index (w, Vvertical_divider_face);
1304 width = window_divider_width (w);
1305 shadow_thickness = XINT (w->vertical_divider_shadow_thickness);
1306 spacing = XINT (w->vertical_divider_spacing);
1307 line_width = XINT (w->vertical_divider_line_width);
1308 x = WINDOW_RIGHT (w) - width;
1309 y1 = WINDOW_TOP (w);
1310 y2 = WINDOW_BOTTOM (w);
1312 memset (&gcv, ~0, sizeof (XGCValues));
1314 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1315 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1317 /* First, get the GC's. */
1318 gcv.background = tmp_color.pixel;
1319 gcv.foreground = tmp_color.pixel;
1320 gcv.graphics_exposures = False;
1321 mask = GCForeground | GCBackground | GCGraphicsExposures;
1322 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1324 /* Clear the divider area first. This needs to be done when a
1325 window split occurs. */
1327 XClearArea (dpy, x_win, x, y1, width, y2 - y1, False);
1329 /* Draw the divider line. */
1330 XFillRectangle (dpy, x_win, background_gc,
1331 x + spacing + shadow_thickness, y1,
1332 line_width, y2 - y1);
1334 if (shadow_thickness < 0)
1336 shadow_thickness = -shadow_thickness;
1337 style = EDGE_BEVEL_IN;
1341 style = EDGE_BEVEL_OUT;
1344 /* Draw the shadows around the divider line */
1345 x_bevel_area (w, div_face, x + spacing, y1,
1346 width - 2 * spacing, y2 - y1,
1347 shadow_thickness, EDGE_ALL, style);
1350 /*****************************************************************************
1353 Output a blank by clearing the area it covers in the foreground color
1355 ****************************************************************************/
1357 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
1358 int start_pixpos, int cursor_start, int cursor_width)
1360 struct frame *f = XFRAME (w->frame);
1361 struct device *d = XDEVICE (f->device);
1363 Display *dpy = DEVICE_X_DISPLAY (d);
1364 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1366 struct face_cachel *cursor_cachel =
1367 WINDOW_FACE_CACHEL (w,
1368 get_builtin_face_cache_index
1369 (w, Vtext_cursor_face));
1370 Lisp_Object bg_pmap;
1371 Lisp_Object buffer = WINDOW_BUFFER (w);
1372 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1376 int y = DISPLAY_LINE_YPOS (dl);
1377 int width = rb->width;
1378 int height = DISPLAY_LINE_HEIGHT (dl);
1380 /* Unmap all subwindows in the area we are going to blank. */
1381 redisplay_unmap_subwindows_maybe (f, x, y, width, height);
1383 if (start_pixpos > x)
1385 if (start_pixpos >= (x + width))
1389 width -= (start_pixpos - x);
1394 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
1395 if (!IMAGE_INSTANCEP (bg_pmap)
1396 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
1400 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1403 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1404 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
1407 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1409 /* If this rune is marked as having the cursor, then it is actually
1410 representing a tab. */
1411 if (!NILP (w->text_cursor_visible_p)
1412 && (rb->cursor_type == CURSOR_ON
1414 && (cursor_start + cursor_width > x)
1415 && cursor_start < (x + width))))
1417 int cursor_height, cursor_y;
1418 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1419 Lisp_Font_Instance *fi;
1421 fi = XFONT_INSTANCE (FACE_CACHEL_FONT
1422 (WINDOW_FACE_CACHEL (w, rb->findex),
1425 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1427 cursor_y = dl->ypos - fi->ascent;
1428 cursor_height = fi->height;
1429 if (cursor_y + cursor_height > y + height)
1430 cursor_height = y + height - cursor_y;
1434 if (NILP (bar_cursor_value))
1436 XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1437 fi->width, cursor_height);
1441 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1443 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1444 make_int (bar_width));
1445 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
1446 cursor_y, cursor_start + bar_width - 1,
1447 cursor_y + cursor_height - 1);
1450 else if (NILP (bar_cursor_value))
1452 XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1453 fi->width - 1, cursor_height - 1);
1458 /*****************************************************************************
1461 Output a horizontal line in the foreground of its face.
1462 ****************************************************************************/
1464 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
1466 struct frame *f = XFRAME (w->frame);
1467 struct device *d = XDEVICE (f->device);
1469 Display *dpy = DEVICE_X_DISPLAY (d);
1470 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1474 int width = rb->width;
1475 int height = DISPLAY_LINE_HEIGHT (dl);
1476 int ypos1, ypos2, ypos3, ypos4;
1478 ypos1 = DISPLAY_LINE_YPOS (dl);
1479 ypos2 = ypos1 + rb->object.hline.yoffset;
1480 ypos3 = ypos2 + rb->object.hline.thickness;
1481 ypos4 = dl->ypos + dl->descent - dl->clip;
1483 /* First clear the area not covered by the line. */
1484 if (height - rb->object.hline.thickness > 0)
1486 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1489 if (ypos2 - ypos1 > 0)
1490 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1491 if (ypos4 - ypos3 > 0)
1492 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1495 /* Now draw the line. */
1496 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1504 if (ypos3 - ypos2 > 0)
1505 XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1508 /*****************************************************************************
1511 Draw a shadow around the given area using the given GC's. It is the
1512 callers responsibility to set the GC's appropriately.
1513 ****************************************************************************/
1515 x_output_shadows (struct frame *f, int x, int y, int width, int height,
1516 GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
1517 int shadow_thickness, int edges)
1519 struct device *d = XDEVICE (f->device);
1521 Display *dpy = DEVICE_X_DISPLAY (d);
1522 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1524 XSegment top_shadow[20], bottom_shadow[20];
1527 if (shadow_thickness > 10)
1528 shadow_thickness = 10;
1529 else if (shadow_thickness < 0)
1530 shadow_thickness = 0;
1531 if (shadow_thickness > (width / 2))
1532 shadow_thickness = width / 2;
1533 if (shadow_thickness > (height / 2))
1534 shadow_thickness = height / 2;
1536 for (elt = 0; elt < shadow_thickness; elt++)
1539 int seg2 = (edges & EDGE_TOP) ? elt + shadow_thickness : elt;
1540 int bot_seg2 = (edges & EDGE_BOTTOM) ? elt + shadow_thickness : elt;
1542 if (edges & EDGE_TOP)
1544 top_shadow[seg1].x1 = x + elt;
1545 top_shadow[seg1].x2 = x + width - elt - 1;
1546 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
1548 if (edges & EDGE_LEFT)
1550 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
1551 top_shadow[seg2].y1 = y + elt;
1552 top_shadow[seg2].y2 = y + height - elt - 1;
1554 if (edges & EDGE_BOTTOM)
1556 bottom_shadow[seg1].x1 = x + elt;
1557 bottom_shadow[seg1].x2 = x + width - elt - 1;
1558 bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
1560 if (edges & EDGE_RIGHT)
1562 bottom_shadow[bot_seg2].x1 = bottom_shadow[bot_seg2].x2 = x + width - elt - 1;
1563 bottom_shadow[bot_seg2].y1 = y + elt;
1564 bottom_shadow[bot_seg2].y2 = y + height - elt - 1;
1568 XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow,
1569 ((edges & EDGE_TOP) ? shadow_thickness : 0)
1570 + ((edges & EDGE_LEFT) ? shadow_thickness : 0));
1571 XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
1572 ((edges & EDGE_BOTTOM) ? shadow_thickness : 0)
1573 + ((edges & EDGE_RIGHT) ? shadow_thickness : 0));
1576 /*****************************************************************************
1577 x_generate_shadow_pixels
1579 Given three pixels (top shadow, bottom shadow, background) massage
1580 the top and bottom shadow colors to guarantee that they differ. The
1581 background pixels are not allowed to be modified.
1583 This function modifies its parameters.
1585 This code is modified from code blatantly stolen from lwlib/xlwmenu.c
1586 ****************************************************************************/
1587 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
1588 ? ((unsigned long) (x)) : ((unsigned long) (y)))
1591 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
1592 unsigned long *bottom_shadow,
1593 unsigned long background,
1594 unsigned long core_background)
1596 struct device *d = XDEVICE (f->device);
1597 Display *dpy = DEVICE_X_DISPLAY (d);
1598 Colormap cmap = DEVICE_X_COLORMAP (d);
1599 Visual *visual = DEVICE_X_VISUAL (d);
1602 int top_frobbed = 0, bottom_frobbed = 0;
1604 /* If the top shadow is the same color as the background, try to
1606 if (*top_shadow == background)
1608 topc.pixel = background;
1609 XQueryColor (dpy, cmap, &topc);
1610 /* don't overflow/wrap! */
1611 topc.red = MINL (65535, (unsigned long) topc.red * 6 / 5);
1612 topc.green = MINL (65535, (unsigned long) topc.green * 6 / 5);
1613 topc.blue = MINL (65535, (unsigned long) topc.blue * 6 / 5);
1614 if (allocate_nearest_color (dpy, cmap, visual, &topc))
1616 *top_shadow = topc.pixel;
1621 /* If the bottom shadow is the same color as the background, try to
1623 if (*bottom_shadow == background)
1625 botc.pixel = background;
1626 XQueryColor (dpy, cmap, &botc);
1627 botc.red = (unsigned short) ((unsigned long) botc.red * 3 / 5);
1628 botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5);
1629 botc.blue = (unsigned short) ((unsigned long) botc.blue * 3 / 5);
1630 if (allocate_nearest_color (dpy, cmap, visual, &botc))
1632 *bottom_shadow = botc.pixel;
1637 /* If we had to adjust both shadows, then we have to do some
1639 if (top_frobbed && bottom_frobbed)
1641 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
1642 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
1643 if (bot_avg > top_avg)
1645 Pixel tmp = *top_shadow;
1647 *top_shadow = *bottom_shadow;
1648 *bottom_shadow = tmp;
1650 else if (topc.pixel == botc.pixel)
1652 if (botc.pixel == background)
1653 *top_shadow = core_background;
1655 *bottom_shadow = background;
1660 /*****************************************************************************
1661 x_redraw_exposed_window
1663 Given a bounding box for an area that needs to be redrawn, determine
1664 what parts of what lines are contained within and re-output their
1666 ****************************************************************************/
1668 x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
1670 struct frame *f = XFRAME (w->frame);
1672 int start_x, start_y, end_x, end_y;
1673 int orig_windows_structure_changed;
1675 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1677 if (!NILP (w->vchild))
1679 x_redraw_exposed_windows (w->vchild, x, y, width, height);
1682 else if (!NILP (w->hchild))
1684 x_redraw_exposed_windows (w->hchild, x, y, width, height);
1688 /* If the window doesn't intersect the exposed region, we're done here. */
1689 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w)
1690 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w))
1696 start_x = max (WINDOW_LEFT (w), x);
1697 end_x = min (WINDOW_RIGHT (w), (x + width));
1698 start_y = max (WINDOW_TOP (w), y);
1699 end_y = min (WINDOW_BOTTOM (w), y + height);
1701 /* We do this to make sure that the 3D modelines get redrawn if
1702 they are in the exposed region. */
1703 orig_windows_structure_changed = f->windows_structure_changed;
1704 f->windows_structure_changed = 1;
1707 if (window_needs_vertical_divider (w))
1709 x_output_vertical_divider (w, 0);
1712 for (line = 0; line < Dynarr_length (cdla); line++)
1714 struct display_line *cdl = Dynarr_atp (cdla, line);
1715 int top_y = cdl->ypos - cdl->ascent;
1716 int bottom_y = cdl->ypos + cdl->descent;
1718 if (bottom_y >= start_y)
1729 output_display_line (w, 0, cdla, line, start_x, end_x);
1734 f->windows_structure_changed = orig_windows_structure_changed;
1736 /* If there have never been any face cache_elements created, then this
1737 expose event doesn't actually have anything to do. */
1738 if (Dynarr_largest (w->face_cachels))
1739 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
1742 /*****************************************************************************
1743 x_redraw_exposed_windows
1745 For each window beneath the given window in the window hierarchy,
1746 ensure that it is redrawn if necessary after an Expose event.
1747 ****************************************************************************/
1749 x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
1752 for (; !NILP (window); window = XWINDOW (window)->next)
1753 x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
1756 /*****************************************************************************
1757 x_redraw_exposed_area
1759 For each window on the given frame, ensure that any area in the
1760 Exposed area is redrawn.
1761 ****************************************************************************/
1763 x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
1765 /* If any window on the frame has had its face cache reset then the
1766 redisplay structures are effectively invalid. If we attempt to
1767 use them we'll blow up. We mark the frame as changed to ensure
1768 that redisplay will do a full update. This probably isn't
1769 necessary but it can't hurt. */
1771 #ifdef HAVE_TOOLBARS
1772 /* #### We would rather put these off as well but there is currently
1773 no combination of flags which will force an unchanged toolbar to
1775 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
1777 redraw_exposed_gutters (f, x, y, width, height);
1779 if (!f->window_face_cache_reset)
1781 x_redraw_exposed_windows (f->root_window, x, y, width, height);
1783 XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
1786 MARK_FRAME_CHANGED (f);
1789 /****************************************************************************
1792 Clear the area in the box defined by the given parameters using the
1794 ****************************************************************************/
1796 x_clear_region (Lisp_Object locale, struct device* d, struct frame* f, face_index findex,
1798 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1799 Lisp_Object background_pixmap)
1805 dpy = DEVICE_X_DISPLAY (d);
1806 x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1808 if (!UNBOUNDP (background_pixmap))
1810 gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
1814 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1816 XClearArea (dpy, x_win, x, y, width, height, False);
1819 /*****************************************************************************
1822 Draw a cursor at the end of a line. The end-of-line cursor is
1823 narrower than the normal cursor.
1824 ****************************************************************************/
1826 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos,
1829 struct frame *f = XFRAME (w->frame);
1830 struct device *d = XDEVICE (f->device);
1833 Display *dpy = DEVICE_X_DISPLAY (d);
1834 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1836 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
1837 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
1839 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1840 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1844 int y = DISPLAY_LINE_YPOS (dl);
1845 int width = EOL_CURSOR_WIDTH;
1846 int height = DISPLAY_LINE_HEIGHT (dl);
1847 int cursor_height, cursor_y;
1848 int defheight, defascent;
1850 XSETWINDOW (window, w);
1851 redisplay_clear_region (window, findex, x, y, width, height);
1853 if (NILP (w->text_cursor_visible_p))
1856 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1858 default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
1860 /* make sure the cursor is entirely contained between y and y+height */
1861 cursor_height = min (defheight, height);
1862 cursor_y = max (y, min (y + height - cursor_height,
1863 dl->ypos - defascent));
1868 XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2);
1869 #endif /* HAVE_XIM */
1871 if (NILP (bar_cursor_value))
1873 XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
1877 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1879 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1880 make_int (bar_width));
1881 XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
1882 x + bar_width - 1, cursor_y + cursor_height - 1);
1885 else if (NILP (bar_cursor_value))
1887 XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
1893 x_clear_frame_window (Lisp_Object window)
1895 struct window *w = XWINDOW (window);
1897 if (!NILP (w->vchild))
1899 x_clear_frame_windows (w->vchild);
1903 if (!NILP (w->hchild))
1905 x_clear_frame_windows (w->hchild);
1909 redisplay_clear_to_window_end (w, WINDOW_TEXT_TOP (w),
1910 WINDOW_TEXT_BOTTOM (w));
1914 x_clear_frame_windows (Lisp_Object window)
1916 for (; !NILP (window); window = XWINDOW (window)->next)
1917 x_clear_frame_window (window);
1921 x_clear_frame (struct frame *f)
1923 struct device *d = XDEVICE (f->device);
1924 Display *dpy = DEVICE_X_DISPLAY (d);
1925 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1926 int x, y, width, height;
1929 x = FRAME_LEFT_BORDER_START (f);
1930 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
1931 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
1932 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) -
1933 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f));
1934 /* #### This adjustment by 1 should be being done in the macros.
1935 There is some small differences between when the menubar is on
1936 and off that we still need to deal with. */
1937 y = FRAME_TOP_BORDER_START (f) - 1;
1938 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
1939 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
1940 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) -
1941 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1;
1943 XClearArea (dpy, x_win, x, y, width, height, False);
1945 XSETFRAME (frame, f);
1947 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
1948 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
1949 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
1951 x_clear_frame_windows (f->root_window);
1954 XFlush (DEVICE_X_DISPLAY (d));
1957 /* briefly swap the foreground and background colors.
1961 x_flash (struct device *d)
1967 XColor tmp_fcolor, tmp_bcolor;
1968 Lisp_Object tmp_pixel, frame;
1969 struct frame *f = device_selected_frame (d);
1970 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f));
1971 Widget shell = FRAME_X_SHELL_WIDGET (f);
1974 XSETFRAME (frame, f);
1976 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
1977 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1978 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
1979 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1981 dpy = XtDisplay (shell);
1982 win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1983 memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
1984 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
1985 gcv.function = GXxor;
1986 gcv.graphics_exposures = False;
1987 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
1988 (GCForeground | GCFunction | GCGraphicsExposures));
1989 default_face_height_and_width (frame, &flash_height, 0);
1991 /* If window is tall, flash top and bottom line. */
1992 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
1994 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
1995 w->pixel_width, flash_height);
1996 XFillRectangle (dpy, win, gc, w->pixel_left,
1997 w->pixel_top + w->pixel_height - flash_height,
1998 w->pixel_width, flash_height);
2001 /* If it is short, flash it all. */
2002 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2003 w->pixel_width, w->pixel_height);
2011 tv.tv_sec = usecs / 1000000L;
2012 tv.tv_usec = usecs % 1000000L;
2013 /* I'm sure someone is going to complain about this... */
2014 select (0, 0, 0, 0, &tv);
2019 #else /* !HAVE_POLL */
2021 #endif /* HAVE_POLL */
2022 #endif /* HAVE_SELECT */
2024 /* If window is tall, flash top and bottom line. */
2025 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
2027 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2028 w->pixel_width, flash_height);
2029 XFillRectangle (dpy, win, gc, w->pixel_left,
2030 w->pixel_top + w->pixel_height - flash_height,
2031 w->pixel_width, flash_height);
2034 /* If it is short, flash it all. */
2035 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2036 w->pixel_width, w->pixel_height);
2043 /* Make audible bell. */
2046 x_ring_bell (struct device *d, int volume, int pitch, int duration)
2048 Display *display = DEVICE_X_DISPLAY (d);
2050 if (volume < 0) volume = 0;
2051 else if (volume > 100) volume = 100;
2052 if (pitch < 0 && duration < 0)
2054 XBell (display, (volume * 2) - 100);
2059 XKeyboardState state;
2060 XKeyboardControl ctl;
2062 /* #### grab server? */
2063 XGetKeyboardControl (display, &state);
2065 ctl.bell_pitch = (pitch >= 0 ? pitch : state.bell_pitch);
2066 ctl.bell_duration = (duration >= 0 ? duration : state.bell_duration);
2067 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2069 XBell (display, (volume * 2) - 100);
2071 ctl.bell_pitch = state.bell_pitch;
2072 ctl.bell_duration = state.bell_duration;
2073 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2075 /* #### ungrab server? */
2081 /************************************************************************/
2082 /* initialization */
2083 /************************************************************************/
2086 console_type_create_redisplay_x (void)
2088 /* redisplay methods */
2089 CONSOLE_HAS_METHOD (x, text_width);
2090 CONSOLE_HAS_METHOD (x, output_display_block);
2091 CONSOLE_HAS_METHOD (x, divider_height);
2092 CONSOLE_HAS_METHOD (x, eol_cursor_width);
2093 CONSOLE_HAS_METHOD (x, output_vertical_divider);
2094 CONSOLE_HAS_METHOD (x, clear_region);
2095 CONSOLE_HAS_METHOD (x, clear_frame);
2096 CONSOLE_HAS_METHOD (x, output_begin);
2097 CONSOLE_HAS_METHOD (x, output_end);
2098 CONSOLE_HAS_METHOD (x, flash);
2099 CONSOLE_HAS_METHOD (x, ring_bell);
2100 CONSOLE_HAS_METHOD (x, bevel_area);
2101 CONSOLE_HAS_METHOD (x, output_string);
2102 CONSOLE_HAS_METHOD (x, output_pixmap);