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.
6 This file is part of XEmacs.
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
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
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. */
23 /* Synched up with: Not in FSF. */
28 Lots of work done by Ben Wing for Mule
29 Partially rewritten for mswindows by Jonathan Harris, November 1997 for 21.0.
35 #include "console-msw.h"
36 #include "objects-msw.h"
43 #include "glyphs-msw.h"
44 #include "redisplay.h"
51 #include "mule-charset.h"
54 #define MSWINDOWS_EOL_CURSOR_WIDTH 5
57 * Random forward declarations
59 static void mswindows_update_dc (HDC hdc, Lisp_Object font, Lisp_Object fg,
60 Lisp_Object bg, Lisp_Object bg_pmap);
61 static void mswindows_output_vertical_divider (struct window *w, int clear);
62 static void mswindows_redraw_exposed_windows (Lisp_Object window, int x,
63 int y, int width, int height);
64 static void mswindows_output_dibitmap (struct frame *f,
65 struct Lisp_Image_Instance *p,
67 int clip_x, int clip_y,
68 int clip_width, int clip_height,
69 int width, int height,
72 static void mswindows_output_pixmap (struct window *w, struct display_line *dl,
73 Lisp_Object image_instance, int xpos,
74 int xoffset, int start_pixpos, int width,
75 face_index findex, int cursor_start,
76 int cursor_width, int cursor_height,
79 typedef struct textual_run
87 /* Separate out the text in DYN into a series of textual runs of a
88 particular charset. Also convert the characters as necessary into
89 the format needed by XDrawImageString(), XDrawImageString16(), et
90 al. (This means converting to one or two byte format, possibly
91 tweaking the high bits, and possibly running a CCL program.) You
92 must pre-allocate the space used and pass it in. (This is done so
93 you can alloca() the space.) You need to allocate (2 * len) bytes
94 of TEXT_STORAGE and (len * sizeof (textual_run)) bytes of
95 RUN_STORAGE, where LEN is the length of the dynarr.
97 Returns the number of runs actually used. */
100 separate_textual_runs (unsigned char *text_storage,
101 textual_run *run_storage,
102 CONST Emchar *str, Charcount len)
104 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a
105 possible valid charset when
106 MULE is not defined */
110 struct ccl_program char_converter;
111 int need_ccl_conversion = 0;
114 for (i = 0; i < len; i++)
122 BREAKUP_CHAR (ch, charset, byte1, byte2);
123 dimension = XCHARSET_DIMENSION (charset);
124 graphic = XCHARSET_GRAPHIC (charset);
126 if (!EQ (charset, prev_charset))
128 run_storage[runs_so_far].ptr = text_storage;
129 run_storage[runs_so_far].charset = charset;
130 run_storage[runs_so_far].dimension = dimension;
134 run_storage[runs_so_far - 1].len =
135 text_storage - run_storage[runs_so_far - 1].ptr;
136 if (run_storage[runs_so_far - 1].dimension == 2)
137 run_storage[runs_so_far - 1].len >>= 1;
140 prev_charset = charset;
143 Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset);
144 need_ccl_conversion = !NILP (ccl_prog);
145 if (need_ccl_conversion)
146 setup_ccl_program (&char_converter, ccl_prog);
156 else if (graphic == 1)
162 if (need_ccl_conversion)
164 char_converter.reg[0] = XCHARSET_ID (charset);
165 char_converter.reg[1] = byte1;
166 char_converter.reg[2] = byte2;
167 char_converter.ic = 0; /* start at beginning each time */
168 ccl_driver (&char_converter, 0, 0, 0, 0);
169 byte1 = char_converter.reg[1];
170 byte2 = char_converter.reg[2];
173 *text_storage++ = (unsigned char) byte1;
175 *text_storage++ = (unsigned char) byte2;
180 run_storage[runs_so_far - 1].len =
181 text_storage - run_storage[runs_so_far - 1].ptr;
182 if (run_storage[runs_so_far - 1].dimension == 2)
183 run_storage[runs_so_far - 1].len >>= 1;
191 mswindows_text_width_single_run (HDC hdc, struct face_cachel *cachel,
194 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
195 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
198 if (!fi->proportional_p || !hdc)
199 return (fi->width * run->len);
202 assert(run->dimension == 1); /* #### FIXME! */
203 mswindows_update_dc (hdc, font_inst, Qnil, Qnil, Qnil);
204 GetTextExtentPoint32 (hdc, run->ptr, run->len, &size);
210 /*****************************************************************************
213 Given a number of parameters munge the DC so it has those properties.
214 ****************************************************************************/
216 mswindows_update_dc (HDC hdc, Lisp_Object font, Lisp_Object fg,
217 Lisp_Object bg, Lisp_Object bg_pmap)
220 SelectObject(hdc, FONT_INSTANCE_MSWINDOWS_HFONT (XFONT_INSTANCE (font)));
225 SetTextColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR
226 (XCOLOR_INSTANCE (fg)));
230 SetBkMode (hdc, OPAQUE);
231 SetBkColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (bg)));
235 SetBkMode (hdc, TRANSPARENT);
240 /*****************************************************************************
241 mswindows_apply_face_effects
243 Draw underline and strikeout as if this was X.
244 #### On mswindows this really should be done as part of drawing the font.
245 The line width used is chosen arbitrarily from the font height.
246 ****************************************************************************/
248 mswindows_apply_face_effects (HDC hdc, struct display_line *dl, int xpos,
249 int width, struct Lisp_Font_Instance *fi,
250 struct face_cachel *cachel,
251 struct face_cachel *color_cachel)
254 HBRUSH brush, oldbrush;
257 brush = CreateSolidBrush (COLOR_INSTANCE_MSWINDOWS_COLOR (
258 XCOLOR_INSTANCE (color_cachel->foreground)));
261 yclip = dl->ypos + dl->descent - dl->clip;
263 rect.right = xpos + width;
264 oldbrush = SelectObject (hdc, brush);
266 if (cachel->underline)
268 rect.top = dl->ypos + dl->descent/2;
269 rect.bottom = rect.top + (fi->height >= 0x20 ? 2 : 1);
270 if (rect.bottom <= yclip)
271 FillRect (hdc, &rect, brush);
273 if (cachel->strikethru)
275 rect.top = dl->ypos + dl->descent - (dl->ascent + dl->descent)/2;
276 rect.bottom = rect.top + (fi->height >= 0x20 ? 2 : 1);
277 if (rect.bottom <= yclip)
278 FillRect (hdc, &rect, brush);
281 SelectObject (hdc, oldbrush);
282 DeleteObject (brush);
287 /*****************************************************************************
288 mswindows_output_hline
290 Output a horizontal line in the foreground of its face.
291 ****************************************************************************/
293 mswindows_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
294 { /* XXX Implement me */
298 /*****************************************************************************
299 mswindows_output_blank
301 Output a blank by clearing the area it covers in the background color
303 ****************************************************************************/
305 mswindows_output_blank (struct window *w, struct display_line *dl, struct rune *rb, int start_pixpos)
307 struct frame *f = XFRAME (w->frame);
308 RECT rect = { rb->xpos, dl->ypos-dl->ascent,
309 rb->xpos+rb->width, dl->ypos+dl->descent-dl->clip };
310 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, rb->findex);
312 Lisp_Object bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
314 if (!IMAGE_INSTANCEP (bg_pmap)
315 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
320 /* blank the background in the appropriate color */
321 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, cachel->foreground,
322 cachel->background, Qnil);
324 mswindows_output_pixmap (w, dl, bg_pmap,
325 rb->xpos, 0 /*rb->object.dglyph.xoffset*/,
326 start_pixpos, rb->width, rb->findex,
331 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
332 cachel->background, Qnil);
334 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
335 &rect, NULL, 0, NULL);
340 /*****************************************************************************
341 mswindows_output_cursor
343 Draw a normal or end-of-line cursor. The end-of-line cursor is
344 narrower than the normal cursor.
345 ****************************************************************************/
347 mswindows_output_cursor (struct window *w, struct display_line *dl, int xpos,
348 int width, face_index findex, Emchar ch, int image_p)
350 struct frame *f = XFRAME (w->frame);
351 struct device *d = XDEVICE (f->device);
352 struct face_cachel *cachel=0;
353 Lisp_Object font = Qnil;
354 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
355 HDC hdc = FRAME_MSWINDOWS_DC (f);
356 unsigned int face_index=0;
360 dl->ypos - dl->ascent,
362 dl->ypos + dl->descent - dl->clip};
363 Lisp_Object bar = symbol_value_in_buffer (Qbar_cursor,
365 int bar_p = image_p || !NILP (bar);
366 int cursor_p = !NILP (w->text_cursor_visible_p);
367 int real_char_p = ch != 0;
371 /* Use the font from the underlying character */
372 cachel = WINDOW_FACE_CACHEL (w, findex);
374 /* #### MULE: Need to know the charset! */
375 font = FACE_CACHEL_FONT (cachel, Vcharset_ascii);
378 if ((focus || bar_p) && real_char_p)
380 p_char = (char*) &ch;
386 struct face_cachel *color_cachel;
388 /* Use cursor fg/bg for block cursor, or character fg/bg for the bar
389 or when we need to erase the cursor. Output nothing at eol if bar
391 face_index = get_builtin_face_cache_index (w, Vtext_cursor_face);
392 color_cachel = WINDOW_FACE_CACHEL (w, ((!cursor_p || bar_p) ?
393 findex : face_index));
394 mswindows_update_dc (hdc, font, color_cachel->foreground,
395 color_cachel->background, Qnil);
396 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE|ETO_CLIPPED, &rect, p_char, n_char, NULL);
397 if (real_char_p && (cachel->underline || cachel->strikethru))
398 mswindows_apply_face_effects (hdc, dl, xpos, width,
399 XFONT_INSTANCE (font),
400 cachel, color_cachel);
408 rect.right = rect.left + (EQ (bar, Qt) ? 1 : min (2, width));
409 face_index = get_builtin_face_cache_index (w, Vtext_cursor_face);
410 cachel = WINDOW_FACE_CACHEL (w, face_index);
411 mswindows_update_dc (hdc, Qnil, Qnil, cachel->background, Qnil);
412 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE, &rect, NULL, 0, NULL);
416 /* Now have real character drawn in its own color. We deflate
417 the rectangle so character cell will be bounded by the
418 previously drawn cursor shape */
419 InflateRect (&rect, -1, -1);
423 p_char = (char*) &ch;
427 face_index = get_builtin_face_cache_index (w, Vdefault_face);
428 cachel = WINDOW_FACE_CACHEL (w, (real_char_p ? findex : face_index));
429 mswindows_update_dc (hdc, Qnil, cachel->foreground,
430 cachel->background, Qnil);
431 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE | ETO_CLIPPED,
432 &rect, p_char, n_char, NULL);
433 if (cachel->underline || cachel->strikethru)
434 mswindows_apply_face_effects (hdc, dl, xpos+1, width-2,
435 XFONT_INSTANCE (font),
441 /*****************************************************************************
442 mswindows_output_string
444 Given a string and a starting position, output that string in the
446 Correctly handles multiple charsets in the string.
448 The meaning of the parameters is something like this:
450 W Window that the text is to be displayed in.
451 DL Display line that this text is on. The values in the
452 structure are used to determine the vertical position and
453 clipping range of the text.
454 BUF Dynamic array of Emchars specifying what is actually to be
456 XPOS X position in pixels where the text should start being drawn.
457 XOFFSET Number of pixels to be chopped off the left side of the
458 text. The effect is as if the text were shifted to the
459 left this many pixels and clipped at XPOS.
460 CLIP_START Clip everything left of this X position.
461 WIDTH Clip everything right of XPOS + WIDTH.
462 FINDEX Index for the face cache element describing how to display
464 ****************************************************************************/
466 mswindows_output_string (struct window *w, struct display_line *dl,
467 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
468 int width, face_index findex)
470 struct frame *f = XFRAME (w->frame);
471 /* struct device *d = XDEVICE (f->device);*/
473 HDC hdc = FRAME_MSWINDOWS_DC (f);
476 int len = Dynarr_length (buf);
477 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
478 textual_run *runs = alloca_array (textual_run, len);
482 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
484 XSETWINDOW (window, w);
486 #if 0 /* #### FIXME? */
487 /* We can't work out the width before we've set the font in the DC */
489 width = mswindows_text_width (cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
494 /* Regularize the variables passed in. */
495 if (clip_start < xpos)
497 clip_end = xpos + width;
498 if (clip_start >= clip_end)
499 /* It's all clipped out. */
504 /* sort out the destination rectangle */
505 height = dl->ascent + dl->descent - dl->clip;
506 rect.left = clip_start;
507 rect.top = dl->ypos - dl->ascent;
508 rect.right = clip_end;
509 rect.bottom = height + dl->ypos - dl->ascent;
511 /* output the background pixmap if there is one */
512 bg_pmap = cachel->background_pixmap;
513 if (!IMAGE_INSTANCEP (bg_pmap)
514 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
519 /* blank the background in the appropriate color */
520 mswindows_update_dc (hdc, Qnil, cachel->foreground,
521 cachel->background, Qnil);
523 mswindows_output_pixmap (w, dl, bg_pmap,
525 clip_start, width, findex,
527 /* output pixmap calls this so we have to recall to get correct
529 cachel = WINDOW_FACE_CACHEL (w, findex);
532 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
533 Dynarr_length (buf));
535 for (i = 0; i < nruns; i++)
537 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
538 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
541 if (EQ (font, Vthe_null_font_instance))
544 mswindows_update_dc (hdc, font, cachel->foreground,
545 NILP(bg_pmap) ? cachel->background : Qnil, Qnil);
547 this_width = mswindows_text_width_single_run (hdc, cachel, runs + i);
549 /* cope with fonts taller than lines */
550 if ((int) fi->height < (int) (height + dl->clip))
552 int clear_start = max (xpos, clip_start);
553 int clear_end = min (xpos + this_width, clip_end);
556 redisplay_clear_region (window, findex, clear_start,
557 dl->ypos - dl->ascent,
558 clear_end - clear_start,
560 /* output pixmap calls this so we have to recall to get correct
562 cachel = WINDOW_FACE_CACHEL (w, findex);
566 assert (runs[i].dimension == 1); /* #### FIXME: Broken when Mule? */
567 ExtTextOut (hdc, xpos, dl->ypos,
568 NILP(bg_pmap) ? ETO_CLIPPED | ETO_OPAQUE : ETO_CLIPPED,
569 &rect, (char *) runs[i].ptr, runs[i].len, NULL);
571 /* #### X does underline/strikethrough here so we do the same.
572 On mswindows, underline/strikethrough really belongs to the font */
573 if (cachel->underline || cachel->strikethru)
574 mswindows_apply_face_effects (hdc, dl, xpos, this_width, fi,
581 mswindows_output_dibitmap (struct frame *f, struct Lisp_Image_Instance *p,
583 int clip_x, int clip_y,
584 int clip_width, int clip_height,
585 int width, int height, int pixmap_offset,
588 HDC hdc = FRAME_MSWINDOWS_DC (f);
590 COLORREF bgcolor = GetBkColor (hdc);
591 int need_clipping = (clip_x || clip_y);
594 /* do we need to offset the pixmap vertically? this is necessary
595 for background pixmaps. */
598 yoffset = y % IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
599 xoffset = x % IMAGE_INSTANCE_PIXMAP_WIDTH (p);
600 /* the width is handled by mswindows_output_pixmap_region */
607 /* first blt the mask */
608 if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
611 col.rgbBlue = GetBValue (bgcolor);
612 col.rgbRed = GetRValue (bgcolor);
613 col.rgbGreen = GetGValue (bgcolor);
616 old = SelectObject (FRAME_MSWINDOWS_CDC (f),
617 IMAGE_INSTANCE_MSWINDOWS_MASK (p));
619 SetDIBColorTable (FRAME_MSWINDOWS_CDC (f), 1, 1, &col);
624 FRAME_MSWINDOWS_CDC (f),
628 SelectObject (FRAME_MSWINDOWS_CDC (f), old);
631 /* now blt the bitmap itself. */
632 old = SelectObject (FRAME_MSWINDOWS_CDC (f),
633 IMAGE_INSTANCE_MSWINDOWS_BITMAP (p));
638 FRAME_MSWINDOWS_CDC (f),
640 IMAGE_INSTANCE_MSWINDOWS_MASK (p) ? SRCINVERT : SRCCOPY);
642 SelectObject (FRAME_MSWINDOWS_CDC (f),old);
650 * X gc's have this nice property that setting the bg pixmap will
651 * output it offset relative to the window. Windows doesn't have this
652 * feature so we have to emulate this by outputting multiple pixmaps
655 mswindows_output_dibitmap_region (struct frame *f,
656 struct Lisp_Image_Instance *p,
658 int clip_x, int clip_y,
659 int clip_width, int clip_height,
660 int width, int height, int pixmap_offset,
663 int pwidth = min (width, IMAGE_INSTANCE_PIXMAP_WIDTH (p));
664 int pheight = min (height, IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
665 int pxoffset = 0, pyoffset = 0;
667 /* when doing a bg pixmap do a partial pixmap first so that we
668 blt whole pixmaps thereafter */
672 pheight = min (pheight, IMAGE_INSTANCE_PIXMAP_HEIGHT (p) -
673 y % IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
680 pwidth = min (min (width, IMAGE_INSTANCE_PIXMAP_WIDTH (p)),
681 IMAGE_INSTANCE_PIXMAP_WIDTH (p) -
682 x % IMAGE_INSTANCE_PIXMAP_WIDTH (p));
687 mswindows_output_dibitmap (f, p,
688 x + pxoffset, y + pyoffset,
690 clip_width, clip_height,
691 pwidth, pheight, pixmap_offset,
694 pwidth = min ((width-pxoffset),
695 IMAGE_INSTANCE_PIXMAP_WIDTH (p));
698 pheight = min ((height-pyoffset),
699 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
704 mswindows_output_pixmap (struct window *w, struct display_line *dl,
705 Lisp_Object image_instance, int xpos, int xoffset,
706 int start_pixpos, int width, face_index findex,
707 int cursor_start, int cursor_width, int cursor_height,
710 struct frame *f = XFRAME (w->frame);
711 HDC hdc = FRAME_MSWINDOWS_DC (f);
713 struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
716 int lheight = dl->ascent + dl->descent - dl->clip;
717 int pheight = ((int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > lheight ? lheight :
718 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
719 int clip_x, clip_y, clip_width, clip_height;
721 /* The pixmap_offset is used to center the pixmap on lines which are
722 shorter than it is. This results in odd effects when scrolling
723 pixmaps off of the bottom. Let's try not using it. */
725 int pixmap_offset = (int) (IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - lheight) / 2;
727 int pixmap_offset = 0;
730 XSETWINDOW (window, w);
732 if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
734 if (start_pixpos > xpos && start_pixpos > xpos + width)
739 if (start_pixpos > xpos)
741 clip_x += (start_pixpos - xpos);
742 clip_width -= (start_pixpos - xpos);
751 /* Place markers for possible future functionality (clipping the top
752 half instead of the bottom half; think pixel scrolling). */
754 clip_height = pheight;
756 /* Clear the area the pixmap is going into. The pixmap itself will
757 always take care of the full width. We don't want to clear where
758 it is going to go in order to avoid flicker. So, all we have to
759 take care of is any area above or below the pixmap. */
760 /* #### We take a shortcut for now. We know that since we have
761 pixmap_offset hardwired to 0 that the pixmap is against the top
762 edge so all we have to worry about is below it. */
763 /* #### Unless the pixmap has a mask in which case we have to clear
764 the whole damn thing since we can't yet clear just the area not
765 included in the mask. */
766 if (((int) (dl->ypos - dl->ascent + pheight) <
767 (int) (dl->ypos + dl->descent - dl->clip))
768 || IMAGE_INSTANCE_MSWINDOWS_MASK (p))
770 int clear_x, clear_y, clear_width, clear_height;
772 if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
774 clear_y = dl->ypos - dl->ascent;
775 clear_height = lheight;
779 clear_y = dl->ypos - dl->ascent + pheight;
780 clear_height = lheight - pheight;
783 if (start_pixpos >= 0 && start_pixpos > xpos)
785 clear_x = start_pixpos;
786 clear_width = xpos + width - start_pixpos;
794 if (!offset_bitmap) /* i.e. not a bg pixmap */
795 redisplay_clear_region (window, findex, clear_x, clear_y,
796 clear_width, clear_height);
799 /* Output the pixmap. Have to do this as many times as is required
800 to fill the given area */
801 mswindows_update_dc (hdc, Qnil,
802 WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
803 WINDOW_FACE_CACHEL_BACKGROUND (w, findex), Qnil);
805 mswindows_output_dibitmap_region (f, p, xpos - xoffset,
806 dl->ypos - dl->ascent,
807 clip_x, clip_y, clip_width, clip_height,
808 width + xoffset, pheight, pixmap_offset,
812 #ifdef HAVE_SCROLLBARS
814 * This function paints window's deadbox, a rectangle between window
815 * borders and two short edges of both scrollbars.
817 * Function checks whether deadbox intersects with the rectangle pointed
818 * to by PRC, and paints only the intersection
821 mswindows_redisplay_deadbox_maybe (struct window *w, CONST RECT* prc)
823 int sbh = window_scrollbar_height (w);
824 int sbw = window_scrollbar_width (w);
825 RECT rect_dead, rect_paint;
826 if (sbh == 0 || sbw == 0)
829 if (!NILP (w->scrollbar_on_left_p))
830 rect_dead.left = WINDOW_LEFT (w);
832 rect_dead.left = WINDOW_TEXT_RIGHT (w);
833 rect_dead.right = rect_dead.left + sbw;
835 if (!NILP (w->scrollbar_on_top_p))
836 rect_dead.top = WINDOW_TOP (w);
838 rect_dead.top = WINDOW_TEXT_BOTTOM (w);
839 rect_dead.bottom = rect_dead.top + sbh;
841 if (IntersectRect (&rect_paint, &rect_dead, prc))
843 struct frame *f = XFRAME (WINDOW_FRAME (w));
844 FillRect (FRAME_MSWINDOWS_DC (f), &rect_paint,
845 (HBRUSH) (COLOR_BTNFACE+1));
849 #endif /* HAVE_SCROLLBARS */
851 /*****************************************************************************
852 mswindows_redraw_exposed_window
854 Given a bounding box for an area that needs to be redrawn, determine
855 what parts of what lines are contained within and re-output their
857 Copied from redisplay-x.c
858 ****************************************************************************/
860 mswindows_redraw_exposed_window (struct window *w, int x, int y, int width,
863 struct frame *f = XFRAME (w->frame);
865 int orig_windows_structure_changed;
866 RECT rect_window = { WINDOW_LEFT (w), WINDOW_TOP (w),
867 WINDOW_RIGHT (w), WINDOW_BOTTOM (w) };
868 RECT rect_expose = { x, y, x + width, y + height };
871 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
873 if (!NILP (w->vchild))
875 mswindows_redraw_exposed_windows (w->vchild, x, y, width, height);
878 else if (!NILP (w->hchild))
880 mswindows_redraw_exposed_windows (w->hchild, x, y, width, height);
884 /* If the window doesn't intersect the exposed region, we're done here. */
885 if (!IntersectRect (&rect_draw, &rect_window, &rect_expose))
888 /* We do this to make sure that the 3D modelines get redrawn if
889 they are in the exposed region. */
890 orig_windows_structure_changed = f->windows_structure_changed;
891 f->windows_structure_changed = 1;
893 if (window_needs_vertical_divider (w))
895 mswindows_output_vertical_divider (w, 0);
898 for (line = 0; line < Dynarr_length (cdla); line++)
900 struct display_line *cdl = Dynarr_atp (cdla, line);
901 int top_y = cdl->ypos - cdl->ascent;
902 int bottom_y = cdl->ypos + cdl->descent;
904 if (bottom_y >= rect_draw.top)
906 if (top_y > rect_draw.bottom)
915 output_display_line (w, 0, cdla, line,
916 rect_draw.left, rect_draw.right);
921 f->windows_structure_changed = orig_windows_structure_changed;
923 /* If there have never been any face cache_elements created, then this
924 expose event doesn't actually have anything to do. */
925 if (Dynarr_largest (w->face_cachels))
926 redisplay_clear_bottom_of_window (w, cdla, rect_draw.top, rect_draw.bottom);
928 #ifdef HAVE_SCROLLBARS
929 mswindows_redisplay_deadbox_maybe (w, &rect_expose);
933 /*****************************************************************************
934 mswindows_redraw_exposed_windows
936 For each window beneath the given window in the window hierarchy,
937 ensure that it is redrawn if necessary after an Expose event.
938 ****************************************************************************/
940 mswindows_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
943 for (; !NILP (window); window = XWINDOW (window)->next)
944 mswindows_redraw_exposed_window (XWINDOW (window), x, y, width, height);
947 /*****************************************************************************
948 mswindows_redraw_exposed_area
950 For each window on the given frame, ensure that any area in the
951 Exposed area is redrawn.
952 ****************************************************************************/
954 mswindows_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
956 /* If any window on the frame has had its face cache reset then the
957 redisplay structures are effectively invalid. If we attempt to
958 use them we'll blow up. We mark the frame as changed to ensure
959 that redisplay will do a full update. This probably isn't
960 necessary but it can't hurt. */
962 /* #### We would rather put these off as well but there is currently
963 no combination of flags which will force an unchanged toolbar to
965 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
968 if (!f->window_face_cache_reset)
970 mswindows_redraw_exposed_windows (f->root_window, x, y, width, height);
974 MARK_FRAME_CHANGED (f);
978 /*****************************************************************************
979 mswindows_bevel_modeline
981 Draw a 3d border around the modeline on window W.
982 ****************************************************************************/
984 mswindows_bevel_modeline (struct window *w, struct display_line *dl)
986 struct frame *f = XFRAME (w->frame);
988 int shadow_width = MODELINE_SHADOW_THICKNESS (w);
989 RECT rect = { WINDOW_MODELINE_LEFT (w),
990 dl->ypos - dl->ascent - shadow_width,
991 WINDOW_MODELINE_RIGHT (w),
992 dl->ypos + dl->descent + shadow_width};
995 color = WINDOW_FACE_CACHEL_BACKGROUND (w, MODELINE_INDEX);
996 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, color, Qnil);
998 if (XINT (w->modeline_shadow_thickness) < 0)
999 shadow_width = -shadow_width;
1001 if (shadow_width < -1)
1003 else if (shadow_width < 0)
1004 edge = BDR_SUNKENINNER;
1005 else if (shadow_width == 1)
1006 edge = BDR_RAISEDINNER;
1010 DrawEdge (FRAME_MSWINDOWS_DC (f), &rect, edge, BF_RECT);
1014 /*****************************************************************************
1016 *****************************************************************************/
1018 /*****************************************************************************
1019 mswindows_divider_height
1021 Return the height of the horizontal divider.
1022 ****************************************************************************/
1024 mswindows_divider_height (void)
1026 return 1; /* XXX Copied from redisplay-X.c. What is this? */
1029 /*****************************************************************************
1030 mswindows_eol_cursor_width
1032 Return the width of the end-of-line cursor.
1033 ****************************************************************************/
1035 mswindows_eol_cursor_width (void)
1037 return MSWINDOWS_EOL_CURSOR_WIDTH;
1040 /*****************************************************************************
1041 mswindows_output_begin
1043 Perform any necessary initialization prior to an update.
1044 ****************************************************************************/
1046 mswindows_output_begin (struct device *d)
1050 /*****************************************************************************
1051 mswindows_output_end
1053 Perform any necessary flushing of queues when an update has completed.
1054 ****************************************************************************/
1056 mswindows_output_end (struct device *d)
1062 mswindows_flash (struct device *d)
1064 struct frame *f = device_selected_frame (d);
1067 GetClientRect (FRAME_MSWINDOWS_HANDLE (f), &rc);
1068 InvertRect (FRAME_MSWINDOWS_DC (f), &rc);
1071 InvertRect (FRAME_MSWINDOWS_DC (f), &rc);
1077 mswindows_ring_bell (struct device *d, int volume, int pitch, int duration)
1079 /* Beep does not work at all, anyways! -kkm */
1080 MessageBeep (MB_OK);
1083 /*****************************************************************************
1084 mswindows_output_display_block
1086 Given a display line, a block number for that start line, output all
1087 runes between start and end in the specified display block.
1088 Ripped off with minimal thought from the corresponding X routine.
1089 ****************************************************************************/
1091 mswindows_output_display_block (struct window *w, struct display_line *dl, int block,
1092 int start, int end, int start_pixpos, int cursor_start,
1093 int cursor_width, int cursor_height)
1095 struct frame *f = XFRAME (w->frame);
1096 Emchar_dynarr *buf = Dynarr_new (Emchar);
1099 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
1100 rune_dynarr *rba = db->runes;
1106 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
1107 MULE is not defined */
1108 XSETWINDOW (window, w);
1109 rb = Dynarr_atp (rba, start);
1113 /* Nothing to do so don't do anything. */
1118 findex = rb->findex;
1121 if (rb->type == RUNE_CHAR)
1122 charset = CHAR_CHARSET (rb->object.chr.ch);
1126 end = Dynarr_length (rba);
1131 rb = Dynarr_atp (rba, elt);
1133 if (rb->findex == findex && rb->type == RUNE_CHAR
1134 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
1135 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
1137 Dynarr_add (buf, rb->object.chr.ch);
1143 if (Dynarr_length (buf))
1145 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
1153 if (rb->type == RUNE_CHAR)
1155 findex = rb->findex;
1157 charset = CHAR_CHARSET (rb->object.chr.ch);
1159 if (rb->cursor_type == CURSOR_ON)
1161 if (rb->object.chr.ch == '\n')
1163 mswindows_output_cursor (w, dl, xpos, cursor_width,
1168 Dynarr_add (buf, rb->object.chr.ch);
1169 mswindows_output_cursor (w, dl, xpos, cursor_width,
1170 findex, rb->object.chr.ch, 0);
1177 else if (rb->object.chr.ch == '\n')
1179 /* Clear in case a cursor was formerly here. */
1180 int height = dl->ascent + dl->descent - dl->clip;
1182 redisplay_clear_region (window, findex, xpos, dl->ypos - dl->ascent,
1187 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
1189 if (rb->type == RUNE_BLANK)
1190 mswindows_output_blank (w, dl, rb, start_pixpos);
1193 /* #### Our flagging of when we need to redraw the
1194 modeline shadows sucks. Since RUNE_HLINE is only used
1195 by the modeline at the moment it is a good bet
1196 that if it gets redrawn then we should also
1197 redraw the shadows. This won't be true forever.
1198 We borrow the shadow_thickness_changed flag for
1200 w->shadow_thickness_changed = 1;
1201 mswindows_output_hline (w, dl, rb);
1204 if (rb->cursor_type == CURSOR_ON)
1205 mswindows_output_cursor (w, dl, xpos, cursor_width, rb->findex, 0, 0);
1210 rb = Dynarr_atp (rba, elt);
1212 findex = rb->findex;
1216 else if (rb->type == RUNE_DGLYPH)
1218 Lisp_Object instance;
1220 XSETWINDOW (window, w);
1221 instance = glyph_image_instance (rb->object.dglyph.glyph,
1222 window, ERROR_ME_NOT, 1);
1223 findex = rb->findex;
1225 if (IMAGE_INSTANCEP (instance))
1226 switch (XIMAGE_INSTANCE_TYPE (instance))
1230 /* #### This is way losing. See the comment in
1231 add_glyph_rune(). */
1232 Lisp_Object string =
1233 XIMAGE_INSTANCE_TEXT_STRING (instance);
1234 convert_bufbyte_string_into_emchar_dynarr
1235 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
1237 if (rb->cursor_type == CURSOR_ON)
1238 mswindows_output_cursor (w, dl, xpos, cursor_width,
1239 findex, Dynarr_at (buf, 0), 0);
1240 else /* #### redisplay-x passes -1 as the width: why ? */
1241 mswindows_output_string (w, dl, buf, xpos,
1242 rb->object.dglyph.xoffset,
1243 start_pixpos, rb->width, findex);
1248 case IMAGE_MONO_PIXMAP:
1249 case IMAGE_COLOR_PIXMAP:
1250 mswindows_output_pixmap (w, dl, instance, xpos,
1251 rb->object.dglyph.xoffset, start_pixpos,
1252 rb->width, findex, cursor_start,
1253 cursor_width, cursor_height, 0);
1254 if (rb->cursor_type == CURSOR_ON)
1255 mswindows_output_cursor (w, dl, xpos, cursor_width,
1262 case IMAGE_SUBWINDOW:
1264 redisplay_output_subwindow (w, dl, instance, xpos,
1265 rb->object.dglyph.xoffset, start_pixpos,
1266 rb->width, findex, cursor_start,
1267 cursor_width, cursor_height);
1268 if (rb->cursor_type == CURSOR_ON)
1269 mswindows_output_cursor (w, dl, xpos, cursor_width,
1274 /* nothing is as nothing does */
1289 if (Dynarr_length (buf))
1290 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex);
1293 && !EQ (Qzero, w->modeline_shadow_thickness)
1295 || f->windows_structure_changed
1296 || w->shadow_thickness_changed))
1297 mswindows_bevel_modeline (w, dl);
1303 /*****************************************************************************
1304 mswindows_output_vertical_divider
1306 Draw a vertical divider down the right side of the given window.
1307 ****************************************************************************/
1309 mswindows_output_vertical_divider (struct window *w, int clear_unused)
1311 struct frame *f = XFRAME (w->frame);
1313 int spacing = XINT (w->vertical_divider_spacing);
1314 int shadow = XINT (w->vertical_divider_shadow_thickness);
1315 int abs_shadow = abs (shadow);
1316 int line_width = XINT (w->vertical_divider_line_width);
1317 int div_left = WINDOW_RIGHT (w) - window_divider_width (w);
1319 /* Clear left and right spacing areas */
1322 rect.top = WINDOW_TOP (w);
1323 rect.bottom = WINDOW_BOTTOM (w);
1324 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
1325 WINDOW_FACE_CACHEL_BACKGROUND (w, DEFAULT_INDEX), Qnil);
1326 rect.right = WINDOW_RIGHT (w);
1327 rect.left = rect.right - spacing;
1328 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
1329 &rect, NULL, 0, NULL);
1330 rect.left = div_left;
1331 rect.right = div_left + spacing;
1332 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
1333 &rect, NULL, 0, NULL);
1336 /* Clear divider face */
1337 rect.top = WINDOW_TOP (w) + abs_shadow;
1338 rect.bottom = WINDOW_BOTTOM (w) - abs_shadow;
1339 rect.left = div_left + spacing + abs_shadow;
1340 rect.right = rect.left + line_width;
1341 if (rect.left < rect.right)
1344 = get_builtin_face_cache_index (w, Vvertical_divider_face);
1345 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
1346 WINDOW_FACE_CACHEL_BACKGROUND (w, div_face), Qnil);
1347 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
1348 &rect, NULL, 0, NULL);
1351 /* Draw a shadow around the divider */
1354 /* #### This will be fixed to support arbitrary thickness */
1355 InflateRect (&rect, abs_shadow, abs_shadow);
1356 DrawEdge (FRAME_MSWINDOWS_DC (f), &rect,
1357 shadow > 0 ? EDGE_RAISED : EDGE_SUNKEN, BF_RECT);
1361 /****************************************************************************
1362 mswindows_text_width
1364 Given a string and a face, return the string's length in pixels when
1365 displayed in the font associated with the face.
1366 ****************************************************************************/
1368 mswindows_text_width (struct frame *f, struct face_cachel *cachel,
1369 CONST Emchar *str, Charcount len)
1371 int width_so_far = 0;
1372 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
1373 textual_run *runs = alloca_array (textual_run, len);
1377 nruns = separate_textual_runs (text_storage, runs, str, len);
1379 for (i = 0; i < nruns; i++)
1380 width_so_far += mswindows_text_width_single_run (FRAME_MSWINDOWS_DC (f),
1383 return width_so_far;
1387 /****************************************************************************
1388 mswindows_clear_region
1390 Clear the area in the box defined by the given parameters using the
1392 ****************************************************************************/
1394 mswindows_clear_region (Lisp_Object locale, struct device* d, struct frame* f,
1395 face_index findex, int x, int y,
1396 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1397 Lisp_Object background_pixmap)
1399 RECT rect = { x, y, x+width, y+height };
1401 if (!NILP (background_pixmap))
1403 mswindows_update_dc (FRAME_MSWINDOWS_DC (f),
1404 Qnil, fcolor, bcolor, background_pixmap);
1406 mswindows_output_dibitmap_region
1407 ( f, XIMAGE_INSTANCE (background_pixmap),
1408 x, y, 0, 0, 0, 0, width, height, 0, TRUE);
1412 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, fcolor, Qnil);
1413 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
1414 &rect, NULL, 0, NULL);
1417 #ifdef HAVE_SCROLLBARS
1418 if (WINDOWP (locale))
1419 mswindows_redisplay_deadbox_maybe (XWINDOW (locale), &rect);
1423 /*****************************************************************************
1424 mswindows_clear_to_window_end
1426 Clear the area between ypos1 and ypos2. Each margin area and the
1427 text area is handled separately since they may each have their own
1429 ****************************************************************************/
1431 mswindows_clear_to_window_end (struct window *w, int ypos1, int ypos2)
1433 int height = ypos2 - ypos1;
1437 struct frame *f = XFRAME (w->frame);
1439 int bflag = (window_needs_vertical_divider (w) ? 0 : 1);
1440 layout_bounds bounds;
1442 bounds = calculate_display_line_boundaries (w, bflag);
1443 XSETWINDOW (window, w);
1445 if (window_is_leftmost (w))
1446 redisplay_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f),
1447 ypos1, FRAME_BORDER_WIDTH (f), height);
1449 if (bounds.left_in - bounds.left_out > 0)
1450 redisplay_clear_region (window,
1451 get_builtin_face_cache_index (w, Vleft_margin_face),
1452 bounds.left_out, ypos1,
1453 bounds.left_in - bounds.left_out, height);
1455 if (bounds.right_in - bounds.left_in > 0)
1456 redisplay_clear_region (window, DEFAULT_INDEX, bounds.left_in, ypos1,
1457 bounds.right_in - bounds.left_in, height);
1459 if (bounds.right_out - bounds.right_in > 0)
1460 redisplay_clear_region (window,
1461 get_builtin_face_cache_index (w, Vright_margin_face),
1462 bounds.right_in, ypos1,
1463 bounds.right_out - bounds.right_in, height);
1465 if (window_is_rightmost (w))
1466 redisplay_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f),
1467 ypos1, FRAME_BORDER_WIDTH (f), height);
1473 /* XXX Implement me! */
1475 mswindows_clear_frame (struct frame *f)
1482 /************************************************************************/
1483 /* initialization */
1484 /************************************************************************/
1487 console_type_create_redisplay_mswindows (void)
1489 /* redisplay methods */
1490 CONSOLE_HAS_METHOD (mswindows, text_width);
1491 CONSOLE_HAS_METHOD (mswindows, output_display_block);
1492 CONSOLE_HAS_METHOD (mswindows, divider_height);
1493 CONSOLE_HAS_METHOD (mswindows, eol_cursor_width);
1494 CONSOLE_HAS_METHOD (mswindows, output_vertical_divider);
1495 CONSOLE_HAS_METHOD (mswindows, clear_to_window_end);
1496 CONSOLE_HAS_METHOD (mswindows, clear_region);
1497 CONSOLE_HAS_METHOD (mswindows, clear_frame);
1498 CONSOLE_HAS_METHOD (mswindows, output_begin);
1499 CONSOLE_HAS_METHOD (mswindows, output_end);
1500 CONSOLE_HAS_METHOD (mswindows, flash);
1501 CONSOLE_HAS_METHOD (mswindows, ring_bell);