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"
43 #include "redisplay.h"
46 #include <X11/bitmaps/gray>
48 #include "sysproc.h" /* for select() */
52 #include "file-coding.h" /* for CCL conversion */
55 /* Number of pixels below each line. */
56 /* #### implement me */
57 int x_interline_space;
59 #define EOL_CURSOR_WIDTH 5
61 static void x_output_pixmap (struct window *w, struct display_line *dl,
62 Lisp_Object image_instance, int xpos,
64 int start_pixpos, int width, face_index findex,
65 int cursor_start, int cursor_width,
67 static void x_output_vertical_divider (struct window *w, int clear);
68 static void x_output_blank (struct window *w, struct display_line *dl,
69 struct rune *rb, int start_pixpos,
70 int cursor_start, int cursor_width);
71 static void x_output_hline (struct window *w, struct display_line *dl,
73 static void x_redraw_exposed_window (struct window *w, int x, int y,
74 int width, int height);
75 static void x_redraw_exposed_windows (Lisp_Object window, int x, int y,
76 int width, int height);
77 static void x_clear_region (Lisp_Object window, face_index findex, int x,
78 int y, int width, int height);
79 static void x_output_eol_cursor (struct window *w, struct display_line *dl,
80 int xpos, face_index findex);
81 static void x_clear_frame (struct frame *f);
82 static void x_clear_frame_windows (Lisp_Object window);
83 static void x_bevel_modeline (struct window *w, struct display_line *dl);
86 /* Note: We do not use the Xmb*() functions and XFontSets.
87 Those functions are generally losing for a number of reasons:
89 1) They only support one locale (e.g. you could display
90 Japanese and ASCII text, but not mixed Japanese/Chinese
91 text). You could maybe call setlocale() frequently
92 to try to deal with this, but that would generally
93 fail because an XFontSet is tied to one locale and
94 won't have the other character sets in it.
95 2) Not all (or even very many) OS's support the useful
96 locales. For example, as far as I know SunOS and
97 Solaris only support the Japanese locale if you get the
98 special Asian-language version of the OS. Yuck yuck
99 yuck. Linux doesn't support the Japanese locale at
101 3) The locale support in X only exists in R5, not in R4.
102 (Not sure how big of a problem this is: how many
103 people are using R4?)
104 4) Who knows if the multi-byte text format (which is locale-
105 specific) is even the same for the same locale on
106 different OS's? It's not even documented anywhere that
107 I can find what the multi-byte text format for the
108 Japanese locale under SunOS and Solaris is, but I assume
120 /* Separate out the text in DYN into a series of textual runs of a
121 particular charset. Also convert the characters as necessary into
122 the format needed by XDrawImageString(), XDrawImageString16(), et
123 al. (This means converting to one or two byte format, possibly
124 tweaking the high bits, and possibly running a CCL program.) You
125 must pre-allocate the space used and pass it in. (This is done so
126 you can alloca() the space.) You need to allocate (2 * len) bytes
127 of TEXT_STORAGE and (len * sizeof (struct textual_run)) bytes of
128 RUN_STORAGE, where LEN is the length of the dynarr.
130 Returns the number of runs actually used. */
133 separate_textual_runs (unsigned char *text_storage,
134 struct textual_run *run_storage,
135 CONST Emchar *str, Charcount len)
137 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a
138 possible valid charset when
139 MULE is not defined */
143 struct ccl_program char_converter;
144 int need_ccl_conversion = 0;
147 for (i = 0; i < len; i++)
155 BREAKUP_CHAR (ch, charset, byte1, byte2);
156 dimension = XCHARSET_DIMENSION (charset);
157 graphic = XCHARSET_GRAPHIC (charset);
159 if (!EQ (charset, prev_charset))
161 run_storage[runs_so_far].ptr = text_storage;
162 run_storage[runs_so_far].charset = charset;
163 run_storage[runs_so_far].dimension = dimension;
167 run_storage[runs_so_far - 1].len =
168 text_storage - run_storage[runs_so_far - 1].ptr;
169 if (run_storage[runs_so_far - 1].dimension == 2)
170 run_storage[runs_so_far - 1].len >>= 1;
173 prev_charset = charset;
176 Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset);
177 need_ccl_conversion = !NILP (ccl_prog);
178 if (need_ccl_conversion)
179 setup_ccl_program (&char_converter, ccl_prog);
189 else if (graphic == 1)
195 if (need_ccl_conversion)
197 char_converter.reg[0] = XCHARSET_ID (charset);
198 char_converter.reg[1] = byte1;
199 char_converter.reg[2] = byte2;
200 ccl_driver (&char_converter, 0, 0, 0, 0);
201 byte1 = char_converter.reg[1];
202 byte2 = char_converter.reg[2];
205 *text_storage++ = (unsigned char) byte1;
207 *text_storage++ = (unsigned char) byte2;
212 run_storage[runs_so_far - 1].len =
213 text_storage - run_storage[runs_so_far - 1].ptr;
214 if (run_storage[runs_so_far - 1].dimension == 2)
215 run_storage[runs_so_far - 1].len >>= 1;
221 /****************************************************************************/
223 /* X output routines */
225 /****************************************************************************/
228 x_text_width_single_run (struct face_cachel *cachel, struct textual_run *run)
230 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
231 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
232 if (!fi->proportional_p)
233 return fi->width * run->len;
236 if (run->dimension == 2)
237 return XTextWidth16 (FONT_INSTANCE_X_FONT (fi),
238 (XChar2b *) run->ptr, run->len);
240 return XTextWidth (FONT_INSTANCE_X_FONT (fi),
241 (char *) run->ptr, run->len);
248 Given a string and a face, return the string's length in pixels when
249 displayed in the font associated with the face.
253 x_text_width (struct frame *f, struct face_cachel *cachel, CONST Emchar *str,
256 int width_so_far = 0;
257 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
258 struct textual_run *runs = alloca_array (struct textual_run, len);
262 nruns = separate_textual_runs (text_storage, runs, str, len);
264 for (i = 0; i < nruns; i++)
265 width_so_far += x_text_width_single_run (cachel, runs + i);
270 /*****************************************************************************
273 Return the height of the horizontal divider. This is a function because
274 divider_height is a device method.
276 #### If we add etched horizontal divider lines this will have to get
278 ****************************************************************************/
280 x_divider_height (void)
285 /*****************************************************************************
288 Return the width of the end-of-line cursor. This is a function
289 because eol_cursor_width is a device method.
290 ****************************************************************************/
292 x_eol_cursor_width (void)
294 return EOL_CURSOR_WIDTH;
297 /*****************************************************************************
300 Perform any necessary initialization prior to an update.
301 ****************************************************************************/
303 x_output_begin (struct device *d)
307 /*****************************************************************************
310 Perform any necessary flushing of queues when an update has completed.
311 ****************************************************************************/
313 x_output_end (struct device *d)
315 XFlush (DEVICE_X_DISPLAY (d));
318 /*****************************************************************************
319 x_output_display_block
321 Given a display line, a block number for that start line, output all
322 runes between start and end in the specified display block.
323 ****************************************************************************/
325 x_output_display_block (struct window *w, struct display_line *dl, int block,
326 int start, int end, int start_pixpos, int cursor_start,
327 int cursor_width, int cursor_height)
329 struct frame *f = XFRAME (w->frame);
330 Emchar_dynarr *buf = Dynarr_new (Emchar);
333 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
334 rune_dynarr *rba = db->runes;
340 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
341 MULE is not defined */
343 XSETWINDOW (window, w);
344 rb = Dynarr_atp (rba, start);
348 /* Nothing to do so don't do anything. */
356 if (rb->type == RUNE_CHAR)
357 charset = CHAR_CHARSET (rb->object.chr.ch);
361 end = Dynarr_length (rba);
366 rb = Dynarr_atp (rba, elt);
368 if (rb->findex == findex && rb->type == RUNE_CHAR
369 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
370 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
372 Dynarr_add (buf, rb->object.chr.ch);
378 if (Dynarr_length (buf))
380 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
381 findex, 0, cursor_start, cursor_width,
389 if (rb->type == RUNE_CHAR)
393 charset = CHAR_CHARSET (rb->object.chr.ch);
395 if (rb->cursor_type == CURSOR_ON)
397 if (rb->object.chr.ch == '\n')
399 x_output_eol_cursor (w, dl, xpos, findex);
403 Dynarr_add (buf, rb->object.chr.ch);
404 x_output_string (w, dl, buf, xpos, 0, start_pixpos,
405 rb->width, findex, 1,
406 cursor_start, cursor_width,
414 else if (rb->object.chr.ch == '\n')
416 /* Clear in case a cursor was formerly here. */
417 int height = dl->ascent + dl->descent - dl->clip;
419 x_clear_region (window, findex, xpos, dl->ypos - dl->ascent,
424 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
426 if (rb->type == RUNE_BLANK)
427 x_output_blank (w, dl, rb, start_pixpos, cursor_start,
431 /* #### Our flagging of when we need to redraw the
432 modeline shadows sucks. Since RUNE_HLINE is only used
433 by the modeline at the moment it is a good bet
434 that if it gets redrawn then we should also
435 redraw the shadows. This won't be true forever.
436 We borrow the shadow_thickness_changed flag for
438 w->shadow_thickness_changed = 1;
439 x_output_hline (w, dl, rb);
445 rb = Dynarr_atp (rba, elt);
451 else if (rb->type == RUNE_DGLYPH)
453 Lisp_Object instance;
455 XSETWINDOW (window, w);
456 instance = glyph_image_instance (rb->object.dglyph.glyph,
457 window, ERROR_ME_NOT, 1);
460 if (IMAGE_INSTANCEP (instance))
461 switch (XIMAGE_INSTANCE_TYPE (instance))
465 /* #### This is way losing. See the comment in
468 XIMAGE_INSTANCE_TEXT_STRING (instance);
469 convert_bufbyte_string_into_emchar_dynarr
470 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
472 x_output_string (w, dl, buf, xpos,
473 rb->object.dglyph.xoffset,
474 start_pixpos, -1, findex,
475 (rb->cursor_type == CURSOR_ON),
476 cursor_start, cursor_width,
482 case IMAGE_MONO_PIXMAP:
483 case IMAGE_COLOR_PIXMAP:
484 x_output_pixmap (w, dl, instance, xpos,
485 rb->object.dglyph.xoffset, start_pixpos,
486 rb->width, findex, cursor_start,
487 cursor_width, cursor_height);
493 case IMAGE_SUBWINDOW:
494 /* #### implement me */
498 /* nothing is as nothing does */
513 if (Dynarr_length (buf))
514 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
515 0, cursor_start, cursor_width, cursor_height);
517 /* #### This is really conditionalized well for optimized
520 && !EQ (Qzero, w->modeline_shadow_thickness)
522 || f->windows_structure_changed
523 || w->shadow_thickness_changed))
524 x_bevel_modeline (w, dl);
529 /*****************************************************************************
532 Draw a 3d border around the modeline on window W.
533 ****************************************************************************/
535 x_bevel_modeline (struct window *w, struct display_line *dl)
537 struct frame *f = XFRAME (w->frame);
538 struct device *d = XDEVICE (f->device);
539 Display *dpy = DEVICE_X_DISPLAY (d);
540 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
541 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
542 GC top_shadow_gc, bottom_shadow_gc, background_gc;
543 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
545 Lisp_Object tmp_pixel;
546 int x, y, width, height;
551 int shadow_thickness;
553 memset (&gcv, ~0, sizeof (XGCValues));
555 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, MODELINE_INDEX);
556 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
558 /* First, get the GC's. */
559 top_shadow_pixel = tmp_color.pixel;
560 bottom_shadow_pixel = tmp_color.pixel;
561 background_pixel = tmp_color.pixel;
563 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
564 background_pixel, ef->core.background_pixel);
566 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, MODELINE_INDEX);
567 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
568 gcv.background = tmp_color.pixel;
569 gcv.graphics_exposures = False;
570 mask = GCForeground | GCBackground | GCGraphicsExposures;
572 if (top_shadow_pixel == background_pixel ||
573 bottom_shadow_pixel == background_pixel)
578 if (DEVICE_X_GRAY_PIXMAP (d) == None)
580 DEVICE_X_GRAY_PIXMAP (d) =
581 XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
582 gray_width, gray_height, 1, 0, 1);
585 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, MODELINE_INDEX);
586 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
587 gcv.foreground = tmp_color.pixel;
588 gcv.fill_style = FillOpaqueStippled;
589 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
590 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
591 (mask | GCStipple | GCFillStyle));
593 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, MODELINE_INDEX);
594 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
595 bottom_shadow_pixel = tmp_color.pixel;
597 flip_gcs = (bottom_shadow_pixel ==
598 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
602 gcv.foreground = top_shadow_pixel;
603 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
606 gcv.foreground = bottom_shadow_pixel;
607 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
609 if (use_pixmap && flip_gcs)
611 GC tmp_gc = bottom_shadow_gc;
612 bottom_shadow_gc = top_shadow_gc;
613 top_shadow_gc = tmp_gc;
616 gcv.foreground = background_pixel;
617 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
619 if (XINT (w->modeline_shadow_thickness) < 0)
623 temp = top_shadow_gc;
624 top_shadow_gc = bottom_shadow_gc;
625 bottom_shadow_gc = temp;
628 shadow_thickness = MODELINE_SHADOW_THICKNESS (w);
630 x = WINDOW_MODELINE_LEFT (w);
631 width = WINDOW_MODELINE_RIGHT (w) - x;
632 y = dl->ypos - dl->ascent - shadow_thickness;
633 height = dl->ascent + dl->descent + 2 * shadow_thickness;
635 x_output_shadows (f, x, y, width, height, top_shadow_gc, bottom_shadow_gc,
636 background_gc, shadow_thickness);
639 /*****************************************************************************
642 Given a number of parameters return a GC with those properties.
643 ****************************************************************************/
645 x_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
646 Lisp_Object bg_pmap, Lisp_Object lwidth)
651 memset (&gcv, ~0, sizeof (XGCValues));
652 gcv.graphics_exposures = False;
653 /* Make absolutely sure that we don't pick up a clipping region in
654 the GC returned by this function. */
655 gcv.clip_mask = None;
656 gcv.clip_x_origin = 0;
657 gcv.clip_y_origin = 0;
658 gcv.fill_style = FillSolid;
659 mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
664 gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
669 if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg))
671 /* #### I fixed once case where this was getting it. It was a
672 bad macro expansion (compiler bug). */
673 fprintf (stderr, "Help! x_get_gc got a bogus fg value! fg = ");
680 if (COLOR_INSTANCEP (fg))
681 gcv.foreground = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (fg)).pixel;
683 gcv.foreground = XINT (fg);
684 mask |= GCForeground;
689 if (COLOR_INSTANCEP (bg))
690 gcv.background = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (bg)).pixel;
692 gcv.background = XINT (bg);
693 mask |= GCBackground;
696 /* This special case comes from a request to draw text with a face which has
697 the dim property. We'll use a stippled foreground GC. */
698 if (EQ (bg_pmap, Qdim))
700 assert (DEVICE_X_GRAY_PIXMAP (d) != None);
702 gcv.fill_style = FillStippled;
703 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
704 mask |= (GCFillStyle | GCStipple);
706 else if (IMAGE_INSTANCEP (bg_pmap)
707 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
709 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
711 gcv.fill_style = FillOpaqueStippled;
712 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
713 mask |= (GCStipple | GCFillStyle);
717 gcv.fill_style = FillTiled;
718 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
719 mask |= (GCTile | GCFillStyle);
725 gcv.line_width = XINT (lwidth);
729 return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
732 /*****************************************************************************
735 Given a string and a starting position, output that string in the
736 given face. If cursor is true, draw a cursor around the string.
737 Correctly handles multiple charsets in the string.
739 The meaning of the parameters is something like this:
741 W Window that the text is to be displayed in.
742 DL Display line that this text is on. The values in the
743 structure are used to determine the vertical position and
744 clipping range of the text.
745 BUF Dynamic array of Emchars specifying what is actually to be
747 XPOS X position in pixels where the text should start being drawn.
748 XOFFSET Number of pixels to be chopped off the left side of the
749 text. The effect is as if the text were shifted to the
750 left this many pixels and clipped at XPOS.
751 CLIP_START Clip everything left of this X position.
752 WIDTH Clip everything right of XPOS + WIDTH.
753 FINDEX Index for the face cache element describing how to display
755 CURSOR #### I don't understand this. There's something
756 strange and overcomplexified with this variable.
757 Chuck, explain please?
758 CURSOR_START Starting X position of cursor.
759 CURSOR_WIDTH Width of cursor in pixels.
760 CURSOR_HEIGHT Height of cursor in pixels.
762 Starting Y position of cursor is the top of the text line.
763 The cursor is drawn sometimes whether or not CURSOR is set. ???
764 ****************************************************************************/
766 x_output_string (struct window *w, struct display_line *dl,
767 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
768 int width, face_index findex, int cursor,
769 int cursor_start, int cursor_width, int cursor_height)
771 /* General variables */
772 struct frame *f = XFRAME (w->frame);
773 struct device *d = XDEVICE (f->device);
776 Display *dpy = DEVICE_X_DISPLAY (d);
777 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
781 /* Cursor-related variables */
782 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
784 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
786 struct face_cachel *cursor_cachel = 0;
788 /* Text-related variables */
792 int len = Dynarr_length (buf);
793 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
794 struct textual_run *runs = alloca_array (struct textual_run, len);
797 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
799 XSETDEVICE (device, d);
800 XSETWINDOW (window, w);
803 width = x_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
804 height = dl->ascent + dl->descent - dl->clip;
806 /* Regularize the variables passed in. */
808 if (clip_start < xpos)
810 clip_end = xpos + width;
811 if (clip_start >= clip_end)
812 /* It's all clipped out. */
817 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
818 Dynarr_length (buf));
820 cursor_clip = (cursor_start >= clip_start &&
821 cursor_start < clip_end);
823 /* This cursor code is really a mess. */
824 if (!NILP (w->text_cursor_visible_p)
828 && (cursor_start + cursor_width >= clip_start)
829 && !NILP (bar_cursor_value))))
831 /* These have to be in separate statements in order to avoid a
833 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face);
834 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks);
836 /* We have to reset this since any call to WINDOW_FACE_CACHEL
837 may cause the cache to resize and any pointers to it to
839 cachel = WINDOW_FACE_CACHEL (w, findex);
843 if (cursor && focus && (cursor_start == clip_start) && cursor_height)
844 XIM_SetSpotLocation (f, xpos - 2, dl->ypos + dl->descent - 2);
845 #endif /* HAVE_XIM */
847 bg_pmap = cachel->background_pixmap;
848 if (!IMAGE_INSTANCEP (bg_pmap)
849 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
852 if ((cursor && focus && NILP (bar_cursor_value)
853 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap))
856 bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
860 XFillRectangle (dpy, x_win, bgc, clip_start,
861 dl->ypos - dl->ascent, clip_end - clip_start,
864 for (i = 0; i < nruns; i++)
866 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
867 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
871 if (EQ (font, Vthe_null_font_instance))
874 this_width = x_text_width_single_run (cachel, runs + i);
875 need_clipping = (dl->clip || clip_start > xpos ||
876 clip_end < xpos + this_width);
878 /* XDrawImageString only clears the area equal to the height of
879 the given font. It is possible that a font is being displayed
880 on a line taller than it is, so this would cause us to fail to
882 if ((int) fi->height < (int) (height + dl->clip))
884 int clear_start = max (xpos, clip_start);
885 int clear_end = min (xpos + this_width, clip_end);
889 int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
891 ypos1_string = dl->ypos - fi->ascent;
892 ypos2_string = dl->ypos + fi->descent;
893 ypos1_line = dl->ypos - dl->ascent;
894 ypos2_line = dl->ypos + dl->descent - dl->clip;
896 /* Make sure we don't clear below the real bottom of the
898 if (ypos1_string > ypos2_line)
899 ypos1_string = ypos2_line;
900 if (ypos2_string > ypos2_line)
901 ypos2_string = ypos2_line;
903 if (ypos1_line < ypos1_string)
905 x_clear_region (window, findex, clear_start, ypos1_line,
906 clear_end - clear_start,
907 ypos1_string - ypos1_line);
910 if (ypos2_line > ypos2_string)
912 x_clear_region (window, findex, clear_start, ypos2_string,
913 clear_end - clear_start,
914 ypos2_line - ypos2_string);
919 x_clear_region (window, findex, clear_start,
920 dl->ypos - dl->ascent, clear_end - clear_start,
925 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value))
926 gc = x_get_gc (d, font, cursor_cachel->foreground,
927 cursor_cachel->background, Qnil, Qnil);
928 else if (cachel->dim)
930 /* Ensure the gray bitmap exists */
931 if (DEVICE_X_GRAY_PIXMAP (d) == None)
932 DEVICE_X_GRAY_PIXMAP (d) =
933 XCreateBitmapFromData (dpy, x_win, (char *)gray_bits,
934 gray_width, gray_height);
936 /* Request a GC with the gray stipple pixmap to draw dimmed text */
937 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
941 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
946 XRectangle clip_box[1];
950 clip_box[0].width = clip_end - clip_start;
951 clip_box[0].height = height;
953 XSetClipRectangles (dpy, gc, clip_start, dl->ypos - dl->ascent,
954 clip_box, 1, Unsorted);
957 if (runs[i].dimension == 1)
958 (bgc ? XDrawString : XDrawImageString) (dpy, x_win, gc, xpos,
959 dl->ypos, (char *) runs[i].ptr,
962 (bgc ? XDrawString16 : XDrawImageString16) (dpy, x_win, gc, xpos,
964 (XChar2b *) runs[i].ptr,
967 /* We draw underlines in the same color as the text. */
968 if (cachel->underline)
970 unsigned long upos, uthick;
973 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
974 if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos))
975 upos = dl->descent / 2;
976 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
979 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
981 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
982 uthick = dl->descent - dl->clip - upos;
986 XDrawLine (dpy, x_win, gc, xpos, dl->ypos + upos,
987 xpos + this_width, dl->ypos + upos);
991 XFillRectangle (dpy, x_win, gc, xpos,
992 dl->ypos + upos, this_width, uthick);
997 if (cachel->strikethru) {
998 unsigned long ascent,descent,upos, uthick;
1001 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
1003 if (!XGetFontProperty (xfont, XA_STRIKEOUT_ASCENT, &ascent))
1004 ascent = xfont->ascent;
1005 if (!XGetFontProperty (xfont, XA_STRIKEOUT_DESCENT, &descent))
1006 descent = xfont->descent;
1007 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
1010 upos = ascent - ((ascent + descent) / 2) + 1;
1012 /* Generally, upos will be positive (above the baseline),so subtract */
1013 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip)
1015 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip)
1016 uthick = dl->descent - dl->clip + upos;
1020 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos,
1021 xpos + this_width, dl->ypos - upos);
1023 else if (uthick > 1)
1025 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos,
1026 this_width, uthick);
1031 /* Restore the GC */
1034 XSetClipMask (dpy, gc, None);
1035 XSetClipOrigin (dpy, gc, 0, 0);
1038 /* If we are actually superimposing the cursor then redraw with just
1039 the appropriate section highlighted. */
1040 if (cursor_clip && !cursor && focus && cursor_cachel)
1043 XRectangle clip_box[1];
1045 cgc = x_get_gc (d, font, cursor_cachel->foreground,
1046 cursor_cachel->background, Qnil, Qnil);
1050 clip_box[0].width = cursor_width;
1051 clip_box[0].height = height;
1053 XSetClipRectangles (dpy, cgc, cursor_start, dl->ypos - dl->ascent,
1054 clip_box, 1, Unsorted);
1056 if (runs[i].dimension == 1)
1057 XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
1058 (char *) runs[i].ptr, runs[i].len);
1060 XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
1061 (XChar2b *) runs[i].ptr, runs[i].len);
1063 XSetClipMask (dpy, cgc, None);
1064 XSetClipOrigin (dpy, cgc, 0, 0);
1070 /* Draw the non-focus box or bar-cursor as needed. */
1071 /* Can't this logic be simplified? */
1073 && ((cursor && !focus && NILP (bar_cursor_value))
1075 && (cursor_start + cursor_width >= clip_start)
1076 && !NILP (bar_cursor_value))))
1078 int tmp_height, tmp_y;
1079 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1080 int need_clipping = (cursor_start < clip_start
1081 || clip_end < cursor_start + cursor_width);
1083 /* #### This value is correct (as far as I know) because
1084 all of the times we need to draw this cursor, we will
1085 be called with exactly one character, so we know we
1086 can always use runs[0].
1088 This is bogus as all hell, however. The cursor handling in
1089 this function is way bogus and desperately needs to be
1090 cleaned up. (In particular, the drawing of the cursor should
1091 really really be separated out of this function. This may be
1092 a bit tricky now because this function itself does way too
1093 much stuff, a lot of which needs to be moved into
1094 redisplay.c) This is the only way to be able to easily add
1095 new cursor types or (e.g.) make the bar cursor be able to
1096 span two characters instead of overlaying just one. */
1097 int bogusly_obtained_ascent_value =
1098 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent;
1100 if (!NILP (bar_cursor_value))
1102 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1103 make_int (bar_width));
1107 gc = x_get_gc (d, Qnil, cursor_cachel->background,
1111 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1112 tmp_height = cursor_height;
1113 if (tmp_y + tmp_height > (int) (dl->ypos - dl->ascent + height))
1115 tmp_y = dl->ypos - dl->ascent + height - tmp_height;
1116 if (tmp_y < (int) (dl->ypos - dl->ascent))
1117 tmp_y = dl->ypos - dl->ascent;
1118 tmp_height = dl->ypos - dl->ascent + height - tmp_y;
1123 XRectangle clip_box[1];
1126 clip_box[0].width = clip_end - clip_start;
1127 clip_box[0].height = tmp_height;
1128 XSetClipRectangles (dpy, gc, clip_start, tmp_y,
1129 clip_box, 1, Unsorted);
1132 if (!focus && NILP (bar_cursor_value))
1134 XDrawRectangle (dpy, x_win, gc, cursor_start, tmp_y,
1135 cursor_width - 1, tmp_height - 1);
1137 else if (focus && !NILP (bar_cursor_value))
1139 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1, tmp_y,
1140 cursor_start + bar_width - 1, tmp_y + tmp_height - 1);
1143 /* Restore the GC */
1146 XSetClipMask (dpy, gc, None);
1147 XSetClipOrigin (dpy, gc, 0, 0);
1153 x_output_x_pixmap (struct frame *f, struct Lisp_Image_Instance *p, int x,
1154 int y, int clip_x, int clip_y, int clip_width,
1155 int clip_height, int width, int height, int pixmap_offset,
1156 unsigned long fg, unsigned long bg, GC override_gc)
1158 struct device *d = XDEVICE (f->device);
1159 Display *dpy = DEVICE_X_DISPLAY (d);
1160 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1164 unsigned long pixmap_mask;
1165 int need_clipping = (clip_x || clip_y);
1169 memset (&gcv, ~0, sizeof (XGCValues));
1170 gcv.graphics_exposures = False;
1171 gcv.foreground = fg;
1172 gcv.background = bg;
1173 pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
1175 if (IMAGE_INSTANCE_X_MASK (p))
1177 gcv.function = GXcopy;
1178 gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
1179 gcv.clip_x_origin = x;
1180 gcv.clip_y_origin = y - pixmap_offset;
1181 pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
1183 /* Can't set a clip rectangle below because we already have a mask.
1184 We could conceivably create a new clipmask by zeroing out
1185 everything outside the clip region. Is it worth it?
1186 Is it possible to get an equivalent effect by changing the
1187 args to XCopyArea below rather than messing with a clip box?
1188 - dkindred@cs.cmu.edu */
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. */
1205 XRectangle clip_box[1];
1207 clip_box[0].x = clip_x;
1208 clip_box[0].y = clip_y;
1209 clip_box[0].width = clip_width;
1210 clip_box[0].height = clip_height;
1212 XSetClipRectangles (dpy, gc, x, y, clip_box, 1, Unsorted);
1215 /* depth of 0 means it's a bitmap, not a pixmap, and we should use
1216 XCopyPlane (1 = current foreground color, 0 = background) instead
1217 of XCopyArea, which means that the bits in the pixmap are actual
1218 pixel values, instead of symbolic of fg/bg. */
1219 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
1221 XCopyArea (dpy, IMAGE_INSTANCE_X_PIXMAP (p), x_win, gc, 0,
1222 pixmap_offset, width,
1227 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP (p), x_win, gc, 0,
1240 XSetClipMask (dpy, gc, None);
1241 XSetClipOrigin (dpy, gc, 0, 0);
1246 x_output_pixmap (struct window *w, struct display_line *dl,
1247 Lisp_Object image_instance, int xpos, int xoffset,
1248 int start_pixpos, int width, face_index findex,
1249 int cursor_start, int cursor_width, int cursor_height)
1251 struct frame *f = XFRAME (w->frame);
1252 struct device *d = XDEVICE (f->device);
1253 struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1256 Display *dpy = DEVICE_X_DISPLAY (d);
1257 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1258 int lheight = dl->ascent + dl->descent - dl->clip;
1259 int pheight = ((int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > lheight ? lheight :
1260 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
1261 int pwidth = min (width + xoffset, (int) IMAGE_INSTANCE_PIXMAP_WIDTH (p));
1262 int clip_x, clip_y, clip_width, clip_height;
1264 /* The pixmap_offset is used to center the pixmap on lines which are
1265 shorter than it is. This results in odd effects when scrolling
1266 pixmaps off of the bottom. Let's try not using it. */
1268 int pixmap_offset = (int) (IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - lheight) / 2;
1270 int pixmap_offset = 0;
1273 XSETWINDOW (window, w);
1275 if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
1277 if (start_pixpos > xpos && start_pixpos > xpos + width)
1282 if (start_pixpos > xpos)
1284 clip_x += (start_pixpos - xpos);
1285 clip_width -= (start_pixpos - xpos);
1294 /* Place markers for possible future functionality (clipping the top
1295 half instead of the bottom half; think pixel scrolling). */
1297 clip_height = pheight;
1299 /* Clear the area the pixmap is going into. The pixmap itself will
1300 always take care of the full width. We don't want to clear where
1301 it is going to go in order to avoid flicker. So, all we have to
1302 take care of is any area above or below the pixmap. */
1303 /* #### We take a shortcut for now. We know that since we have
1304 pixmap_offset hardwired to 0 that the pixmap is against the top
1305 edge so all we have to worry about is below it. */
1306 /* #### Unless the pixmap has a mask in which case we have to clear
1307 the whole damn thing since we can't yet clear just the area not
1308 included in the mask. */
1309 if (((int) (dl->ypos - dl->ascent + pheight) <
1310 (int) (dl->ypos + dl->descent - dl->clip))
1311 || IMAGE_INSTANCE_X_MASK (p))
1313 int clear_x, clear_y, clear_width, clear_height;
1315 if (IMAGE_INSTANCE_X_MASK (p))
1317 clear_y = dl->ypos - dl->ascent;
1318 clear_height = lheight;
1322 clear_y = dl->ypos - dl->ascent + pheight;
1323 clear_height = lheight - pheight;
1326 if (start_pixpos >= 0 && start_pixpos > xpos)
1328 clear_x = start_pixpos;
1329 clear_width = xpos + width - start_pixpos;
1334 clear_width = width;
1337 x_clear_region (window, findex, clear_x, clear_y,
1338 clear_width, clear_height);
1341 /* Output the pixmap. */
1343 Lisp_Object tmp_pixel;
1344 XColor tmp_bcolor, tmp_fcolor;
1346 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1347 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1348 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1349 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1351 x_output_x_pixmap (f, p, xpos - xoffset, dl->ypos - dl->ascent, clip_x,
1352 clip_y, clip_width, clip_height,
1353 pwidth, pheight, pixmap_offset,
1354 tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
1357 /* Draw a cursor over top of the pixmap. */
1358 if (cursor_width && cursor_height && (cursor_start >= xpos)
1359 && !NILP (w->text_cursor_visible_p)
1360 && (cursor_start < xpos + pwidth))
1363 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1364 int y = dl->ypos - dl->ascent;
1365 struct face_cachel *cursor_cachel =
1366 WINDOW_FACE_CACHEL (w,
1367 get_builtin_face_cache_index
1368 (w, Vtext_cursor_face));
1370 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1372 if (cursor_width > xpos + pwidth - cursor_start)
1373 cursor_width = xpos + pwidth - cursor_start;
1377 XFillRectangle (dpy, x_win, gc, cursor_start, y, cursor_width,
1382 XDrawRectangle (dpy, x_win, gc, cursor_start, y, cursor_width,
1388 /*****************************************************************************
1389 x_output_vertical_divider
1391 Draw a vertical divider down the right side of the given window.
1392 ****************************************************************************/
1394 x_output_vertical_divider (struct window *w, int clear)
1396 struct frame *f = XFRAME (w->frame);
1397 struct device *d = XDEVICE (f->device);
1399 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
1400 Display *dpy = DEVICE_X_DISPLAY (d);
1401 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1402 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
1403 Lisp_Object tmp_pixel;
1406 GC top_shadow_gc, bottom_shadow_gc, background_gc;
1411 int x, y1, y2, width, shadow_thickness, spacing, line_width;
1412 face_index div_face = get_builtin_face_cache_index (w, Vvertical_divider_face);
1414 width = window_divider_width (w);
1415 shadow_thickness = XINT (w->vertical_divider_shadow_thickness);
1416 spacing = XINT (w->vertical_divider_spacing);
1417 line_width = XINT (w->vertical_divider_line_width);
1418 x = WINDOW_RIGHT (w) - width;
1419 y1 = WINDOW_TOP (w);
1420 y2 = WINDOW_BOTTOM (w);
1422 memset (&gcv, ~0, sizeof (XGCValues));
1424 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1425 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1427 /* First, get the GC's. */
1428 top_shadow_pixel = tmp_color.pixel;
1429 bottom_shadow_pixel = tmp_color.pixel;
1430 background_pixel = tmp_color.pixel;
1432 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
1433 background_pixel, ef->core.background_pixel);
1435 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, div_face);
1436 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1437 gcv.background = tmp_color.pixel;
1438 gcv.graphics_exposures = False;
1439 mask = GCForeground | GCBackground | GCGraphicsExposures;
1441 /* If we can't distinguish one of the shadows (the color is the same as the
1442 background), it's better to use a pixmap to generate a dithrered gray. */
1443 if (top_shadow_pixel == background_pixel ||
1444 bottom_shadow_pixel == background_pixel)
1449 if (DEVICE_X_GRAY_PIXMAP (d) == None)
1451 DEVICE_X_GRAY_PIXMAP (d) =
1452 XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
1453 gray_width, gray_height, 1, 0, 1);
1456 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1457 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1458 gcv.foreground = tmp_color.pixel;
1459 /* this is needed because the GC draws with a pixmap here */
1460 gcv.fill_style = FillOpaqueStippled;
1461 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
1462 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
1463 (mask | GCStipple | GCFillStyle));
1465 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, div_face);
1466 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1467 bottom_shadow_pixel = tmp_color.pixel;
1469 flip_gcs = (bottom_shadow_pixel ==
1470 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
1474 gcv.foreground = top_shadow_pixel;
1475 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1478 gcv.foreground = bottom_shadow_pixel;
1479 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1481 if (use_pixmap && flip_gcs)
1483 GC tmp_gc = bottom_shadow_gc;
1484 bottom_shadow_gc = top_shadow_gc;
1485 top_shadow_gc = tmp_gc;
1488 gcv.foreground = background_pixel;
1489 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1491 /* possibly revert the GC's in case the shadow thickness is < 0.
1492 This will give a depressed look to the divider */
1493 if (shadow_thickness < 0)
1497 temp = top_shadow_gc;
1498 top_shadow_gc = bottom_shadow_gc;
1499 bottom_shadow_gc = temp;
1501 /* better avoid a Bad Adress XLib error ;-) */
1502 shadow_thickness = - shadow_thickness;
1505 /* Clear the divider area first. This needs to be done when a
1506 window split occurs. */
1508 XClearArea (dpy, x_win, x, y1, width, y2 - y1, False);
1510 /* Draw the divider line. */
1511 XFillRectangle (dpy, x_win, background_gc,
1512 x + spacing + shadow_thickness, y1,
1513 line_width, y2 - y1);
1515 /* Draw the shadows around the divider line */
1516 x_output_shadows (f, x + spacing, y1,
1517 width - 2 * spacing, y2 - y1,
1518 top_shadow_gc, bottom_shadow_gc,
1519 background_gc, shadow_thickness);
1522 /*****************************************************************************
1525 Output a blank by clearing the area it covers in the foreground color
1527 ****************************************************************************/
1529 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
1530 int start_pixpos, int cursor_start, int cursor_width)
1532 struct frame *f = XFRAME (w->frame);
1533 struct device *d = XDEVICE (f->device);
1535 Display *dpy = DEVICE_X_DISPLAY (d);
1536 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1538 struct face_cachel *cursor_cachel =
1539 WINDOW_FACE_CACHEL (w,
1540 get_builtin_face_cache_index
1541 (w, Vtext_cursor_face));
1542 Lisp_Object bg_pmap;
1543 Lisp_Object buffer = WINDOW_BUFFER (w);
1544 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1548 int y = dl->ypos - dl->ascent;
1549 int width = rb->width;
1550 int height = dl->ascent + dl->descent - dl->clip;
1552 if (start_pixpos > x)
1554 if (start_pixpos >= (x + width))
1558 width -= (start_pixpos - x);
1563 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
1564 if (!IMAGE_INSTANCEP (bg_pmap)
1565 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
1569 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1572 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1573 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
1576 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1578 /* If this rune is marked as having the cursor, then it is actually
1579 representing a tab. */
1580 if (!NILP (w->text_cursor_visible_p)
1581 && (rb->cursor_type == CURSOR_ON
1583 && (cursor_start + cursor_width > x)
1584 && cursor_start < (x + width))))
1586 int cursor_height, cursor_y;
1587 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1588 struct Lisp_Font_Instance *fi;
1590 fi = XFONT_INSTANCE (FACE_CACHEL_FONT
1591 (WINDOW_FACE_CACHEL (w, rb->findex),
1594 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1596 cursor_y = dl->ypos - fi->ascent;
1597 cursor_height = fi->height;
1598 if (cursor_y + cursor_height > y + height)
1599 cursor_height = y + height - cursor_y;
1603 if (NILP (bar_cursor_value))
1605 XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1606 fi->width, cursor_height);
1610 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1612 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1613 make_int (bar_width));
1614 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
1615 cursor_y, cursor_start + bar_width - 1,
1616 cursor_y + cursor_height - 1);
1619 else if (NILP (bar_cursor_value))
1621 XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1622 fi->width - 1, cursor_height - 1);
1627 /*****************************************************************************
1630 Output a horizontal line in the foreground of its face.
1631 ****************************************************************************/
1633 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
1635 struct frame *f = XFRAME (w->frame);
1636 struct device *d = XDEVICE (f->device);
1638 Display *dpy = DEVICE_X_DISPLAY (d);
1639 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1643 int width = rb->width;
1644 int height = dl->ascent + dl->descent - dl->clip;
1645 int ypos1, ypos2, ypos3, ypos4;
1647 ypos1 = dl->ypos - dl->ascent;
1648 ypos2 = ypos1 + rb->object.hline.yoffset;
1649 ypos3 = ypos2 + rb->object.hline.thickness;
1650 ypos4 = dl->ypos + dl->descent - dl->clip;
1652 /* First clear the area not covered by the line. */
1653 if (height - rb->object.hline.thickness > 0)
1655 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1658 if (ypos2 - ypos1 > 0)
1659 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1660 if (ypos4 - ypos3 > 0)
1661 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1664 /* Now draw the line. */
1665 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1673 if (ypos3 - ypos2 > 0)
1674 XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1677 /*****************************************************************************
1680 Draw a shadow around the given area using the given GC's. It is the
1681 callers responsibility to ste the GC's appropriately.
1682 ****************************************************************************/
1684 x_output_shadows (struct frame *f, int x, int y, int width, int height,
1685 GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
1686 int shadow_thickness)
1688 struct device *d = XDEVICE (f->device);
1690 Display *dpy = DEVICE_X_DISPLAY (d);
1691 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1693 XSegment top_shadow[20], bottom_shadow[20];
1696 if (shadow_thickness > 10)
1697 shadow_thickness = 10;
1698 else if (shadow_thickness < 0)
1699 shadow_thickness = 0;
1700 if (shadow_thickness > (width / 2))
1701 shadow_thickness = width / 2;
1702 if (shadow_thickness > (height / 2))
1703 shadow_thickness = height / 2;
1705 for (elt = 0; elt < shadow_thickness; elt++)
1708 int seg2 = elt + shadow_thickness;
1710 top_shadow[seg1].x1 = x;
1711 top_shadow[seg1].x2 = x + width - elt - 1;
1712 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
1714 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
1715 top_shadow[seg2].y1 = y + shadow_thickness;
1716 top_shadow[seg2].y2 = y + height - elt - 1;
1718 bottom_shadow[seg1].x1 = x + elt + 1;
1719 bottom_shadow[seg1].x2 = x + width - 1;
1720 bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
1722 bottom_shadow[seg2].x1 = bottom_shadow[seg2].x2 = x + width - elt - 1;
1723 bottom_shadow[seg2].y1 = y + elt + 1;
1724 bottom_shadow[seg2].y2 = y + height - shadow_thickness;
1727 XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow, shadow_thickness * 2);
1728 XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
1729 shadow_thickness * 2);
1732 /*****************************************************************************
1733 x_generate_shadow_pixels
1735 Given three pixels (top shadow, bottom shadow, background) massage
1736 the top and bottom shadow colors to guarantee that they differ. The
1737 background pixels are not allowed to be modified.
1739 This function modifies its parameters.
1741 This code is modified from code blatantly stolen from lwlib/xlwmenu.c
1742 ****************************************************************************/
1743 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
1744 ? ((unsigned long) (x)) : ((unsigned long) (y)))
1747 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
1748 unsigned long *bottom_shadow,
1749 unsigned long background,
1750 unsigned long core_background)
1752 struct device *d = XDEVICE (f->device);
1753 Display *dpy = DEVICE_X_DISPLAY (d);
1754 Colormap cmap = DEVICE_X_COLORMAP (d);
1755 Visual *visual = DEVICE_X_VISUAL (d);
1758 int top_frobbed = 0, bottom_frobbed = 0;
1760 /* If the top shadow is the same color as the background, try to
1762 if (*top_shadow == background)
1764 topc.pixel = background;
1765 XQueryColor (dpy, cmap, &topc);
1766 /* don't overflow/wrap! */
1767 topc.red = MINL (65535, (unsigned long) topc.red * 6 / 5);
1768 topc.green = MINL (65535, (unsigned long) topc.green * 6 / 5);
1769 topc.blue = MINL (65535, (unsigned long) topc.blue * 6 / 5);
1770 if (allocate_nearest_color (dpy, cmap, visual, &topc))
1772 *top_shadow = topc.pixel;
1777 /* If the bottom shadow is the same color as the background, try to
1779 if (*bottom_shadow == background)
1781 botc.pixel = background;
1782 XQueryColor (dpy, cmap, &botc);
1783 botc.red = (unsigned short) ((unsigned long) botc.red * 3 / 5);
1784 botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5);
1785 botc.blue = (unsigned short) ((unsigned long) botc.blue * 3 / 5);
1786 if (allocate_nearest_color (dpy, cmap, visual, &botc))
1788 *bottom_shadow = botc.pixel;
1793 /* If we had to adjust both shadows, then we have to do some
1795 if (top_frobbed && bottom_frobbed)
1797 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
1798 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
1799 if (bot_avg > top_avg)
1801 Pixel tmp = *top_shadow;
1803 *top_shadow = *bottom_shadow;
1804 *bottom_shadow = tmp;
1806 else if (topc.pixel == botc.pixel)
1808 if (botc.pixel == background)
1809 *top_shadow = core_background;
1811 *bottom_shadow = background;
1816 /*****************************************************************************
1817 x_clear_to_window_end
1819 Clear the area between ypos1 and ypos2. Each margin area and the
1820 text area is handled separately since they may each have their own
1822 ****************************************************************************/
1824 x_clear_to_window_end (struct window *w, int ypos1, int ypos2)
1826 int height = ypos2 - ypos1;
1830 struct frame *f = XFRAME (w->frame);
1832 int bflag = (window_needs_vertical_divider (w) ? 0 : 1);
1833 layout_bounds bounds;
1835 bounds = calculate_display_line_boundaries (w, bflag);
1836 XSETWINDOW (window, w);
1838 if (window_is_leftmost (w))
1839 x_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f),
1840 ypos1, FRAME_BORDER_WIDTH (f), height);
1842 if (bounds.left_in - bounds.left_out > 0)
1843 x_clear_region (window,
1844 get_builtin_face_cache_index (w, Vleft_margin_face),
1845 bounds.left_out, ypos1,
1846 bounds.left_in - bounds.left_out, height);
1848 if (bounds.right_in - bounds.left_in > 0)
1849 x_clear_region (window, DEFAULT_INDEX, bounds.left_in, ypos1,
1850 bounds.right_in - bounds.left_in, height);
1852 if (bounds.right_out - bounds.right_in > 0)
1853 x_clear_region (window,
1854 get_builtin_face_cache_index (w, Vright_margin_face),
1855 bounds.right_in, ypos1,
1856 bounds.right_out - bounds.right_in, height);
1858 if (window_is_rightmost (w))
1859 x_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f),
1860 ypos1, FRAME_BORDER_WIDTH (f), height);
1864 /*****************************************************************************
1865 x_redraw_exposed_window
1867 Given a bounding box for an area that needs to be redrawn, determine
1868 what parts of what lines are contained within and re-output their
1870 ****************************************************************************/
1872 x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
1874 struct frame *f = XFRAME (w->frame);
1876 int start_x, start_y, end_x, end_y;
1877 int orig_windows_structure_changed;
1879 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1881 if (!NILP (w->vchild))
1883 x_redraw_exposed_windows (w->vchild, x, y, width, height);
1886 else if (!NILP (w->hchild))
1888 x_redraw_exposed_windows (w->hchild, x, y, width, height);
1892 /* If the window doesn't intersect the exposed region, we're done here. */
1893 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w)
1894 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w))
1900 start_x = max (WINDOW_LEFT (w), x);
1901 end_x = min (WINDOW_RIGHT (w), (x + width));
1902 start_y = max (WINDOW_TOP (w), y);
1903 end_y = min (WINDOW_BOTTOM (w), y + height);
1905 /* We do this to make sure that the 3D modelines get redrawn if
1906 they are in the exposed region. */
1907 orig_windows_structure_changed = f->windows_structure_changed;
1908 f->windows_structure_changed = 1;
1911 if (window_needs_vertical_divider (w))
1913 x_output_vertical_divider (w, 0);
1916 for (line = 0; line < Dynarr_length (cdla); line++)
1918 struct display_line *cdl = Dynarr_atp (cdla, line);
1919 int top_y = cdl->ypos - cdl->ascent;
1920 int bottom_y = cdl->ypos + cdl->descent;
1922 if (bottom_y >= start_y)
1933 output_display_line (w, 0, cdla, line, start_x, end_x);
1938 f->windows_structure_changed = orig_windows_structure_changed;
1940 /* If there have never been any face cache_elements created, then this
1941 expose event doesn't actually have anything to do. */
1942 if (Dynarr_largest (w->face_cachels))
1943 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
1946 /*****************************************************************************
1947 x_redraw_exposed_windows
1949 For each window beneath the given window in the window hierarchy,
1950 ensure that it is redrawn if necessary after an Expose event.
1951 ****************************************************************************/
1953 x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
1956 for (; !NILP (window); window = XWINDOW (window)->next)
1957 x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
1960 /*****************************************************************************
1961 x_redraw_exposed_area
1963 For each window on the given frame, ensure that any area in the
1964 Exposed area is redrawn.
1965 ****************************************************************************/
1967 x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
1969 /* If any window on the frame has had its face cache reset then the
1970 redisplay structures are effectively invalid. If we attempt to
1971 use them we'll blow up. We mark the frame as changed to ensure
1972 that redisplay will do a full update. This probably isn't
1973 necessary but it can't hurt. */
1975 #ifdef HAVE_TOOLBARS
1976 /* #### We would rather put these off as well but there is currently
1977 no combination of flags which will force an unchanged toolbar to
1979 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
1982 if (!f->window_face_cache_reset)
1984 x_redraw_exposed_windows (f->root_window, x, y, width, height);
1986 XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
1989 MARK_FRAME_CHANGED (f);
1992 /****************************************************************************
1995 Clear the area in the box defined by the given parameters using the
1997 ****************************************************************************/
1999 x_clear_region (Lisp_Object locale, face_index findex, int x, int y,
2000 int width, int height)
2002 struct window *w = NULL;
2003 struct frame *f = NULL;
2005 Lisp_Object background_pixmap;
2010 if (WINDOWP (locale))
2012 w = XWINDOW (locale);
2013 f = XFRAME (w->frame);
2015 else if (FRAMEP (locale))
2018 f = XFRAME (locale);
2023 d = XDEVICE (f->device);
2024 dpy = DEVICE_X_DISPLAY (d);
2025 x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2027 /* #### This function is going to have to be made cursor aware. */
2028 if (width && height)
2032 /* #### This isn't quite right for when this function is called
2033 from the toolbar code. */
2034 background_pixmap = Qunbound;
2036 /* Don't use a backing pixmap in the border area */
2037 if (x >= FRAME_LEFT_BORDER_END (f)
2038 && x < FRAME_RIGHT_BORDER_START (f)
2039 && y >= FRAME_TOP_BORDER_END (f)
2040 && y < FRAME_BOTTOM_BORDER_START (f))
2046 temp = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, findex);
2048 if (IMAGE_INSTANCEP (temp)
2049 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
2051 /* #### maybe we could implement such that a string
2052 can be a background pixmap? */
2053 background_pixmap = temp;
2058 temp = FACE_BACKGROUND_PIXMAP (Vdefault_face, locale);
2060 if (IMAGE_INSTANCEP (temp)
2061 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
2063 background_pixmap = temp;
2067 if (!UNBOUNDP (background_pixmap) &&
2068 XIMAGE_INSTANCE_PIXMAP_DEPTH (background_pixmap) == 0)
2070 Lisp_Object fcolor, bcolor;
2074 fcolor = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
2075 bcolor = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
2079 fcolor = FACE_FOREGROUND (Vdefault_face, locale);
2080 bcolor = FACE_BACKGROUND (Vdefault_face, locale);
2083 gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
2087 Lisp_Object color = (w ?
2088 WINDOW_FACE_CACHEL_BACKGROUND (w, findex) :
2089 FACE_BACKGROUND (Vdefault_face, locale));
2091 if (UNBOUNDP (background_pixmap))
2092 background_pixmap = Qnil;
2094 gc = x_get_gc (d, Qnil, color, Qnil, background_pixmap, Qnil);
2099 XFillRectangle (dpy, x_win, gc, x, y, width, height);
2101 XClearArea (dpy, x_win, x, y, width, height, False);
2105 /*****************************************************************************
2108 Draw a cursor at the end of a line. The end-of-line cursor is
2109 narrower than the normal cursor.
2110 ****************************************************************************/
2112 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos,
2115 struct frame *f = XFRAME (w->frame);
2116 struct device *d = XDEVICE (f->device);
2119 Display *dpy = DEVICE_X_DISPLAY (d);
2120 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2122 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
2123 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
2125 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
2126 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
2130 int y = dl->ypos - dl->ascent;
2131 int width = EOL_CURSOR_WIDTH;
2132 int height = dl->ascent + dl->descent - dl->clip;
2133 int cursor_height, cursor_y;
2134 int defheight, defascent;
2136 XSETWINDOW (window, w);
2137 x_clear_region (window, findex, x, y, width, height);
2139 if (NILP (w->text_cursor_visible_p))
2142 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
2144 default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
2146 /* make sure the cursor is entirely contained between y and y+height */
2147 cursor_height = min (defheight, height);
2148 cursor_y = max (y, min (y + height - cursor_height,
2149 dl->ypos - defascent));
2154 XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2);
2155 #endif /* HAVE_XIM */
2157 if (NILP (bar_cursor_value))
2159 XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
2163 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
2165 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
2166 make_int (bar_width));
2167 XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
2168 x + bar_width - 1, cursor_y + cursor_height - 1);
2171 else if (NILP (bar_cursor_value))
2173 XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
2179 x_clear_frame_window (Lisp_Object window)
2181 struct window *w = XWINDOW (window);
2183 if (!NILP (w->vchild))
2185 x_clear_frame_windows (w->vchild);
2189 if (!NILP (w->hchild))
2191 x_clear_frame_windows (w->hchild);
2195 x_clear_to_window_end (w, WINDOW_TEXT_TOP (w), WINDOW_TEXT_BOTTOM (w));
2199 x_clear_frame_windows (Lisp_Object window)
2201 for (; !NILP (window); window = XWINDOW (window)->next)
2202 x_clear_frame_window (window);
2206 x_clear_frame (struct frame *f)
2208 struct device *d = XDEVICE (f->device);
2209 Display *dpy = DEVICE_X_DISPLAY (d);
2210 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2211 int x, y, width, height;
2214 x = FRAME_LEFT_BORDER_START (f);
2215 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
2216 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
2217 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) -
2218 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f));
2219 /* #### This adjustment by 1 should be being done in the macros.
2220 There is some small differences between when the menubar is on
2221 and off that we still need to deal with. */
2222 y = FRAME_TOP_BORDER_START (f) - 1;
2223 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
2224 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
2225 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) -
2226 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1;
2228 XClearArea (dpy, x_win, x, y, width, height, False);
2230 XSETFRAME (frame, f);
2232 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
2233 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
2234 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
2236 x_clear_frame_windows (f->root_window);
2239 XFlush (DEVICE_X_DISPLAY (d));
2242 /* briefly swap the foreground and background colors.
2246 x_flash (struct device *d)
2252 XColor tmp_fcolor, tmp_bcolor;
2253 Lisp_Object tmp_pixel, frame;
2254 struct frame *f = device_selected_frame (d);
2255 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f));
2256 Widget shell = FRAME_X_SHELL_WIDGET (f);
2258 XSETFRAME (frame, f);
2260 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
2261 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
2262 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
2263 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
2265 dpy = XtDisplay (shell);
2266 win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2267 memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
2268 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
2269 gcv.function = GXxor;
2270 gcv.graphics_exposures = False;
2271 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
2272 (GCForeground | GCFunction | GCGraphicsExposures));
2273 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2274 w->pixel_width, w->pixel_height);
2281 tv.tv_sec = usecs / 1000000L;
2282 tv.tv_usec = usecs % 1000000L;
2283 /* I'm sure someone is going to complain about this... */
2284 select (0, 0, 0, 0, &tv);
2289 #else /* !HAVE_POLL */
2291 #endif /* HAVE_POLL */
2292 #endif /* HAVE_SELECT */
2294 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2295 w->pixel_width, w->pixel_height);
2301 /* Make audible bell. */
2304 x_ring_bell (struct device *d, int volume, int pitch, int duration)
2306 Display *display = DEVICE_X_DISPLAY (d);
2308 if (volume < 0) volume = 0;
2309 else if (volume > 100) volume = 100;
2310 if (pitch < 0 && duration < 0)
2312 XBell (display, (volume * 2) - 100);
2317 XKeyboardState state;
2318 XKeyboardControl ctl;
2320 /* #### grab server? */
2321 XGetKeyboardControl (display, &state);
2323 ctl.bell_pitch = (pitch >= 0 ? pitch : state.bell_pitch);
2324 ctl.bell_duration = (duration >= 0 ? duration : state.bell_duration);
2325 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2327 XBell (display, (volume * 2) - 100);
2329 ctl.bell_pitch = state.bell_pitch;
2330 ctl.bell_duration = state.bell_duration;
2331 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2333 /* #### ungrab server? */
2339 /************************************************************************/
2340 /* initialization */
2341 /************************************************************************/
2344 console_type_create_redisplay_x (void)
2346 /* redisplay methods */
2347 CONSOLE_HAS_METHOD (x, text_width);
2348 CONSOLE_HAS_METHOD (x, output_display_block);
2349 CONSOLE_HAS_METHOD (x, divider_height);
2350 CONSOLE_HAS_METHOD (x, eol_cursor_width);
2351 CONSOLE_HAS_METHOD (x, output_vertical_divider);
2352 CONSOLE_HAS_METHOD (x, clear_to_window_end);
2353 CONSOLE_HAS_METHOD (x, clear_region);
2354 CONSOLE_HAS_METHOD (x, clear_frame);
2355 CONSOLE_HAS_METHOD (x, output_begin);
2356 CONSOLE_HAS_METHOD (x, output_end);
2357 CONSOLE_HAS_METHOD (x, flash);
2358 CONSOLE_HAS_METHOD (x, ring_bell);