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