Use "character.h" instead of "mule-charset.h" if CHAR_IS_UCS4 is
[chise/xemacs-chise.git] / src / redisplay-msw.c
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 21.0.
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-msw.h"
44 #include "redisplay.h"
45 #include "sysdep.h"
46 #include "window.h"
47
48 #include "windows.h"
49 #ifdef MULE
50 #include "mule-ccl.h"
51 #ifdef CHAR_IS_UCS4
52 #include "character.h"
53 #else
54 #include "mule-charset.h"
55 #endif
56 #endif
57
58 #define MSWINDOWS_EOL_CURSOR_WIDTH      5
59
60 /*
61  * Random forward declarations
62  */
63 static void mswindows_update_dc (HDC hdc, Lisp_Object font, Lisp_Object fg,
64                                  Lisp_Object bg, Lisp_Object bg_pmap);
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 static void mswindows_output_dibitmap (struct frame *f, 
69                                        struct Lisp_Image_Instance *p,
70                                        int x, int y, 
71                                        int clip_x, int clip_y, 
72                                        int clip_width, int clip_height, 
73                                        int width, int height,
74                                        int pixmap_offset,
75                                        int offset_bitmap);
76 static void mswindows_output_pixmap (struct window *w, struct display_line *dl,
77                                      Lisp_Object image_instance, int xpos,
78                                      int xoffset, int start_pixpos, int width,
79                                      face_index findex, int cursor_start, 
80                                      int cursor_width, int cursor_height,
81                                      int offset_bitmap);
82
83 typedef struct textual_run
84 {
85   Lisp_Object charset;
86   unsigned char *ptr;
87   int len;
88   int dimension;
89 } textual_run;
90
91 /* Separate out the text in DYN into a series of textual runs of a
92    particular charset.  Also convert the characters as necessary into
93    the format needed by XDrawImageString(), XDrawImageString16(), et
94    al.  (This means converting to one or two byte format, possibly
95    tweaking the high bits, and possibly running a CCL program.) You
96    must pre-allocate the space used and pass it in. (This is done so
97    you can alloca() the space.)  You need to allocate (2 * len) bytes
98    of TEXT_STORAGE and (len * sizeof (textual_run)) bytes of
99    RUN_STORAGE, where LEN is the length of the dynarr.
100
101    Returns the number of runs actually used. */
102
103 static int
104 separate_textual_runs (unsigned char *text_storage,
105                        textual_run *run_storage,
106                        CONST Emchar *str, Charcount len)
107 {
108   Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a
109                                           possible valid charset when
110                                           MULE is not defined */
111   int runs_so_far = 0;
112   int i;
113 #ifdef MULE
114   struct ccl_program char_converter;
115   int need_ccl_conversion = 0;
116 #endif
117
118   for (i = 0; i < len; i++)
119     {
120       Emchar ch = str[i];
121       Lisp_Object charset;
122       int byte1, byte2;
123       int dimension;
124       int graphic;
125
126       BREAKUP_CHAR (ch, charset, byte1, byte2);
127       dimension = XCHARSET_DIMENSION (charset);
128       graphic   = XCHARSET_GRAPHIC   (charset);
129
130       if (!EQ (charset, prev_charset))
131         {
132           run_storage[runs_so_far].ptr       = text_storage;
133           run_storage[runs_so_far].charset   = charset;
134           run_storage[runs_so_far].dimension = dimension;
135
136           if (runs_so_far)
137             {
138               run_storage[runs_so_far - 1].len =
139                 text_storage - run_storage[runs_so_far - 1].ptr;
140               if (run_storage[runs_so_far - 1].dimension == 2)
141                 run_storage[runs_so_far - 1].len >>= 1;
142             }
143           runs_so_far++;
144           prev_charset = charset;
145 #ifdef MULE
146           {
147             Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset);
148             need_ccl_conversion = !NILP (ccl_prog);
149             if (need_ccl_conversion)
150               setup_ccl_program (&char_converter, ccl_prog);
151           }
152 #endif
153         }
154
155       if (graphic == 0)
156         {
157           byte1 &= 0x7F;
158           byte2 &= 0x7F;
159         }
160       else if (graphic == 1)
161         {
162           byte1 |= 0x80;
163           byte2 |= 0x80;
164         }
165 #ifdef MULE
166       if (need_ccl_conversion)
167         {
168           char_converter.reg[0] = XCHARSET_ID (charset);
169           char_converter.reg[1] = byte1;
170           char_converter.reg[2] = byte2;
171           char_converter.ic = 0; /* start at beginning each time */
172           ccl_driver (&char_converter, 0, 0, 0, 0);
173           byte1 = char_converter.reg[1];
174           byte2 = char_converter.reg[2];
175         }
176 #endif
177       *text_storage++ = (unsigned char) byte1;
178       if (dimension == 2)
179         *text_storage++ = (unsigned char) byte2;
180     }
181
182   if (runs_so_far)
183     {
184       run_storage[runs_so_far - 1].len =
185         text_storage - run_storage[runs_so_far - 1].ptr;
186       if (run_storage[runs_so_far - 1].dimension == 2)
187         run_storage[runs_so_far - 1].len >>= 1;
188     }
189
190   return runs_so_far;
191 }
192
193
194 static int
195 mswindows_text_width_single_run (HDC hdc, struct face_cachel *cachel,
196                                  textual_run *run)
197 {
198   Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
199   struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
200   SIZE size;
201
202   if (!fi->proportional_p || !hdc)
203     return (fi->width * run->len);
204   else
205     {
206       assert(run->dimension == 1);      /* #### FIXME! */
207       mswindows_update_dc (hdc, font_inst, Qnil, Qnil, Qnil);
208       GetTextExtentPoint32 (hdc, run->ptr, run->len, &size);
209       return(size.cx);
210     }
211 }
212
213
214 /*****************************************************************************
215  mswindows_update_dc
216
217  Given a number of parameters munge the DC so it has those properties.
218  ****************************************************************************/
219 static void
220 mswindows_update_dc (HDC hdc, Lisp_Object font, Lisp_Object fg,
221                      Lisp_Object bg, Lisp_Object bg_pmap)
222 {
223   if (!NILP (font))
224     SelectObject(hdc, FONT_INSTANCE_MSWINDOWS_HFONT (XFONT_INSTANCE (font)));
225
226
227   if (!NILP (fg))
228     {
229       SetTextColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR 
230                     (XCOLOR_INSTANCE (fg)));
231     }
232   if (!NILP (bg))
233     { 
234       SetBkMode (hdc, OPAQUE);
235       SetBkColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (bg)));
236     }
237   else 
238     {
239       SetBkMode (hdc, TRANSPARENT);
240     }
241 }
242
243
244 /*****************************************************************************
245  mswindows_apply_face_effects
246
247  Draw underline and strikeout as if this was X.
248  #### On mswindows this really should be done as part of drawing the font.
249  The line width used is chosen arbitrarily from the font height.
250  ****************************************************************************/
251 static void
252 mswindows_apply_face_effects (HDC hdc, struct display_line *dl, int xpos,
253                               int width, struct Lisp_Font_Instance *fi,
254                               struct face_cachel *cachel,
255                               struct face_cachel *color_cachel)
256 {
257   int yclip;
258   HBRUSH brush, oldbrush;
259   RECT rect;
260
261   brush = CreateSolidBrush (COLOR_INSTANCE_MSWINDOWS_COLOR (
262                             XCOLOR_INSTANCE (color_cachel->foreground)));
263   if (brush)
264     {
265       yclip = dl->ypos + dl->descent - dl->clip;
266       rect.left = xpos;
267       rect.right = xpos + width;
268       oldbrush = SelectObject (hdc, brush);
269
270       if (cachel->underline)
271         {
272           rect.top = dl->ypos + dl->descent/2;
273           rect.bottom = rect.top + (fi->height >= 0x20 ? 2 : 1);
274           if (rect.bottom <= yclip)
275             FillRect (hdc, &rect, brush);
276         }
277       if (cachel->strikethru)
278         {
279           rect.top = dl->ypos + dl->descent - (dl->ascent + dl->descent)/2;
280           rect.bottom = rect.top + (fi->height >= 0x20 ? 2 : 1);
281           if (rect.bottom <= yclip)
282             FillRect (hdc, &rect, brush);
283         }
284
285       SelectObject (hdc, oldbrush);
286       DeleteObject (brush);
287     }
288 }
289
290
291 /*****************************************************************************
292  mswindows_output_hline
293
294  Output a horizontal line in the foreground of its face.
295  ****************************************************************************/
296 static void
297 mswindows_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
298 { /* XXX Implement me */
299 }
300
301
302 /*****************************************************************************
303  mswindows_output_blank
304
305  Output a blank by clearing the area it covers in the background color
306  of its face.
307  ****************************************************************************/
308 static void
309 mswindows_output_blank (struct window *w, struct display_line *dl, struct rune *rb, int start_pixpos)
310 {
311   struct frame *f = XFRAME (w->frame);
312   RECT rect = { rb->xpos, dl->ypos-dl->ascent,
313                 rb->xpos+rb->width, dl->ypos+dl->descent-dl->clip };
314   struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, rb->findex);
315
316   Lisp_Object bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
317
318   if (!IMAGE_INSTANCEP (bg_pmap)
319       || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
320     bg_pmap = Qnil;
321
322   if (!NILP(bg_pmap))
323     {
324       /* blank the background in the appropriate color */
325       mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, cachel->foreground,
326                            cachel->background, Qnil);
327
328       mswindows_output_pixmap (w, dl, bg_pmap, 
329                                rb->xpos, 0 /*rb->object.dglyph.xoffset*/,
330                                start_pixpos, rb->width, rb->findex,
331                                0, 0, 0, TRUE);
332     }
333   else 
334     {
335       mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
336                            cachel->background, Qnil);
337       
338       ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, 
339                   &rect, NULL, 0, NULL);
340     }
341 }
342
343
344 /*****************************************************************************
345  mswindows_output_cursor
346
347  Draw a normal or end-of-line cursor. The end-of-line cursor is
348  narrower than the normal cursor.
349  ****************************************************************************/
350 static void
351 mswindows_output_cursor (struct window *w, struct display_line *dl, int xpos,
352                          int width, face_index findex, Emchar ch, int image_p)
353 {
354   struct frame *f = XFRAME (w->frame);
355   struct device *d = XDEVICE (f->device);
356   struct face_cachel *cachel=0;
357   Lisp_Object font = Qnil;
358   int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
359   HDC hdc = FRAME_MSWINDOWS_DC (f);
360   unsigned int face_index=0;
361   char *p_char = NULL;
362   int n_char = 0;
363   RECT rect = { xpos,
364                 dl->ypos - dl->ascent,
365                 xpos + width,
366                 dl->ypos + dl->descent - dl->clip};
367   Lisp_Object bar = symbol_value_in_buffer (Qbar_cursor,
368                                             WINDOW_BUFFER (w));
369   int bar_p = image_p || !NILP (bar);
370   int cursor_p = !NILP (w->text_cursor_visible_p);
371   int real_char_p = ch != 0;
372
373   if (real_char_p)
374     {
375       /* Use the font from the underlying character */
376       cachel = WINDOW_FACE_CACHEL (w, findex);
377
378       /* #### MULE: Need to know the charset! */
379       font = FACE_CACHEL_FONT (cachel, Vcharset_ascii);
380     }
381
382   if ((focus || bar_p) && real_char_p)
383     {
384       p_char = (char*) &ch;
385       n_char = 1;
386     }
387
388   if (!image_p)
389     {
390       struct face_cachel *color_cachel;
391
392       /* Use cursor fg/bg for block cursor, or character fg/bg for the bar
393          or when we need to erase the cursor. Output nothing at eol if bar
394          cursor */
395       face_index = get_builtin_face_cache_index (w, Vtext_cursor_face);
396       color_cachel = WINDOW_FACE_CACHEL (w, ((!cursor_p || bar_p) ?
397                                              findex : face_index));
398       mswindows_update_dc (hdc, font, color_cachel->foreground,
399                            color_cachel->background, Qnil);
400       ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE|ETO_CLIPPED, &rect, p_char, n_char, NULL);
401       if (real_char_p && (cachel->underline || cachel->strikethru))
402         mswindows_apply_face_effects (hdc, dl, xpos, width,
403                                       XFONT_INSTANCE (font),
404                                       cachel, color_cachel);
405     }
406
407   if (!cursor_p)
408     return;
409
410   if (focus && bar_p)
411     {
412       rect.right = rect.left + (EQ (bar, Qt) ? 1 : min (2, width));
413       face_index = get_builtin_face_cache_index (w, Vtext_cursor_face);
414       cachel = WINDOW_FACE_CACHEL (w, face_index);
415       mswindows_update_dc (hdc, Qnil, Qnil, cachel->background, Qnil);
416       ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE, &rect, NULL, 0, NULL);
417     }
418   else if (!focus)
419     {
420       /* Now have real character drawn in its own color. We deflate
421          the rectangle so character cell will be bounded by the
422          previously drawn cursor shape */
423       InflateRect (&rect, -1, -1);
424
425       if (real_char_p)
426         {
427           p_char = (char*) &ch;
428           n_char = 1;
429         }
430
431       face_index = get_builtin_face_cache_index (w, Vdefault_face);
432       cachel = WINDOW_FACE_CACHEL (w, (real_char_p ? findex : face_index));
433       mswindows_update_dc (hdc, Qnil, cachel->foreground,
434                            cachel->background, Qnil);
435       ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE | ETO_CLIPPED,
436                   &rect, p_char, n_char, NULL);
437       if (cachel->underline || cachel->strikethru)
438         mswindows_apply_face_effects (hdc, dl, xpos+1, width-2,
439                                       XFONT_INSTANCE (font),
440                                       cachel, cachel);
441     }
442 }
443
444
445 /*****************************************************************************
446  mswindows_output_string
447
448  Given a string and a starting position, output that string in the
449  given face.
450  Correctly handles multiple charsets in the string.
451
452  The meaning of the parameters is something like this:
453
454  W              Window that the text is to be displayed in.
455  DL             Display line that this text is on.  The values in the
456                 structure are used to determine the vertical position and
457                 clipping range of the text.
458  BUF            Dynamic array of Emchars specifying what is actually to be
459                 drawn.
460  XPOS           X position in pixels where the text should start being drawn.
461  XOFFSET        Number of pixels to be chopped off the left side of the
462                 text.  The effect is as if the text were shifted to the
463                 left this many pixels and clipped at XPOS.
464  CLIP_START     Clip everything left of this X position.
465  WIDTH          Clip everything right of XPOS + WIDTH.
466  FINDEX         Index for the face cache element describing how to display
467                 the text.
468  ****************************************************************************/
469 void
470 mswindows_output_string (struct window *w, struct display_line *dl,
471                    Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
472                    int width, face_index findex)
473 {
474   struct frame *f = XFRAME (w->frame);
475   /* struct device *d = XDEVICE (f->device);*/
476   Lisp_Object window;
477   HDC hdc = FRAME_MSWINDOWS_DC (f);
478   int clip_end;
479   Lisp_Object bg_pmap;
480   int len = Dynarr_length (buf);
481   unsigned char *text_storage = (unsigned char *) alloca (2 * len);
482   textual_run *runs = alloca_array (textual_run, len);
483   int nruns;
484   int i, height;
485   RECT rect;
486   struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
487
488   XSETWINDOW (window, w);
489
490 #if 0   /* #### FIXME? */
491   /* We can't work out the width before we've set the font in the DC */
492   if (width < 0)
493     width = mswindows_text_width (cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
494 #else
495   assert(width>=0);
496 #endif
497
498   /* Regularize the variables passed in. */
499   if (clip_start < xpos)
500     clip_start = xpos;
501   clip_end = xpos + width;
502   if (clip_start >= clip_end)
503     /* It's all clipped out. */
504     return;
505
506   xpos -= xoffset;
507
508   /* sort out the destination rectangle */
509   height = DISPLAY_LINE_HEIGHT (dl);
510   rect.left = clip_start;
511   rect.top  = dl->ypos - dl->ascent;
512   rect.right = clip_end;
513   rect.bottom = height + dl->ypos - dl->ascent;
514
515   /* output the background pixmap if there is one */
516   bg_pmap = cachel->background_pixmap;
517   if (!IMAGE_INSTANCEP (bg_pmap)
518       || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
519     bg_pmap = Qnil;
520
521   if (!NILP(bg_pmap))
522     {
523       /* blank the background in the appropriate color */
524       mswindows_update_dc (hdc, Qnil, cachel->foreground,
525                            cachel->background, Qnil);
526
527       mswindows_output_pixmap (w, dl, bg_pmap, 
528                                xpos, xoffset,
529                                clip_start, width, findex,
530                                0, 0, 0, TRUE);
531       /* output pixmap calls this so we have to recall to get correct
532          references */
533       cachel = WINDOW_FACE_CACHEL (w, findex);
534     }
535
536   nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
537                                  Dynarr_length (buf));
538
539   for (i = 0; i < nruns; i++)
540     {
541       Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
542       struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
543       int this_width;
544
545       if (EQ (font, Vthe_null_font_instance))
546         continue;
547
548       mswindows_update_dc (hdc, font, cachel->foreground,
549                            NILP(bg_pmap) ? cachel->background : Qnil, Qnil);
550
551       this_width = mswindows_text_width_single_run (hdc, cachel, runs + i);
552       
553       /* cope with fonts taller than lines */
554       if ((int) fi->height < (int) (height + dl->clip))
555         {
556           int clear_start = max (xpos, clip_start);
557           int clear_end = min (xpos + this_width, clip_end);
558           
559           {
560             redisplay_clear_region (window, findex, clear_start,
561                                     dl->ypos - dl->ascent, 
562                                     clear_end - clear_start,
563                                     height);
564             /* output pixmap calls this so we have to recall to get correct
565                references */
566             cachel = WINDOW_FACE_CACHEL (w, findex);
567           }
568         }
569
570       assert (runs[i].dimension == 1);  /* #### FIXME: Broken when Mule? */
571       ExtTextOut (hdc, xpos, dl->ypos,
572                   NILP(bg_pmap) ? ETO_CLIPPED | ETO_OPAQUE : ETO_CLIPPED,
573                   &rect, (char *) runs[i].ptr, runs[i].len, NULL); 
574
575       /* #### X does underline/strikethrough here so we do the same.
576          On mswindows, underline/strikethrough really belongs to the font */
577       if (cachel->underline || cachel->strikethru)
578         mswindows_apply_face_effects (hdc, dl, xpos, this_width, fi,
579                                       cachel, cachel);
580       xpos += this_width;
581     }
582 }
583
584 static void
585 mswindows_output_dibitmap (struct frame *f, struct Lisp_Image_Instance *p,
586                            int x, int y, 
587                            int clip_x, int clip_y, 
588                            int clip_width, int clip_height, 
589                            int width, int height, int pixmap_offset,
590                            int offset_bitmap)
591 {
592   HDC hdc = FRAME_MSWINDOWS_DC (f);
593   HGDIOBJ old=NULL;
594   COLORREF bgcolor = GetBkColor (hdc);
595   int need_clipping = (clip_x || clip_y);
596   int yoffset=0;
597   int xoffset=0;
598
599   /* do we need to offset the pixmap vertically? this is necessary
600      for background pixmaps. */
601   if (offset_bitmap)
602     {
603       yoffset = y % IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
604       xoffset = x % IMAGE_INSTANCE_PIXMAP_WIDTH (p);
605       /* the width is handled by mswindows_output_pixmap_region */
606     }
607
608   if (need_clipping)
609     {
610     }
611
612   /* first blt the mask */
613   if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
614     {
615       RGBQUAD col;
616       col.rgbBlue = GetBValue (bgcolor);
617       col.rgbRed = GetRValue (bgcolor);
618       col.rgbGreen = GetGValue (bgcolor);
619       col.rgbReserved = 0;
620
621       old = SelectObject (FRAME_MSWINDOWS_CDC (f),
622                           IMAGE_INSTANCE_MSWINDOWS_MASK (p));
623       
624       SetDIBColorTable (FRAME_MSWINDOWS_CDC (f), 1, 1, &col);
625
626       BitBlt (hdc, 
627               x,y,
628               width, height, 
629               FRAME_MSWINDOWS_CDC (f),
630               xoffset,yoffset, 
631               SRCCOPY);                  
632
633       SelectObject (FRAME_MSWINDOWS_CDC (f), old);
634     }
635   
636   /* now blt the bitmap itself. */
637   old = SelectObject (FRAME_MSWINDOWS_CDC (f),
638                       IMAGE_INSTANCE_MSWINDOWS_BITMAP (p));
639
640   BitBlt (hdc, 
641           x,y,
642           width, height, 
643           FRAME_MSWINDOWS_CDC (f),
644           xoffset, yoffset, 
645           IMAGE_INSTANCE_MSWINDOWS_MASK (p) ? SRCINVERT : SRCCOPY);
646
647   SelectObject (FRAME_MSWINDOWS_CDC (f),old);
648
649   if (need_clipping)
650     {
651     }
652 }
653
654 /*
655  * X gc's have this nice property that setting the bg pixmap will
656  * output it offset relative to the window. Windows doesn't have this
657  * feature so we have to emulate this by outputting multiple pixmaps 
658  */
659 static void
660 mswindows_output_dibitmap_region (struct frame *f, 
661                                   struct Lisp_Image_Instance *p,
662                                   int x, int y, 
663                                   int clip_x, int clip_y, 
664                                   int clip_width, int clip_height, 
665                                   int width, int height, int pixmap_offset,
666                                   int offset_bitmap)
667 {
668   int pwidth = min (width, IMAGE_INSTANCE_PIXMAP_WIDTH (p));
669   int pheight = min (height, IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
670   int pxoffset = 0, pyoffset = 0;
671
672   /* when doing a bg pixmap do a partial pixmap first so that we
673      blt whole pixmaps thereafter */
674
675   if (offset_bitmap)
676     {
677       pheight = min (pheight, IMAGE_INSTANCE_PIXMAP_HEIGHT (p) -
678                      y % IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
679     }
680   
681   while (pheight > 0)
682     {
683       if (offset_bitmap)
684         {
685           pwidth = min (min (width, IMAGE_INSTANCE_PIXMAP_WIDTH (p)),
686                         IMAGE_INSTANCE_PIXMAP_WIDTH (p) -
687                         x % IMAGE_INSTANCE_PIXMAP_WIDTH (p));
688           pxoffset = 0;
689         }
690       while (pwidth > 0)
691         {
692           mswindows_output_dibitmap (f, p,
693                                      x + pxoffset, y + pyoffset, 
694                                      clip_x, clip_y, 
695                                      clip_width, clip_height, 
696                                      pwidth, pheight, pixmap_offset,
697                                      offset_bitmap);
698           pxoffset += pwidth;
699           pwidth = min ((width-pxoffset), 
700                         IMAGE_INSTANCE_PIXMAP_WIDTH (p));
701         }
702       pyoffset += pheight;
703       pheight = min ((height-pyoffset), 
704                      IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
705     }
706 }
707
708 static void
709 mswindows_output_pixmap (struct window *w, struct display_line *dl,
710                          Lisp_Object image_instance, int xpos, int xoffset,
711                          int start_pixpos, int width, face_index findex,
712                          int cursor_start, int cursor_width, int cursor_height,
713                          int offset_bitmap)
714 {
715   struct frame *f = XFRAME (w->frame);
716   HDC hdc = FRAME_MSWINDOWS_DC (f);
717
718   struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
719   Lisp_Object window;
720
721   int lheight = DISPLAY_LINE_HEIGHT (dl);
722   int pheight = ((int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > lheight ? lheight :
723                  IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
724   int clip_x, clip_y, clip_width, clip_height;
725
726   /* The pixmap_offset is used to center the pixmap on lines which are
727      shorter than it is.  This results in odd effects when scrolling
728      pixmaps off of the bottom.  Let's try not using it. */
729 #if 0
730   int pixmap_offset = (int) (IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - lheight) / 2;
731 #else
732   int pixmap_offset = 0;
733 #endif
734
735   XSETWINDOW (window, w);
736
737   if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
738     {
739       if (start_pixpos > xpos && start_pixpos > xpos + width)
740         return;
741
742       clip_x = xoffset;
743       clip_width = width;
744       if (start_pixpos > xpos)
745         {
746           clip_x += (start_pixpos - xpos);
747           clip_width -= (start_pixpos - xpos);
748         }
749     }
750   else
751     {
752       clip_x = 0;
753       clip_width = 0;
754     }
755
756   /* Place markers for possible future functionality (clipping the top
757      half instead of the bottom half; think pixel scrolling). */
758   clip_y = 0;
759   clip_height = pheight;
760
761   /* Clear the area the pixmap is going into.  The pixmap itself will
762      always take care of the full width.  We don't want to clear where
763      it is going to go in order to avoid flicker.  So, all we have to
764      take care of is any area above or below the pixmap. */
765   /* #### We take a shortcut for now.  We know that since we have
766      pixmap_offset hardwired to 0 that the pixmap is against the top
767      edge so all we have to worry about is below it. */
768   /* #### Unless the pixmap has a mask in which case we have to clear
769      the whole damn thing since we can't yet clear just the area not
770      included in the mask. */
771   if (((int) (dl->ypos - dl->ascent + pheight) <
772        (int) (dl->ypos + dl->descent - dl->clip))
773       || IMAGE_INSTANCE_MSWINDOWS_MASK (p))
774     {
775       int clear_x, clear_y, clear_width, clear_height;
776
777       if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
778         {
779           clear_y = dl->ypos - dl->ascent;
780           clear_height = lheight;
781         }
782       else
783         {
784           clear_y = dl->ypos - dl->ascent + pheight;
785           clear_height = lheight - pheight;
786         }
787
788       if (start_pixpos >= 0 && start_pixpos > xpos)
789         {
790           clear_x = start_pixpos;
791           clear_width = xpos + width - start_pixpos;
792         }
793       else
794         {
795           clear_x = xpos;
796           clear_width = width;
797         }
798
799       if (!offset_bitmap)       /* i.e. not a bg pixmap */
800         redisplay_clear_region (window, findex, clear_x, clear_y,
801                                 clear_width, clear_height);
802     }
803
804   /* Output the pixmap. Have to do this as many times as is required
805    to fill the given area */
806   mswindows_update_dc (hdc, Qnil,
807                        WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
808                        WINDOW_FACE_CACHEL_BACKGROUND (w, findex), Qnil);
809
810   mswindows_output_dibitmap_region (f, p, xpos - xoffset,
811                                     dl->ypos - dl->ascent,
812                                     clip_x, clip_y, clip_width, clip_height,
813                                     width + xoffset, pheight, pixmap_offset,
814                                     offset_bitmap);
815 }
816
817 #ifdef HAVE_SCROLLBARS
818 /*
819  * This function paints window's deadbox, a rectangle between window
820  * borders and two short edges of both scrollbars.
821  *
822  * Function checks whether deadbox intersects with the rectangle pointed
823  * to by PRC, and paints only the intersection
824  */
825 static void
826 mswindows_redisplay_deadbox_maybe (struct window *w, CONST RECT* prc)
827 {
828   int sbh = window_scrollbar_height (w);
829   int sbw = window_scrollbar_width (w);
830   RECT rect_dead, rect_paint;
831   if (sbh == 0 || sbw == 0)
832     return;
833
834   if (!NILP (w->scrollbar_on_left_p))
835     rect_dead.left = WINDOW_LEFT (w);
836   else
837     rect_dead.left = WINDOW_TEXT_RIGHT (w);
838   rect_dead.right = rect_dead.left + sbw;
839
840   if (!NILP (w->scrollbar_on_top_p))
841     rect_dead.top = WINDOW_TOP (w);
842   else
843     rect_dead.top = WINDOW_TEXT_BOTTOM (w);
844   rect_dead.bottom = rect_dead.top + sbh;
845       
846   if (IntersectRect (&rect_paint, &rect_dead, prc))
847     {
848       struct frame *f = XFRAME (WINDOW_FRAME (w));
849       FillRect (FRAME_MSWINDOWS_DC (f), &rect_paint,
850                 (HBRUSH) (COLOR_BTNFACE+1));
851     }
852 }
853
854 #endif /* HAVE_SCROLLBARS */
855
856 /*****************************************************************************
857  mswindows_redraw_exposed_window
858
859  Given a bounding box for an area that needs to be redrawn, determine
860  what parts of what lines are contained within and re-output their
861  contents.
862  Copied from redisplay-x.c
863  ****************************************************************************/
864 static void
865 mswindows_redraw_exposed_window (struct window *w, int x, int y, int width,
866                            int height)
867 {
868   struct frame *f = XFRAME (w->frame);
869   int line;
870   int orig_windows_structure_changed;
871   RECT rect_window = { WINDOW_LEFT (w), WINDOW_TOP (w),
872                        WINDOW_RIGHT (w), WINDOW_BOTTOM (w) };
873   RECT rect_expose = { x, y, x + width, y + height };
874   RECT rect_draw;
875
876   display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
877
878   if (!NILP (w->vchild))
879     {
880       mswindows_redraw_exposed_windows (w->vchild, x, y, width, height);
881       return;
882     }
883   else if (!NILP (w->hchild))
884     {
885       mswindows_redraw_exposed_windows (w->hchild, x, y, width, height);
886       return;
887     }
888
889   /* If the window doesn't intersect the exposed region, we're done here. */
890   if (!IntersectRect (&rect_draw, &rect_window, &rect_expose))
891       return;
892
893   /* We do this to make sure that the 3D modelines get redrawn if
894      they are in the exposed region. */
895   orig_windows_structure_changed = f->windows_structure_changed;
896   f->windows_structure_changed = 1;
897
898   if (window_needs_vertical_divider (w))
899     {
900       mswindows_output_vertical_divider (w, 0);
901     }
902
903   for (line = 0; line < Dynarr_length (cdla); line++)
904     {
905       struct display_line *cdl = Dynarr_atp (cdla, line);
906       int top_y = cdl->ypos - cdl->ascent;
907       int bottom_y = cdl->ypos + cdl->descent;
908
909       if (bottom_y >= rect_draw.top)
910         {
911           if (top_y > rect_draw.bottom)
912             {
913               if (line == 0)
914                 continue;
915               else
916                 break;
917             }
918           else
919             {
920               output_display_line (w, 0, cdla, line,
921                                    rect_draw.left, rect_draw.right);
922             }
923         }
924     }
925
926   f->windows_structure_changed = orig_windows_structure_changed;
927
928   /* If there have never been any face cache_elements created, then this
929      expose event doesn't actually have anything to do. */
930   if (Dynarr_largest (w->face_cachels))
931     redisplay_clear_bottom_of_window (w, cdla, rect_draw.top, rect_draw.bottom);
932
933 #ifdef HAVE_SCROLLBARS
934   mswindows_redisplay_deadbox_maybe (w, &rect_expose);
935 #endif
936 }
937
938 /*****************************************************************************
939  mswindows_redraw_exposed_windows
940
941  For each window beneath the given window in the window hierarchy,
942  ensure that it is redrawn if necessary after an Expose event.
943  ****************************************************************************/
944 static void
945 mswindows_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
946                             int height)
947 {
948   for (; !NILP (window); window = XWINDOW (window)->next)
949     mswindows_redraw_exposed_window (XWINDOW (window), x, y, width, height);
950 }
951
952 /*****************************************************************************
953  mswindows_redraw_exposed_area
954
955  For each window on the given frame, ensure that any area in the
956  Exposed area is redrawn.
957  ****************************************************************************/
958 void
959 mswindows_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
960 {
961   /* If any window on the frame has had its face cache reset then the
962      redisplay structures are effectively invalid.  If we attempt to
963      use them we'll blow up.  We mark the frame as changed to ensure
964      that redisplay will do a full update.  This probably isn't
965      necessary but it can't hurt. */
966 #ifdef HAVE_TOOLBARS
967   /* #### We would rather put these off as well but there is currently
968      no combination of flags which will force an unchanged toolbar to
969      redraw anyhow. */
970   MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
971 #endif
972
973   if (!f->window_face_cache_reset)
974         {
975           mswindows_redraw_exposed_windows (f->root_window, x, y, width, height);
976           GdiFlush();
977         }
978   else
979     MARK_FRAME_CHANGED (f);
980 }
981
982
983 /*****************************************************************************
984  mswindows_bevel_modeline
985
986  Draw a 3d border around the modeline on window W.
987  ****************************************************************************/
988 static void
989 mswindows_bevel_modeline (struct window *w, struct display_line *dl)
990 {
991   struct frame *f = XFRAME (w->frame);
992   Lisp_Object color;
993   int shadow_width = MODELINE_SHADOW_THICKNESS (w);
994   RECT rect = { WINDOW_MODELINE_LEFT (w), 
995                 dl->ypos - dl->ascent - shadow_width,
996                 WINDOW_MODELINE_RIGHT (w),
997                 dl->ypos + dl->descent + shadow_width};
998   UINT edge;
999
1000   color = WINDOW_FACE_CACHEL_BACKGROUND (w, MODELINE_INDEX);
1001   mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, color, Qnil);
1002
1003   if (XINT (w->modeline_shadow_thickness) < 0)
1004     shadow_width = -shadow_width;
1005
1006   if (shadow_width < -1)
1007     edge = EDGE_SUNKEN;
1008   else if (shadow_width < 0)
1009     edge = BDR_SUNKENINNER;
1010   else if (shadow_width == 1)
1011     edge = BDR_RAISEDINNER;
1012   else
1013     edge = EDGE_RAISED;
1014     
1015   DrawEdge (FRAME_MSWINDOWS_DC (f), &rect, edge, BF_RECT);
1016 }
1017
1018 \f
1019 /*****************************************************************************
1020  Display methods
1021 *****************************************************************************/
1022
1023 /*****************************************************************************
1024  mswindows_divider_height
1025
1026  Return the height of the horizontal divider.
1027  ****************************************************************************/
1028 static int
1029 mswindows_divider_height (void)
1030 {
1031   return 1;   /* XXX Copied from redisplay-X.c. What is this? */
1032 }
1033
1034 /*****************************************************************************
1035  mswindows_eol_cursor_width
1036
1037  Return the width of the end-of-line cursor.
1038  ****************************************************************************/
1039 static int
1040 mswindows_eol_cursor_width (void)
1041 {
1042   return MSWINDOWS_EOL_CURSOR_WIDTH;
1043 }
1044
1045 /*****************************************************************************
1046  mswindows_output_begin
1047
1048  Perform any necessary initialization prior to an update.
1049  ****************************************************************************/
1050 static void
1051 mswindows_output_begin (struct device *d)
1052 {
1053 }
1054
1055 /*****************************************************************************
1056  mswindows_output_end
1057
1058  Perform any necessary flushing of queues when an update has completed.
1059  ****************************************************************************/
1060 static void
1061 mswindows_output_end (struct device *d)
1062 {
1063   GdiFlush();
1064 }
1065
1066 static int
1067 mswindows_flash (struct device *d)
1068 {
1069   struct frame *f = device_selected_frame (d);
1070   RECT rc;
1071
1072   GetClientRect (FRAME_MSWINDOWS_HANDLE (f), &rc);
1073   InvertRect (FRAME_MSWINDOWS_DC (f), &rc);
1074   GdiFlush ();
1075   Sleep (25);
1076   InvertRect (FRAME_MSWINDOWS_DC (f), &rc);
1077
1078   return 1;
1079 }
1080
1081 static void
1082 mswindows_ring_bell (struct device *d, int volume, int pitch, int duration)
1083 {
1084   /* Beep does not work at all, anyways! -kkm */
1085   MessageBeep (MB_OK);
1086 }
1087
1088 /*****************************************************************************
1089  mswindows_output_display_block
1090
1091  Given a display line, a block number for that start line, output all
1092  runes between start and end in the specified display block.
1093  Ripped off with minimal thought from the corresponding X routine.
1094  ****************************************************************************/
1095 static void
1096 mswindows_output_display_block (struct window *w, struct display_line *dl, int block,
1097                           int start, int end, int start_pixpos, int cursor_start,
1098                           int cursor_width, int cursor_height)
1099 {
1100   struct frame *f = XFRAME (w->frame);
1101   Emchar_dynarr *buf = Dynarr_new (Emchar);
1102   Lisp_Object window;
1103
1104   struct display_block *db = Dynarr_atp (dl->display_blocks, block);
1105   rune_dynarr *rba = db->runes;
1106   struct rune *rb;
1107
1108   int elt = start;
1109   face_index findex;
1110   int xpos, width;
1111   Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
1112                                      MULE is not defined */
1113   XSETWINDOW (window, w);
1114   rb = Dynarr_atp (rba, start);
1115
1116   if (!rb)
1117     {
1118       /* Nothing to do so don't do anything. */
1119       return;
1120     }
1121   else
1122     {
1123       findex = rb->findex;
1124       xpos = rb->xpos;
1125       width = 0;
1126       if (rb->type == RUNE_CHAR)
1127         charset = CHAR_CHARSET (rb->object.chr.ch);
1128     }
1129
1130   if (end < 0)
1131     end = Dynarr_length (rba);
1132   Dynarr_reset (buf);
1133
1134   while (elt < end)
1135     {
1136       rb = Dynarr_atp (rba, elt);
1137
1138       if (rb->findex == findex && rb->type == RUNE_CHAR
1139           && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
1140           && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
1141         {
1142           Dynarr_add (buf, rb->object.chr.ch);
1143           width += rb->width;
1144           elt++;
1145         }
1146       else
1147         {
1148           if (Dynarr_length (buf))
1149             {
1150               mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
1151                                  findex);
1152               xpos = rb->xpos;
1153               width = 0;
1154             }
1155           Dynarr_reset (buf);
1156           width = 0;
1157
1158           if (rb->type == RUNE_CHAR)
1159             {
1160               findex = rb->findex;
1161               xpos = rb->xpos;
1162               charset = CHAR_CHARSET (rb->object.chr.ch);
1163
1164               if (rb->cursor_type == CURSOR_ON)
1165                 {
1166                   if (rb->object.chr.ch == '\n')
1167                     {
1168                       mswindows_output_cursor (w, dl, xpos, cursor_width,
1169                                                findex, 0, 0);
1170                     }
1171                   else
1172                     {
1173                       Dynarr_add (buf, rb->object.chr.ch);
1174                       mswindows_output_cursor (w, dl, xpos, cursor_width,
1175                                                findex, rb->object.chr.ch, 0);
1176                       Dynarr_reset (buf);
1177                     }
1178
1179                   xpos += rb->width;
1180                   elt++;
1181                 }
1182               else if (rb->object.chr.ch == '\n')
1183                 {
1184                   /* Clear in case a cursor was formerly here. */
1185                   int height = DISPLAY_LINE_HEIGHT (dl);
1186
1187                   redisplay_clear_region (window, findex, xpos, dl->ypos - dl->ascent,
1188                                     rb->width, height);
1189                   elt++;
1190                 }
1191             }
1192           else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
1193             {
1194               if (rb->type == RUNE_BLANK)
1195                 mswindows_output_blank (w, dl, rb, start_pixpos);
1196               else
1197                 {
1198                   /* #### Our flagging of when we need to redraw the
1199                      modeline shadows sucks.  Since RUNE_HLINE is only used
1200                      by the modeline at the moment it is a good bet
1201                      that if it gets redrawn then we should also
1202                      redraw the shadows.  This won't be true forever.
1203                      We borrow the shadow_thickness_changed flag for
1204                      now. */
1205                   w->shadow_thickness_changed = 1;
1206                   mswindows_output_hline (w, dl, rb);
1207                 }
1208
1209               if (rb->cursor_type == CURSOR_ON)
1210                 mswindows_output_cursor (w, dl, xpos, cursor_width, rb->findex, 0, 0);
1211
1212               elt++;
1213               if (elt < end)
1214                 {
1215                   rb = Dynarr_atp (rba, elt);
1216
1217                   findex = rb->findex;
1218                   xpos = rb->xpos;
1219                 }
1220             }
1221           else if (rb->type == RUNE_DGLYPH)
1222             {
1223               Lisp_Object instance;
1224
1225               XSETWINDOW (window, w);
1226               instance = glyph_image_instance (rb->object.dglyph.glyph,
1227                                                window, ERROR_ME_NOT, 1);
1228               findex = rb->findex;
1229
1230               if (IMAGE_INSTANCEP (instance))
1231                 switch (XIMAGE_INSTANCE_TYPE (instance))
1232                   {
1233                   case IMAGE_TEXT:
1234                     {
1235                       /* #### This is way losing.  See the comment in
1236                          add_glyph_rune(). */
1237                       Lisp_Object string =
1238                         XIMAGE_INSTANCE_TEXT_STRING (instance);
1239                       convert_bufbyte_string_into_emchar_dynarr
1240                         (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
1241
1242                       if (rb->cursor_type == CURSOR_ON)
1243                         mswindows_output_cursor (w, dl, xpos, cursor_width,
1244                                                  findex, Dynarr_at (buf, 0), 0);
1245                       else /* #### redisplay-x passes -1 as the width: why ? */
1246                         mswindows_output_string (w, dl, buf, xpos,
1247                                            rb->object.dglyph.xoffset,
1248                                            start_pixpos, rb->width, findex);
1249                       Dynarr_reset (buf);
1250                     }
1251                     break;
1252
1253                   case IMAGE_MONO_PIXMAP:
1254                   case IMAGE_COLOR_PIXMAP:
1255                     mswindows_output_pixmap (w, dl, instance, xpos,
1256                                      rb->object.dglyph.xoffset, start_pixpos,
1257                                      rb->width, findex, cursor_start,
1258                                      cursor_width, cursor_height, 0);
1259                     if (rb->cursor_type == CURSOR_ON)
1260                       mswindows_output_cursor (w, dl, xpos, cursor_width,
1261                                                findex, 0, 1);
1262                     break;
1263
1264                   case IMAGE_POINTER:
1265                     abort ();
1266
1267                   case IMAGE_SUBWINDOW:
1268                   case IMAGE_WIDGET:
1269                     redisplay_output_subwindow (w, dl, instance, xpos,
1270                                                 rb->object.dglyph.xoffset, start_pixpos,
1271                                                 rb->width, findex, cursor_start,
1272                                                 cursor_width, cursor_height);
1273                     if (rb->cursor_type == CURSOR_ON)
1274                       mswindows_output_cursor (w, dl, xpos, cursor_width,
1275                                                findex, 0, 1);
1276                     break;
1277
1278                   case IMAGE_NOTHING:
1279                     /* nothing is as nothing does */
1280                     break;
1281
1282                   default:
1283                     abort ();
1284                   }
1285
1286               xpos += rb->width;
1287               elt++;
1288             }
1289           else
1290             abort ();
1291         }
1292     }
1293
1294   if (Dynarr_length (buf))
1295     mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex);
1296
1297   if (dl->modeline
1298       && !EQ (Qzero, w->modeline_shadow_thickness)
1299       && (f->clear
1300           || f->windows_structure_changed
1301           || w->shadow_thickness_changed))
1302     mswindows_bevel_modeline (w, dl);
1303
1304   Dynarr_free (buf);
1305 }
1306
1307
1308 /*****************************************************************************
1309  mswindows_output_vertical_divider
1310
1311  Draw a vertical divider down the right side of the given window.
1312  ****************************************************************************/
1313 static void
1314 mswindows_output_vertical_divider (struct window *w, int clear_unused)
1315 {
1316   struct frame *f = XFRAME (w->frame);
1317   RECT rect;
1318   int spacing = XINT (w->vertical_divider_spacing);
1319   int shadow = XINT (w->vertical_divider_shadow_thickness);
1320   int abs_shadow = abs (shadow);
1321   int line_width = XINT (w->vertical_divider_line_width);
1322   int div_left = WINDOW_RIGHT (w) - window_divider_width (w);
1323
1324   /* Clear left and right spacing areas */
1325   if (spacing)
1326     {
1327       rect.top = WINDOW_TOP (w);
1328       rect.bottom = WINDOW_BOTTOM (w);
1329       mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
1330                    WINDOW_FACE_CACHEL_BACKGROUND (w, DEFAULT_INDEX), Qnil);
1331       rect.right = WINDOW_RIGHT (w);
1332       rect.left = rect.right - spacing;
1333       ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, 
1334                   &rect, NULL, 0, NULL);
1335       rect.left = div_left;
1336       rect.right = div_left + spacing;
1337       ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, 
1338                   &rect, NULL, 0, NULL);
1339     }
1340   
1341   /* Clear divider face */
1342   rect.top = WINDOW_TOP (w) + abs_shadow;
1343   rect.bottom = WINDOW_BOTTOM (w) - abs_shadow;
1344   rect.left = div_left + spacing + abs_shadow;
1345   rect.right = rect.left + line_width;
1346   if (rect.left < rect.right)
1347     {
1348       face_index div_face
1349         = get_builtin_face_cache_index (w, Vvertical_divider_face);
1350       mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
1351                    WINDOW_FACE_CACHEL_BACKGROUND (w, div_face), Qnil);
1352       ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, 
1353                   &rect, NULL, 0, NULL);
1354     }
1355
1356   /* Draw a shadow around the divider */
1357   if (shadow != 0)
1358     {
1359       /* #### This will be fixed to support arbitrary thickness */
1360       InflateRect (&rect, abs_shadow, abs_shadow);
1361       DrawEdge (FRAME_MSWINDOWS_DC (f), &rect,
1362                 shadow > 0 ? EDGE_RAISED : EDGE_SUNKEN, BF_RECT);
1363     }
1364 }
1365
1366 /****************************************************************************
1367  mswindows_text_width
1368
1369  Given a string and a face, return the string's length in pixels when
1370  displayed in the font associated with the face.
1371  ****************************************************************************/
1372 static int
1373 mswindows_text_width (struct frame *f, struct face_cachel *cachel,
1374                       CONST Emchar *str, Charcount len)
1375 {
1376   int width_so_far = 0;
1377   unsigned char *text_storage = (unsigned char *) alloca (2 * len);
1378   textual_run *runs = alloca_array (textual_run, len);
1379   int nruns;
1380   int i;
1381
1382   nruns = separate_textual_runs (text_storage, runs, str, len);
1383
1384   for (i = 0; i < nruns; i++)
1385     width_so_far += mswindows_text_width_single_run (FRAME_MSWINDOWS_DC (f),
1386                                                      cachel, runs + i);
1387
1388   return width_so_far;
1389 }
1390
1391
1392 /****************************************************************************
1393  mswindows_clear_region
1394
1395  Clear the area in the box defined by the given parameters using the
1396  given face.
1397  ****************************************************************************/
1398 static void
1399 mswindows_clear_region (Lisp_Object locale, struct device* d, struct frame* f, 
1400                         face_index findex, int x, int y,
1401                         int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1402                         Lisp_Object background_pixmap)
1403 {
1404   RECT rect = { x, y, x+width, y+height };
1405
1406   if (!NILP (background_pixmap))
1407     {
1408       mswindows_update_dc (FRAME_MSWINDOWS_DC (f),
1409                            Qnil, fcolor, bcolor, background_pixmap);
1410
1411       mswindows_output_dibitmap_region 
1412         ( f, XIMAGE_INSTANCE (background_pixmap),
1413           x, y, 0, 0, 0, 0, width, height, 0, TRUE);
1414     }
1415   else
1416     {
1417       mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, fcolor, Qnil);
1418       ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, 
1419                   &rect, NULL, 0, NULL);
1420     }
1421
1422 #ifdef HAVE_SCROLLBARS
1423   if (WINDOWP (locale))
1424     mswindows_redisplay_deadbox_maybe (XWINDOW (locale), &rect);
1425 #endif
1426 }
1427
1428 /*****************************************************************************
1429  mswindows_clear_to_window_end
1430
1431  Clear the area between ypos1 and ypos2.  Each margin area and the
1432  text area is handled separately since they may each have their own
1433  background color.
1434  ****************************************************************************/
1435 static void
1436 mswindows_clear_to_window_end (struct window *w, int ypos1, int ypos2)
1437 {
1438   int height = ypos2 - ypos1;
1439
1440   if (height)
1441     {
1442       struct frame *f = XFRAME (w->frame);
1443       Lisp_Object window;
1444       int bflag = (window_needs_vertical_divider (w) ? 0 : 1);
1445       layout_bounds bounds;
1446
1447       bounds = calculate_display_line_boundaries (w, bflag);
1448       XSETWINDOW (window, w);
1449
1450       if (window_is_leftmost (w))
1451         redisplay_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f),
1452                           ypos1, FRAME_BORDER_WIDTH (f), height);
1453
1454       if (bounds.left_in - bounds.left_out > 0)
1455         redisplay_clear_region (window,
1456                           get_builtin_face_cache_index (w, Vleft_margin_face),
1457                           bounds.left_out, ypos1,
1458                           bounds.left_in - bounds.left_out, height);
1459
1460       if (bounds.right_in - bounds.left_in > 0)
1461         redisplay_clear_region (window, DEFAULT_INDEX, bounds.left_in, ypos1,
1462                           bounds.right_in - bounds.left_in, height);
1463
1464       if (bounds.right_out - bounds.right_in > 0)
1465         redisplay_clear_region (window,
1466                           get_builtin_face_cache_index (w, Vright_margin_face),
1467                           bounds.right_in, ypos1,
1468                           bounds.right_out - bounds.right_in, height);
1469
1470       if (window_is_rightmost (w))
1471         redisplay_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f),
1472                           ypos1, FRAME_BORDER_WIDTH (f), height);
1473     }
1474
1475 }
1476
1477
1478 /* XXX Implement me! */
1479 static void
1480 mswindows_clear_frame (struct frame *f)
1481 {
1482   GdiFlush();
1483 }
1484
1485
1486 \f
1487 /************************************************************************/
1488 /*                            initialization                            */
1489 /************************************************************************/
1490
1491 void
1492 console_type_create_redisplay_mswindows (void)
1493 {
1494   /* redisplay methods */
1495   CONSOLE_HAS_METHOD (mswindows, text_width);
1496   CONSOLE_HAS_METHOD (mswindows, output_display_block);
1497   CONSOLE_HAS_METHOD (mswindows, divider_height);
1498   CONSOLE_HAS_METHOD (mswindows, eol_cursor_width);
1499   CONSOLE_HAS_METHOD (mswindows, output_vertical_divider);
1500   CONSOLE_HAS_METHOD (mswindows, clear_to_window_end);
1501   CONSOLE_HAS_METHOD (mswindows, clear_region);
1502   CONSOLE_HAS_METHOD (mswindows, clear_frame);
1503   CONSOLE_HAS_METHOD (mswindows, output_begin);
1504   CONSOLE_HAS_METHOD (mswindows, output_end);
1505   CONSOLE_HAS_METHOD (mswindows, flash);
1506   CONSOLE_HAS_METHOD (mswindows, ring_bell);
1507 }