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