comparison src/redisplay-x.c @ 428:3ecd8885ac67 r21-2-22

Import from CVS: tag r21-2-22
author cvs
date Mon, 13 Aug 2007 11:28:15 +0200
parents
children 8de8e3f6228a
comparison
equal deleted inserted replaced
427:0a0253eac470 428:3ecd8885ac67
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.
5
6 This file is part of XEmacs.
7
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
11 later version.
12
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
16 for more details.
17
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. */
22
23 /* Synched up with: Not in FSF. */
24
25 /* Author: Chuck Thompson */
26
27 /* Lots of work done by Ben Wing for Mule */
28
29 #include <config.h>
30 #include "lisp.h"
31
32 #include "console-x.h"
33 #include "EmacsFrame.h"
34 #include "EmacsFrameP.h"
35 #include "xgccache.h"
36 #include "glyphs-x.h"
37 #include "objects-x.h"
38
39 #include "buffer.h"
40 #include "debug.h"
41 #include "faces.h"
42 #include "frame.h"
43 #include "gutter.h"
44 #include "redisplay.h"
45 #include "sysdep.h"
46 #include "window.h"
47 #include <X11/bitmaps/gray>
48
49 #include "sysproc.h" /* for select() */
50
51 #ifdef MULE
52 #include "mule-ccl.h"
53 #include "file-coding.h" /* for CCL conversion */
54 #endif
55
56 /* Number of pixels below each line. */
57 int x_interline_space; /* #### implement me */
58
59 #define EOL_CURSOR_WIDTH 5
60
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,
66 struct rune *rb);
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);
75
76
77 /* Note: We do not use the Xmb*() functions and XFontSets.
78 Those functions are generally losing for a number of reasons:
79
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
91 all.
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
94 people are using R4?)
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
100 it's EUC.
101 */
102
103 struct textual_run
104 {
105 Lisp_Object charset;
106 unsigned char *ptr;
107 int len;
108 int dimension;
109 };
110
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.
120
121 Returns the number of runs actually used. */
122
123 static int
124 separate_textual_runs (unsigned char *text_storage,
125 struct textual_run *run_storage,
126 CONST Emchar *str, Charcount len)
127 {
128 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a
129 possible valid charset when
130 MULE is not defined */
131 int runs_so_far = 0;
132 int i;
133 #ifdef MULE
134 struct ccl_program char_converter;
135 int need_ccl_conversion = 0;
136 #endif
137
138 for (i = 0; i < len; i++)
139 {
140 Emchar ch = str[i];
141 Lisp_Object charset;
142 int byte1, byte2;
143 int dimension;
144 int graphic;
145
146 BREAKUP_CHAR (ch, charset, byte1, byte2);
147 dimension = XCHARSET_DIMENSION (charset);
148 graphic = XCHARSET_GRAPHIC (charset);
149
150 if (!EQ (charset, prev_charset))
151 {
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;
155
156 if (runs_so_far)
157 {
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;
162 }
163 runs_so_far++;
164 prev_charset = charset;
165 #ifdef MULE
166 {
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);
171 }
172 #endif
173 }
174
175 if (graphic == 0)
176 {
177 byte1 &= 0x7F;
178 byte2 &= 0x7F;
179 }
180 else if (graphic == 1)
181 {
182 byte1 |= 0x80;
183 byte2 |= 0x80;
184 }
185 #ifdef MULE
186 if (need_ccl_conversion)
187 {
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];
194 }
195 #endif
196 *text_storage++ = (unsigned char) byte1;
197 if (dimension == 2)
198 *text_storage++ = (unsigned char) byte2;
199 }
200
201 if (runs_so_far)
202 {
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;
207 }
208
209 return runs_so_far;
210 }
211
212 /****************************************************************************/
213 /* */
214 /* X output routines */
215 /* */
216 /****************************************************************************/
217
218 static int
219 x_text_width_single_run (struct face_cachel *cachel, struct textual_run *run)
220 {
221 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
222 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
223 if (!fi->proportional_p)
224 return fi->width * run->len;
225 else
226 {
227 if (run->dimension == 2)
228 return XTextWidth16 (FONT_INSTANCE_X_FONT (fi),
229 (XChar2b *) run->ptr, run->len);
230 else
231 return XTextWidth (FONT_INSTANCE_X_FONT (fi),
232 (char *) run->ptr, run->len);
233 }
234 }
235
236 /*
237 x_text_width
238
239 Given a string and a face, return the string's length in pixels when
240 displayed in the font associated with the face.
241 */
242
243 static int
244 x_text_width (struct frame *f, struct face_cachel *cachel, CONST Emchar *str,
245 Charcount len)
246 {
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);
250 int nruns;
251 int i;
252
253 nruns = separate_textual_runs (text_storage, runs, str, len);
254
255 for (i = 0; i < nruns; i++)
256 width_so_far += x_text_width_single_run (cachel, runs + i);
257
258 return width_so_far;
259 }
260
261 /*****************************************************************************
262 x_divider_height
263
264 Return the height of the horizontal divider. This is a function because
265 divider_height is a device method.
266
267 #### If we add etched horizontal divider lines this will have to get
268 smarter.
269 ****************************************************************************/
270 static int
271 x_divider_height (void)
272 {
273 return 1;
274 }
275
276 /*****************************************************************************
277 x_eol_cursor_width
278
279 Return the width of the end-of-line cursor. This is a function
280 because eol_cursor_width is a device method.
281 ****************************************************************************/
282 static int
283 x_eol_cursor_width (void)
284 {
285 return EOL_CURSOR_WIDTH;
286 }
287
288 /*****************************************************************************
289 x_output_begin
290
291 Perform any necessary initialization prior to an update.
292 ****************************************************************************/
293 static void
294 x_output_begin (struct device *d)
295 {
296 }
297
298 /*****************************************************************************
299 x_output_end
300
301 Perform any necessary flushing of queues when an update has completed.
302 ****************************************************************************/
303 static void
304 x_output_end (struct device *d)
305 {
306 XFlush (DEVICE_X_DISPLAY (d));
307 }
308
309 /*****************************************************************************
310 x_output_display_block
311
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 ****************************************************************************/
315 static void
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)
319 {
320 struct frame *f = XFRAME (w->frame);
321 Emchar_dynarr *buf = Dynarr_new (Emchar);
322 Lisp_Object window;
323
324 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
325 rune_dynarr *rba = db->runes;
326 struct rune *rb;
327
328 int elt = start;
329 face_index findex;
330 int xpos, width = 0;
331 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
332 MULE is not defined */
333
334 XSETWINDOW (window, w);
335 rb = Dynarr_atp (rba, start);
336
337 if (!rb)
338 /* Nothing to do so don't do anything. */
339 return;
340
341 findex = rb->findex;
342 xpos = rb->xpos;
343 if (rb->type == RUNE_CHAR)
344 charset = CHAR_CHARSET (rb->object.chr.ch);
345
346 if (end < 0)
347 end = Dynarr_length (rba);
348 Dynarr_reset (buf);
349
350 while (elt < end)
351 {
352 rb = Dynarr_atp (rba, elt);
353
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)))
357 {
358 Dynarr_add (buf, rb->object.chr.ch);
359 width += rb->width;
360 elt++;
361 }
362 else
363 {
364 if (Dynarr_length (buf))
365 {
366 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
367 findex, 0, cursor_start, cursor_width,
368 cursor_height);
369 xpos = rb->xpos;
370 width = 0;
371 }
372 Dynarr_reset (buf);
373 width = 0;
374
375 if (rb->type == RUNE_CHAR)
376 {
377 findex = rb->findex;
378 xpos = rb->xpos;
379 charset = CHAR_CHARSET (rb->object.chr.ch);
380
381 if (rb->cursor_type == CURSOR_ON)
382 {
383 if (rb->object.chr.ch == '\n')
384 {
385 x_output_eol_cursor (w, dl, xpos, findex);
386 }
387 else
388 {
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,
393 cursor_height);
394 Dynarr_reset (buf);
395 }
396
397 xpos += rb->width;
398 elt++;
399 }
400 else if (rb->object.chr.ch == '\n')
401 {
402 /* Clear in case a cursor was formerly here. */
403 redisplay_clear_region (window, findex, xpos,
404 DISPLAY_LINE_YPOS (dl),
405 rb->width,
406 DISPLAY_LINE_HEIGHT (dl));
407 elt++;
408 }
409 }
410 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
411 {
412 if (rb->type == RUNE_BLANK)
413 x_output_blank (w, dl, rb, start_pixpos, cursor_start,
414 cursor_width);
415 else
416 {
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
423 now. */
424 w->shadow_thickness_changed = 1;
425 x_output_hline (w, dl, rb);
426 }
427
428 elt++;
429 if (elt < end)
430 {
431 rb = Dynarr_atp (rba, elt);
432
433 findex = rb->findex;
434 xpos = rb->xpos;
435 }
436 }
437 else if (rb->type == RUNE_DGLYPH)
438 {
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,
444 &dbox, &dga);
445
446 XSETWINDOW (window, w);
447 instance = glyph_image_instance (rb->object.dglyph.glyph,
448 window, ERROR_ME_NOT, 1);
449 findex = rb->findex;
450
451 if (IMAGE_INSTANCEP (instance))
452 switch (XIMAGE_INSTANCE_TYPE (instance))
453 {
454 case IMAGE_TEXT:
455 {
456 /* #### This is way losing. See the comment in
457 add_glyph_rune(). */
458 Lisp_Object string =
459 XIMAGE_INSTANCE_TEXT_STRING (instance);
460 convert_bufbyte_string_into_emchar_dynarr
461 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
462
463 x_output_string (w, dl, buf, xpos,
464 rb->object.dglyph.xoffset,
465 start_pixpos, -1, findex,
466 (rb->cursor_type == CURSOR_ON),
467 cursor_start, cursor_width,
468 cursor_height);
469 Dynarr_reset (buf);
470 }
471 break;
472
473 case IMAGE_MONO_PIXMAP:
474 case IMAGE_COLOR_PIXMAP:
475 redisplay_output_pixmap (w, instance, &dbox, &dga, findex,
476 cursor_start, cursor_width,
477 cursor_height, 0);
478 break;
479
480 case IMAGE_WIDGET:
481 case IMAGE_SUBWINDOW:
482 redisplay_output_subwindow (w, instance, &dbox, &dga, findex,
483 cursor_start, cursor_width,
484 cursor_height);
485 break;
486
487 case IMAGE_LAYOUT:
488 redisplay_output_layout (w, instance, &dbox, &dga, findex,
489 cursor_start, cursor_width,
490 cursor_height);
491 break;
492
493 case IMAGE_NOTHING:
494 /* nothing is as nothing does */
495 break;
496
497 case IMAGE_POINTER:
498 default:
499 abort ();
500 }
501
502 xpos += rb->width;
503 elt++;
504 }
505 else
506 abort ();
507 }
508 }
509
510 if (Dynarr_length (buf))
511 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
512 0, cursor_start, cursor_width, cursor_height);
513
514 /* #### This is really conditionalized well for optimized
515 performance. */
516 if (dl->modeline
517 && !EQ (Qzero, w->modeline_shadow_thickness)
518 && (f->clear
519 || f->windows_structure_changed
520 || w->shadow_thickness_changed))
521 bevel_modeline (w, dl);
522
523 Dynarr_free (buf);
524 }
525
526 /*****************************************************************************
527 x_bevel_area
528
529 Draw a shadows for the given area in the given face.
530 ****************************************************************************/
531 static void
532 x_bevel_area (struct window *w, face_index findex,
533 int x, int y, int width, int height,
534 int shadow_thickness, int edges, enum edge_style style)
535 {
536 struct frame *f = XFRAME (w->frame);
537 struct device *d = XDEVICE (f->device);
538
539 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
540 Display *dpy = DEVICE_X_DISPLAY (d);
541 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
542 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
543 Lisp_Object tmp_pixel;
544 XColor tmp_color;
545 XGCValues gcv;
546 GC top_shadow_gc, bottom_shadow_gc, background_gc;
547
548 int use_pixmap = 0;
549 int flip_gcs = 0;
550 unsigned long mask;
551
552 assert (shadow_thickness >=0);
553 memset (&gcv, ~0, sizeof (XGCValues));
554
555 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
556 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
557
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;
562
563 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
564 background_pixel, ef->core.background_pixel);
565
566 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
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;
571
572 /* If we can't distinguish one of the shadows (the color is the same as the
573 background), it's better to use a pixmap to generate a dithered gray. */
574 if (top_shadow_pixel == background_pixel ||
575 bottom_shadow_pixel == background_pixel)
576 use_pixmap = 1;
577
578 if (use_pixmap)
579 {
580 if (DEVICE_X_GRAY_PIXMAP (d) == None)
581 {
582 DEVICE_X_GRAY_PIXMAP (d) =
583 XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
584 gray_width, gray_height, 1, 0, 1);
585 }
586
587 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
588 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
589 gcv.foreground = tmp_color.pixel;
590 /* this is needed because the GC draws with a pixmap here */
591 gcv.fill_style = FillOpaqueStippled;
592 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
593 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
594 (mask | GCStipple | GCFillStyle));
595
596 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
597 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
598 bottom_shadow_pixel = tmp_color.pixel;
599
600 flip_gcs = (bottom_shadow_pixel ==
601 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
602 }
603 else
604 {
605 gcv.foreground = top_shadow_pixel;
606 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
607 }
608
609 gcv.foreground = bottom_shadow_pixel;
610 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
611
612 if (use_pixmap && flip_gcs)
613 {
614 GC tmp_gc = bottom_shadow_gc;
615 bottom_shadow_gc = top_shadow_gc;
616 top_shadow_gc = tmp_gc;
617 }
618
619 gcv.foreground = background_pixel;
620 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
621
622 /* possibly revert the GC's This will give a depressed look to the
623 divider */
624 if (style == EDGE_ETCHED_IN || style == EDGE_BEVEL_IN)
625 {
626 GC temp;
627
628 temp = top_shadow_gc;
629 top_shadow_gc = bottom_shadow_gc;
630 bottom_shadow_gc = temp;
631 }
632
633 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
634 shadow_thickness /= 2;
635
636 /* Draw the shadows around the divider line */
637 x_output_shadows (f, x, y, width, height,
638 top_shadow_gc, bottom_shadow_gc,
639 background_gc, shadow_thickness, edges);
640
641 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT)
642 {
643 /* Draw the shadows around the divider line */
644 x_output_shadows (f, x + shadow_thickness, y + shadow_thickness,
645 width - 2*shadow_thickness, height - 2*shadow_thickness,
646 bottom_shadow_gc, top_shadow_gc,
647 background_gc, shadow_thickness, edges);
648 }
649 }
650
651 /*****************************************************************************
652 x_get_gc
653
654 Given a number of parameters return a GC with those properties.
655 ****************************************************************************/
656 static GC
657 x_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
658 Lisp_Object bg_pmap, Lisp_Object lwidth)
659 {
660 XGCValues gcv;
661 unsigned long mask;
662
663 memset (&gcv, ~0, sizeof (XGCValues));
664 gcv.graphics_exposures = False;
665 /* Make absolutely sure that we don't pick up a clipping region in
666 the GC returned by this function. */
667 gcv.clip_mask = None;
668 gcv.clip_x_origin = 0;
669 gcv.clip_y_origin = 0;
670 gcv.fill_style = FillSolid;
671 mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
672 mask |= GCFillStyle;
673
674 if (!NILP (font))
675 {
676 gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
677 mask |= GCFont;
678 }
679
680 /* evil kludge! */
681 if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg))
682 {
683 /* #### I fixed once case where this was getting it. It was a
684 bad macro expansion (compiler bug). */
685 fprintf (stderr, "Help! x_get_gc got a bogus fg value! fg = ");
686 debug_print (fg);
687 fg = Qnil;
688 }
689
690 if (!NILP (fg))
691 {
692 if (COLOR_INSTANCEP (fg))
693 gcv.foreground = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (fg)).pixel;
694 else
695 gcv.foreground = XINT (fg);
696 mask |= GCForeground;
697 }
698
699 if (!NILP (bg))
700 {
701 if (COLOR_INSTANCEP (bg))
702 gcv.background = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (bg)).pixel;
703 else
704 gcv.background = XINT (bg);
705 mask |= GCBackground;
706 }
707
708 /* This special case comes from a request to draw text with a face which has
709 the dim property. We'll use a stippled foreground GC. */
710 if (EQ (bg_pmap, Qdim))
711 {
712 assert (DEVICE_X_GRAY_PIXMAP (d) != None);
713
714 gcv.fill_style = FillStippled;
715 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
716 mask |= (GCFillStyle | GCStipple);
717 }
718 else if (IMAGE_INSTANCEP (bg_pmap)
719 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
720 {
721 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
722 {
723 gcv.fill_style = FillOpaqueStippled;
724 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
725 mask |= (GCStipple | GCFillStyle);
726 }
727 else
728 {
729 gcv.fill_style = FillTiled;
730 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
731 mask |= (GCTile | GCFillStyle);
732 }
733 }
734
735 if (!NILP (lwidth))
736 {
737 gcv.line_width = XINT (lwidth);
738 mask |= GCLineWidth;
739 }
740
741 return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
742 }
743
744 /*****************************************************************************
745 x_output_string
746
747 Given a string and a starting position, output that string in the
748 given face. If cursor is true, draw a cursor around the string.
749 Correctly handles multiple charsets in the string.
750
751 The meaning of the parameters is something like this:
752
753 W Window that the text is to be displayed in.
754 DL Display line that this text is on. The values in the
755 structure are used to determine the vertical position and
756 clipping range of the text.
757 BUF Dynamic array of Emchars specifying what is actually to be
758 drawn.
759 XPOS X position in pixels where the text should start being drawn.
760 XOFFSET Number of pixels to be chopped off the left side of the
761 text. The effect is as if the text were shifted to the
762 left this many pixels and clipped at XPOS.
763 CLIP_START Clip everything left of this X position.
764 WIDTH Clip everything right of XPOS + WIDTH.
765 FINDEX Index for the face cache element describing how to display
766 the text.
767 CURSOR #### I don't understand this. There's something
768 strange and overcomplexified with this variable.
769 Chuck, explain please?
770 CURSOR_START Starting X position of cursor.
771 CURSOR_WIDTH Width of cursor in pixels.
772 CURSOR_HEIGHT Height of cursor in pixels.
773
774 Starting Y position of cursor is the top of the text line.
775 The cursor is drawn sometimes whether or not CURSOR is set. ???
776 ****************************************************************************/
777 void
778 x_output_string (struct window *w, struct display_line *dl,
779 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
780 int width, face_index findex, int cursor,
781 int cursor_start, int cursor_width, int cursor_height)
782 {
783 /* General variables */
784 struct frame *f = XFRAME (w->frame);
785 struct device *d = XDEVICE (f->device);
786 Lisp_Object device;
787 Lisp_Object window;
788 Display *dpy = DEVICE_X_DISPLAY (d);
789 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
790
791 int clip_end;
792
793 /* Cursor-related variables */
794 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
795 int cursor_clip;
796 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
797 WINDOW_BUFFER (w));
798 struct face_cachel *cursor_cachel = 0;
799
800 /* Text-related variables */
801 Lisp_Object bg_pmap;
802 GC bgc, gc;
803 int height;
804 int len = Dynarr_length (buf);
805 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
806 struct textual_run *runs = alloca_array (struct textual_run, len);
807 int nruns;
808 int i;
809 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
810
811 XSETDEVICE (device, d);
812 XSETWINDOW (window, w);
813
814 if (width < 0)
815 width = x_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
816 height = DISPLAY_LINE_HEIGHT (dl);
817
818 /* Regularize the variables passed in. */
819
820 if (clip_start < xpos)
821 clip_start = xpos;
822 clip_end = xpos + width;
823 if (clip_start >= clip_end)
824 /* It's all clipped out. */
825 return;
826
827 xpos -= xoffset;
828
829 /* make sure the area we are about to display is subwindow free. */
830 redisplay_unmap_subwindows_maybe (f, clip_start, DISPLAY_LINE_YPOS (dl),
831 clip_end - clip_start, DISPLAY_LINE_HEIGHT (dl));
832
833 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
834 Dynarr_length (buf));
835
836 cursor_clip = (cursor_start >= clip_start &&
837 cursor_start < clip_end);
838
839 /* This cursor code is really a mess. */
840 if (!NILP (w->text_cursor_visible_p)
841 && (cursor
842 || cursor_clip
843 || (cursor_width
844 && (cursor_start + cursor_width >= clip_start)
845 && !NILP (bar_cursor_value))))
846 {
847 /* These have to be in separate statements in order to avoid a
848 compiler bug. */
849 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face);
850 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks);
851
852 /* We have to reset this since any call to WINDOW_FACE_CACHEL
853 may cause the cache to resize and any pointers to it to
854 become invalid. */
855 cachel = WINDOW_FACE_CACHEL (w, findex);
856 }
857
858 #ifdef HAVE_XIM
859 if (cursor && focus && (cursor_start == clip_start) && cursor_height)
860 XIM_SetSpotLocation (f, xpos - 2, dl->ypos + dl->descent - 2);
861 #endif /* HAVE_XIM */
862
863 bg_pmap = cachel->background_pixmap;
864 if (!IMAGE_INSTANCEP (bg_pmap)
865 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
866 bg_pmap = Qnil;
867
868 if ((cursor && focus && NILP (bar_cursor_value)
869 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap))
870 bgc = 0;
871 else
872 bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
873 bg_pmap, Qnil);
874
875 if (bgc)
876 XFillRectangle (dpy, x_win, bgc, clip_start,
877 DISPLAY_LINE_YPOS (dl), clip_end - clip_start,
878 height);
879
880 for (i = 0; i < nruns; i++)
881 {
882 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
883 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
884 int this_width;
885 int need_clipping;
886
887 if (EQ (font, Vthe_null_font_instance))
888 continue;
889
890 this_width = x_text_width_single_run (cachel, runs + i);
891 need_clipping = (dl->clip || clip_start > xpos ||
892 clip_end < xpos + this_width);
893
894 /* XDrawImageString only clears the area equal to the height of
895 the given font. It is possible that a font is being displayed
896 on a line taller than it is, so this would cause us to fail to
897 clear some areas. */
898 if ((int) fi->height < (int) (height + dl->clip + dl->top_clip))
899 {
900 int clear_start = max (xpos, clip_start);
901 int clear_end = min (xpos + this_width, clip_end);
902
903 if (cursor)
904 {
905 int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
906
907 ypos1_string = dl->ypos - fi->ascent;
908 ypos2_string = dl->ypos + fi->descent;
909 ypos1_line = DISPLAY_LINE_YPOS (dl);
910 ypos2_line = ypos1_line + DISPLAY_LINE_HEIGHT (dl);
911
912 /* Make sure we don't clear below the real bottom of the
913 line. */
914 if (ypos1_string > ypos2_line)
915 ypos1_string = ypos2_line;
916 if (ypos2_string > ypos2_line)
917 ypos2_string = ypos2_line;
918
919 if (ypos1_line < ypos1_string)
920 {
921 redisplay_clear_region (window, findex, clear_start, ypos1_line,
922 clear_end - clear_start,
923 ypos1_string - ypos1_line);
924 }
925
926 if (ypos2_line > ypos2_string)
927 {
928 redisplay_clear_region (window, findex, clear_start, ypos2_string,
929 clear_end - clear_start,
930 ypos2_line - ypos2_string);
931 }
932 }
933 else
934 {
935 redisplay_clear_region (window, findex, clear_start,
936 DISPLAY_LINE_YPOS (dl), clear_end - clear_start,
937 height);
938 }
939 }
940
941 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value))
942 gc = x_get_gc (d, font, cursor_cachel->foreground,
943 cursor_cachel->background, Qnil, Qnil);
944 else if (cachel->dim)
945 {
946 /* Ensure the gray bitmap exists */
947 if (DEVICE_X_GRAY_PIXMAP (d) == None)
948 DEVICE_X_GRAY_PIXMAP (d) =
949 XCreateBitmapFromData (dpy, x_win, (char *)gray_bits,
950 gray_width, gray_height);
951
952 /* Request a GC with the gray stipple pixmap to draw dimmed text */
953 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
954 Qdim, Qnil);
955 }
956 else
957 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
958 Qnil, Qnil);
959
960 if (need_clipping)
961 {
962 XRectangle clip_box[1];
963
964 clip_box[0].x = 0;
965 clip_box[0].y = 0;
966 clip_box[0].width = clip_end - clip_start;
967 clip_box[0].height = height;
968
969 XSetClipRectangles (dpy, gc, clip_start, DISPLAY_LINE_YPOS (dl),
970 clip_box, 1, Unsorted);
971 }
972
973 if (runs[i].dimension == 1)
974 (bgc ? XDrawString : XDrawImageString) (dpy, x_win, gc, xpos,
975 dl->ypos, (char *) runs[i].ptr,
976 runs[i].len);
977 else
978 (bgc ? XDrawString16 : XDrawImageString16) (dpy, x_win, gc, xpos,
979 dl->ypos,
980 (XChar2b *) runs[i].ptr,
981 runs[i].len);
982
983 /* We draw underlines in the same color as the text. */
984 if (cachel->underline)
985 {
986 unsigned long upos, uthick;
987 XFontStruct *xfont;
988
989 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
990 if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos))
991 upos = dl->descent / 2;
992 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
993 uthick = 1;
994
995 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
996 {
997 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
998 uthick = dl->descent - dl->clip - upos;
999
1000 if (uthick == 1)
1001 {
1002 XDrawLine (dpy, x_win, gc, xpos, dl->ypos + upos,
1003 xpos + this_width, dl->ypos + upos);
1004 }
1005 else if (uthick > 1)
1006 {
1007 XFillRectangle (dpy, x_win, gc, xpos,
1008 dl->ypos + upos, this_width, uthick);
1009 }
1010 }
1011 }
1012
1013 if (cachel->strikethru) {
1014 unsigned long ascent,descent,upos, uthick;
1015 XFontStruct *xfont;
1016
1017 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
1018
1019 if (!XGetFontProperty (xfont, XA_STRIKEOUT_ASCENT, &ascent))
1020 ascent = xfont->ascent;
1021 if (!XGetFontProperty (xfont, XA_STRIKEOUT_DESCENT, &descent))
1022 descent = xfont->descent;
1023 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
1024 uthick = 1;
1025
1026 upos = ascent - ((ascent + descent) / 2) + 1;
1027
1028 /* Generally, upos will be positive (above the baseline),so subtract */
1029 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip)
1030 {
1031 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip)
1032 uthick = dl->descent - dl->clip + upos;
1033
1034 if (uthick == 1)
1035 {
1036 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos,
1037 xpos + this_width, dl->ypos - upos);
1038 }
1039 else if (uthick > 1)
1040 {
1041 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos,
1042 this_width, uthick);
1043 }
1044 }
1045 }
1046
1047 /* Restore the GC */
1048 if (need_clipping)
1049 {
1050 XSetClipMask (dpy, gc, None);
1051 XSetClipOrigin (dpy, gc, 0, 0);
1052 }
1053
1054 /* If we are actually superimposing the cursor then redraw with just
1055 the appropriate section highlighted. */
1056 if (cursor_clip && !cursor && focus && cursor_cachel)
1057 {
1058 GC cgc;
1059 XRectangle clip_box[1];
1060
1061 cgc = x_get_gc (d, font, cursor_cachel->foreground,
1062 cursor_cachel->background, Qnil, Qnil);
1063
1064 clip_box[0].x = 0;
1065 clip_box[0].y = 0;
1066 clip_box[0].width = cursor_width;
1067 clip_box[0].height = height;
1068
1069 XSetClipRectangles (dpy, cgc, cursor_start, DISPLAY_LINE_YPOS (dl),
1070 clip_box, 1, Unsorted);
1071
1072 if (runs[i].dimension == 1)
1073 XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
1074 (char *) runs[i].ptr, runs[i].len);
1075 else
1076 XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
1077 (XChar2b *) runs[i].ptr, runs[i].len);
1078
1079 XSetClipMask (dpy, cgc, None);
1080 XSetClipOrigin (dpy, cgc, 0, 0);
1081 }
1082
1083 xpos += this_width;
1084 }
1085
1086 /* Draw the non-focus box or bar-cursor as needed. */
1087 /* Can't this logic be simplified? */
1088 if (cursor_cachel
1089 && ((cursor && !focus && NILP (bar_cursor_value))
1090 || (cursor_width
1091 && (cursor_start + cursor_width >= clip_start)
1092 && !NILP (bar_cursor_value))))
1093 {
1094 int tmp_height, tmp_y;
1095 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1096 int need_clipping = (cursor_start < clip_start
1097 || clip_end < cursor_start + cursor_width);
1098
1099 /* #### This value is correct (as far as I know) because
1100 all of the times we need to draw this cursor, we will
1101 be called with exactly one character, so we know we
1102 can always use runs[0].
1103
1104 This is bogus as all hell, however. The cursor handling in
1105 this function is way bogus and desperately needs to be
1106 cleaned up. (In particular, the drawing of the cursor should
1107 really really be separated out of this function. This may be
1108 a bit tricky now because this function itself does way too
1109 much stuff, a lot of which needs to be moved into
1110 redisplay.c) This is the only way to be able to easily add
1111 new cursor types or (e.g.) make the bar cursor be able to
1112 span two characters instead of overlaying just one. */
1113 int bogusly_obtained_ascent_value =
1114 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent;
1115
1116 if (!NILP (bar_cursor_value))
1117 {
1118 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1119 make_int (bar_width));
1120 }
1121 else
1122 {
1123 gc = x_get_gc (d, Qnil, cursor_cachel->background,
1124 Qnil, Qnil, Qnil);
1125 }
1126
1127 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1128 tmp_height = cursor_height;
1129 if (tmp_y + tmp_height > (int) (DISPLAY_LINE_YPOS(dl) + height))
1130 {
1131 tmp_y = DISPLAY_LINE_YPOS (dl) + height - tmp_height;
1132 if (tmp_y < (int) DISPLAY_LINE_YPOS (dl))
1133 tmp_y = DISPLAY_LINE_YPOS (dl);
1134 tmp_height = DISPLAY_LINE_YPOS (dl) + height - tmp_y;
1135 }
1136
1137 if (need_clipping)
1138 {
1139 XRectangle clip_box[1];
1140 clip_box[0].x = 0;
1141 clip_box[0].y = 0;
1142 clip_box[0].width = clip_end - clip_start;
1143 clip_box[0].height = tmp_height;
1144 XSetClipRectangles (dpy, gc, clip_start, tmp_y,
1145 clip_box, 1, Unsorted);
1146 }
1147
1148 if (!focus && NILP (bar_cursor_value))
1149 {
1150 XDrawRectangle (dpy, x_win, gc, cursor_start, tmp_y,
1151 cursor_width - 1, tmp_height - 1);
1152 }
1153 else if (focus && !NILP (bar_cursor_value))
1154 {
1155 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1, tmp_y,
1156 cursor_start + bar_width - 1, tmp_y + tmp_height - 1);
1157 }
1158
1159 /* Restore the GC */
1160 if (need_clipping)
1161 {
1162 XSetClipMask (dpy, gc, None);
1163 XSetClipOrigin (dpy, gc, 0, 0);
1164 }
1165 }
1166 }
1167
1168 void
1169 x_output_x_pixmap (struct frame *f, struct Lisp_Image_Instance *p, int x,
1170 int y, int xoffset, int yoffset,
1171 int width, int height, unsigned long fg, unsigned long bg,
1172 GC override_gc)
1173 {
1174 struct device *d = XDEVICE (f->device);
1175 Display *dpy = DEVICE_X_DISPLAY (d);
1176 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1177
1178 GC gc;
1179 XGCValues gcv;
1180 unsigned long pixmap_mask;
1181
1182 if (!override_gc)
1183 {
1184 memset (&gcv, ~0, sizeof (XGCValues));
1185 gcv.graphics_exposures = False;
1186 gcv.foreground = fg;
1187 gcv.background = bg;
1188 pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
1189
1190 if (IMAGE_INSTANCE_X_MASK (p))
1191 {
1192 gcv.function = GXcopy;
1193 gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
1194 gcv.clip_x_origin = x - xoffset;
1195 gcv.clip_y_origin = y - yoffset;
1196 pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
1197 GCClipYOrigin);
1198 /* Can't set a clip rectangle because we already have a mask.
1199 Is it possible to get an equivalent effect by changing the
1200 args to XCopyArea below rather than messing with a clip box?
1201 - dkindred@cs.cmu.edu
1202 Yes. We don't clip at all now - andy@xemacs.org
1203 */
1204 }
1205
1206 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
1207 }
1208 else
1209 {
1210 gc = override_gc;
1211 /* override_gc might have a mask already--we don't want to nuke it.
1212 Maybe we can insist that override_gc have no mask, or use
1213 one of the suggestions above. */
1214 }
1215
1216 /* depth of 0 means it's a bitmap, not a pixmap, and we should use
1217 XCopyPlane (1 = current foreground color, 0 = background) instead
1218 of XCopyArea, which means that the bits in the pixmap are actual
1219 pixel values, instead of symbolic of fg/bg. */
1220 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
1221 {
1222 XCopyArea (dpy,
1223 IMAGE_INSTANCE_X_PIXMAP_SLICE
1224 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc, xoffset,
1225 yoffset, width,
1226 height, x, y);
1227 }
1228 else
1229 {
1230 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP_SLICE
1231 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc,
1232 xoffset, yoffset, width, height, x, y, 1L);
1233 }
1234 }
1235
1236 static void
1237 x_output_pixmap (struct window *w, Lisp_Object image_instance,
1238 struct display_box *db, struct display_glyph_area *dga,
1239 face_index findex, int cursor_start, int cursor_width,
1240 int cursor_height, int bg_pixmap)
1241 {
1242 struct frame *f = XFRAME (w->frame);
1243 struct device *d = XDEVICE (f->device);
1244 struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1245
1246 Display *dpy = DEVICE_X_DISPLAY (d);
1247 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1248
1249 /* Output the pixmap. */
1250 {
1251 Lisp_Object tmp_pixel;
1252 XColor tmp_bcolor, tmp_fcolor;
1253
1254 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1255 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1256 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1257 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1258
1259 x_output_x_pixmap (f, p, db->xpos, db->ypos,
1260 dga->xoffset, dga->yoffset,
1261 dga->width, dga->height,
1262 tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
1263 }
1264
1265 /* Draw a cursor over top of the pixmap. */
1266 if (cursor_width && cursor_height && (cursor_start >= db->xpos)
1267 && !NILP (w->text_cursor_visible_p)
1268 && (cursor_start < db->xpos + dga->width))
1269 {
1270 GC gc;
1271 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1272 struct face_cachel *cursor_cachel =
1273 WINDOW_FACE_CACHEL (w,
1274 get_builtin_face_cache_index
1275 (w, Vtext_cursor_face));
1276
1277 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1278
1279 if (cursor_width > db->xpos + dga->width - cursor_start)
1280 cursor_width = db->xpos + dga->width - cursor_start;
1281
1282 if (focus)
1283 {
1284 XFillRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1285 cursor_height);
1286 }
1287 else
1288 {
1289 XDrawRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1290 cursor_height);
1291 }
1292 }
1293 }
1294
1295 /*****************************************************************************
1296 x_output_vertical_divider
1297
1298 Draw a vertical divider down the right side of the given window.
1299 ****************************************************************************/
1300 static void
1301 x_output_vertical_divider (struct window *w, int clear)
1302 {
1303 struct frame *f = XFRAME (w->frame);
1304 struct device *d = XDEVICE (f->device);
1305
1306 Display *dpy = DEVICE_X_DISPLAY (d);
1307 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1308 Lisp_Object tmp_pixel;
1309 XColor tmp_color;
1310 XGCValues gcv;
1311 GC background_gc;
1312 enum edge_style style;
1313
1314 unsigned long mask;
1315 int x, y1, y2, width, shadow_thickness, spacing, line_width;
1316 face_index div_face = get_builtin_face_cache_index (w, Vvertical_divider_face);
1317
1318 width = window_divider_width (w);
1319 shadow_thickness = XINT (w->vertical_divider_shadow_thickness);
1320 spacing = XINT (w->vertical_divider_spacing);
1321 line_width = XINT (w->vertical_divider_line_width);
1322 x = WINDOW_RIGHT (w) - width;
1323 y1 = WINDOW_TOP (w) + FRAME_TOP_GUTTER_BOUNDS (f);
1324 y2 = WINDOW_BOTTOM (w) + FRAME_BOTTOM_GUTTER_BOUNDS (f);
1325
1326 memset (&gcv, ~0, sizeof (XGCValues));
1327
1328 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1329 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1330
1331 /* First, get the GC's. */
1332 gcv.background = tmp_color.pixel;
1333 gcv.foreground = tmp_color.pixel;
1334 gcv.graphics_exposures = False;
1335 mask = GCForeground | GCBackground | GCGraphicsExposures;
1336 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1337
1338 /* Clear the divider area first. This needs to be done when a
1339 window split occurs. */
1340 if (clear)
1341 XClearArea (dpy, x_win, x, y1, width, y2 - y1, False);
1342
1343 /* Draw the divider line. */
1344 XFillRectangle (dpy, x_win, background_gc,
1345 x + spacing + shadow_thickness, y1,
1346 line_width, y2 - y1);
1347
1348 if (shadow_thickness < 0)
1349 {
1350 shadow_thickness = -shadow_thickness;
1351 style = EDGE_BEVEL_IN;
1352 }
1353 else
1354 {
1355 style = EDGE_BEVEL_OUT;
1356 }
1357
1358 /* Draw the shadows around the divider line */
1359 x_bevel_area (w, div_face, x + spacing, y1,
1360 width - 2 * spacing, y2 - y1,
1361 shadow_thickness, EDGE_ALL, style);
1362 }
1363
1364 /*****************************************************************************
1365 x_output_blank
1366
1367 Output a blank by clearing the area it covers in the foreground color
1368 of its face.
1369 ****************************************************************************/
1370 static void
1371 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
1372 int start_pixpos, int cursor_start, int cursor_width)
1373 {
1374 struct frame *f = XFRAME (w->frame);
1375 struct device *d = XDEVICE (f->device);
1376
1377 Display *dpy = DEVICE_X_DISPLAY (d);
1378 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1379 GC gc;
1380 struct face_cachel *cursor_cachel =
1381 WINDOW_FACE_CACHEL (w,
1382 get_builtin_face_cache_index
1383 (w, Vtext_cursor_face));
1384 Lisp_Object bg_pmap;
1385 Lisp_Object buffer = WINDOW_BUFFER (w);
1386 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1387 buffer);
1388
1389 int x = rb->xpos;
1390 int y = DISPLAY_LINE_YPOS (dl);
1391 int width = rb->width;
1392 int height = DISPLAY_LINE_HEIGHT (dl);
1393
1394 /* Unmap all subwindows in the area we are going to blank. */
1395 redisplay_unmap_subwindows_maybe (f, x, y, width, height);
1396
1397 if (start_pixpos > x)
1398 {
1399 if (start_pixpos >= (x + width))
1400 return;
1401 else
1402 {
1403 width -= (start_pixpos - x);
1404 x = start_pixpos;
1405 }
1406 }
1407
1408 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
1409 if (!IMAGE_INSTANCEP (bg_pmap)
1410 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
1411 bg_pmap = Qnil;
1412
1413 if (NILP (bg_pmap))
1414 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1415 Qnil, Qnil, Qnil);
1416 else
1417 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1418 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
1419 Qnil);
1420
1421 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1422
1423 /* If this rune is marked as having the cursor, then it is actually
1424 representing a tab. */
1425 if (!NILP (w->text_cursor_visible_p)
1426 && (rb->cursor_type == CURSOR_ON
1427 || (cursor_width
1428 && (cursor_start + cursor_width > x)
1429 && cursor_start < (x + width))))
1430 {
1431 int cursor_height, cursor_y;
1432 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1433 struct Lisp_Font_Instance *fi;
1434
1435 fi = XFONT_INSTANCE (FACE_CACHEL_FONT
1436 (WINDOW_FACE_CACHEL (w, rb->findex),
1437 Vcharset_ascii));
1438
1439 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1440
1441 cursor_y = dl->ypos - fi->ascent;
1442 cursor_height = fi->height;
1443 if (cursor_y + cursor_height > y + height)
1444 cursor_height = y + height - cursor_y;
1445
1446 if (focus)
1447 {
1448 if (NILP (bar_cursor_value))
1449 {
1450 XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1451 fi->width, cursor_height);
1452 }
1453 else
1454 {
1455 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1456
1457 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1458 make_int (bar_width));
1459 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
1460 cursor_y, cursor_start + bar_width - 1,
1461 cursor_y + cursor_height - 1);
1462 }
1463 }
1464 else if (NILP (bar_cursor_value))
1465 {
1466 XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1467 fi->width - 1, cursor_height - 1);
1468 }
1469 }
1470 }
1471
1472 /*****************************************************************************
1473 x_output_hline
1474
1475 Output a horizontal line in the foreground of its face.
1476 ****************************************************************************/
1477 static void
1478 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
1479 {
1480 struct frame *f = XFRAME (w->frame);
1481 struct device *d = XDEVICE (f->device);
1482
1483 Display *dpy = DEVICE_X_DISPLAY (d);
1484 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1485 GC gc;
1486
1487 int x = rb->xpos;
1488 int width = rb->width;
1489 int height = DISPLAY_LINE_HEIGHT (dl);
1490 int ypos1, ypos2, ypos3, ypos4;
1491
1492 ypos1 = DISPLAY_LINE_YPOS (dl);
1493 ypos2 = ypos1 + rb->object.hline.yoffset;
1494 ypos3 = ypos2 + rb->object.hline.thickness;
1495 ypos4 = dl->ypos + dl->descent - dl->clip;
1496
1497 /* First clear the area not covered by the line. */
1498 if (height - rb->object.hline.thickness > 0)
1499 {
1500 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1501 Qnil, Qnil, Qnil);
1502
1503 if (ypos2 - ypos1 > 0)
1504 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1505 if (ypos4 - ypos3 > 0)
1506 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1507 }
1508
1509 /* Now draw the line. */
1510 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1511 Qnil, Qnil, Qnil);
1512
1513 if (ypos2 < ypos1)
1514 ypos2 = ypos1;
1515 if (ypos3 > ypos4)
1516 ypos3 = ypos4;
1517
1518 if (ypos3 - ypos2 > 0)
1519 XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1520 }
1521
1522 /*****************************************************************************
1523 x_output_shadows
1524
1525 Draw a shadow around the given area using the given GC's. It is the
1526 callers responsibility to set the GC's appropriately.
1527 ****************************************************************************/
1528 void
1529 x_output_shadows (struct frame *f, int x, int y, int width, int height,
1530 GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
1531 int shadow_thickness, int edges)
1532 {
1533 struct device *d = XDEVICE (f->device);
1534
1535 Display *dpy = DEVICE_X_DISPLAY (d);
1536 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1537
1538 XSegment top_shadow[20], bottom_shadow[20];
1539 int elt;
1540
1541 if (shadow_thickness > 10)
1542 shadow_thickness = 10;
1543 else if (shadow_thickness < 0)
1544 shadow_thickness = 0;
1545 if (shadow_thickness > (width / 2))
1546 shadow_thickness = width / 2;
1547 if (shadow_thickness > (height / 2))
1548 shadow_thickness = height / 2;
1549
1550 for (elt = 0; elt < shadow_thickness; elt++)
1551 {
1552 int seg1 = elt;
1553 int seg2 = (edges & EDGE_TOP) ? elt + shadow_thickness : elt;
1554 int bot_seg2 = (edges & EDGE_BOTTOM) ? elt + shadow_thickness : elt;
1555
1556 if (edges & EDGE_TOP)
1557 {
1558 top_shadow[seg1].x1 = x + elt;
1559 top_shadow[seg1].x2 = x + width - elt - 1;
1560 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
1561 }
1562 if (edges & EDGE_LEFT)
1563 {
1564 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
1565 top_shadow[seg2].y1 = y + elt;
1566 top_shadow[seg2].y2 = y + height - elt - 1;
1567 }
1568 if (edges & EDGE_BOTTOM)
1569 {
1570 bottom_shadow[seg1].x1 = x + elt;
1571 bottom_shadow[seg1].x2 = x + width - elt - 1;
1572 bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
1573 }
1574 if (edges & EDGE_RIGHT)
1575 {
1576 bottom_shadow[bot_seg2].x1 = bottom_shadow[bot_seg2].x2 = x + width - elt - 1;
1577 bottom_shadow[bot_seg2].y1 = y + elt;
1578 bottom_shadow[bot_seg2].y2 = y + height - elt - 1;
1579 }
1580 }
1581
1582 XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow,
1583 ((edges & EDGE_TOP) ? shadow_thickness : 0)
1584 + ((edges & EDGE_LEFT) ? shadow_thickness : 0));
1585 XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
1586 ((edges & EDGE_BOTTOM) ? shadow_thickness : 0)
1587 + ((edges & EDGE_RIGHT) ? shadow_thickness : 0));
1588 }
1589
1590 /*****************************************************************************
1591 x_generate_shadow_pixels
1592
1593 Given three pixels (top shadow, bottom shadow, background) massage
1594 the top and bottom shadow colors to guarantee that they differ. The
1595 background pixels are not allowed to be modified.
1596
1597 This function modifies its parameters.
1598
1599 This code is modified from code blatantly stolen from lwlib/xlwmenu.c
1600 ****************************************************************************/
1601 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
1602 ? ((unsigned long) (x)) : ((unsigned long) (y)))
1603
1604 void
1605 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
1606 unsigned long *bottom_shadow,
1607 unsigned long background,
1608 unsigned long core_background)
1609 {
1610 struct device *d = XDEVICE (f->device);
1611 Display *dpy = DEVICE_X_DISPLAY (d);
1612 Colormap cmap = DEVICE_X_COLORMAP (d);
1613 Visual *visual = DEVICE_X_VISUAL (d);
1614
1615 XColor topc, botc;
1616 int top_frobbed = 0, bottom_frobbed = 0;
1617
1618 /* If the top shadow is the same color as the background, try to
1619 adjust it. */
1620 if (*top_shadow == background)
1621 {
1622 topc.pixel = background;
1623 XQueryColor (dpy, cmap, &topc);
1624 /* don't overflow/wrap! */
1625 topc.red = MINL (65535, (unsigned long) topc.red * 6 / 5);
1626 topc.green = MINL (65535, (unsigned long) topc.green * 6 / 5);
1627 topc.blue = MINL (65535, (unsigned long) topc.blue * 6 / 5);
1628 if (allocate_nearest_color (dpy, cmap, visual, &topc))
1629 {
1630 *top_shadow = topc.pixel;
1631 top_frobbed = 1;
1632 }
1633 }
1634
1635 /* If the bottom shadow is the same color as the background, try to
1636 adjust it. */
1637 if (*bottom_shadow == background)
1638 {
1639 botc.pixel = background;
1640 XQueryColor (dpy, cmap, &botc);
1641 botc.red = (unsigned short) ((unsigned long) botc.red * 3 / 5);
1642 botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5);
1643 botc.blue = (unsigned short) ((unsigned long) botc.blue * 3 / 5);
1644 if (allocate_nearest_color (dpy, cmap, visual, &botc))
1645 {
1646 *bottom_shadow = botc.pixel;
1647 bottom_frobbed = 1;
1648 }
1649 }
1650
1651 /* If we had to adjust both shadows, then we have to do some
1652 additional work. */
1653 if (top_frobbed && bottom_frobbed)
1654 {
1655 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
1656 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
1657 if (bot_avg > top_avg)
1658 {
1659 Pixel tmp = *top_shadow;
1660
1661 *top_shadow = *bottom_shadow;
1662 *bottom_shadow = tmp;
1663 }
1664 else if (topc.pixel == botc.pixel)
1665 {
1666 if (botc.pixel == background)
1667 *top_shadow = core_background;
1668 else
1669 *bottom_shadow = background;
1670 }
1671 }
1672 }
1673
1674 /*****************************************************************************
1675 x_redraw_exposed_window
1676
1677 Given a bounding box for an area that needs to be redrawn, determine
1678 what parts of what lines are contained within and re-output their
1679 contents.
1680 ****************************************************************************/
1681 static void
1682 x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
1683 {
1684 struct frame *f = XFRAME (w->frame);
1685 int line;
1686 int start_x, start_y, end_x, end_y;
1687 int orig_windows_structure_changed;
1688
1689 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1690
1691 if (!NILP (w->vchild))
1692 {
1693 x_redraw_exposed_windows (w->vchild, x, y, width, height);
1694 return;
1695 }
1696 else if (!NILP (w->hchild))
1697 {
1698 x_redraw_exposed_windows (w->hchild, x, y, width, height);
1699 return;
1700 }
1701
1702 /* If the window doesn't intersect the exposed region, we're done here. */
1703 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w)
1704 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w))
1705 {
1706 return;
1707 }
1708 else
1709 {
1710 start_x = max (WINDOW_LEFT (w), x);
1711 end_x = min (WINDOW_RIGHT (w), (x + width));
1712 start_y = max (WINDOW_TOP (w), y);
1713 end_y = min (WINDOW_BOTTOM (w), y + height);
1714
1715 /* We do this to make sure that the 3D modelines get redrawn if
1716 they are in the exposed region. */
1717 orig_windows_structure_changed = f->windows_structure_changed;
1718 f->windows_structure_changed = 1;
1719 }
1720
1721 if (window_needs_vertical_divider (w))
1722 {
1723 x_output_vertical_divider (w, 0);
1724 }
1725
1726 for (line = 0; line < Dynarr_length (cdla); line++)
1727 {
1728 struct display_line *cdl = Dynarr_atp (cdla, line);
1729 int top_y = cdl->ypos - cdl->ascent;
1730 int bottom_y = cdl->ypos + cdl->descent;
1731
1732 if (bottom_y >= start_y)
1733 {
1734 if (top_y > end_y)
1735 {
1736 if (line == 0)
1737 continue;
1738 else
1739 break;
1740 }
1741 else
1742 {
1743 output_display_line (w, 0, cdla, line, start_x, end_x);
1744 }
1745 }
1746 }
1747
1748 f->windows_structure_changed = orig_windows_structure_changed;
1749
1750 /* If there have never been any face cache_elements created, then this
1751 expose event doesn't actually have anything to do. */
1752 if (Dynarr_largest (w->face_cachels))
1753 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
1754 }
1755
1756 /*****************************************************************************
1757 x_redraw_exposed_windows
1758
1759 For each window beneath the given window in the window hierarchy,
1760 ensure that it is redrawn if necessary after an Expose event.
1761 ****************************************************************************/
1762 static void
1763 x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
1764 int height)
1765 {
1766 for (; !NILP (window); window = XWINDOW (window)->next)
1767 x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
1768 }
1769
1770 /*****************************************************************************
1771 x_redraw_exposed_area
1772
1773 For each window on the given frame, ensure that any area in the
1774 Exposed area is redrawn.
1775 ****************************************************************************/
1776 void
1777 x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
1778 {
1779 /* If any window on the frame has had its face cache reset then the
1780 redisplay structures are effectively invalid. If we attempt to
1781 use them we'll blow up. We mark the frame as changed to ensure
1782 that redisplay will do a full update. This probably isn't
1783 necessary but it can't hurt. */
1784
1785 #ifdef HAVE_TOOLBARS
1786 /* #### We would rather put these off as well but there is currently
1787 no combination of flags which will force an unchanged toolbar to
1788 redraw anyhow. */
1789 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
1790 #endif
1791 redraw_exposed_gutters (f, x, y, width, height);
1792
1793 if (!f->window_face_cache_reset)
1794 {
1795 x_redraw_exposed_windows (f->root_window, x, y, width, height);
1796
1797 XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
1798 }
1799 else
1800 MARK_FRAME_CHANGED (f);
1801 }
1802
1803 /****************************************************************************
1804 x_clear_region
1805
1806 Clear the area in the box defined by the given parameters using the
1807 given face.
1808 ****************************************************************************/
1809 static void
1810 x_clear_region (Lisp_Object locale, struct device* d, struct frame* f, face_index findex,
1811 int x, int y,
1812 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1813 Lisp_Object background_pixmap)
1814 {
1815 Display *dpy;
1816 Window x_win;
1817 GC gc = NULL;
1818
1819 dpy = DEVICE_X_DISPLAY (d);
1820 x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1821
1822 if (!UNBOUNDP (background_pixmap))
1823 {
1824 gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
1825 }
1826
1827 if (gc)
1828 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1829 else
1830 XClearArea (dpy, x_win, x, y, width, height, False);
1831 }
1832
1833 /*****************************************************************************
1834 x_output_eol_cursor
1835
1836 Draw a cursor at the end of a line. The end-of-line cursor is
1837 narrower than the normal cursor.
1838 ****************************************************************************/
1839 static void
1840 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos,
1841 face_index findex)
1842 {
1843 struct frame *f = XFRAME (w->frame);
1844 struct device *d = XDEVICE (f->device);
1845 Lisp_Object window;
1846
1847 Display *dpy = DEVICE_X_DISPLAY (d);
1848 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1849 GC gc;
1850 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
1851 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
1852
1853 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1854 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1855 WINDOW_BUFFER (w));
1856
1857 int x = xpos;
1858 int y = DISPLAY_LINE_YPOS (dl);
1859 int width = EOL_CURSOR_WIDTH;
1860 int height = DISPLAY_LINE_HEIGHT (dl);
1861 int cursor_height, cursor_y;
1862 int defheight, defascent;
1863
1864 XSETWINDOW (window, w);
1865 redisplay_clear_region (window, findex, x, y, width, height);
1866
1867 if (NILP (w->text_cursor_visible_p))
1868 return;
1869
1870 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1871
1872 default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
1873
1874 /* make sure the cursor is entirely contained between y and y+height */
1875 cursor_height = min (defheight, height);
1876 cursor_y = max (y, min (y + height - cursor_height,
1877 dl->ypos - defascent));
1878
1879 if (focus)
1880 {
1881 #ifdef HAVE_XIM
1882 XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2);
1883 #endif /* HAVE_XIM */
1884
1885 if (NILP (bar_cursor_value))
1886 {
1887 XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
1888 }
1889 else
1890 {
1891 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1892
1893 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1894 make_int (bar_width));
1895 XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
1896 x + bar_width - 1, cursor_y + cursor_height - 1);
1897 }
1898 }
1899 else if (NILP (bar_cursor_value))
1900 {
1901 XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
1902 cursor_height - 1);
1903 }
1904 }
1905
1906 static void
1907 x_clear_frame_window (Lisp_Object window)
1908 {
1909 struct window *w = XWINDOW (window);
1910
1911 if (!NILP (w->vchild))
1912 {
1913 x_clear_frame_windows (w->vchild);
1914 return;
1915 }
1916
1917 if (!NILP (w->hchild))
1918 {
1919 x_clear_frame_windows (w->hchild);
1920 return;
1921 }
1922
1923 redisplay_clear_to_window_end (w, WINDOW_TEXT_TOP (w),
1924 WINDOW_TEXT_BOTTOM (w));
1925 }
1926
1927 static void
1928 x_clear_frame_windows (Lisp_Object window)
1929 {
1930 for (; !NILP (window); window = XWINDOW (window)->next)
1931 x_clear_frame_window (window);
1932 }
1933
1934 static void
1935 x_clear_frame (struct frame *f)
1936 {
1937 struct device *d = XDEVICE (f->device);
1938 Display *dpy = DEVICE_X_DISPLAY (d);
1939 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1940 int x, y, width, height;
1941 Lisp_Object frame;
1942
1943 x = FRAME_LEFT_BORDER_START (f);
1944 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
1945 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
1946 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) -
1947 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f));
1948 /* #### This adjustment by 1 should be being done in the macros.
1949 There is some small differences between when the menubar is on
1950 and off that we still need to deal with. */
1951 y = FRAME_TOP_BORDER_START (f) - 1;
1952 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
1953 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
1954 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) -
1955 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1;
1956
1957 XClearArea (dpy, x_win, x, y, width, height, False);
1958
1959 XSETFRAME (frame, f);
1960
1961 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
1962 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
1963 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
1964 {
1965 x_clear_frame_windows (f->root_window);
1966 }
1967
1968 XFlush (DEVICE_X_DISPLAY (d));
1969 }
1970
1971 /* briefly swap the foreground and background colors.
1972 */
1973
1974 static int
1975 x_flash (struct device *d)
1976 {
1977 Display *dpy;
1978 Window win;
1979 XGCValues gcv;
1980 GC gc;
1981 XColor tmp_fcolor, tmp_bcolor;
1982 Lisp_Object tmp_pixel, frame;
1983 struct frame *f = device_selected_frame (d);
1984 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f));
1985 Widget shell = FRAME_X_SHELL_WIDGET (f);
1986
1987 XSETFRAME (frame, f);
1988
1989 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
1990 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1991 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
1992 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1993
1994 dpy = XtDisplay (shell);
1995 win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1996 memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
1997 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
1998 gcv.function = GXxor;
1999 gcv.graphics_exposures = False;
2000 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
2001 (GCForeground | GCFunction | GCGraphicsExposures));
2002 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2003 w->pixel_width, w->pixel_height);
2004 XSync (dpy, False);
2005
2006 #ifdef HAVE_SELECT
2007 {
2008 int usecs = 100000;
2009 struct timeval tv;
2010 tv.tv_sec = usecs / 1000000L;
2011 tv.tv_usec = usecs % 1000000L;
2012 /* I'm sure someone is going to complain about this... */
2013 select (0, 0, 0, 0, &tv);
2014 }
2015 #else
2016 #ifdef HAVE_POLL
2017 poll (0, 0, 100);
2018 #else /* !HAVE_POLL */
2019 bite me
2020 #endif /* HAVE_POLL */
2021 #endif /* HAVE_SELECT */
2022
2023 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2024 w->pixel_width, w->pixel_height);
2025 XSync (dpy, False);
2026
2027 return 1;
2028 }
2029
2030 /* Make audible bell. */
2031
2032 static void
2033 x_ring_bell (struct device *d, int volume, int pitch, int duration)
2034 {
2035 Display *display = DEVICE_X_DISPLAY (d);
2036
2037 if (volume < 0) volume = 0;
2038 else if (volume > 100) volume = 100;
2039 if (pitch < 0 && duration < 0)
2040 {
2041 XBell (display, (volume * 2) - 100);
2042 XFlush (display);
2043 }
2044 else
2045 {
2046 XKeyboardState state;
2047 XKeyboardControl ctl;
2048 XSync (display, 0);
2049 /* #### grab server? */
2050 XGetKeyboardControl (display, &state);
2051
2052 ctl.bell_pitch = (pitch >= 0 ? pitch : state.bell_pitch);
2053 ctl.bell_duration = (duration >= 0 ? duration : state.bell_duration);
2054 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2055
2056 XBell (display, (volume * 2) - 100);
2057
2058 ctl.bell_pitch = state.bell_pitch;
2059 ctl.bell_duration = state.bell_duration;
2060 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2061
2062 /* #### ungrab server? */
2063 XSync (display, 0);
2064 }
2065 }
2066
2067
2068 /************************************************************************/
2069 /* initialization */
2070 /************************************************************************/
2071
2072 void
2073 console_type_create_redisplay_x (void)
2074 {
2075 /* redisplay methods */
2076 CONSOLE_HAS_METHOD (x, text_width);
2077 CONSOLE_HAS_METHOD (x, output_display_block);
2078 CONSOLE_HAS_METHOD (x, divider_height);
2079 CONSOLE_HAS_METHOD (x, eol_cursor_width);
2080 CONSOLE_HAS_METHOD (x, output_vertical_divider);
2081 CONSOLE_HAS_METHOD (x, clear_region);
2082 CONSOLE_HAS_METHOD (x, clear_frame);
2083 CONSOLE_HAS_METHOD (x, output_begin);
2084 CONSOLE_HAS_METHOD (x, output_end);
2085 CONSOLE_HAS_METHOD (x, flash);
2086 CONSOLE_HAS_METHOD (x, ring_bell);
2087 CONSOLE_HAS_METHOD (x, bevel_area);
2088 CONSOLE_HAS_METHOD (x, output_string);
2089 CONSOLE_HAS_METHOD (x, output_pixmap);
2090 }