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