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