XEmacs 21.2.7
[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 = dl->ascent + dl->descent - dl->clip;
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   /* do we need to offset the pixmap vertically? this is necessary
595      for background pixmaps. */
596   if (offset_bitmap)
597     {
598       yoffset = y % IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
599       xoffset = x % IMAGE_INSTANCE_PIXMAP_WIDTH (p);
600       /* the width is handled by mswindows_output_pixmap_region */
601     }
602
603   if (need_clipping)
604     {
605     }
606
607   /* first blt the mask */
608   if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
609     {
610       RGBQUAD col;
611       col.rgbBlue = GetBValue (bgcolor);
612       col.rgbRed = GetRValue (bgcolor);
613       col.rgbGreen = GetGValue (bgcolor);
614       col.rgbReserved = 0;
615
616       old = SelectObject (FRAME_MSWINDOWS_CDC (f),
617                           IMAGE_INSTANCE_MSWINDOWS_MASK (p));
618       
619       SetDIBColorTable (FRAME_MSWINDOWS_CDC (f), 1, 1, &col);
620
621       BitBlt (hdc, 
622               x,y,
623               width, height, 
624               FRAME_MSWINDOWS_CDC (f),
625               xoffset,yoffset, 
626               SRCCOPY);                  
627
628       SelectObject (FRAME_MSWINDOWS_CDC (f), old);
629     }
630   
631   /* now blt the bitmap itself. */
632   old = SelectObject (FRAME_MSWINDOWS_CDC (f),
633                       IMAGE_INSTANCE_MSWINDOWS_BITMAP (p));
634
635   BitBlt (hdc, 
636           x,y,
637           width, height, 
638           FRAME_MSWINDOWS_CDC (f),
639           xoffset, yoffset, 
640           IMAGE_INSTANCE_MSWINDOWS_MASK (p) ? SRCINVERT : SRCCOPY);
641
642   SelectObject (FRAME_MSWINDOWS_CDC (f),old);
643
644   if (need_clipping)
645     {
646     }
647 }
648
649 /*
650  * X gc's have this nice property that setting the bg pixmap will
651  * output it offset relative to the window. Windows doesn't have this
652  * feature so we have to emulate this by outputting multiple pixmaps 
653  */
654 static void
655 mswindows_output_dibitmap_region (struct frame *f, 
656                                   struct Lisp_Image_Instance *p,
657                                   int x, int y, 
658                                   int clip_x, int clip_y, 
659                                   int clip_width, int clip_height, 
660                                   int width, int height, int pixmap_offset,
661                                   int offset_bitmap)
662 {
663   int pwidth = min (width, IMAGE_INSTANCE_PIXMAP_WIDTH (p));
664   int pheight = min (height, IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
665   int pxoffset = 0, pyoffset = 0;
666
667   /* when doing a bg pixmap do a partial pixmap first so that we
668      blt whole pixmaps thereafter */
669
670   if (offset_bitmap)
671     {
672       pheight = min (pheight, IMAGE_INSTANCE_PIXMAP_HEIGHT (p) -
673                      y % IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
674     }
675   
676   while (pheight > 0)
677     {
678       if (offset_bitmap)
679         {
680           pwidth = min (min (width, IMAGE_INSTANCE_PIXMAP_WIDTH (p)),
681                         IMAGE_INSTANCE_PIXMAP_WIDTH (p) -
682                         x % IMAGE_INSTANCE_PIXMAP_WIDTH (p));
683           pxoffset = 0;
684         }
685       while (pwidth > 0)
686         {
687           mswindows_output_dibitmap (f, p,
688                                      x + pxoffset, y + pyoffset, 
689                                      clip_x, clip_y, 
690                                      clip_width, clip_height, 
691                                      pwidth, pheight, pixmap_offset,
692                                      offset_bitmap);
693           pxoffset += pwidth;
694           pwidth = min ((width-pxoffset), 
695                         IMAGE_INSTANCE_PIXMAP_WIDTH (p));
696         }
697       pyoffset += pheight;
698       pheight = min ((height-pyoffset), 
699                      IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
700     }
701 }
702
703 static void
704 mswindows_output_pixmap (struct window *w, struct display_line *dl,
705                          Lisp_Object image_instance, int xpos, int xoffset,
706                          int start_pixpos, int width, face_index findex,
707                          int cursor_start, int cursor_width, int cursor_height,
708                          int offset_bitmap)
709 {
710   struct frame *f = XFRAME (w->frame);
711   HDC hdc = FRAME_MSWINDOWS_DC (f);
712
713   struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
714   Lisp_Object window;
715
716   int lheight = dl->ascent + dl->descent - dl->clip;
717   int pheight = ((int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > lheight ? lheight :
718                  IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
719   int clip_x, clip_y, clip_width, clip_height;
720
721   /* The pixmap_offset is used to center the pixmap on lines which are
722      shorter than it is.  This results in odd effects when scrolling
723      pixmaps off of the bottom.  Let's try not using it. */
724 #if 0
725   int pixmap_offset = (int) (IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - lheight) / 2;
726 #else
727   int pixmap_offset = 0;
728 #endif
729
730   XSETWINDOW (window, w);
731
732   if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
733     {
734       if (start_pixpos > xpos && start_pixpos > xpos + width)
735         return;
736
737       clip_x = xoffset;
738       clip_width = width;
739       if (start_pixpos > xpos)
740         {
741           clip_x += (start_pixpos - xpos);
742           clip_width -= (start_pixpos - xpos);
743         }
744     }
745   else
746     {
747       clip_x = 0;
748       clip_width = 0;
749     }
750
751   /* Place markers for possible future functionality (clipping the top
752      half instead of the bottom half; think pixel scrolling). */
753   clip_y = 0;
754   clip_height = pheight;
755
756   /* Clear the area the pixmap is going into.  The pixmap itself will
757      always take care of the full width.  We don't want to clear where
758      it is going to go in order to avoid flicker.  So, all we have to
759      take care of is any area above or below the pixmap. */
760   /* #### We take a shortcut for now.  We know that since we have
761      pixmap_offset hardwired to 0 that the pixmap is against the top
762      edge so all we have to worry about is below it. */
763   /* #### Unless the pixmap has a mask in which case we have to clear
764      the whole damn thing since we can't yet clear just the area not
765      included in the mask. */
766   if (((int) (dl->ypos - dl->ascent + pheight) <
767        (int) (dl->ypos + dl->descent - dl->clip))
768       || IMAGE_INSTANCE_MSWINDOWS_MASK (p))
769     {
770       int clear_x, clear_y, clear_width, clear_height;
771
772       if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
773         {
774           clear_y = dl->ypos - dl->ascent;
775           clear_height = lheight;
776         }
777       else
778         {
779           clear_y = dl->ypos - dl->ascent + pheight;
780           clear_height = lheight - pheight;
781         }
782
783       if (start_pixpos >= 0 && start_pixpos > xpos)
784         {
785           clear_x = start_pixpos;
786           clear_width = xpos + width - start_pixpos;
787         }
788       else
789         {
790           clear_x = xpos;
791           clear_width = width;
792         }
793
794       if (!offset_bitmap)       /* i.e. not a bg pixmap */
795         redisplay_clear_region (window, findex, clear_x, clear_y,
796                                 clear_width, clear_height);
797     }
798
799   /* Output the pixmap. Have to do this as many times as is required
800    to fill the given area */
801   mswindows_update_dc (hdc, Qnil,
802                        WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
803                        WINDOW_FACE_CACHEL_BACKGROUND (w, findex), Qnil);
804
805   mswindows_output_dibitmap_region (f, p, xpos - xoffset,
806                                     dl->ypos - dl->ascent,
807                                     clip_x, clip_y, clip_width, clip_height,
808                                     width + xoffset, pheight, pixmap_offset,
809                                     offset_bitmap);
810 }
811
812 #ifdef HAVE_SCROLLBARS
813 /*
814  * This function paints window's deadbox, a rectangle between window
815  * borders and two short edges of both scrollbars.
816  *
817  * Function checks whether deadbox intersects with the rectangle pointed
818  * to by PRC, and paints only the intersection
819  */
820 static void
821 mswindows_redisplay_deadbox_maybe (struct window *w, CONST RECT* prc)
822 {
823   int sbh = window_scrollbar_height (w);
824   int sbw = window_scrollbar_width (w);
825   RECT rect_dead, rect_paint;
826   if (sbh == 0 || sbw == 0)
827     return;
828
829   if (!NILP (w->scrollbar_on_left_p))
830     rect_dead.left = WINDOW_LEFT (w);
831   else
832     rect_dead.left = WINDOW_TEXT_RIGHT (w);
833   rect_dead.right = rect_dead.left + sbw;
834
835   if (!NILP (w->scrollbar_on_top_p))
836     rect_dead.top = WINDOW_TOP (w);
837   else
838     rect_dead.top = WINDOW_TEXT_BOTTOM (w);
839   rect_dead.bottom = rect_dead.top + sbh;
840       
841   if (IntersectRect (&rect_paint, &rect_dead, prc))
842     {
843       struct frame *f = XFRAME (WINDOW_FRAME (w));
844       FillRect (FRAME_MSWINDOWS_DC (f), &rect_paint,
845                 (HBRUSH) (COLOR_BTNFACE+1));
846     }
847 }
848
849 #endif /* HAVE_SCROLLBARS */
850
851 /*****************************************************************************
852  mswindows_redraw_exposed_window
853
854  Given a bounding box for an area that needs to be redrawn, determine
855  what parts of what lines are contained within and re-output their
856  contents.
857  Copied from redisplay-x.c
858  ****************************************************************************/
859 static void
860 mswindows_redraw_exposed_window (struct window *w, int x, int y, int width,
861                            int height)
862 {
863   struct frame *f = XFRAME (w->frame);
864   int line;
865   int orig_windows_structure_changed;
866   RECT rect_window = { WINDOW_LEFT (w), WINDOW_TOP (w),
867                        WINDOW_RIGHT (w), WINDOW_BOTTOM (w) };
868   RECT rect_expose = { x, y, x + width, y + height };
869   RECT rect_draw;
870
871   display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
872
873   if (!NILP (w->vchild))
874     {
875       mswindows_redraw_exposed_windows (w->vchild, x, y, width, height);
876       return;
877     }
878   else if (!NILP (w->hchild))
879     {
880       mswindows_redraw_exposed_windows (w->hchild, x, y, width, height);
881       return;
882     }
883
884   /* If the window doesn't intersect the exposed region, we're done here. */
885   if (!IntersectRect (&rect_draw, &rect_window, &rect_expose))
886       return;
887
888   /* We do this to make sure that the 3D modelines get redrawn if
889      they are in the exposed region. */
890   orig_windows_structure_changed = f->windows_structure_changed;
891   f->windows_structure_changed = 1;
892
893   if (window_needs_vertical_divider (w))
894     {
895       mswindows_output_vertical_divider (w, 0);
896     }
897
898   for (line = 0; line < Dynarr_length (cdla); line++)
899     {
900       struct display_line *cdl = Dynarr_atp (cdla, line);
901       int top_y = cdl->ypos - cdl->ascent;
902       int bottom_y = cdl->ypos + cdl->descent;
903
904       if (bottom_y >= rect_draw.top)
905         {
906           if (top_y > rect_draw.bottom)
907             {
908               if (line == 0)
909                 continue;
910               else
911                 break;
912             }
913           else
914             {
915               output_display_line (w, 0, cdla, line,
916                                    rect_draw.left, rect_draw.right);
917             }
918         }
919     }
920
921   f->windows_structure_changed = orig_windows_structure_changed;
922
923   /* If there have never been any face cache_elements created, then this
924      expose event doesn't actually have anything to do. */
925   if (Dynarr_largest (w->face_cachels))
926     redisplay_clear_bottom_of_window (w, cdla, rect_draw.top, rect_draw.bottom);
927
928 #ifdef HAVE_SCROLLBARS
929   mswindows_redisplay_deadbox_maybe (w, &rect_expose);
930 #endif
931 }
932
933 /*****************************************************************************
934  mswindows_redraw_exposed_windows
935
936  For each window beneath the given window in the window hierarchy,
937  ensure that it is redrawn if necessary after an Expose event.
938  ****************************************************************************/
939 static void
940 mswindows_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
941                             int height)
942 {
943   for (; !NILP (window); window = XWINDOW (window)->next)
944     mswindows_redraw_exposed_window (XWINDOW (window), x, y, width, height);
945 }
946
947 /*****************************************************************************
948  mswindows_redraw_exposed_area
949
950  For each window on the given frame, ensure that any area in the
951  Exposed area is redrawn.
952  ****************************************************************************/
953 void
954 mswindows_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
955 {
956   /* If any window on the frame has had its face cache reset then the
957      redisplay structures are effectively invalid.  If we attempt to
958      use them we'll blow up.  We mark the frame as changed to ensure
959      that redisplay will do a full update.  This probably isn't
960      necessary but it can't hurt. */
961 #ifdef HAVE_TOOLBARS
962   /* #### We would rather put these off as well but there is currently
963      no combination of flags which will force an unchanged toolbar to
964      redraw anyhow. */
965   MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
966 #endif
967
968   if (!f->window_face_cache_reset)
969         {
970           mswindows_redraw_exposed_windows (f->root_window, x, y, width, height);
971           GdiFlush();
972         }
973   else
974     MARK_FRAME_CHANGED (f);
975 }
976
977
978 /*****************************************************************************
979  mswindows_bevel_modeline
980
981  Draw a 3d border around the modeline on window W.
982  ****************************************************************************/
983 static void
984 mswindows_bevel_modeline (struct window *w, struct display_line *dl)
985 {
986   struct frame *f = XFRAME (w->frame);
987   Lisp_Object color;
988   int shadow_width = MODELINE_SHADOW_THICKNESS (w);
989   RECT rect = { WINDOW_MODELINE_LEFT (w), 
990                 dl->ypos - dl->ascent - shadow_width,
991                 WINDOW_MODELINE_RIGHT (w),
992                 dl->ypos + dl->descent + shadow_width};
993   UINT edge;
994
995   color = WINDOW_FACE_CACHEL_BACKGROUND (w, MODELINE_INDEX);
996   mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, color, Qnil);
997
998   if (XINT (w->modeline_shadow_thickness) < 0)
999     shadow_width = -shadow_width;
1000
1001   if (shadow_width < -1)
1002     edge = EDGE_SUNKEN;
1003   else if (shadow_width < 0)
1004     edge = BDR_SUNKENINNER;
1005   else if (shadow_width == 1)
1006     edge = BDR_RAISEDINNER;
1007   else
1008     edge = EDGE_RAISED;
1009     
1010   DrawEdge (FRAME_MSWINDOWS_DC (f), &rect, edge, BF_RECT);
1011 }
1012
1013 \f
1014 /*****************************************************************************
1015  Display methods
1016 *****************************************************************************/
1017
1018 /*****************************************************************************
1019  mswindows_divider_height
1020
1021  Return the height of the horizontal divider.
1022  ****************************************************************************/
1023 static int
1024 mswindows_divider_height (void)
1025 {
1026   return 1;   /* XXX Copied from redisplay-X.c. What is this? */
1027 }
1028
1029 /*****************************************************************************
1030  mswindows_eol_cursor_width
1031
1032  Return the width of the end-of-line cursor.
1033  ****************************************************************************/
1034 static int
1035 mswindows_eol_cursor_width (void)
1036 {
1037   return MSWINDOWS_EOL_CURSOR_WIDTH;
1038 }
1039
1040 /*****************************************************************************
1041  mswindows_output_begin
1042
1043  Perform any necessary initialization prior to an update.
1044  ****************************************************************************/
1045 static void
1046 mswindows_output_begin (struct device *d)
1047 {
1048 }
1049
1050 /*****************************************************************************
1051  mswindows_output_end
1052
1053  Perform any necessary flushing of queues when an update has completed.
1054  ****************************************************************************/
1055 static void
1056 mswindows_output_end (struct device *d)
1057 {
1058   GdiFlush();
1059 }
1060
1061 static int
1062 mswindows_flash (struct device *d)
1063 {
1064   struct frame *f = device_selected_frame (d);
1065   RECT rc;
1066
1067   GetClientRect (FRAME_MSWINDOWS_HANDLE (f), &rc);
1068   InvertRect (FRAME_MSWINDOWS_DC (f), &rc);
1069   GdiFlush ();
1070   Sleep (25);
1071   InvertRect (FRAME_MSWINDOWS_DC (f), &rc);
1072
1073   return 1;
1074 }
1075
1076 static void
1077 mswindows_ring_bell (struct device *d, int volume, int pitch, int duration)
1078 {
1079   /* Beep does not work at all, anyways! -kkm */
1080   MessageBeep (MB_OK);
1081 }
1082
1083 /*****************************************************************************
1084  mswindows_output_display_block
1085
1086  Given a display line, a block number for that start line, output all
1087  runes between start and end in the specified display block.
1088  Ripped off with minimal thought from the corresponding X routine.
1089  ****************************************************************************/
1090 static void
1091 mswindows_output_display_block (struct window *w, struct display_line *dl, int block,
1092                           int start, int end, int start_pixpos, int cursor_start,
1093                           int cursor_width, int cursor_height)
1094 {
1095   struct frame *f = XFRAME (w->frame);
1096   Emchar_dynarr *buf = Dynarr_new (Emchar);
1097   Lisp_Object window;
1098
1099   struct display_block *db = Dynarr_atp (dl->display_blocks, block);
1100   rune_dynarr *rba = db->runes;
1101   struct rune *rb;
1102
1103   int elt = start;
1104   face_index findex;
1105   int xpos, width;
1106   Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
1107                                      MULE is not defined */
1108   XSETWINDOW (window, w);
1109   rb = Dynarr_atp (rba, start);
1110
1111   if (!rb)
1112     {
1113       /* Nothing to do so don't do anything. */
1114       return;
1115     }
1116   else
1117     {
1118       findex = rb->findex;
1119       xpos = rb->xpos;
1120       width = 0;
1121       if (rb->type == RUNE_CHAR)
1122         charset = CHAR_CHARSET (rb->object.chr.ch);
1123     }
1124
1125   if (end < 0)
1126     end = Dynarr_length (rba);
1127   Dynarr_reset (buf);
1128
1129   while (elt < end)
1130     {
1131       rb = Dynarr_atp (rba, elt);
1132
1133       if (rb->findex == findex && rb->type == RUNE_CHAR
1134           && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
1135           && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
1136         {
1137           Dynarr_add (buf, rb->object.chr.ch);
1138           width += rb->width;
1139           elt++;
1140         }
1141       else
1142         {
1143           if (Dynarr_length (buf))
1144             {
1145               mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
1146                                  findex);
1147               xpos = rb->xpos;
1148               width = 0;
1149             }
1150           Dynarr_reset (buf);
1151           width = 0;
1152
1153           if (rb->type == RUNE_CHAR)
1154             {
1155               findex = rb->findex;
1156               xpos = rb->xpos;
1157               charset = CHAR_CHARSET (rb->object.chr.ch);
1158
1159               if (rb->cursor_type == CURSOR_ON)
1160                 {
1161                   if (rb->object.chr.ch == '\n')
1162                     {
1163                       mswindows_output_cursor (w, dl, xpos, cursor_width,
1164                                                findex, 0, 0);
1165                     }
1166                   else
1167                     {
1168                       Dynarr_add (buf, rb->object.chr.ch);
1169                       mswindows_output_cursor (w, dl, xpos, cursor_width,
1170                                                findex, rb->object.chr.ch, 0);
1171                       Dynarr_reset (buf);
1172                     }
1173
1174                   xpos += rb->width;
1175                   elt++;
1176                 }
1177               else if (rb->object.chr.ch == '\n')
1178                 {
1179                   /* Clear in case a cursor was formerly here. */
1180                   int height = dl->ascent + dl->descent - dl->clip;
1181
1182                   redisplay_clear_region (window, findex, xpos, dl->ypos - dl->ascent,
1183                                     rb->width, height);
1184                   elt++;
1185                 }
1186             }
1187           else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
1188             {
1189               if (rb->type == RUNE_BLANK)
1190                 mswindows_output_blank (w, dl, rb, start_pixpos);
1191               else
1192                 {
1193                   /* #### Our flagging of when we need to redraw the
1194                      modeline shadows sucks.  Since RUNE_HLINE is only used
1195                      by the modeline at the moment it is a good bet
1196                      that if it gets redrawn then we should also
1197                      redraw the shadows.  This won't be true forever.
1198                      We borrow the shadow_thickness_changed flag for
1199                      now. */
1200                   w->shadow_thickness_changed = 1;
1201                   mswindows_output_hline (w, dl, rb);
1202                 }
1203
1204               if (rb->cursor_type == CURSOR_ON)
1205                 mswindows_output_cursor (w, dl, xpos, cursor_width, rb->findex, 0, 0);
1206
1207               elt++;
1208               if (elt < end)
1209                 {
1210                   rb = Dynarr_atp (rba, elt);
1211
1212                   findex = rb->findex;
1213                   xpos = rb->xpos;
1214                 }
1215             }
1216           else if (rb->type == RUNE_DGLYPH)
1217             {
1218               Lisp_Object instance;
1219
1220               XSETWINDOW (window, w);
1221               instance = glyph_image_instance (rb->object.dglyph.glyph,
1222                                                window, ERROR_ME_NOT, 1);
1223               findex = rb->findex;
1224
1225               if (IMAGE_INSTANCEP (instance))
1226                 switch (XIMAGE_INSTANCE_TYPE (instance))
1227                   {
1228                   case IMAGE_TEXT:
1229                     {
1230                       /* #### This is way losing.  See the comment in
1231                          add_glyph_rune(). */
1232                       Lisp_Object string =
1233                         XIMAGE_INSTANCE_TEXT_STRING (instance);
1234                       convert_bufbyte_string_into_emchar_dynarr
1235                         (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
1236
1237                       if (rb->cursor_type == CURSOR_ON)
1238                         mswindows_output_cursor (w, dl, xpos, cursor_width,
1239                                                  findex, Dynarr_at (buf, 0), 0);
1240                       else /* #### redisplay-x passes -1 as the width: why ? */
1241                         mswindows_output_string (w, dl, buf, xpos,
1242                                            rb->object.dglyph.xoffset,
1243                                            start_pixpos, rb->width, findex);
1244                       Dynarr_reset (buf);
1245                     }
1246                     break;
1247
1248                   case IMAGE_MONO_PIXMAP:
1249                   case IMAGE_COLOR_PIXMAP:
1250                     mswindows_output_pixmap (w, dl, instance, xpos,
1251                                      rb->object.dglyph.xoffset, start_pixpos,
1252                                      rb->width, findex, cursor_start,
1253                                      cursor_width, cursor_height, 0);
1254                     if (rb->cursor_type == CURSOR_ON)
1255                       mswindows_output_cursor (w, dl, xpos, cursor_width,
1256                                                findex, 0, 1);
1257                     break;
1258
1259                   case IMAGE_POINTER:
1260                     abort ();
1261
1262                   case IMAGE_SUBWINDOW:
1263                   case IMAGE_WIDGET:
1264                     redisplay_output_subwindow (w, dl, instance, xpos,
1265                                                 rb->object.dglyph.xoffset, start_pixpos,
1266                                                 rb->width, findex, cursor_start,
1267                                                 cursor_width, cursor_height);
1268                     if (rb->cursor_type == CURSOR_ON)
1269                       mswindows_output_cursor (w, dl, xpos, cursor_width,
1270                                                findex, 0, 1);
1271                     break;
1272
1273                   case IMAGE_NOTHING:
1274                     /* nothing is as nothing does */
1275                     break;
1276
1277                   default:
1278                     abort ();
1279                   }
1280
1281               xpos += rb->width;
1282               elt++;
1283             }
1284           else
1285             abort ();
1286         }
1287     }
1288
1289   if (Dynarr_length (buf))
1290     mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex);
1291
1292   if (dl->modeline
1293       && !EQ (Qzero, w->modeline_shadow_thickness)
1294       && (f->clear
1295           || f->windows_structure_changed
1296           || w->shadow_thickness_changed))
1297     mswindows_bevel_modeline (w, dl);
1298
1299   Dynarr_free (buf);
1300 }
1301
1302
1303 /*****************************************************************************
1304  mswindows_output_vertical_divider
1305
1306  Draw a vertical divider down the right side of the given window.
1307  ****************************************************************************/
1308 static void
1309 mswindows_output_vertical_divider (struct window *w, int clear_unused)
1310 {
1311   struct frame *f = XFRAME (w->frame);
1312   RECT rect;
1313   int spacing = XINT (w->vertical_divider_spacing);
1314   int shadow = XINT (w->vertical_divider_shadow_thickness);
1315   int abs_shadow = abs (shadow);
1316   int line_width = XINT (w->vertical_divider_line_width);
1317   int div_left = WINDOW_RIGHT (w) - window_divider_width (w);
1318
1319   /* Clear left and right spacing areas */
1320   if (spacing)
1321     {
1322       rect.top = WINDOW_TOP (w);
1323       rect.bottom = WINDOW_BOTTOM (w);
1324       mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
1325                    WINDOW_FACE_CACHEL_BACKGROUND (w, DEFAULT_INDEX), Qnil);
1326       rect.right = WINDOW_RIGHT (w);
1327       rect.left = rect.right - spacing;
1328       ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, 
1329                   &rect, NULL, 0, NULL);
1330       rect.left = div_left;
1331       rect.right = div_left + spacing;
1332       ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, 
1333                   &rect, NULL, 0, NULL);
1334     }
1335   
1336   /* Clear divider face */
1337   rect.top = WINDOW_TOP (w) + abs_shadow;
1338   rect.bottom = WINDOW_BOTTOM (w) - abs_shadow;
1339   rect.left = div_left + spacing + abs_shadow;
1340   rect.right = rect.left + line_width;
1341   if (rect.left < rect.right)
1342     {
1343       face_index div_face
1344         = get_builtin_face_cache_index (w, Vvertical_divider_face);
1345       mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
1346                    WINDOW_FACE_CACHEL_BACKGROUND (w, div_face), Qnil);
1347       ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, 
1348                   &rect, NULL, 0, NULL);
1349     }
1350
1351   /* Draw a shadow around the divider */
1352   if (shadow != 0)
1353     {
1354       /* #### This will be fixed to support arbitrary thickness */
1355       InflateRect (&rect, abs_shadow, abs_shadow);
1356       DrawEdge (FRAME_MSWINDOWS_DC (f), &rect,
1357                 shadow > 0 ? EDGE_RAISED : EDGE_SUNKEN, BF_RECT);
1358     }
1359 }
1360
1361 /****************************************************************************
1362  mswindows_text_width
1363
1364  Given a string and a face, return the string's length in pixels when
1365  displayed in the font associated with the face.
1366  ****************************************************************************/
1367 static int
1368 mswindows_text_width (struct frame *f, struct face_cachel *cachel,
1369                       CONST Emchar *str, Charcount len)
1370 {
1371   int width_so_far = 0;
1372   unsigned char *text_storage = (unsigned char *) alloca (2 * len);
1373   textual_run *runs = alloca_array (textual_run, len);
1374   int nruns;
1375   int i;
1376
1377   nruns = separate_textual_runs (text_storage, runs, str, len);
1378
1379   for (i = 0; i < nruns; i++)
1380     width_so_far += mswindows_text_width_single_run (FRAME_MSWINDOWS_DC (f),
1381                                                      cachel, runs + i);
1382
1383   return width_so_far;
1384 }
1385
1386
1387 /****************************************************************************
1388  mswindows_clear_region
1389
1390  Clear the area in the box defined by the given parameters using the
1391  given face.
1392  ****************************************************************************/
1393 static void
1394 mswindows_clear_region (Lisp_Object locale, struct device* d, struct frame* f, 
1395                         face_index findex, int x, int y,
1396                         int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1397                         Lisp_Object background_pixmap)
1398 {
1399   RECT rect = { x, y, x+width, y+height };
1400
1401   if (!NILP (background_pixmap))
1402     {
1403       mswindows_update_dc (FRAME_MSWINDOWS_DC (f),
1404                            Qnil, fcolor, bcolor, background_pixmap);
1405
1406       mswindows_output_dibitmap_region 
1407         ( f, XIMAGE_INSTANCE (background_pixmap),
1408           x, y, 0, 0, 0, 0, width, height, 0, TRUE);
1409     }
1410   else
1411     {
1412       mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, fcolor, Qnil);
1413       ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, 
1414                   &rect, NULL, 0, NULL);
1415     }
1416
1417 #ifdef HAVE_SCROLLBARS
1418   if (WINDOWP (locale))
1419     mswindows_redisplay_deadbox_maybe (XWINDOW (locale), &rect);
1420 #endif
1421 }
1422
1423 /*****************************************************************************
1424  mswindows_clear_to_window_end
1425
1426  Clear the area between ypos1 and ypos2.  Each margin area and the
1427  text area is handled separately since they may each have their own
1428  background color.
1429  ****************************************************************************/
1430 static void
1431 mswindows_clear_to_window_end (struct window *w, int ypos1, int ypos2)
1432 {
1433   int height = ypos2 - ypos1;
1434
1435   if (height)
1436     {
1437       struct frame *f = XFRAME (w->frame);
1438       Lisp_Object window;
1439       int bflag = (window_needs_vertical_divider (w) ? 0 : 1);
1440       layout_bounds bounds;
1441
1442       bounds = calculate_display_line_boundaries (w, bflag);
1443       XSETWINDOW (window, w);
1444
1445       if (window_is_leftmost (w))
1446         redisplay_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f),
1447                           ypos1, FRAME_BORDER_WIDTH (f), height);
1448
1449       if (bounds.left_in - bounds.left_out > 0)
1450         redisplay_clear_region (window,
1451                           get_builtin_face_cache_index (w, Vleft_margin_face),
1452                           bounds.left_out, ypos1,
1453                           bounds.left_in - bounds.left_out, height);
1454
1455       if (bounds.right_in - bounds.left_in > 0)
1456         redisplay_clear_region (window, DEFAULT_INDEX, bounds.left_in, ypos1,
1457                           bounds.right_in - bounds.left_in, height);
1458
1459       if (bounds.right_out - bounds.right_in > 0)
1460         redisplay_clear_region (window,
1461                           get_builtin_face_cache_index (w, Vright_margin_face),
1462                           bounds.right_in, ypos1,
1463                           bounds.right_out - bounds.right_in, height);
1464
1465       if (window_is_rightmost (w))
1466         redisplay_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f),
1467                           ypos1, FRAME_BORDER_WIDTH (f), height);
1468     }
1469
1470 }
1471
1472
1473 /* XXX Implement me! */
1474 static void
1475 mswindows_clear_frame (struct frame *f)
1476 {
1477   GdiFlush();
1478 }
1479
1480
1481 \f
1482 /************************************************************************/
1483 /*                            initialization                            */
1484 /************************************************************************/
1485
1486 void
1487 console_type_create_redisplay_mswindows (void)
1488 {
1489   /* redisplay methods */
1490   CONSOLE_HAS_METHOD (mswindows, text_width);
1491   CONSOLE_HAS_METHOD (mswindows, output_display_block);
1492   CONSOLE_HAS_METHOD (mswindows, divider_height);
1493   CONSOLE_HAS_METHOD (mswindows, eol_cursor_width);
1494   CONSOLE_HAS_METHOD (mswindows, output_vertical_divider);
1495   CONSOLE_HAS_METHOD (mswindows, clear_to_window_end);
1496   CONSOLE_HAS_METHOD (mswindows, clear_region);
1497   CONSOLE_HAS_METHOD (mswindows, clear_frame);
1498   CONSOLE_HAS_METHOD (mswindows, output_begin);
1499   CONSOLE_HAS_METHOD (mswindows, output_end);
1500   CONSOLE_HAS_METHOD (mswindows, flash);
1501   CONSOLE_HAS_METHOD (mswindows, ring_bell);
1502 }