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