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 = DISPLAY_LINE_HEIGHT (dl);
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);
595 /* do we need to offset the pixmap vertically? this is necessary
596 for background pixmaps. */
599 yoffset = y % IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
600 xoffset = x % IMAGE_INSTANCE_PIXMAP_WIDTH (p);
601 /* the width is handled by mswindows_output_pixmap_region */
608 /* first blt the mask */
609 if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
612 col.rgbBlue = GetBValue (bgcolor);
613 col.rgbRed = GetRValue (bgcolor);
614 col.rgbGreen = GetGValue (bgcolor);
617 old = SelectObject (FRAME_MSWINDOWS_CDC (f),
618 IMAGE_INSTANCE_MSWINDOWS_MASK (p));
620 SetDIBColorTable (FRAME_MSWINDOWS_CDC (f), 1, 1, &col);
625 FRAME_MSWINDOWS_CDC (f),
629 SelectObject (FRAME_MSWINDOWS_CDC (f), old);
632 /* now blt the bitmap itself. */
633 old = SelectObject (FRAME_MSWINDOWS_CDC (f),
634 IMAGE_INSTANCE_MSWINDOWS_BITMAP (p));
639 FRAME_MSWINDOWS_CDC (f),
641 IMAGE_INSTANCE_MSWINDOWS_MASK (p) ? SRCINVERT : SRCCOPY);
643 SelectObject (FRAME_MSWINDOWS_CDC (f),old);
651 * X gc's have this nice property that setting the bg pixmap will
652 * output it offset relative to the window. Windows doesn't have this
653 * feature so we have to emulate this by outputting multiple pixmaps
656 mswindows_output_dibitmap_region (struct frame *f,
657 struct Lisp_Image_Instance *p,
659 int clip_x, int clip_y,
660 int clip_width, int clip_height,
661 int width, int height, int pixmap_offset,
664 int pwidth = min (width, IMAGE_INSTANCE_PIXMAP_WIDTH (p));
665 int pheight = min (height, IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
666 int pxoffset = 0, pyoffset = 0;
668 /* when doing a bg pixmap do a partial pixmap first so that we
669 blt whole pixmaps thereafter */
673 pheight = min (pheight, IMAGE_INSTANCE_PIXMAP_HEIGHT (p) -
674 y % IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
681 pwidth = min (min (width, IMAGE_INSTANCE_PIXMAP_WIDTH (p)),
682 IMAGE_INSTANCE_PIXMAP_WIDTH (p) -
683 x % IMAGE_INSTANCE_PIXMAP_WIDTH (p));
688 mswindows_output_dibitmap (f, p,
689 x + pxoffset, y + pyoffset,
691 clip_width, clip_height,
692 pwidth, pheight, pixmap_offset,
695 pwidth = min ((width-pxoffset),
696 IMAGE_INSTANCE_PIXMAP_WIDTH (p));
699 pheight = min ((height-pyoffset),
700 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
705 mswindows_output_pixmap (struct window *w, struct display_line *dl,
706 Lisp_Object image_instance, int xpos, int xoffset,
707 int start_pixpos, int width, face_index findex,
708 int cursor_start, int cursor_width, int cursor_height,
711 struct frame *f = XFRAME (w->frame);
712 HDC hdc = FRAME_MSWINDOWS_DC (f);
714 struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
717 int lheight = DISPLAY_LINE_HEIGHT (dl);
718 int pheight = ((int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > lheight ? lheight :
719 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
720 int clip_x, clip_y, clip_width, clip_height;
722 /* The pixmap_offset is used to center the pixmap on lines which are
723 shorter than it is. This results in odd effects when scrolling
724 pixmaps off of the bottom. Let's try not using it. */
726 int pixmap_offset = (int) (IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - lheight) / 2;
728 int pixmap_offset = 0;
731 XSETWINDOW (window, w);
733 if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
735 if (start_pixpos > xpos && start_pixpos > xpos + width)
740 if (start_pixpos > xpos)
742 clip_x += (start_pixpos - xpos);
743 clip_width -= (start_pixpos - xpos);
752 /* Place markers for possible future functionality (clipping the top
753 half instead of the bottom half; think pixel scrolling). */
755 clip_height = pheight;
757 /* Clear the area the pixmap is going into. The pixmap itself will
758 always take care of the full width. We don't want to clear where
759 it is going to go in order to avoid flicker. So, all we have to
760 take care of is any area above or below the pixmap. */
761 /* #### We take a shortcut for now. We know that since we have
762 pixmap_offset hardwired to 0 that the pixmap is against the top
763 edge so all we have to worry about is below it. */
764 /* #### Unless the pixmap has a mask in which case we have to clear
765 the whole damn thing since we can't yet clear just the area not
766 included in the mask. */
767 if (((int) (dl->ypos - dl->ascent + pheight) <
768 (int) (dl->ypos + dl->descent - dl->clip))
769 || IMAGE_INSTANCE_MSWINDOWS_MASK (p))
771 int clear_x, clear_y, clear_width, clear_height;
773 if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
775 clear_y = dl->ypos - dl->ascent;
776 clear_height = lheight;
780 clear_y = dl->ypos - dl->ascent + pheight;
781 clear_height = lheight - pheight;
784 if (start_pixpos >= 0 && start_pixpos > xpos)
786 clear_x = start_pixpos;
787 clear_width = xpos + width - start_pixpos;
795 if (!offset_bitmap) /* i.e. not a bg pixmap */
796 redisplay_clear_region (window, findex, clear_x, clear_y,
797 clear_width, clear_height);
800 /* Output the pixmap. Have to do this as many times as is required
801 to fill the given area */
802 mswindows_update_dc (hdc, Qnil,
803 WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
804 WINDOW_FACE_CACHEL_BACKGROUND (w, findex), Qnil);
806 mswindows_output_dibitmap_region (f, p, xpos - xoffset,
807 dl->ypos - dl->ascent,
808 clip_x, clip_y, clip_width, clip_height,
809 width + xoffset, pheight, pixmap_offset,
813 #ifdef HAVE_SCROLLBARS
815 * This function paints window's deadbox, a rectangle between window
816 * borders and two short edges of both scrollbars.
818 * Function checks whether deadbox intersects with the rectangle pointed
819 * to by PRC, and paints only the intersection
822 mswindows_redisplay_deadbox_maybe (struct window *w, CONST RECT* prc)
824 int sbh = window_scrollbar_height (w);
825 int sbw = window_scrollbar_width (w);
826 RECT rect_dead, rect_paint;
827 if (sbh == 0 || sbw == 0)
830 if (!NILP (w->scrollbar_on_left_p))
831 rect_dead.left = WINDOW_LEFT (w);
833 rect_dead.left = WINDOW_TEXT_RIGHT (w);
834 rect_dead.right = rect_dead.left + sbw;
836 if (!NILP (w->scrollbar_on_top_p))
837 rect_dead.top = WINDOW_TOP (w);
839 rect_dead.top = WINDOW_TEXT_BOTTOM (w);
840 rect_dead.bottom = rect_dead.top + sbh;
842 if (IntersectRect (&rect_paint, &rect_dead, prc))
844 struct frame *f = XFRAME (WINDOW_FRAME (w));
845 FillRect (FRAME_MSWINDOWS_DC (f), &rect_paint,
846 (HBRUSH) (COLOR_BTNFACE+1));
850 #endif /* HAVE_SCROLLBARS */
852 /*****************************************************************************
853 mswindows_redraw_exposed_window
855 Given a bounding box for an area that needs to be redrawn, determine
856 what parts of what lines are contained within and re-output their
858 Copied from redisplay-x.c
859 ****************************************************************************/
861 mswindows_redraw_exposed_window (struct window *w, int x, int y, int width,
864 struct frame *f = XFRAME (w->frame);
866 int orig_windows_structure_changed;
867 RECT rect_window = { WINDOW_LEFT (w), WINDOW_TOP (w),
868 WINDOW_RIGHT (w), WINDOW_BOTTOM (w) };
869 RECT rect_expose = { x, y, x + width, y + height };
872 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
874 if (!NILP (w->vchild))
876 mswindows_redraw_exposed_windows (w->vchild, x, y, width, height);
879 else if (!NILP (w->hchild))
881 mswindows_redraw_exposed_windows (w->hchild, x, y, width, height);
885 /* If the window doesn't intersect the exposed region, we're done here. */
886 if (!IntersectRect (&rect_draw, &rect_window, &rect_expose))
889 /* We do this to make sure that the 3D modelines get redrawn if
890 they are in the exposed region. */
891 orig_windows_structure_changed = f->windows_structure_changed;
892 f->windows_structure_changed = 1;
894 if (window_needs_vertical_divider (w))
896 mswindows_output_vertical_divider (w, 0);
899 for (line = 0; line < Dynarr_length (cdla); line++)
901 struct display_line *cdl = Dynarr_atp (cdla, line);
902 int top_y = cdl->ypos - cdl->ascent;
903 int bottom_y = cdl->ypos + cdl->descent;
905 if (bottom_y >= rect_draw.top)
907 if (top_y > rect_draw.bottom)
916 output_display_line (w, 0, cdla, line,
917 rect_draw.left, rect_draw.right);
922 f->windows_structure_changed = orig_windows_structure_changed;
924 /* If there have never been any face cache_elements created, then this
925 expose event doesn't actually have anything to do. */
926 if (Dynarr_largest (w->face_cachels))
927 redisplay_clear_bottom_of_window (w, cdla, rect_draw.top, rect_draw.bottom);
929 #ifdef HAVE_SCROLLBARS
930 mswindows_redisplay_deadbox_maybe (w, &rect_expose);
934 /*****************************************************************************
935 mswindows_redraw_exposed_windows
937 For each window beneath the given window in the window hierarchy,
938 ensure that it is redrawn if necessary after an Expose event.
939 ****************************************************************************/
941 mswindows_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
944 for (; !NILP (window); window = XWINDOW (window)->next)
945 mswindows_redraw_exposed_window (XWINDOW (window), x, y, width, height);
948 /*****************************************************************************
949 mswindows_redraw_exposed_area
951 For each window on the given frame, ensure that any area in the
952 Exposed area is redrawn.
953 ****************************************************************************/
955 mswindows_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
957 /* If any window on the frame has had its face cache reset then the
958 redisplay structures are effectively invalid. If we attempt to
959 use them we'll blow up. We mark the frame as changed to ensure
960 that redisplay will do a full update. This probably isn't
961 necessary but it can't hurt. */
963 /* #### We would rather put these off as well but there is currently
964 no combination of flags which will force an unchanged toolbar to
966 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
969 if (!f->window_face_cache_reset)
971 mswindows_redraw_exposed_windows (f->root_window, x, y, width, height);
975 MARK_FRAME_CHANGED (f);
979 /*****************************************************************************
980 mswindows_bevel_modeline
982 Draw a 3d border around the modeline on window W.
983 ****************************************************************************/
985 mswindows_bevel_modeline (struct window *w, struct display_line *dl)
987 struct frame *f = XFRAME (w->frame);
989 int shadow_width = MODELINE_SHADOW_THICKNESS (w);
990 RECT rect = { WINDOW_MODELINE_LEFT (w),
991 dl->ypos - dl->ascent - shadow_width,
992 WINDOW_MODELINE_RIGHT (w),
993 dl->ypos + dl->descent + shadow_width};
996 color = WINDOW_FACE_CACHEL_BACKGROUND (w, MODELINE_INDEX);
997 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, color, Qnil);
999 if (XINT (w->modeline_shadow_thickness) < 0)
1000 shadow_width = -shadow_width;
1002 if (shadow_width < -1)
1004 else if (shadow_width < 0)
1005 edge = BDR_SUNKENINNER;
1006 else if (shadow_width == 1)
1007 edge = BDR_RAISEDINNER;
1011 DrawEdge (FRAME_MSWINDOWS_DC (f), &rect, edge, BF_RECT);
1015 /*****************************************************************************
1017 *****************************************************************************/
1019 /*****************************************************************************
1020 mswindows_divider_height
1022 Return the height of the horizontal divider.
1023 ****************************************************************************/
1025 mswindows_divider_height (void)
1027 return 1; /* XXX Copied from redisplay-X.c. What is this? */
1030 /*****************************************************************************
1031 mswindows_eol_cursor_width
1033 Return the width of the end-of-line cursor.
1034 ****************************************************************************/
1036 mswindows_eol_cursor_width (void)
1038 return MSWINDOWS_EOL_CURSOR_WIDTH;
1041 /*****************************************************************************
1042 mswindows_output_begin
1044 Perform any necessary initialization prior to an update.
1045 ****************************************************************************/
1047 mswindows_output_begin (struct device *d)
1051 /*****************************************************************************
1052 mswindows_output_end
1054 Perform any necessary flushing of queues when an update has completed.
1055 ****************************************************************************/
1057 mswindows_output_end (struct device *d)
1063 mswindows_flash (struct device *d)
1065 struct frame *f = device_selected_frame (d);
1068 GetClientRect (FRAME_MSWINDOWS_HANDLE (f), &rc);
1069 InvertRect (FRAME_MSWINDOWS_DC (f), &rc);
1072 InvertRect (FRAME_MSWINDOWS_DC (f), &rc);
1078 mswindows_ring_bell (struct device *d, int volume, int pitch, int duration)
1080 /* Beep does not work at all, anyways! -kkm */
1081 MessageBeep (MB_OK);
1084 /*****************************************************************************
1085 mswindows_output_display_block
1087 Given a display line, a block number for that start line, output all
1088 runes between start and end in the specified display block.
1089 Ripped off with minimal thought from the corresponding X routine.
1090 ****************************************************************************/
1092 mswindows_output_display_block (struct window *w, struct display_line *dl, int block,
1093 int start, int end, int start_pixpos, int cursor_start,
1094 int cursor_width, int cursor_height)
1096 struct frame *f = XFRAME (w->frame);
1097 Emchar_dynarr *buf = Dynarr_new (Emchar);
1100 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
1101 rune_dynarr *rba = db->runes;
1107 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
1108 MULE is not defined */
1109 XSETWINDOW (window, w);
1110 rb = Dynarr_atp (rba, start);
1114 /* Nothing to do so don't do anything. */
1119 findex = rb->findex;
1122 if (rb->type == RUNE_CHAR)
1123 charset = CHAR_CHARSET (rb->object.chr.ch);
1127 end = Dynarr_length (rba);
1132 rb = Dynarr_atp (rba, elt);
1134 if (rb->findex == findex && rb->type == RUNE_CHAR
1135 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
1136 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
1138 Dynarr_add (buf, rb->object.chr.ch);
1144 if (Dynarr_length (buf))
1146 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
1154 if (rb->type == RUNE_CHAR)
1156 findex = rb->findex;
1158 charset = CHAR_CHARSET (rb->object.chr.ch);
1160 if (rb->cursor_type == CURSOR_ON)
1162 if (rb->object.chr.ch == '\n')
1164 mswindows_output_cursor (w, dl, xpos, cursor_width,
1169 Dynarr_add (buf, rb->object.chr.ch);
1170 mswindows_output_cursor (w, dl, xpos, cursor_width,
1171 findex, rb->object.chr.ch, 0);
1178 else if (rb->object.chr.ch == '\n')
1180 /* Clear in case a cursor was formerly here. */
1181 int height = DISPLAY_LINE_HEIGHT (dl);
1183 redisplay_clear_region (window, findex, xpos, dl->ypos - dl->ascent,
1188 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
1190 if (rb->type == RUNE_BLANK)
1191 mswindows_output_blank (w, dl, rb, start_pixpos);
1194 /* #### Our flagging of when we need to redraw the
1195 modeline shadows sucks. Since RUNE_HLINE is only used
1196 by the modeline at the moment it is a good bet
1197 that if it gets redrawn then we should also
1198 redraw the shadows. This won't be true forever.
1199 We borrow the shadow_thickness_changed flag for
1201 w->shadow_thickness_changed = 1;
1202 mswindows_output_hline (w, dl, rb);
1205 if (rb->cursor_type == CURSOR_ON)
1206 mswindows_output_cursor (w, dl, xpos, cursor_width, rb->findex, 0, 0);
1211 rb = Dynarr_atp (rba, elt);
1213 findex = rb->findex;
1217 else if (rb->type == RUNE_DGLYPH)
1219 Lisp_Object instance;
1221 XSETWINDOW (window, w);
1222 instance = glyph_image_instance (rb->object.dglyph.glyph,
1223 window, ERROR_ME_NOT, 1);
1224 findex = rb->findex;
1226 if (IMAGE_INSTANCEP (instance))
1227 switch (XIMAGE_INSTANCE_TYPE (instance))
1231 /* #### This is way losing. See the comment in
1232 add_glyph_rune(). */
1233 Lisp_Object string =
1234 XIMAGE_INSTANCE_TEXT_STRING (instance);
1235 convert_bufbyte_string_into_emchar_dynarr
1236 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
1238 if (rb->cursor_type == CURSOR_ON)
1239 mswindows_output_cursor (w, dl, xpos, cursor_width,
1240 findex, Dynarr_at (buf, 0), 0);
1241 else /* #### redisplay-x passes -1 as the width: why ? */
1242 mswindows_output_string (w, dl, buf, xpos,
1243 rb->object.dglyph.xoffset,
1244 start_pixpos, rb->width, findex);
1249 case IMAGE_MONO_PIXMAP:
1250 case IMAGE_COLOR_PIXMAP:
1251 mswindows_output_pixmap (w, dl, instance, xpos,
1252 rb->object.dglyph.xoffset, start_pixpos,
1253 rb->width, findex, cursor_start,
1254 cursor_width, cursor_height, 0);
1255 if (rb->cursor_type == CURSOR_ON)
1256 mswindows_output_cursor (w, dl, xpos, cursor_width,
1263 case IMAGE_SUBWINDOW:
1265 redisplay_output_subwindow (w, dl, instance, xpos,
1266 rb->object.dglyph.xoffset, start_pixpos,
1267 rb->width, findex, cursor_start,
1268 cursor_width, cursor_height);
1269 if (rb->cursor_type == CURSOR_ON)
1270 mswindows_output_cursor (w, dl, xpos, cursor_width,
1275 /* nothing is as nothing does */
1290 if (Dynarr_length (buf))
1291 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex);
1294 && !EQ (Qzero, w->modeline_shadow_thickness)
1296 || f->windows_structure_changed
1297 || w->shadow_thickness_changed))
1298 mswindows_bevel_modeline (w, dl);
1304 /*****************************************************************************
1305 mswindows_output_vertical_divider
1307 Draw a vertical divider down the right side of the given window.
1308 ****************************************************************************/
1310 mswindows_output_vertical_divider (struct window *w, int clear_unused)
1312 struct frame *f = XFRAME (w->frame);
1314 int spacing = XINT (w->vertical_divider_spacing);
1315 int shadow = XINT (w->vertical_divider_shadow_thickness);
1316 int abs_shadow = abs (shadow);
1317 int line_width = XINT (w->vertical_divider_line_width);
1318 int div_left = WINDOW_RIGHT (w) - window_divider_width (w);
1320 /* Clear left and right spacing areas */
1323 rect.top = WINDOW_TOP (w);
1324 rect.bottom = WINDOW_BOTTOM (w);
1325 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
1326 WINDOW_FACE_CACHEL_BACKGROUND (w, DEFAULT_INDEX), Qnil);
1327 rect.right = WINDOW_RIGHT (w);
1328 rect.left = rect.right - spacing;
1329 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
1330 &rect, NULL, 0, NULL);
1331 rect.left = div_left;
1332 rect.right = div_left + spacing;
1333 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
1334 &rect, NULL, 0, NULL);
1337 /* Clear divider face */
1338 rect.top = WINDOW_TOP (w) + abs_shadow;
1339 rect.bottom = WINDOW_BOTTOM (w) - abs_shadow;
1340 rect.left = div_left + spacing + abs_shadow;
1341 rect.right = rect.left + line_width;
1342 if (rect.left < rect.right)
1345 = get_builtin_face_cache_index (w, Vvertical_divider_face);
1346 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
1347 WINDOW_FACE_CACHEL_BACKGROUND (w, div_face), Qnil);
1348 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
1349 &rect, NULL, 0, NULL);
1352 /* Draw a shadow around the divider */
1355 /* #### This will be fixed to support arbitrary thickness */
1356 InflateRect (&rect, abs_shadow, abs_shadow);
1357 DrawEdge (FRAME_MSWINDOWS_DC (f), &rect,
1358 shadow > 0 ? EDGE_RAISED : EDGE_SUNKEN, BF_RECT);
1362 /****************************************************************************
1363 mswindows_text_width
1365 Given a string and a face, return the string's length in pixels when
1366 displayed in the font associated with the face.
1367 ****************************************************************************/
1369 mswindows_text_width (struct frame *f, struct face_cachel *cachel,
1370 CONST Emchar *str, Charcount len)
1372 int width_so_far = 0;
1373 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
1374 textual_run *runs = alloca_array (textual_run, len);
1378 nruns = separate_textual_runs (text_storage, runs, str, len);
1380 for (i = 0; i < nruns; i++)
1381 width_so_far += mswindows_text_width_single_run (FRAME_MSWINDOWS_DC (f),
1384 return width_so_far;
1388 /****************************************************************************
1389 mswindows_clear_region
1391 Clear the area in the box defined by the given parameters using the
1393 ****************************************************************************/
1395 mswindows_clear_region (Lisp_Object locale, struct device* d, struct frame* f,
1396 face_index findex, int x, int y,
1397 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1398 Lisp_Object background_pixmap)
1400 RECT rect = { x, y, x+width, y+height };
1402 if (!NILP (background_pixmap))
1404 mswindows_update_dc (FRAME_MSWINDOWS_DC (f),
1405 Qnil, fcolor, bcolor, background_pixmap);
1407 mswindows_output_dibitmap_region
1408 ( f, XIMAGE_INSTANCE (background_pixmap),
1409 x, y, 0, 0, 0, 0, width, height, 0, TRUE);
1413 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, fcolor, Qnil);
1414 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
1415 &rect, NULL, 0, NULL);
1418 #ifdef HAVE_SCROLLBARS
1419 if (WINDOWP (locale))
1420 mswindows_redisplay_deadbox_maybe (XWINDOW (locale), &rect);
1424 /*****************************************************************************
1425 mswindows_clear_to_window_end
1427 Clear the area between ypos1 and ypos2. Each margin area and the
1428 text area is handled separately since they may each have their own
1430 ****************************************************************************/
1432 mswindows_clear_to_window_end (struct window *w, int ypos1, int ypos2)
1434 int height = ypos2 - ypos1;
1438 struct frame *f = XFRAME (w->frame);
1440 int bflag = (window_needs_vertical_divider (w) ? 0 : 1);
1441 layout_bounds bounds;
1443 bounds = calculate_display_line_boundaries (w, bflag);
1444 XSETWINDOW (window, w);
1446 if (window_is_leftmost (w))
1447 redisplay_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f),
1448 ypos1, FRAME_BORDER_WIDTH (f), height);
1450 if (bounds.left_in - bounds.left_out > 0)
1451 redisplay_clear_region (window,
1452 get_builtin_face_cache_index (w, Vleft_margin_face),
1453 bounds.left_out, ypos1,
1454 bounds.left_in - bounds.left_out, height);
1456 if (bounds.right_in - bounds.left_in > 0)
1457 redisplay_clear_region (window, DEFAULT_INDEX, bounds.left_in, ypos1,
1458 bounds.right_in - bounds.left_in, height);
1460 if (bounds.right_out - bounds.right_in > 0)
1461 redisplay_clear_region (window,
1462 get_builtin_face_cache_index (w, Vright_margin_face),
1463 bounds.right_in, ypos1,
1464 bounds.right_out - bounds.right_in, height);
1466 if (window_is_rightmost (w))
1467 redisplay_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f),
1468 ypos1, FRAME_BORDER_WIDTH (f), height);
1474 /* XXX Implement me! */
1476 mswindows_clear_frame (struct frame *f)
1483 /************************************************************************/
1484 /* initialization */
1485 /************************************************************************/
1488 console_type_create_redisplay_mswindows (void)
1490 /* redisplay methods */
1491 CONSOLE_HAS_METHOD (mswindows, text_width);
1492 CONSOLE_HAS_METHOD (mswindows, output_display_block);
1493 CONSOLE_HAS_METHOD (mswindows, divider_height);
1494 CONSOLE_HAS_METHOD (mswindows, eol_cursor_width);
1495 CONSOLE_HAS_METHOD (mswindows, output_vertical_divider);
1496 CONSOLE_HAS_METHOD (mswindows, clear_to_window_end);
1497 CONSOLE_HAS_METHOD (mswindows, clear_region);
1498 CONSOLE_HAS_METHOD (mswindows, clear_frame);
1499 CONSOLE_HAS_METHOD (mswindows, output_begin);
1500 CONSOLE_HAS_METHOD (mswindows, output_end);
1501 CONSOLE_HAS_METHOD (mswindows, flash);
1502 CONSOLE_HAS_METHOD (mswindows, ring_bell);