comparison src/redisplay-msw.c @ 213:78f53ef88e17 r20-4b5

Import from CVS: tag r20-4b5
author cvs
date Mon, 13 Aug 2007 10:06:47 +0200
parents
children 1f0dabaa0855
comparison
equal deleted inserted replaced
212:d8688acf4c5b 213:78f53ef88e17
1 /* mswindows 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 /* Authorship:
26
27 Chuck Thompson
28 Lots of work done by Ben Wing for Mule
29 Partially rewritten for mswindows by Jonathan Harris, November 1997 for 20.4.
30 */
31
32 #include <config.h>
33 #include "lisp.h"
34
35 #include "console-msw.h"
36 #include "objects-msw.h"
37
38 #include "buffer.h"
39 #include "debug.h"
40 #include "events.h"
41 #include "faces.h"
42 #include "frame.h"
43 #include "glyphs.h" /* XXX FIXME: Should be glyphs-mswindows when we make one */
44 #include "redisplay.h"
45 #include "sysdep.h"
46 #include "window.h"
47
48 #include "windows.h"
49
50 /* MSWINDOWS_DIVIDER_LINE_WIDTH is the width of the line drawn in the gutter.
51 MSWINDOWS_DIVIDER_SPACING is the amount of blank space on each side of the line.
52 MSWINDOWS_DIVIDER_WIDTH = MSWINDOWS_DIVIDER_LINE_WIDTH + 2*MSWINDOWS_DIVIDER_SPACING
53 */
54 #define MSWINDOWS_DIVIDER_LINE_WIDTH 7
55 #define MSWINDOWS_DIVIDER_SPACING 0
56 #define MSWINDOWS_DIVIDER_WIDTH (MSWINDOWS_DIVIDER_LINE_WIDTH + 2 * MSWINDOWS_DIVIDER_SPACING)
57
58 #define MSWINDOWS_EOL_CURSOR_WIDTH 5
59
60 /*
61 * Random forward delarations
62 */
63 static void mswindows_clear_region (Lisp_Object locale, face_index findex,
64 int x, int y, int width, int height);
65 static void mswindows_output_vertical_divider (struct window *w, int clear);
66 static void mswindows_redraw_exposed_windows (Lisp_Object window, int x,
67 int y, int width, int height);
68
69
70
71 typedef struct textual_run
72 {
73 Lisp_Object charset;
74 unsigned char *ptr;
75 int len;
76 int dimension;
77 } textual_run;
78
79 /* Separate out the text in DYN into a series of textual runs of a
80 particular charset. Also convert the characters as necessary into
81 the format needed by XDrawImageString(), XDrawImageString16(), et
82 al. (This means converting to one or two byte format, possibly
83 tweaking the high bits, and possibly running a CCL program.) You
84 must pre-allocate the space used and pass it in. (This is done so
85 you can alloca() the space.) You need to allocate (2 * len) bytes
86 of TEXT_STORAGE and (len * sizeof (textual_run)) bytes of
87 RUN_STORAGE, where LEN is the length of the dynarr.
88
89 Returns the number of runs actually used. */
90
91 static int
92 separate_textual_runs (unsigned char *text_storage,
93 textual_run *run_storage,
94 CONST Emchar *str, Charcount len)
95 {
96 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a
97 possible valid charset when
98 MULE is not defined */
99 int runs_so_far = 0;
100 int i;
101 #ifdef MULE
102 struct ccl_program char_converter;
103 int need_ccl_conversion = 0;
104 #endif
105
106 for (i = 0; i < len; i++)
107 {
108 Emchar ch = str[i];
109 Lisp_Object charset;
110 int byte1, byte2;
111 int dimension;
112 int graphic;
113
114 BREAKUP_CHAR (ch, charset, byte1, byte2);
115 dimension = XCHARSET_DIMENSION (charset);
116 graphic = XCHARSET_GRAPHIC (charset);
117
118 if (!EQ (charset, prev_charset))
119 {
120 run_storage[runs_so_far].ptr = text_storage;
121 run_storage[runs_so_far].charset = charset;
122 run_storage[runs_so_far].dimension = dimension;
123
124 if (runs_so_far)
125 {
126 run_storage[runs_so_far - 1].len =
127 text_storage - run_storage[runs_so_far - 1].ptr;
128 if (run_storage[runs_so_far - 1].dimension == 2)
129 run_storage[runs_so_far - 1].len >>= 1;
130 }
131 runs_so_far++;
132 prev_charset = charset;
133 #ifdef MULE
134 {
135 Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset);
136 need_ccl_conversion = !NILP (ccl_prog);
137 if (need_ccl_conversion)
138 setup_ccl_program (&char_converter, ccl_prog);
139 }
140 #endif
141 }
142
143 if (graphic == 0)
144 {
145 byte1 &= 0x7F;
146 byte2 &= 0x7F;
147 }
148 else if (graphic == 1)
149 {
150 byte1 |= 0x80;
151 byte2 |= 0x80;
152 }
153 #ifdef MULE
154 if (need_ccl_conversion)
155 {
156 char_converter.reg[0] = XCHARSET_ID (charset);
157 char_converter.reg[1] = byte1;
158 char_converter.reg[2] = byte2;
159 char_converter.ic = 0; /* start at beginning each time */
160 ccl_driver (&char_converter, 0, 0, 0, 0);
161 byte1 = char_converter.reg[1];
162 byte2 = char_converter.reg[2];
163 }
164 #endif
165 *text_storage++ = (unsigned char) byte1;
166 if (dimension == 2)
167 *text_storage++ = (unsigned char) byte2;
168 }
169
170 if (runs_so_far)
171 {
172 run_storage[runs_so_far - 1].len =
173 text_storage - run_storage[runs_so_far - 1].ptr;
174 if (run_storage[runs_so_far - 1].dimension == 2)
175 run_storage[runs_so_far - 1].len >>= 1;
176 }
177
178 return runs_so_far;
179 }
180
181
182 static int
183 mswindows_text_width_single_run (HDC hdc, struct face_cachel *cachel,
184 textual_run *run)
185 {
186 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
187 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
188 SIZE size;
189
190 #if 0 /* XXX HACK: mswindows_text_width is broken and will pass in a NULL hdc */
191 if (!fi->proportional_p)
192 #else
193 if (!fi->proportional_p || !hdc)
194 #endif
195 return (fi->width * run->len);
196 else
197 {
198 assert(run->dimension == 1); /* XXX FIXME! */
199 GetTextExtentPoint32(hdc, run->ptr, run->len, &size);
200 return(size.cx);
201 }
202 }
203
204
205 /*****************************************************************************
206 mswindows_update_gc
207
208 Given a number of parameters munge the GC so it has those properties.
209 ****************************************************************************/
210 static void
211 mswindows_update_gc (HDC hdc, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
212 Lisp_Object bg_pmap, Lisp_Object lwidth)
213 {
214 if (!NILP (font))
215 SelectObject(hdc, (XFONT_INSTANCE (font))->data);
216
217 /* evil kludge! - XXX do we need this? */
218 if (!NILP (fg) && !COLOR_INSTANCEP (fg))
219 {
220 fprintf (stderr, "Help! mswindows_update_gc got a bogus fg value! fg = ");
221 debug_print (fg);
222 fg = Qnil;
223 }
224
225 if (!NILP (fg))
226 SetTextColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (fg)));
227
228 if (!NILP (bg))
229 SetBkColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (bg)));
230
231 #if 0 /* XXX Implement me */
232 /* I expect that the Lisp_Image_Instance's data will point to a brush */
233 if (IMAGE_INSTANCEP (bg_pmap)
234 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
235 {
236 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
237 {
238 gcv.fill_style = FillOpaqueStippled;
239 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
240 mask |= (GCStipple | GCFillStyle);
241 }
242 else
243 {
244 gcv.fill_style = FillTiled;
245 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
246 mask |= (GCTile | GCFillStyle);
247 }
248 }
249 #endif
250
251 #if 0 /* XXX FIXME */
252 if (!NILP (lwidth))
253 {
254 gcv.line_width = XINT (lwidth);
255 mask |= GCLineWidth;
256 }
257 #endif
258 }
259
260
261 /*****************************************************************************
262 mswindows_output_hline
263
264 Output a horizontal line in the foreground of its face.
265 ****************************************************************************/
266 static void
267 mswindows_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
268 { /* XXX Implement me */
269 }
270
271
272 /*****************************************************************************
273 mswindows_output_blank
274
275 Output a blank by clearing the area it covers in the background color
276 of its face.
277 ****************************************************************************/
278 static void
279 mswindows_output_blank (struct window *w, struct display_line *dl, struct rune *rb)
280 {
281 struct frame *f = XFRAME (w->frame);
282 RECT rect = { rb->xpos, dl->ypos-dl->ascent,
283 rb->xpos+rb->width, dl->ypos+dl->descent-dl->clip };
284 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, rb->findex);
285
286 Lisp_Object bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
287
288 if (!IMAGE_INSTANCEP (bg_pmap)
289 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
290 bg_pmap = Qnil;
291
292 FillRect (FRAME_MSWINDOWS_DC (f), &rect,
293 COLOR_INSTANCE_MSWINDOWS_BRUSH (XCOLOR_INSTANCE (cachel->background)));
294 }
295
296
297 /*****************************************************************************
298 mswindows_output_cursor
299
300 Draw a normal or end-of-line cursor. The end-of-line cursor is
301 narrower than the normal cursor.
302 ****************************************************************************/
303 static void
304 mswindows_output_cursor (struct window *w, struct display_line *dl, int xpos,
305 int width, struct rune *rb)
306 {
307 struct frame *f = XFRAME (w->frame);
308 struct device *d = XDEVICE (f->device);
309 struct face_cachel *cachel;
310 Lisp_Object font;
311 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
312 HBRUSH brush;
313 HDC hdc = FRAME_MSWINDOWS_DC (f);
314 int real_char_p = (rb->type == RUNE_CHAR && rb->object.chr.ch != '\n');
315 RECT rect = { xpos,
316 dl->ypos - dl->ascent,
317 xpos + width,
318 dl->ypos + dl->descent - dl->clip};
319
320 #if 0 /* XXX FIXME: Whar about the bar_cursor? */
321 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
322 WINDOW_BUFFER (w));
323 #endif
324
325 if (real_char_p)
326 {
327 /* Use the font from the underlying character */
328 cachel = WINDOW_FACE_CACHEL (w, rb->findex);
329
330 /* XXX MULE: Need to know the charset! */
331 font = FACE_CACHEL_FONT (cachel, Vcharset_ascii);
332 }
333
334 /* Clear the area */
335 if (focus)
336 cachel = WINDOW_FACE_CACHEL (w,
337 get_builtin_face_cache_index (w, Vtext_cursor_face));
338 else if (!real_char_p)
339 cachel = WINDOW_FACE_CACHEL (w, rb->findex);
340
341 brush = COLOR_INSTANCE_MSWINDOWS_BRUSH (XCOLOR_INSTANCE (cachel->background));
342 FillRect (hdc, &rect, brush);
343
344 if (real_char_p)
345 {
346 /* XXX FIXME: Need to clip if dl->clip!=0. How rare is this case? */
347 /* Output the underlying character */
348 mswindows_update_gc (hdc, font, cachel->foreground,
349 cachel->background, Qnil, Qnil);
350 TextOut(hdc, xpos, dl->ypos, (char*) &rb->object.chr.ch, 1);
351 }
352
353 if (!focus)
354 {
355 /* Draw hollow rectangle in cursor's background color */
356 cachel = WINDOW_FACE_CACHEL (w,
357 get_builtin_face_cache_index (w, Vtext_cursor_face));
358 brush = COLOR_INSTANCE_MSWINDOWS_BRUSH (XCOLOR_INSTANCE (cachel->background));
359 FrameRect (hdc, &rect, brush);
360 }
361 }
362
363
364 /*****************************************************************************
365 mswindows_output_string
366
367 Given a string and a starting position, output that string in the
368 given face.
369 Correctly handles multiple charsets in the string.
370
371 The meaning of the parameters is something like this:
372
373 W Window that the text is to be displayed in.
374 DL Display line that this text is on. The values in the
375 structure are used to determine the vertical position and
376 clipping range of the text.
377 BUF Dynamic array of Emchars specifying what is actually to be
378 drawn.
379 XPOS X position in pixels where the text should start being drawn.
380 XOFFSET Number of pixels to be chopped off the left side of the
381 text. The effect is as if the text were shifted to the
382 left this many pixels and clipped at XPOS.
383 CLIP_START Clip everything left of this X position.
384 WIDTH Clip everything right of XPOS + WIDTH.
385 FINDEX Index for the face cache element describing how to display
386 the text.
387 ****************************************************************************/
388 void
389 mswindows_output_string (struct window *w, struct display_line *dl,
390 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
391 int width, face_index findex)
392 {
393 struct frame *f = XFRAME (w->frame);
394 struct device *d = XDEVICE (f->device);
395 Lisp_Object window = Qnil;
396 HDC hdc;
397 int clip_end;
398 Lisp_Object bg_pmap;
399 int len = Dynarr_length (buf);
400 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
401 textual_run *runs = alloca_array (textual_run, len);
402 int nruns;
403 int i;
404 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
405
406 XSETWINDOW (window, w);
407 hdc = FRAME_MSWINDOWS_DC(f);
408
409 #if 0 /* XXX: FIXME? */
410 /* We can't work out the width before we've set the font in the DC */
411 if (width < 0)
412 width = mswindows_text_width (cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
413 #else
414 assert(width>=0);
415 #endif
416
417 /* Regularize the variables passed in. */
418 if (clip_start < xpos)
419 clip_start = xpos;
420 clip_end = xpos + width;
421 if (clip_start >= clip_end)
422 /* It's all clipped out. */
423 return;
424
425 xpos -= xoffset;
426
427 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
428 Dynarr_length (buf));
429
430 bg_pmap = cachel->background_pixmap;
431 if (!IMAGE_INSTANCEP (bg_pmap)
432 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
433 bg_pmap = Qnil;
434
435 for (i = 0; i < nruns; i++)
436 {
437 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
438 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
439 int this_width;
440 int need_clipping;
441 RECT rect = { clip_start, dl->ypos - dl->ascent,
442 clip_end, dl->ypos + dl->descent - dl->clip };
443 HRGN region;
444
445 if (EQ (font, Vthe_null_font_instance))
446 continue;
447
448 mswindows_update_gc (hdc, font, cachel->foreground,
449 cachel->background, Qnil, Qnil);
450
451 this_width = mswindows_text_width_single_run (hdc, cachel, runs + i);
452 need_clipping = (dl->clip || clip_start > xpos ||
453 clip_end < xpos + this_width);
454
455 if (need_clipping)
456 {
457 region = CreateRectRgn (rect.left, rect.top,
458 rect.right, rect.bottom);
459 SelectClipRgn (hdc, region);
460 }
461
462 /* TextOut only clears the area equal to the height of
463 the given font. It is possible that a font is being displayed
464 on a line taller than it is, so this would cause us to fail to
465 clear some areas. */
466 if (fi->ascent < dl->ascent || fi->descent < dl->descent-dl->clip)
467 FillRect (hdc, &rect,
468 COLOR_INSTANCE_MSWINDOWS_BRUSH (XCOLOR_INSTANCE (cachel->background)));
469
470 assert (runs[i].dimension == 1); /* XXX FIXME */
471 TextOut(hdc, xpos, dl->ypos, (char *) runs[i].ptr, runs[i].len);
472
473 /* XXX FIXME? X does underline/strikethrough here
474 we will do it as part of face's font */
475
476 if (need_clipping)
477 {
478 SelectClipRgn (hdc, NULL);
479 DeleteObject (region);
480 }
481
482 xpos += this_width;
483 }
484 }
485
486 /*****************************************************************************
487 mswindows_redraw_exposed_window
488
489 Given a bounding box for an area that needs to be redrawn, determine
490 what parts of what lines are contained within and re-output their
491 contents.
492 Copied from redisplay-x.c
493 ****************************************************************************/
494 static void
495 mswindows_redraw_exposed_window (struct window *w, int x, int y, int width,
496 int height)
497 {
498 struct frame *f = XFRAME (w->frame);
499 int line;
500 int start_x, start_y, end_x, end_y;
501 int orig_windows_structure_changed;
502
503 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
504
505 if (!NILP (w->vchild))
506 {
507 mswindows_redraw_exposed_windows (w->vchild, x, y, width, height);
508 return;
509 }
510 else if (!NILP (w->hchild))
511 {
512 mswindows_redraw_exposed_windows (w->hchild, x, y, width, height);
513 return;
514 }
515
516 /* If the window doesn't intersect the exposed region, we're done here. */
517 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w)
518 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w))
519 {
520 return;
521 }
522 else
523 {
524 start_x = max (WINDOW_LEFT (w), x);
525 end_x = min (WINDOW_RIGHT (w), (x + width));
526 start_y = max (WINDOW_TOP (w), y);
527 end_y = min (WINDOW_BOTTOM (w), y + height);
528
529 /* We do this to make sure that the 3D modelines get redrawn if
530 they are in the exposed region. */
531 orig_windows_structure_changed = f->windows_structure_changed;
532 f->windows_structure_changed = 1;
533 }
534
535 if (window_needs_vertical_divider (w))
536 {
537 mswindows_output_vertical_divider (w, 0);
538 }
539
540 for (line = 0; line < Dynarr_length (cdla); line++)
541 {
542 struct display_line *cdl = Dynarr_atp (cdla, line);
543 int top_y = cdl->ypos - cdl->ascent;
544 int bottom_y = cdl->ypos + cdl->descent;
545
546 if (bottom_y >= start_y)
547 {
548 if (top_y > end_y)
549 {
550 if (line == 0)
551 continue;
552 else
553 break;
554 }
555 else
556 {
557 output_display_line (w, 0, cdla, line, start_x, end_x);
558 }
559 }
560 }
561
562 f->windows_structure_changed = orig_windows_structure_changed;
563
564 /* If there have never been any face cache_elements created, then this
565 expose event doesn't actually have anything to do. */
566 if (Dynarr_largest (w->face_cachels))
567 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
568 }
569
570 /*****************************************************************************
571 mswindows_redraw_exposed_windows
572
573 For each window beneath the given window in the window hierarchy,
574 ensure that it is redrawn if necessary after an Expose event.
575 ****************************************************************************/
576 static void
577 mswindows_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
578 int height)
579 {
580 for (; !NILP (window); window = XWINDOW (window)->next)
581 mswindows_redraw_exposed_window (XWINDOW (window), x, y, width, height);
582 }
583
584 /*****************************************************************************
585 mswindows_redraw_exposed_area
586
587 For each window on the given frame, ensure that any area in the
588 Exposed area is redrawn.
589 ****************************************************************************/
590 void
591 mswindows_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
592 {
593 /* If any window on the frame has had its face cache reset then the
594 redisplay structures are effectively invalid. If we attempt to
595 use them we'll blow up. We mark the frame as changed to ensure
596 that redisplay will do a full update. This probably isn't
597 necessary but it can't hurt. */
598
599 if (!f->window_face_cache_reset)
600 mswindows_redraw_exposed_windows (f->root_window, x, y, width, height);
601 else
602 MARK_FRAME_CHANGED (f);
603 }
604
605
606 /*****************************************************************************
607 mswindows_bevel_modeline
608
609 Draw a 3d border around the modeline on window W.
610 ****************************************************************************/
611 static void
612 mswindows_bevel_modeline (struct window *w, struct display_line *dl)
613 {
614 struct frame *f = XFRAME (w->frame);
615 Lisp_Object color;
616 int shadow_width = MODELINE_SHADOW_THICKNESS (w);
617 RECT rect = { WINDOW_MODELINE_LEFT (w),
618 dl->ypos - dl->ascent - shadow_width,
619 WINDOW_MODELINE_RIGHT (w),
620 dl->ypos + dl->descent + shadow_width};
621
622
623 color = WINDOW_FACE_CACHEL_BACKGROUND (w, MODELINE_INDEX);
624 mswindows_update_gc(FRAME_MSWINDOWS_DC(f), Qnil, Qnil, color, Qnil, Qnil);
625
626 #if 0 /* XXX Eh? */
627 if (shadow_width < 0)
628 {
629 GC temp;
630
631 temp = top_shadow_gc;
632 top_shadow_gc = bottom_shadow_gc;
633 bottom_shadow_gc = temp;
634 }
635 #endif
636
637 DrawEdge (FRAME_MSWINDOWS_DC(f), &rect, shadow_width==1 ? BDR_RAISEDINNER :
638 EDGE_RAISED, BF_RECT);
639 }
640
641
642 /*****************************************************************************
643 #### Display methods
644 /*****************************************************************************
645
646 /*****************************************************************************
647 mswindows_divider_width
648
649 Return the width of the vertical divider.
650 ****************************************************************************/
651 static int
652 mswindows_divider_width (void)
653 {
654 return MSWINDOWS_DIVIDER_WIDTH;
655 }
656
657 /*****************************************************************************
658 mswindows_divider_height
659
660 Return the height of the horizontal divider.
661 ****************************************************************************/
662 static int
663 mswindows_divider_height (void)
664 {
665 return 1; /* XXX Copied from redisplay-X.c. What is this? */
666 }
667
668 /*****************************************************************************
669 mswindows_eol_cursor_width
670
671 Return the width of the end-of-line cursor.
672 ****************************************************************************/
673 static int
674 mswindows_eol_cursor_width (void)
675 {
676 return MSWINDOWS_EOL_CURSOR_WIDTH;
677 }
678
679 /*****************************************************************************
680 mswindows_output_begin
681
682 Perform any necessary initialization prior to an update.
683 ****************************************************************************/
684 static void
685 mswindows_output_begin (struct device *d)
686 {
687 }
688
689 /*****************************************************************************
690 mswindows_output_end
691
692 Perform any necessary flushing of queues when an update has completed.
693 ****************************************************************************/
694 static void
695 mswindows_output_end (struct device *d)
696 {
697 }
698
699 static int
700 mswindows_flash (struct device *d)
701 {
702 struct frame *f = device_selected_frame (d);
703
704 /* XXX FIXME: Do something more visible here, maybe involving a timer */
705 FlashWindow (FRAME_MSWINDOWS_HANDLE (f), TRUE);
706 FlashWindow (FRAME_MSWINDOWS_HANDLE (f), FALSE);
707 }
708
709 static void
710 mswindows_ring_bell (struct device *d, int volume, int pitch, int duration)
711 {
712 /* XXX FIXME: I'm guessing pitch=Hz and duration is milliseconds */
713
714 if ((pitch|duration) == -1) /* Pitch and/or duration may be bogus */
715 MessageBeep(-1); /* Default system sound via speaker */
716 else
717 Beep(pitch, duration);
718 }
719
720
721 /*****************************************************************************
722 mswindows_output_display_block
723
724 Given a display line, a block number for that start line, output all
725 runes between start and end in the specified display block.
726 Ripped off with mininmal thought from the corresponding X routine.
727 ****************************************************************************/
728 static void
729 mswindows_output_display_block (struct window *w, struct display_line *dl, int block,
730 int start, int end, int start_pixpos, int cursor_start,
731 int cursor_width, int cursor_height)
732 {
733 struct frame *f = XFRAME (w->frame);
734 Emchar_dynarr *buf = Dynarr_new (Emchar);
735 Lisp_Object window;
736
737 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
738 rune_dynarr *rba = db->runes;
739 struct rune *rb;
740
741 int elt = start;
742 face_index findex;
743 int xpos, width;
744 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
745 MULE is not defined */
746 XSETWINDOW (window, w);
747 rb = Dynarr_atp (rba, start);
748
749 if (!rb)
750 {
751 /* Nothing to do so don't do anything. */
752 return;
753 }
754 else
755 {
756 findex = rb->findex;
757 xpos = rb->xpos;
758 width = 0;
759 if (rb->type == RUNE_CHAR)
760 charset = CHAR_CHARSET (rb->object.chr.ch);
761 }
762
763 if (end < 0)
764 end = Dynarr_length (rba);
765 Dynarr_reset (buf);
766
767 while (elt < end)
768 {
769 rb = Dynarr_atp (rba, elt);
770
771 if (rb->findex == findex && rb->type == RUNE_CHAR
772 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
773 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
774 {
775 Dynarr_add (buf, rb->object.chr.ch);
776 width += rb->width;
777 elt++;
778 }
779 else
780 {
781 if (Dynarr_length (buf))
782 {
783 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
784 findex);
785 xpos = rb->xpos;
786 width = 0;
787 }
788 Dynarr_reset (buf);
789 width = 0;
790
791 if (rb->type == RUNE_CHAR)
792 {
793 findex = rb->findex;
794 xpos = rb->xpos;
795 charset = CHAR_CHARSET (rb->object.chr.ch);
796
797 if (rb->cursor_type == CURSOR_ON)
798 {
799 if (rb->object.chr.ch == '\n')
800 {
801 mswindows_output_cursor (w, dl, xpos, cursor_width, rb);
802 }
803 else
804 {
805 Dynarr_add (buf, rb->object.chr.ch);
806 #if 0
807 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos,
808 rb->width, findex, 1,
809 cursor_start, cursor_width,
810 cursor_height);
811 #else
812 mswindows_output_cursor (w, dl, xpos, cursor_width, rb);
813 #endif
814 Dynarr_reset (buf);
815 }
816
817 xpos += rb->width;
818 elt++;
819 }
820 else if (rb->object.chr.ch == '\n')
821 {
822 /* Clear in case a cursor was formerly here. */
823 int height = dl->ascent + dl->descent - dl->clip;
824
825 mswindows_clear_region (window, findex, xpos, dl->ypos - dl->ascent,
826 rb->width, height);
827 elt++;
828 }
829 }
830 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
831 {
832 if (rb->type == RUNE_BLANK)
833 mswindows_output_blank (w, dl, rb);
834 else
835 {
836 /* #### Our flagging of when we need to redraw the
837 modeline shadows sucks. Since RUNE_HLINE is only used
838 by the modeline at the moment it is a good bet
839 that if it gets redrawn then we should also
840 redraw the shadows. This won't be true forever.
841 We borrow the shadow_thickness_changed flag for
842 now. */
843 w->shadow_thickness_changed = 1;
844 mswindows_output_hline (w, dl, rb);
845 }
846
847 if (rb->cursor_type == CURSOR_ON)
848 mswindows_output_cursor (w, dl, xpos, cursor_width, rb);
849
850 elt++;
851 if (elt < end)
852 {
853 rb = Dynarr_atp (rba, elt);
854
855 findex = rb->findex;
856 xpos = rb->xpos;
857 }
858 }
859 else if (rb->type == RUNE_DGLYPH)
860 {
861 Lisp_Object instance;
862
863 XSETWINDOW (window, w);
864 instance = glyph_image_instance (rb->object.dglyph.glyph,
865 window, ERROR_ME_NOT, 1);
866 findex = rb->findex;
867
868 if (IMAGE_INSTANCEP (instance))
869 switch (XIMAGE_INSTANCE_TYPE (instance))
870 {
871 case IMAGE_TEXT:
872 {
873 /* #### This is way losing. See the comment in
874 add_glyph_rune(). */
875 Lisp_Object string =
876 XIMAGE_INSTANCE_TEXT_STRING (instance);
877 convert_bufbyte_string_into_emchar_dynarr
878 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
879
880 if (rb->cursor_type == CURSOR_ON)
881 mswindows_output_cursor (w, dl, xpos, cursor_width, rb);
882 else
883 mswindows_output_string (w, dl, buf, xpos,
884 rb->object.dglyph.xoffset,
885 start_pixpos, -1, findex);
886 Dynarr_reset (buf);
887 }
888 break;
889
890 case IMAGE_MONO_PIXMAP:
891 case IMAGE_COLOR_PIXMAP:
892 #if 0
893 mswindows_output_pixmap (w, dl, instance, xpos,
894 rb->object.dglyph.xoffset, start_pixpos,
895 rb->width, findex, cursor_start,
896 cursor_width, cursor_height);
897 #endif
898 break;
899
900 case IMAGE_POINTER:
901 abort ();
902
903 case IMAGE_SUBWINDOW:
904 /* #### implement me */
905 break;
906
907 case IMAGE_NOTHING:
908 /* nothing is as nothing does */
909 break;
910
911 default:
912 abort ();
913 }
914
915 xpos += rb->width;
916 elt++;
917 }
918 else
919 abort ();
920 }
921 }
922
923 if (Dynarr_length (buf))
924 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex);
925
926 if (dl->modeline
927 && !EQ (Qzero, w->modeline_shadow_thickness)
928 && (f->clear
929 || f->windows_structure_changed
930 || w->shadow_thickness_changed))
931 mswindows_bevel_modeline (w, dl);
932
933 Dynarr_free (buf);
934
935 }
936
937
938 /*****************************************************************************
939 mswindows_output_vertical_divider
940
941 Draw a vertical divider down the left side of the given window.
942 ****************************************************************************/
943 static void
944 mswindows_output_vertical_divider (struct window *w, int clear)
945 {
946 struct frame *f = XFRAME (w->frame);
947 Lisp_Object color;
948 RECT rect;
949 HBRUSH brush;
950 int shadow_width = MODELINE_SHADOW_THICKNESS (w);
951
952 /* We don't use the normal gutter measurements here because the
953 horizontal scrollbars and toolbars do not stretch completely over
954 to the right edge of the window. Only the modeline does. */
955 int modeline_height = window_modeline_height (w);
956
957 assert(!MSWINDOWS_DIVIDER_SPACING); /* This code doesn't handle this */
958
959 /* XXX Not sure about this */
960 #ifdef HAVE_SCROLLBARS
961 if (f->scrollbar_on_left)
962 rect.left = WINDOW_LEFT (w);
963 else
964 rect.left = WINDOW_RIGHT (w) - MSWINDOWS_DIVIDER_WIDTH;
965 #else
966 rect.left = WINDOW_LEFT (w);
967 #endif
968 rect.right = rect.left + MSWINDOWS_DIVIDER_WIDTH;
969
970 #ifdef HAVE_SCROLLBARS
971 if (f->scrollbar_on_top)
972 rect.top = WINDOW_TOP (w);
973 else
974 #endif
975 rect.top = WINDOW_TEXT_TOP (w);
976 rect.bottom = WINDOW_BOTTOM (w) - modeline_height;
977
978 /* Draw the divider line */
979 color = WINDOW_FACE_CACHEL_BACKGROUND (w, MODELINE_INDEX);
980 mswindows_update_gc(FRAME_MSWINDOWS_DC(f), Qnil, Qnil, color, Qnil, Qnil);
981 brush = COLOR_INSTANCE_MSWINDOWS_BRUSH (XCOLOR_INSTANCE (color));
982 FillRect (FRAME_MSWINDOWS_DC(f), &rect, brush);
983 if (shadow_width)
984 DrawEdge (FRAME_MSWINDOWS_DC(f), &rect,
985 shadow_width==1 ? BDR_RAISEDINNER : EDGE_RAISED,
986 BF_TOP|BF_RIGHT|BF_LEFT);
987 }
988
989
990 /****************************************************************************
991 mswindows_text_width
992
993 Given a string and a face, return the string's length in pixels when
994 displayed in the font associated with the face.
995 XXX FIXME: get redisplay_text_width_emchar_string() etc to pass in the
996 window so we can get hold of the window's frame's gc
997 ****************************************************************************/
998 static int
999 mswindows_text_width (struct face_cachel *cachel, CONST Emchar *str,
1000 Charcount len)
1001 {
1002 int width_so_far = 0;
1003 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
1004 textual_run *runs = alloca_array (textual_run, len);
1005 int nruns;
1006 int i;
1007 HDC hdc=NULL; /* XXXXX FIXME! only works for non-proportional fonts! */
1008
1009 nruns = separate_textual_runs (text_storage, runs, str, len);
1010
1011 for (i = 0; i < nruns; i++)
1012 width_so_far += mswindows_text_width_single_run (hdc, cachel, runs + i);
1013
1014 return width_so_far;
1015 }
1016
1017
1018 /****************************************************************************
1019 mswindows_clear_region
1020
1021 Clear the area in the box defined by the given parameters using the
1022 given face.
1023 ****************************************************************************/
1024 static void
1025 mswindows_clear_region (Lisp_Object locale, face_index findex, int x, int y,
1026 int width, int height)
1027 {
1028 struct window *w;
1029 struct frame *f;
1030 Lisp_Object background_pixmap = Qunbound;
1031 Lisp_Object temp;
1032 RECT rect = { x, y, x+width, y+height };
1033 HBRUSH brush;
1034
1035 if (!(width && height)) /* We often seem to get called with width==0 */
1036 return;
1037
1038 if (WINDOWP (locale))
1039 {
1040 w = XWINDOW (locale);
1041 f = XFRAME (w->frame);
1042 }
1043 else if (FRAMEP (locale))
1044 {
1045 w = NULL;
1046 f = XFRAME (locale);
1047 }
1048 else
1049 abort ();
1050
1051 if (w)
1052 {
1053 temp = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, findex);
1054
1055 if (IMAGE_INSTANCEP (temp)
1056 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
1057 {
1058 /* #### maybe we could implement such that a string
1059 can be a background pixmap? */
1060 background_pixmap = temp;
1061 }
1062 }
1063 else
1064 {
1065 temp = FACE_BACKGROUND_PIXMAP (Vdefault_face, locale);
1066
1067 if (IMAGE_INSTANCEP (temp)
1068 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
1069 {
1070 background_pixmap = temp;
1071 }
1072 }
1073
1074 if (!UNBOUNDP (background_pixmap))
1075 {
1076 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (background_pixmap) == 0)
1077 {
1078 Lisp_Object fcolor, bcolor;
1079
1080 if (w)
1081 {
1082 fcolor = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1083 bcolor = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1084 }
1085 else
1086 {
1087 fcolor = FACE_FOREGROUND (Vdefault_face, locale);
1088 bcolor = FACE_BACKGROUND (Vdefault_face, locale);
1089 }
1090
1091 mswindows_update_gc (FRAME_MSWINDOWS_DC(f), Qnil, fcolor, bcolor, background_pixmap, Qnil);
1092 }
1093
1094 /* XX FIXME: Get brush from background_pixmap here */
1095 assert(0);
1096 }
1097 else
1098 {
1099 Lisp_Object color = (w ? WINDOW_FACE_CACHEL_BACKGROUND (w, findex) :
1100 FACE_BACKGROUND (Vdefault_face, locale));
1101 brush = COLOR_INSTANCE_MSWINDOWS_BRUSH (XCOLOR_INSTANCE (color));
1102 }
1103
1104 FillRect (FRAME_MSWINDOWS_DC(f), &rect, brush);
1105 }
1106
1107
1108 /*****************************************************************************
1109 mswindows_clear_to_window_end
1110
1111 Clear the area between ypos1 and ypos2. Each margin area and the
1112 text area is handled separately since they may each have their own
1113 background color.
1114 ****************************************************************************/
1115 static void
1116 mswindows_clear_to_window_end (struct window *w, int ypos1, int ypos2)
1117 {
1118 int height = ypos2 - ypos1;
1119
1120 if (height)
1121 {
1122 struct frame *f = XFRAME (w->frame);
1123 Lisp_Object window;
1124 int bflag = (window_needs_vertical_divider (w) ? 0 : 1);
1125 layout_bounds bounds;
1126
1127 bounds = calculate_display_line_boundaries (w, bflag);
1128 XSETWINDOW (window, w);
1129
1130 if (window_is_leftmost (w))
1131 mswindows_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f),
1132 ypos1, FRAME_BORDER_WIDTH (f), height);
1133
1134 if (bounds.left_in - bounds.left_out > 0)
1135 mswindows_clear_region (window,
1136 get_builtin_face_cache_index (w, Vleft_margin_face),
1137 bounds.left_out, ypos1,
1138 bounds.left_in - bounds.left_out, height);
1139
1140 if (bounds.right_in - bounds.left_in > 0)
1141 mswindows_clear_region (window, DEFAULT_INDEX, bounds.left_in, ypos1,
1142 bounds.right_in - bounds.left_in, height);
1143
1144 if (bounds.right_out - bounds.right_in > 0)
1145 mswindows_clear_region (window,
1146 get_builtin_face_cache_index (w, Vright_margin_face),
1147 bounds.right_in, ypos1,
1148 bounds.right_out - bounds.right_in, height);
1149
1150 if (window_is_rightmost (w))
1151 mswindows_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f),
1152 ypos1, FRAME_BORDER_WIDTH (f), height);
1153 }
1154
1155 }
1156
1157
1158 static void
1159 mswindows_clear_frame (struct frame *f)
1160 {
1161 }
1162
1163
1164
1165
1166 /************************************************************************/
1167 /* initialization */
1168 /************************************************************************/
1169
1170 void
1171 console_type_create_redisplay_mswindows (void)
1172 {
1173 /* redisplay methods */
1174 CONSOLE_HAS_METHOD (mswindows, text_width);
1175 CONSOLE_HAS_METHOD (mswindows, output_display_block);
1176 CONSOLE_HAS_METHOD (mswindows, divider_width);
1177 CONSOLE_HAS_METHOD (mswindows, divider_height);
1178 CONSOLE_HAS_METHOD (mswindows, eol_cursor_width);
1179 CONSOLE_HAS_METHOD (mswindows, output_vertical_divider);
1180 CONSOLE_HAS_METHOD (mswindows, clear_to_window_end);
1181 CONSOLE_HAS_METHOD (mswindows, clear_region);
1182 CONSOLE_HAS_METHOD (mswindows, clear_frame);
1183 CONSOLE_HAS_METHOD (mswindows, output_begin);
1184 CONSOLE_HAS_METHOD (mswindows, output_end);
1185 CONSOLE_HAS_METHOD (mswindows, flash);
1186 CONSOLE_HAS_METHOD (mswindows, ring_bell);
1187 }