XEmacs 21.2.33 "Melpomene".
[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_output_begin
961
962  Perform any necessary initialization prior to an update.
963  ****************************************************************************/
964 static void
965 mswindows_output_begin (struct device *d)
966 {
967 }
968
969 /*****************************************************************************
970  mswindows_output_end
971
972  Perform any necessary flushing of queues when an update has completed.
973  ****************************************************************************/
974 static void
975 mswindows_output_end (struct device *d)
976 {
977   GdiFlush();
978 }
979
980 static int
981 mswindows_flash (struct device *d)
982 {
983   struct frame *f = device_selected_frame (d);
984   HDC hdc = get_frame_dc (f, 1);
985   RECT rc;
986
987   GetClientRect (FRAME_MSWINDOWS_HANDLE (f), &rc);
988   InvertRect (hdc, &rc);
989   GdiFlush ();
990   Sleep (25);
991   InvertRect (hdc, &rc);
992
993   return 1;
994 }
995
996 static void
997 mswindows_ring_bell (struct device *d, int volume, int pitch, int duration)
998 {
999   /* Beep does not work at all, anyways! -kkm */
1000   MessageBeep (MB_OK);
1001 }
1002
1003 /*****************************************************************************
1004  mswindows_output_display_block
1005
1006  Given a display line, a block number for that start line, output all
1007  runes between start and end in the specified display block.
1008  Ripped off with minimal thought from the corresponding X routine.
1009  ****************************************************************************/
1010 static void
1011 mswindows_output_display_block (struct window *w, struct display_line *dl, int block,
1012                           int start, int end, int start_pixpos, int cursor_start,
1013                           int cursor_width, int cursor_height)
1014 {
1015   struct frame *f = XFRAME (w->frame);
1016   Emchar_dynarr *buf = Dynarr_new (Emchar);
1017   Lisp_Object window;
1018
1019   struct display_block *db = Dynarr_atp (dl->display_blocks, block);
1020   rune_dynarr *rba = db->runes;
1021   struct rune *rb;
1022
1023   int elt = start;
1024   face_index findex;
1025   int xpos, width;
1026   Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
1027                                      MULE is not defined */
1028   XSETWINDOW (window, w);
1029   rb = Dynarr_atp (rba, start);
1030
1031   if (!rb)
1032       /* Nothing to do so don't do anything. */
1033       return;
1034
1035   findex = rb->findex;
1036   xpos = rb->xpos;
1037   width = 0;
1038   if (rb->type == RUNE_CHAR)
1039     charset = CHAR_CHARSET (rb->object.chr.ch);
1040
1041   if (end < 0)
1042     end = Dynarr_length (rba);
1043   Dynarr_reset (buf);
1044
1045   while (elt < end)
1046     {
1047       rb = Dynarr_atp (rba, elt);
1048
1049       if (rb->findex == findex && rb->type == RUNE_CHAR
1050           && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
1051           && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
1052         {
1053           Dynarr_add (buf, rb->object.chr.ch);
1054           width += rb->width;
1055           elt++;
1056         }
1057       else
1058         {
1059           if (Dynarr_length (buf))
1060             {
1061               mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
1062                                  findex, 0, 0, 0, 0);
1063               xpos = rb->xpos;
1064               width = 0;
1065             }
1066           Dynarr_reset (buf);
1067           width = 0;
1068
1069           if (rb->type == RUNE_CHAR)
1070             {
1071               findex = rb->findex;
1072               xpos = rb->xpos;
1073               charset = CHAR_CHARSET (rb->object.chr.ch);
1074
1075               if (rb->cursor_type == CURSOR_ON)
1076                 {
1077                   if (rb->object.chr.ch == '\n')
1078                     {
1079                       mswindows_output_cursor (w, dl, xpos, cursor_width,
1080                                                findex, 0, 0);
1081                     }
1082                   else
1083                     {
1084                       Dynarr_add (buf, rb->object.chr.ch);
1085                       mswindows_output_cursor (w, dl, xpos, cursor_width,
1086                                                findex, rb->object.chr.ch, 0);
1087                       Dynarr_reset (buf);
1088                     }
1089
1090                   xpos += rb->width;
1091                   elt++;
1092                 }
1093               else if (rb->object.chr.ch == '\n')
1094                 {
1095                   /* Clear in case a cursor was formerly here. */
1096                   redisplay_clear_region (window, findex, xpos, 
1097                                           DISPLAY_LINE_YPOS (dl),
1098                                           rb->width, DISPLAY_LINE_HEIGHT (dl));
1099                   elt++;
1100                 }
1101             }
1102           else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
1103             {
1104               if (rb->type == RUNE_BLANK)
1105                 mswindows_output_blank (w, dl, rb, start_pixpos);
1106               else
1107                 {
1108                   /* #### Our flagging of when we need to redraw the
1109                      modeline shadows sucks.  Since RUNE_HLINE is only used
1110                      by the modeline at the moment it is a good bet
1111                      that if it gets redrawn then we should also
1112                      redraw the shadows.  This won't be true forever.
1113                      We borrow the shadow_thickness_changed flag for
1114                      now. */
1115                   w->shadow_thickness_changed = 1;
1116                   mswindows_output_hline (w, dl, rb);
1117                 }
1118
1119               if (rb->cursor_type == CURSOR_ON)
1120                 mswindows_output_cursor (w, dl, xpos, cursor_width, rb->findex, 0, 0);
1121
1122               elt++;
1123               if (elt < end)
1124                 {
1125                   rb = Dynarr_atp (rba, elt);
1126
1127                   findex = rb->findex;
1128                   xpos = rb->xpos;
1129                 }
1130             }
1131           else if (rb->type == RUNE_DGLYPH)
1132             {
1133               Lisp_Object instance;
1134               struct display_box dbox;
1135               struct display_glyph_area dga;
1136
1137               redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset,
1138                                                  start_pixpos, rb->width,
1139                                                  &dbox, &dga);
1140
1141               XSETWINDOW (window, w);
1142               instance = glyph_image_instance (rb->object.dglyph.glyph,
1143                                                window, ERROR_ME_NOT, 1);
1144               findex = rb->findex;
1145
1146               if (IMAGE_INSTANCEP (instance))
1147                 {
1148                   switch (XIMAGE_INSTANCE_TYPE (instance))
1149                     {
1150                     case IMAGE_MONO_PIXMAP:
1151                     case IMAGE_COLOR_PIXMAP:
1152                       redisplay_output_pixmap (w, instance, &dbox, &dga, findex,
1153                                                cursor_start, cursor_width,
1154                                                cursor_height, 0);
1155                       if (rb->cursor_type == CURSOR_ON)
1156                         mswindows_output_cursor (w, dl, xpos, cursor_width,
1157                                                  findex, 0, 1);
1158                       break;
1159                       
1160                     case IMAGE_SUBWINDOW:
1161                     case IMAGE_WIDGET:
1162                       redisplay_output_subwindow (w, instance, &dbox, &dga, findex,
1163                                                   cursor_start, cursor_width,
1164                                                   cursor_height);
1165                       if (rb->cursor_type == CURSOR_ON)
1166                         mswindows_output_cursor (w, dl, xpos, cursor_width,
1167                                                  findex, 0, 1);
1168                       break;
1169                       
1170                     case IMAGE_LAYOUT:
1171                       redisplay_output_layout (w, instance, &dbox, &dga, findex,
1172                                                cursor_start, cursor_width,
1173                                                cursor_height);
1174                       if (rb->cursor_type == CURSOR_ON)
1175                         mswindows_output_cursor (w, dl, xpos, cursor_width,
1176                                                  findex, 0, 1);
1177                       break;
1178                       
1179                     case IMAGE_NOTHING:
1180                       /* nothing is as nothing does */
1181                       break;
1182
1183                     case IMAGE_TEXT:
1184                     case IMAGE_POINTER:
1185                     default:
1186                       abort ();
1187                     }
1188                   IMAGE_INSTANCE_OPTIMIZE_OUTPUT 
1189                     (XIMAGE_INSTANCE (instance)) = 0;
1190                 }
1191               xpos += rb->width;
1192               elt++;
1193             }
1194           else
1195             abort ();
1196         }
1197     }
1198
1199   if (Dynarr_length (buf))
1200     mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
1201                              0, 0, 0, 0);
1202
1203   if (dl->modeline
1204       && !EQ (Qzero, w->modeline_shadow_thickness)
1205       && (f->clear
1206           || f->windows_structure_changed
1207           || w->shadow_thickness_changed))
1208     bevel_modeline (w, dl);
1209
1210   Dynarr_free (buf);
1211 }
1212
1213
1214 /*****************************************************************************
1215  mswindows_output_vertical_divider
1216
1217  Draw a vertical divider down the right side of the given window.
1218  ****************************************************************************/
1219 static void
1220 mswindows_output_vertical_divider (struct window *w, int clear_unused)
1221 {
1222   struct frame *f = XFRAME (w->frame);
1223   HDC hdc = get_frame_dc (f, 1);
1224   RECT rect;
1225   int spacing = XINT (w->vertical_divider_spacing);
1226   int shadow = XINT (w->vertical_divider_shadow_thickness);
1227   int abs_shadow = abs (shadow);
1228   int line_width = XINT (w->vertical_divider_line_width);
1229   int div_left = WINDOW_RIGHT (w) - window_divider_width (w);
1230   int y1 = WINDOW_TOP (w);
1231   int y2 = WINDOW_BOTTOM (w);
1232
1233   /* Clear left and right spacing areas */
1234   if (spacing)
1235     {
1236       rect.top = y1;
1237       rect.bottom = y2;
1238       mswindows_update_dc (hdc, Qnil,
1239                    WINDOW_FACE_CACHEL_BACKGROUND (w, DEFAULT_INDEX), Qnil);
1240       rect.right = WINDOW_RIGHT (w);
1241       rect.left = rect.right - spacing;
1242       ExtTextOut (hdc, 0, 0, ETO_OPAQUE, 
1243                   &rect, NULL, 0, NULL);
1244       rect.left = div_left;
1245       rect.right = div_left + spacing;
1246       ExtTextOut (hdc, 0, 0, ETO_OPAQUE, 
1247                   &rect, NULL, 0, NULL);
1248     }
1249   
1250   /* Clear divider face */
1251   rect.top = y1 + abs_shadow;
1252   rect.bottom = y2 - abs_shadow;
1253   rect.left = div_left + spacing + abs_shadow;
1254   rect.right = rect.left + line_width;
1255   if (rect.left < rect.right)
1256     {
1257       face_index div_face
1258         = get_builtin_face_cache_index (w, Vvertical_divider_face);
1259       mswindows_update_dc (hdc, Qnil,
1260                    WINDOW_FACE_CACHEL_BACKGROUND (w, div_face), Qnil);
1261       ExtTextOut (hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
1262     }
1263
1264   /* Draw a shadow around the divider */
1265   if (shadow != 0)
1266     {
1267       /* #### This will be fixed to support arbitrary thickness */
1268       InflateRect (&rect, abs_shadow, abs_shadow);
1269       DrawEdge (hdc, &rect,
1270                 shadow > 0 ? EDGE_RAISED : EDGE_SUNKEN, BF_RECT);
1271     }
1272 }
1273
1274 /****************************************************************************
1275  mswindows_text_width
1276
1277  Given a string and a face, return the string's length in pixels when
1278  displayed in the font associated with the face.
1279  ****************************************************************************/
1280 static int
1281 mswindows_text_width (struct frame *f, struct face_cachel *cachel,
1282                       const Emchar *str, Charcount len)
1283 {
1284   HDC hdc = get_frame_dc (f, 0);
1285   int width_so_far = 0;
1286   unsigned char *text_storage = (unsigned char *) alloca (2 * len);
1287   textual_run *runs = alloca_array (textual_run, len);
1288   int nruns;
1289   int i;
1290
1291   nruns = separate_textual_runs (text_storage, runs, str, len);
1292
1293   for (i = 0; i < nruns; i++)
1294     width_so_far += mswindows_text_width_single_run (hdc,
1295                                                      cachel, runs + i);
1296
1297   return width_so_far;
1298 }
1299
1300
1301 /****************************************************************************
1302  mswindows_clear_region
1303
1304  Clear the area in the box defined by the given parameters using the
1305  given face.
1306  ****************************************************************************/
1307 static void
1308 mswindows_clear_region (Lisp_Object locale, struct device* d, struct frame* f, 
1309                         face_index findex, int x, int y,
1310                         int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1311                         Lisp_Object background_pixmap)
1312 {
1313   RECT rect = { x, y, x+width, y+height };
1314   HDC hdc = get_frame_dc (f, 1);
1315
1316   if (!NILP (background_pixmap))
1317     {
1318       struct display_box db = { x, y, width, height };
1319       mswindows_update_dc (hdc,
1320                            fcolor, bcolor, background_pixmap);
1321       mswindows_output_dibitmap_region 
1322         ( f, XIMAGE_INSTANCE (background_pixmap), &db, 0);
1323     }
1324   else
1325     {
1326       mswindows_update_dc (hdc, Qnil, fcolor, Qnil);
1327       ExtTextOut (hdc, 0, 0, ETO_OPAQUE, 
1328                   &rect, NULL, 0, NULL);
1329     }
1330
1331 #ifdef HAVE_SCROLLBARS
1332   if (WINDOWP (locale))
1333     mswindows_redisplay_deadbox_maybe (XWINDOW (locale), &rect);
1334 #endif
1335 }
1336
1337 /* XXX Implement me! */
1338 static void
1339 mswindows_clear_frame (struct frame *f)
1340 {
1341   GdiFlush();
1342 }
1343
1344
1345 \f
1346 /************************************************************************/
1347 /*                            initialization                            */
1348 /************************************************************************/
1349
1350 void
1351 console_type_create_redisplay_mswindows (void)
1352 {
1353   /* redisplay methods - display*/
1354   CONSOLE_HAS_METHOD (mswindows, text_width);
1355   CONSOLE_HAS_METHOD (mswindows, output_display_block);
1356   CONSOLE_HAS_METHOD (mswindows, divider_height);
1357   CONSOLE_HAS_METHOD (mswindows, eol_cursor_width);
1358   CONSOLE_HAS_METHOD (mswindows, output_vertical_divider);
1359   CONSOLE_HAS_METHOD (mswindows, clear_region);
1360   CONSOLE_HAS_METHOD (mswindows, clear_frame);
1361   CONSOLE_HAS_METHOD (mswindows, output_begin);
1362   CONSOLE_HAS_METHOD (mswindows, output_end);
1363   CONSOLE_HAS_METHOD (mswindows, flash);
1364   CONSOLE_HAS_METHOD (mswindows, ring_bell);
1365   CONSOLE_HAS_METHOD (mswindows, bevel_area);
1366   CONSOLE_HAS_METHOD (mswindows, output_string);
1367   CONSOLE_HAS_METHOD (mswindows, output_pixmap);
1368
1369   /* redisplay methods - printer */
1370   CONSOLE_INHERITS_METHOD (msprinter, mswindows, text_width);
1371   CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_display_block);
1372   CONSOLE_INHERITS_METHOD (msprinter, mswindows, divider_height);
1373   CONSOLE_INHERITS_METHOD (msprinter, mswindows, eol_cursor_width);
1374   CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_vertical_divider);
1375   CONSOLE_INHERITS_METHOD (msprinter, mswindows, clear_region);
1376   CONSOLE_INHERITS_METHOD (msprinter, mswindows, clear_frame);
1377   CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_begin);
1378   CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_end);
1379   CONSOLE_INHERITS_METHOD (msprinter, mswindows, bevel_area);
1380   CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_string);
1381   CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_pixmap);
1382 }