XEmacs 21.2.19 "Shinjuku".
[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                                        int x, int y, 
68                                        int clip_x, int clip_y, 
69                                        int clip_width, int clip_height, 
70                                        int width, int height,
71                                        int pixmap_offset,
72                                        int offset_bitmap);
73 static void mswindows_output_pixmap (struct window *w, struct display_line *dl,
74                                      Lisp_Object image_instance, int xpos,
75                                      int xoffset, int start_pixpos, int width,
76                                      face_index findex, int cursor_start, 
77                                      int cursor_width, int cursor_height,
78                                      int offset_bitmap);
79 void bevel_modeline (struct window *w, struct display_line *dl);
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, CCL_MODE_ENCODING);
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=0;
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 = DISPLAY_LINE_HEIGHT (dl);
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             redisplay_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
597   /* do we need to offset the pixmap vertically? this is necessary
598      for background pixmaps. */
599   if (offset_bitmap)
600     {
601       yoffset = y % IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
602       xoffset = x % IMAGE_INSTANCE_PIXMAP_WIDTH (p);
603       /* the width is handled by mswindows_output_pixmap_region */
604     }
605
606   if (need_clipping)
607     {
608     }
609
610   /* first blt the mask */
611   if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
612     {
613       RGBQUAD col;
614       col.rgbBlue = GetBValue (bgcolor);
615       col.rgbRed = GetRValue (bgcolor);
616       col.rgbGreen = GetGValue (bgcolor);
617       col.rgbReserved = 0;
618
619       old = SelectObject (FRAME_MSWINDOWS_CDC (f),
620                           IMAGE_INSTANCE_MSWINDOWS_MASK (p));
621       
622       SetDIBColorTable (FRAME_MSWINDOWS_CDC (f), 1, 1, &col);
623
624       BitBlt (hdc, 
625               x,y,
626               width, height, 
627               FRAME_MSWINDOWS_CDC (f),
628               xoffset,yoffset, 
629               SRCCOPY);                  
630
631       SelectObject (FRAME_MSWINDOWS_CDC (f), old);
632     }
633   
634   /* now blt the bitmap itself. */
635   old = SelectObject (FRAME_MSWINDOWS_CDC (f),
636                       IMAGE_INSTANCE_MSWINDOWS_BITMAP (p));
637
638   BitBlt (hdc, 
639           x,y,
640           width, height, 
641           FRAME_MSWINDOWS_CDC (f),
642           xoffset, yoffset, 
643           IMAGE_INSTANCE_MSWINDOWS_MASK (p) ? SRCINVERT : SRCCOPY);
644
645   SelectObject (FRAME_MSWINDOWS_CDC (f),old);
646
647   if (need_clipping)
648     {
649     }
650 }
651
652 /*
653  * X gc's have this nice property that setting the bg pixmap will
654  * output it offset relative to the window. Windows doesn't have this
655  * feature so we have to emulate this by outputting multiple pixmaps 
656  */
657 static void
658 mswindows_output_dibitmap_region (struct frame *f, 
659                                   struct Lisp_Image_Instance *p,
660                                   int x, int y, 
661                                   int clip_x, int clip_y, 
662                                   int clip_width, int clip_height, 
663                                   int width, int height, int pixmap_offset,
664                                   int offset_bitmap)
665 {
666   int pwidth = min (width, IMAGE_INSTANCE_PIXMAP_WIDTH (p));
667   int pheight = min (height, IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
668   int pxoffset = 0, pyoffset = 0;
669
670   /* when doing a bg pixmap do a partial pixmap first so that we
671      blt whole pixmaps thereafter */
672
673   if (offset_bitmap)
674     {
675       pheight = min (pheight, IMAGE_INSTANCE_PIXMAP_HEIGHT (p) -
676                      y % IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
677     }
678   
679   while (pheight > 0)
680     {
681       if (offset_bitmap)
682         {
683           pwidth = min (min (width, IMAGE_INSTANCE_PIXMAP_WIDTH (p)),
684                         IMAGE_INSTANCE_PIXMAP_WIDTH (p) -
685                         x % IMAGE_INSTANCE_PIXMAP_WIDTH (p));
686           pxoffset = 0;
687         }
688       while (pwidth > 0)
689         {
690           mswindows_output_dibitmap (f, p,
691                                      x + pxoffset, y + pyoffset, 
692                                      clip_x, clip_y, 
693                                      clip_width, clip_height, 
694                                      pwidth, pheight, pixmap_offset,
695                                      offset_bitmap);
696           pxoffset += pwidth;
697           pwidth = min ((width-pxoffset), 
698                         IMAGE_INSTANCE_PIXMAP_WIDTH (p));
699         }
700       pyoffset += pheight;
701       pheight = min ((height-pyoffset), 
702                      IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
703     }
704 }
705
706 static void
707 mswindows_output_pixmap (struct window *w, struct display_line *dl,
708                          Lisp_Object image_instance, int xpos, int xoffset,
709                          int start_pixpos, int width, face_index findex,
710                          int cursor_start, int cursor_width, int cursor_height,
711                          int offset_bitmap)
712 {
713   struct frame *f = XFRAME (w->frame);
714   HDC hdc = FRAME_MSWINDOWS_DC (f);
715
716   struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
717   Lisp_Object window;
718
719   int lheight = DISPLAY_LINE_HEIGHT (dl);
720   int pheight = ((int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > lheight ? lheight :
721                  IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
722   int clip_x, clip_y, clip_width, clip_height;
723
724   /* The pixmap_offset is used to center the pixmap on lines which are
725      shorter than it is.  This results in odd effects when scrolling
726      pixmaps off of the bottom.  Let's try not using it. */
727 #if 0
728   int pixmap_offset = (int) (IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - lheight) / 2;
729 #else
730   int pixmap_offset = 0;
731 #endif
732
733   XSETWINDOW (window, w);
734
735   if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
736     {
737       if (start_pixpos > xpos && start_pixpos > xpos + width)
738         return;
739
740       clip_x = xoffset;
741       clip_width = width;
742       if (start_pixpos > xpos)
743         {
744           clip_x += (start_pixpos - xpos);
745           clip_width -= (start_pixpos - xpos);
746         }
747     }
748   else
749     {
750       clip_x = 0;
751       clip_width = 0;
752     }
753
754   /* Place markers for possible future functionality (clipping the top
755      half instead of the bottom half; think pixel scrolling). */
756   clip_y = 0;
757   clip_height = pheight;
758
759   /* Clear the area the pixmap is going into.  The pixmap itself will
760      always take care of the full width.  We don't want to clear where
761      it is going to go in order to avoid flicker.  So, all we have to
762      take care of is any area above or below the pixmap. */
763   /* #### We take a shortcut for now.  We know that since we have
764      pixmap_offset hardwired to 0 that the pixmap is against the top
765      edge so all we have to worry about is below it. */
766   /* #### Unless the pixmap has a mask in which case we have to clear
767      the whole damn thing since we can't yet clear just the area not
768      included in the mask. */
769   if (((int) (dl->ypos - dl->ascent + pheight) <
770        (int) (dl->ypos + dl->descent - dl->clip))
771       || IMAGE_INSTANCE_MSWINDOWS_MASK (p))
772     {
773       int clear_x, clear_y, clear_width, clear_height;
774
775       if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
776         {
777           clear_y = dl->ypos - dl->ascent;
778           clear_height = lheight;
779         }
780       else
781         {
782           clear_y = dl->ypos - dl->ascent + pheight;
783           clear_height = lheight - pheight;
784         }
785
786       if (start_pixpos >= 0 && start_pixpos > xpos)
787         {
788           clear_x = start_pixpos;
789           clear_width = xpos + width - start_pixpos;
790         }
791       else
792         {
793           clear_x = xpos;
794           clear_width = width;
795         }
796
797       if (!offset_bitmap)       /* i.e. not a bg pixmap */
798         redisplay_clear_region (window, findex, clear_x, clear_y,
799                                 clear_width, clear_height);
800     }
801
802   /* Output the pixmap. Have to do this as many times as is required
803    to fill the given area */
804   mswindows_update_dc (hdc, Qnil,
805                        WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
806                        WINDOW_FACE_CACHEL_BACKGROUND (w, findex), Qnil);
807
808   mswindows_output_dibitmap_region (f, p, xpos - xoffset,
809                                     dl->ypos - dl->ascent,
810                                     clip_x, clip_y, clip_width, clip_height,
811                                     width + xoffset, pheight, pixmap_offset,
812                                     offset_bitmap);
813 }
814
815 #ifdef HAVE_SCROLLBARS
816 /*
817  * This function paints window's deadbox, a rectangle between window
818  * borders and two short edges of both scrollbars.
819  *
820  * Function checks whether deadbox intersects with the rectangle pointed
821  * to by PRC, and paints only the intersection
822  */
823 static void
824 mswindows_redisplay_deadbox_maybe (struct window *w, CONST RECT* prc)
825 {
826   int sbh = window_scrollbar_height (w);
827   int sbw = window_scrollbar_width (w);
828   RECT rect_dead, rect_paint;
829   if (sbh == 0 || sbw == 0)
830     return;
831
832   if (!NILP (w->scrollbar_on_left_p))
833     rect_dead.left = WINDOW_LEFT (w);
834   else
835     rect_dead.left = WINDOW_TEXT_RIGHT (w);
836   rect_dead.right = rect_dead.left + sbw;
837
838   if (!NILP (w->scrollbar_on_top_p))
839     rect_dead.top = WINDOW_TOP (w);
840   else
841     rect_dead.top = WINDOW_TEXT_BOTTOM (w);
842   rect_dead.bottom = rect_dead.top + sbh;
843       
844   if (IntersectRect (&rect_paint, &rect_dead, prc))
845     {
846       struct frame *f = XFRAME (WINDOW_FRAME (w));
847       FillRect (FRAME_MSWINDOWS_DC (f), &rect_paint,
848                 (HBRUSH) (COLOR_BTNFACE+1));
849     }
850 }
851
852 #endif /* HAVE_SCROLLBARS */
853
854 /*****************************************************************************
855  mswindows_redraw_exposed_window
856
857  Given a bounding box for an area that needs to be redrawn, determine
858  what parts of what lines are contained within and re-output their
859  contents.
860  Copied from redisplay-x.c
861  ****************************************************************************/
862 static void
863 mswindows_redraw_exposed_window (struct window *w, int x, int y, int width,
864                            int height)
865 {
866   struct frame *f = XFRAME (w->frame);
867   int line;
868   int orig_windows_structure_changed;
869   RECT rect_window = { WINDOW_LEFT (w), WINDOW_TOP (w),
870                        WINDOW_RIGHT (w), WINDOW_BOTTOM (w) };
871   RECT rect_expose = { x, y, x + width, y + height };
872   RECT rect_draw;
873
874   display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
875
876   if (!NILP (w->vchild))
877     {
878       mswindows_redraw_exposed_windows (w->vchild, x, y, width, height);
879       return;
880     }
881   else if (!NILP (w->hchild))
882     {
883       mswindows_redraw_exposed_windows (w->hchild, x, y, width, height);
884       return;
885     }
886
887   /* If the window doesn't intersect the exposed region, we're done here. */
888   if (!IntersectRect (&rect_draw, &rect_window, &rect_expose))
889       return;
890
891   /* We do this to make sure that the 3D modelines get redrawn if
892      they are in the exposed region. */
893   orig_windows_structure_changed = f->windows_structure_changed;
894   f->windows_structure_changed = 1;
895
896   if (window_needs_vertical_divider (w))
897     {
898       mswindows_output_vertical_divider (w, 0);
899     }
900
901   for (line = 0; line < Dynarr_length (cdla); line++)
902     {
903       struct display_line *cdl = Dynarr_atp (cdla, line);
904       int top_y = cdl->ypos - cdl->ascent;
905       int bottom_y = cdl->ypos + cdl->descent;
906
907       if (bottom_y >= rect_draw.top)
908         {
909           if (top_y > rect_draw.bottom)
910             {
911               if (line == 0)
912                 continue;
913               else
914                 break;
915             }
916           else
917             {
918               output_display_line (w, 0, cdla, line,
919                                    rect_draw.left, rect_draw.right);
920             }
921         }
922     }
923
924   f->windows_structure_changed = orig_windows_structure_changed;
925
926   /* If there have never been any face cache_elements created, then this
927      expose event doesn't actually have anything to do. */
928   if (Dynarr_largest (w->face_cachels))
929     redisplay_clear_bottom_of_window (w, cdla, rect_draw.top, rect_draw.bottom);
930
931 #ifdef HAVE_SCROLLBARS
932   mswindows_redisplay_deadbox_maybe (w, &rect_expose);
933 #endif
934 }
935
936 /*****************************************************************************
937  mswindows_redraw_exposed_windows
938
939  For each window beneath the given window in the window hierarchy,
940  ensure that it is redrawn if necessary after an Expose event.
941  ****************************************************************************/
942 static void
943 mswindows_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
944                             int height)
945 {
946   for (; !NILP (window); window = XWINDOW (window)->next)
947     mswindows_redraw_exposed_window (XWINDOW (window), x, y, width, height);
948 }
949
950 /*****************************************************************************
951  mswindows_redraw_exposed_area
952
953  For each window on the given frame, ensure that any area in the
954  Exposed area is redrawn.
955  ****************************************************************************/
956 void
957 mswindows_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
958 {
959   /* If any window on the frame has had its face cache reset then the
960      redisplay structures are effectively invalid.  If we attempt to
961      use them we'll blow up.  We mark the frame as changed to ensure
962      that redisplay will do a full update.  This probably isn't
963      necessary but it can't hurt. */
964 #ifdef HAVE_TOOLBARS
965   /* #### We would rather put these off as well but there is currently
966      no combination of flags which will force an unchanged toolbar to
967      redraw anyhow. */
968   MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
969 #endif
970   redraw_exposed_gutters (f, x, y, width, height);
971
972   if (!f->window_face_cache_reset)
973         {
974           mswindows_redraw_exposed_windows (f->root_window, x, y, width, height);
975           GdiFlush();
976         }
977   else
978     MARK_FRAME_CHANGED (f);
979 }
980
981
982 /*****************************************************************************
983  mswindows_bevel_area
984
985  Draw a 3d border around the specified area on window W.
986  ****************************************************************************/
987 static void
988 mswindows_bevel_area (struct window *w, face_index findex, int x, int y, 
989                       int width, int height, int shadow_thickness)
990 {
991   struct frame *f = XFRAME (w->frame);
992   UINT edge;
993
994   if (shadow_thickness < -1)
995     edge = EDGE_SUNKEN;
996   else if (shadow_thickness < 0)
997     edge = BDR_SUNKENINNER;
998   else if (shadow_thickness == 1)
999     edge = BDR_RAISEDINNER;
1000   else
1001     edge = EDGE_RAISED;
1002
1003   if (shadow_thickness < 0)
1004     shadow_thickness = -shadow_thickness;
1005
1006   {
1007     RECT rect = { x, y, x + width, y + height };
1008     Lisp_Object color = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1009     mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, color, Qnil);
1010
1011     DrawEdge (FRAME_MSWINDOWS_DC (f), &rect, edge, BF_RECT);
1012   }
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       /* Nothing to do so don't do anything. */
1115       return;
1116
1117   findex = rb->findex;
1118   xpos = rb->xpos;
1119   width = 0;
1120   if (rb->type == RUNE_CHAR)
1121     charset = CHAR_CHARSET (rb->object.chr.ch);
1122
1123   if (end < 0)
1124     end = Dynarr_length (rba);
1125   Dynarr_reset (buf);
1126
1127   while (elt < end)
1128     {
1129       rb = Dynarr_atp (rba, elt);
1130
1131       if (rb->findex == findex && rb->type == RUNE_CHAR
1132           && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
1133           && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
1134         {
1135           Dynarr_add (buf, rb->object.chr.ch);
1136           width += rb->width;
1137           elt++;
1138         }
1139       else
1140         {
1141           if (Dynarr_length (buf))
1142             {
1143               mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
1144                                  findex);
1145               xpos = rb->xpos;
1146               width = 0;
1147             }
1148           Dynarr_reset (buf);
1149           width = 0;
1150
1151           if (rb->type == RUNE_CHAR)
1152             {
1153               findex = rb->findex;
1154               xpos = rb->xpos;
1155               charset = CHAR_CHARSET (rb->object.chr.ch);
1156
1157               if (rb->cursor_type == CURSOR_ON)
1158                 {
1159                   if (rb->object.chr.ch == '\n')
1160                     {
1161                       mswindows_output_cursor (w, dl, xpos, cursor_width,
1162                                                findex, 0, 0);
1163                     }
1164                   else
1165                     {
1166                       Dynarr_add (buf, rb->object.chr.ch);
1167                       mswindows_output_cursor (w, dl, xpos, cursor_width,
1168                                                findex, rb->object.chr.ch, 0);
1169                       Dynarr_reset (buf);
1170                     }
1171
1172                   xpos += rb->width;
1173                   elt++;
1174                 }
1175               else if (rb->object.chr.ch == '\n')
1176                 {
1177                   /* Clear in case a cursor was formerly here. */
1178                   int height = DISPLAY_LINE_HEIGHT (dl);
1179
1180                   redisplay_clear_region (window, findex, xpos, dl->ypos - dl->ascent,
1181                                     rb->width, height);
1182                   elt++;
1183                 }
1184             }
1185           else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
1186             {
1187               if (rb->type == RUNE_BLANK)
1188                 mswindows_output_blank (w, dl, rb, start_pixpos);
1189               else
1190                 {
1191                   /* #### Our flagging of when we need to redraw the
1192                      modeline shadows sucks.  Since RUNE_HLINE is only used
1193                      by the modeline at the moment it is a good bet
1194                      that if it gets redrawn then we should also
1195                      redraw the shadows.  This won't be true forever.
1196                      We borrow the shadow_thickness_changed flag for
1197                      now. */
1198                   w->shadow_thickness_changed = 1;
1199                   mswindows_output_hline (w, dl, rb);
1200                 }
1201
1202               if (rb->cursor_type == CURSOR_ON)
1203                 mswindows_output_cursor (w, dl, xpos, cursor_width, rb->findex, 0, 0);
1204
1205               elt++;
1206               if (elt < end)
1207                 {
1208                   rb = Dynarr_atp (rba, elt);
1209
1210                   findex = rb->findex;
1211                   xpos = rb->xpos;
1212                 }
1213             }
1214           else if (rb->type == RUNE_DGLYPH)
1215             {
1216               Lisp_Object instance;
1217
1218               XSETWINDOW (window, w);
1219               instance = glyph_image_instance (rb->object.dglyph.glyph,
1220                                                window, ERROR_ME_NOT, 1);
1221               findex = rb->findex;
1222
1223               if (IMAGE_INSTANCEP (instance))
1224                 switch (XIMAGE_INSTANCE_TYPE (instance))
1225                   {
1226                   case IMAGE_TEXT:
1227                     {
1228                       /* #### This is way losing.  See the comment in
1229                          add_glyph_rune(). */
1230                       Lisp_Object string =
1231                         XIMAGE_INSTANCE_TEXT_STRING (instance);
1232                       convert_bufbyte_string_into_emchar_dynarr
1233                         (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
1234
1235                       if (rb->cursor_type == CURSOR_ON)
1236                         mswindows_output_cursor (w, dl, xpos, cursor_width,
1237                                                  findex, Dynarr_at (buf, 0), 0);
1238                       else /* #### redisplay-x passes -1 as the width: why ? */
1239                         mswindows_output_string (w, dl, buf, xpos,
1240                                            rb->object.dglyph.xoffset,
1241                                            start_pixpos, rb->width, findex);
1242                       Dynarr_reset (buf);
1243                     }
1244                     break;
1245
1246                   case IMAGE_MONO_PIXMAP:
1247                   case IMAGE_COLOR_PIXMAP:
1248                     mswindows_output_pixmap (w, dl, instance, xpos,
1249                                      rb->object.dglyph.xoffset, start_pixpos,
1250                                      rb->width, findex, cursor_start,
1251                                      cursor_width, cursor_height, 0);
1252                     if (rb->cursor_type == CURSOR_ON)
1253                       mswindows_output_cursor (w, dl, xpos, cursor_width,
1254                                                findex, 0, 1);
1255                     break;
1256
1257                   case IMAGE_POINTER:
1258                     abort ();
1259
1260                   case IMAGE_SUBWINDOW:
1261                   case IMAGE_WIDGET:
1262                     redisplay_output_subwindow (w, dl, instance, xpos,
1263                                                 rb->object.dglyph.xoffset, start_pixpos,
1264                                                 rb->width, findex, cursor_start,
1265                                                 cursor_width, cursor_height);
1266                     if (rb->cursor_type == CURSOR_ON)
1267                       mswindows_output_cursor (w, dl, xpos, cursor_width,
1268                                                findex, 0, 1);
1269                     break;
1270
1271                   case IMAGE_NOTHING:
1272                     /* nothing is as nothing does */
1273                     break;
1274
1275                   default:
1276                     abort ();
1277                   }
1278
1279               xpos += rb->width;
1280               elt++;
1281             }
1282           else
1283             abort ();
1284         }
1285     }
1286
1287   if (Dynarr_length (buf))
1288     mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex);
1289
1290   if (dl->modeline
1291       && !EQ (Qzero, w->modeline_shadow_thickness)
1292       && (f->clear
1293           || f->windows_structure_changed
1294           || w->shadow_thickness_changed))
1295     bevel_modeline (w, dl);
1296
1297   Dynarr_free (buf);
1298 }
1299
1300
1301 /*****************************************************************************
1302  mswindows_output_vertical_divider
1303
1304  Draw a vertical divider down the right side of the given window.
1305  ****************************************************************************/
1306 static void
1307 mswindows_output_vertical_divider (struct window *w, int clear_unused)
1308 {
1309   struct frame *f = XFRAME (w->frame);
1310   RECT rect;
1311   int spacing = XINT (w->vertical_divider_spacing);
1312   int shadow = XINT (w->vertical_divider_shadow_thickness);
1313   int abs_shadow = abs (shadow);
1314   int line_width = XINT (w->vertical_divider_line_width);
1315   int div_left = WINDOW_RIGHT (w) - window_divider_width (w);
1316   int y1 = WINDOW_TOP (w) + FRAME_TOP_GUTTER_BOUNDS (f);
1317   int y2 = WINDOW_BOTTOM (w) + FRAME_BOTTOM_GUTTER_BOUNDS (f);
1318
1319   /* Clear left and right spacing areas */
1320   if (spacing)
1321     {
1322       rect.top = y1;
1323       rect.bottom = y2;
1324       mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
1325                    WINDOW_FACE_CACHEL_BACKGROUND (w, DEFAULT_INDEX), Qnil);
1326       rect.right = WINDOW_RIGHT (w);
1327       rect.left = rect.right - spacing;
1328       ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, 
1329                   &rect, NULL, 0, NULL);
1330       rect.left = div_left;
1331       rect.right = div_left + spacing;
1332       ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, 
1333                   &rect, NULL, 0, NULL);
1334     }
1335   
1336   /* Clear divider face */
1337   rect.top = y1 + abs_shadow;
1338   rect.bottom = y2 - abs_shadow;
1339   rect.left = div_left + spacing + abs_shadow;
1340   rect.right = rect.left + line_width;
1341   if (rect.left < rect.right)
1342     {
1343       face_index div_face
1344         = get_builtin_face_cache_index (w, Vvertical_divider_face);
1345       mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
1346                    WINDOW_FACE_CACHEL_BACKGROUND (w, div_face), Qnil);
1347       ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, 
1348                   &rect, NULL, 0, NULL);
1349     }
1350
1351   /* Draw a shadow around the divider */
1352   if (shadow != 0)
1353     {
1354       /* #### This will be fixed to support arbitrary thickness */
1355       InflateRect (&rect, abs_shadow, abs_shadow);
1356       DrawEdge (FRAME_MSWINDOWS_DC (f), &rect,
1357                 shadow > 0 ? EDGE_RAISED : EDGE_SUNKEN, BF_RECT);
1358     }
1359 }
1360
1361 /****************************************************************************
1362  mswindows_text_width
1363
1364  Given a string and a face, return the string's length in pixels when
1365  displayed in the font associated with the face.
1366  ****************************************************************************/
1367 static int
1368 mswindows_text_width (struct frame *f, struct face_cachel *cachel,
1369                       CONST Emchar *str, Charcount len)
1370 {
1371   int width_so_far = 0;
1372   unsigned char *text_storage = (unsigned char *) alloca (2 * len);
1373   textual_run *runs = alloca_array (textual_run, len);
1374   int nruns;
1375   int i;
1376
1377   nruns = separate_textual_runs (text_storage, runs, str, len);
1378
1379   for (i = 0; i < nruns; i++)
1380     width_so_far += mswindows_text_width_single_run (FRAME_MSWINDOWS_DC (f),
1381                                                      cachel, runs + i);
1382
1383   return width_so_far;
1384 }
1385
1386
1387 /****************************************************************************
1388  mswindows_clear_region
1389
1390  Clear the area in the box defined by the given parameters using the
1391  given face.
1392  ****************************************************************************/
1393 static void
1394 mswindows_clear_region (Lisp_Object locale, struct device* d, struct frame* f, 
1395                         face_index findex, int x, int y,
1396                         int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1397                         Lisp_Object background_pixmap)
1398 {
1399   RECT rect = { x, y, x+width, y+height };
1400
1401   if (!NILP (background_pixmap))
1402     {
1403       mswindows_update_dc (FRAME_MSWINDOWS_DC (f),
1404                            Qnil, fcolor, bcolor, background_pixmap);
1405
1406       mswindows_output_dibitmap_region 
1407         ( f, XIMAGE_INSTANCE (background_pixmap),
1408           x, y, 0, 0, 0, 0, width, height, 0, TRUE);
1409     }
1410   else
1411     {
1412       mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, fcolor, Qnil);
1413       ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, 
1414                   &rect, NULL, 0, NULL);
1415     }
1416
1417 #ifdef HAVE_SCROLLBARS
1418   if (WINDOWP (locale))
1419     mswindows_redisplay_deadbox_maybe (XWINDOW (locale), &rect);
1420 #endif
1421 }
1422
1423 /* XXX Implement me! */
1424 static void
1425 mswindows_clear_frame (struct frame *f)
1426 {
1427   GdiFlush();
1428 }
1429
1430
1431 \f
1432 /************************************************************************/
1433 /*                            initialization                            */
1434 /************************************************************************/
1435
1436 void
1437 console_type_create_redisplay_mswindows (void)
1438 {
1439   /* redisplay methods */
1440   CONSOLE_HAS_METHOD (mswindows, text_width);
1441   CONSOLE_HAS_METHOD (mswindows, output_display_block);
1442   CONSOLE_HAS_METHOD (mswindows, divider_height);
1443   CONSOLE_HAS_METHOD (mswindows, eol_cursor_width);
1444   CONSOLE_HAS_METHOD (mswindows, output_vertical_divider);
1445   CONSOLE_HAS_METHOD (mswindows, clear_region);
1446   CONSOLE_HAS_METHOD (mswindows, clear_frame);
1447   CONSOLE_HAS_METHOD (mswindows, output_begin);
1448   CONSOLE_HAS_METHOD (mswindows, output_end);
1449   CONSOLE_HAS_METHOD (mswindows, flash);
1450   CONSOLE_HAS_METHOD (mswindows, ring_bell);
1451   CONSOLE_HAS_METHOD (mswindows, bevel_area);
1452 }