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