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