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