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