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"
52 #include "character.h"
54 #include "mule-charset.h"
58 #define MSWINDOWS_EOL_CURSOR_WIDTH 5
61 * Random forward declarations
63 static void mswindows_update_dc (HDC hdc, Lisp_Object font, Lisp_Object fg,
64 Lisp_Object bg, Lisp_Object bg_pmap);
65 static void mswindows_output_vertical_divider (struct window *w, int clear);
66 static void mswindows_redraw_exposed_windows (Lisp_Object window, int x,
67 int y, int width, int height);
68 static void mswindows_output_dibitmap (struct frame *f,
69 struct Lisp_Image_Instance *p,
71 int clip_x, int clip_y,
72 int clip_width, int clip_height,
73 int width, int height,
76 static void mswindows_output_pixmap (struct window *w, struct display_line *dl,
77 Lisp_Object image_instance, int xpos,
78 int xoffset, int start_pixpos, int width,
79 face_index findex, int cursor_start,
80 int cursor_width, int cursor_height,
83 typedef struct textual_run
91 /* Separate out the text in DYN into a series of textual runs of a
92 particular charset. Also convert the characters as necessary into
93 the format needed by XDrawImageString(), XDrawImageString16(), et
94 al. (This means converting to one or two byte format, possibly
95 tweaking the high bits, and possibly running a CCL program.) You
96 must pre-allocate the space used and pass it in. (This is done so
97 you can alloca() the space.) You need to allocate (2 * len) bytes
98 of TEXT_STORAGE and (len * sizeof (textual_run)) bytes of
99 RUN_STORAGE, where LEN is the length of the dynarr.
101 Returns the number of runs actually used. */
104 separate_textual_runs (unsigned char *text_storage,
105 textual_run *run_storage,
106 CONST Emchar *str, Charcount len)
108 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a
109 possible valid charset when
110 MULE is not defined */
114 struct ccl_program char_converter;
115 int need_ccl_conversion = 0;
118 for (i = 0; i < len; i++)
126 BREAKUP_CHAR (ch, charset, byte1, byte2);
127 dimension = XCHARSET_DIMENSION (charset);
128 graphic = XCHARSET_GRAPHIC (charset);
130 if (!EQ (charset, prev_charset))
132 run_storage[runs_so_far].ptr = text_storage;
133 run_storage[runs_so_far].charset = charset;
134 run_storage[runs_so_far].dimension = dimension;
138 run_storage[runs_so_far - 1].len =
139 text_storage - run_storage[runs_so_far - 1].ptr;
140 if (run_storage[runs_so_far - 1].dimension == 2)
141 run_storage[runs_so_far - 1].len >>= 1;
144 prev_charset = charset;
147 Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset);
148 need_ccl_conversion = !NILP (ccl_prog);
149 if (need_ccl_conversion)
150 setup_ccl_program (&char_converter, ccl_prog);
160 else if (graphic == 1)
166 if (need_ccl_conversion)
168 char_converter.reg[0] = XCHARSET_ID (charset);
169 char_converter.reg[1] = byte1;
170 char_converter.reg[2] = byte2;
171 char_converter.ic = 0; /* start at beginning each time */
172 ccl_driver (&char_converter, 0, 0, 0, 0);
173 byte1 = char_converter.reg[1];
174 byte2 = char_converter.reg[2];
177 *text_storage++ = (unsigned char) byte1;
179 *text_storage++ = (unsigned char) byte2;
184 run_storage[runs_so_far - 1].len =
185 text_storage - run_storage[runs_so_far - 1].ptr;
186 if (run_storage[runs_so_far - 1].dimension == 2)
187 run_storage[runs_so_far - 1].len >>= 1;
195 mswindows_text_width_single_run (HDC hdc, struct face_cachel *cachel,
198 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
199 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
202 if (!fi->proportional_p || !hdc)
203 return (fi->width * run->len);
206 assert(run->dimension == 1); /* #### FIXME! */
207 mswindows_update_dc (hdc, font_inst, Qnil, Qnil, Qnil);
208 GetTextExtentPoint32 (hdc, run->ptr, run->len, &size);
214 /*****************************************************************************
217 Given a number of parameters munge the DC so it has those properties.
218 ****************************************************************************/
220 mswindows_update_dc (HDC hdc, Lisp_Object font, Lisp_Object fg,
221 Lisp_Object bg, Lisp_Object bg_pmap)
224 SelectObject(hdc, FONT_INSTANCE_MSWINDOWS_HFONT (XFONT_INSTANCE (font)));
229 SetTextColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR
230 (XCOLOR_INSTANCE (fg)));
234 SetBkMode (hdc, OPAQUE);
235 SetBkColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (bg)));
239 SetBkMode (hdc, TRANSPARENT);
244 /*****************************************************************************
245 mswindows_apply_face_effects
247 Draw underline and strikeout as if this was X.
248 #### On mswindows this really should be done as part of drawing the font.
249 The line width used is chosen arbitrarily from the font height.
250 ****************************************************************************/
252 mswindows_apply_face_effects (HDC hdc, struct display_line *dl, int xpos,
253 int width, struct Lisp_Font_Instance *fi,
254 struct face_cachel *cachel,
255 struct face_cachel *color_cachel)
258 HBRUSH brush, oldbrush;
261 brush = CreateSolidBrush (COLOR_INSTANCE_MSWINDOWS_COLOR (
262 XCOLOR_INSTANCE (color_cachel->foreground)));
265 yclip = dl->ypos + dl->descent - dl->clip;
267 rect.right = xpos + width;
268 oldbrush = SelectObject (hdc, brush);
270 if (cachel->underline)
272 rect.top = dl->ypos + dl->descent/2;
273 rect.bottom = rect.top + (fi->height >= 0x20 ? 2 : 1);
274 if (rect.bottom <= yclip)
275 FillRect (hdc, &rect, brush);
277 if (cachel->strikethru)
279 rect.top = dl->ypos + dl->descent - (dl->ascent + dl->descent)/2;
280 rect.bottom = rect.top + (fi->height >= 0x20 ? 2 : 1);
281 if (rect.bottom <= yclip)
282 FillRect (hdc, &rect, brush);
285 SelectObject (hdc, oldbrush);
286 DeleteObject (brush);
291 /*****************************************************************************
292 mswindows_output_hline
294 Output a horizontal line in the foreground of its face.
295 ****************************************************************************/
297 mswindows_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
298 { /* XXX Implement me */
302 /*****************************************************************************
303 mswindows_output_blank
305 Output a blank by clearing the area it covers in the background color
307 ****************************************************************************/
309 mswindows_output_blank (struct window *w, struct display_line *dl, struct rune *rb, int start_pixpos)
311 struct frame *f = XFRAME (w->frame);
312 RECT rect = { rb->xpos, dl->ypos-dl->ascent,
313 rb->xpos+rb->width, dl->ypos+dl->descent-dl->clip };
314 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, rb->findex);
316 Lisp_Object bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
318 if (!IMAGE_INSTANCEP (bg_pmap)
319 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
324 /* blank the background in the appropriate color */
325 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, cachel->foreground,
326 cachel->background, Qnil);
328 mswindows_output_pixmap (w, dl, bg_pmap,
329 rb->xpos, 0 /*rb->object.dglyph.xoffset*/,
330 start_pixpos, rb->width, rb->findex,
335 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
336 cachel->background, Qnil);
338 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
339 &rect, NULL, 0, NULL);
344 /*****************************************************************************
345 mswindows_output_cursor
347 Draw a normal or end-of-line cursor. The end-of-line cursor is
348 narrower than the normal cursor.
349 ****************************************************************************/
351 mswindows_output_cursor (struct window *w, struct display_line *dl, int xpos,
352 int width, face_index findex, Emchar ch, int image_p)
354 struct frame *f = XFRAME (w->frame);
355 struct device *d = XDEVICE (f->device);
356 struct face_cachel *cachel=0;
357 Lisp_Object font = Qnil;
358 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
359 HDC hdc = FRAME_MSWINDOWS_DC (f);
360 unsigned int face_index=0;
364 dl->ypos - dl->ascent,
366 dl->ypos + dl->descent - dl->clip};
367 Lisp_Object bar = symbol_value_in_buffer (Qbar_cursor,
369 int bar_p = image_p || !NILP (bar);
370 int cursor_p = !NILP (w->text_cursor_visible_p);
371 int real_char_p = ch != 0;
375 /* Use the font from the underlying character */
376 cachel = WINDOW_FACE_CACHEL (w, findex);
378 /* #### MULE: Need to know the charset! */
379 font = FACE_CACHEL_FONT (cachel, Vcharset_ascii);
382 if ((focus || bar_p) && real_char_p)
384 p_char = (char*) &ch;
390 struct face_cachel *color_cachel;
392 /* Use cursor fg/bg for block cursor, or character fg/bg for the bar
393 or when we need to erase the cursor. Output nothing at eol if bar
395 face_index = get_builtin_face_cache_index (w, Vtext_cursor_face);
396 color_cachel = WINDOW_FACE_CACHEL (w, ((!cursor_p || bar_p) ?
397 findex : face_index));
398 mswindows_update_dc (hdc, font, color_cachel->foreground,
399 color_cachel->background, Qnil);
400 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE|ETO_CLIPPED, &rect, p_char, n_char, NULL);
401 if (real_char_p && (cachel->underline || cachel->strikethru))
402 mswindows_apply_face_effects (hdc, dl, xpos, width,
403 XFONT_INSTANCE (font),
404 cachel, color_cachel);
412 rect.right = rect.left + (EQ (bar, Qt) ? 1 : min (2, width));
413 face_index = get_builtin_face_cache_index (w, Vtext_cursor_face);
414 cachel = WINDOW_FACE_CACHEL (w, face_index);
415 mswindows_update_dc (hdc, Qnil, Qnil, cachel->background, Qnil);
416 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE, &rect, NULL, 0, NULL);
420 /* Now have real character drawn in its own color. We deflate
421 the rectangle so character cell will be bounded by the
422 previously drawn cursor shape */
423 InflateRect (&rect, -1, -1);
427 p_char = (char*) &ch;
431 face_index = get_builtin_face_cache_index (w, Vdefault_face);
432 cachel = WINDOW_FACE_CACHEL (w, (real_char_p ? findex : face_index));
433 mswindows_update_dc (hdc, Qnil, cachel->foreground,
434 cachel->background, Qnil);
435 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE | ETO_CLIPPED,
436 &rect, p_char, n_char, NULL);
437 if (cachel->underline || cachel->strikethru)
438 mswindows_apply_face_effects (hdc, dl, xpos+1, width-2,
439 XFONT_INSTANCE (font),
445 /*****************************************************************************
446 mswindows_output_string
448 Given a string and a starting position, output that string in the
450 Correctly handles multiple charsets in the string.
452 The meaning of the parameters is something like this:
454 W Window that the text is to be displayed in.
455 DL Display line that this text is on. The values in the
456 structure are used to determine the vertical position and
457 clipping range of the text.
458 BUF Dynamic array of Emchars specifying what is actually to be
460 XPOS X position in pixels where the text should start being drawn.
461 XOFFSET Number of pixels to be chopped off the left side of the
462 text. The effect is as if the text were shifted to the
463 left this many pixels and clipped at XPOS.
464 CLIP_START Clip everything left of this X position.
465 WIDTH Clip everything right of XPOS + WIDTH.
466 FINDEX Index for the face cache element describing how to display
468 ****************************************************************************/
470 mswindows_output_string (struct window *w, struct display_line *dl,
471 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
472 int width, face_index findex)
474 struct frame *f = XFRAME (w->frame);
475 /* struct device *d = XDEVICE (f->device);*/
477 HDC hdc = FRAME_MSWINDOWS_DC (f);
480 int len = Dynarr_length (buf);
481 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
482 textual_run *runs = alloca_array (textual_run, len);
486 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
488 XSETWINDOW (window, w);
490 #if 0 /* #### FIXME? */
491 /* We can't work out the width before we've set the font in the DC */
493 width = mswindows_text_width (cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
498 /* Regularize the variables passed in. */
499 if (clip_start < xpos)
501 clip_end = xpos + width;
502 if (clip_start >= clip_end)
503 /* It's all clipped out. */
508 /* sort out the destination rectangle */
509 height = DISPLAY_LINE_HEIGHT (dl);
510 rect.left = clip_start;
511 rect.top = dl->ypos - dl->ascent;
512 rect.right = clip_end;
513 rect.bottom = height + dl->ypos - dl->ascent;
515 /* output the background pixmap if there is one */
516 bg_pmap = cachel->background_pixmap;
517 if (!IMAGE_INSTANCEP (bg_pmap)
518 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
523 /* blank the background in the appropriate color */
524 mswindows_update_dc (hdc, Qnil, cachel->foreground,
525 cachel->background, Qnil);
527 mswindows_output_pixmap (w, dl, bg_pmap,
529 clip_start, width, findex,
531 /* output pixmap calls this so we have to recall to get correct
533 cachel = WINDOW_FACE_CACHEL (w, findex);
536 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
537 Dynarr_length (buf));
539 for (i = 0; i < nruns; i++)
541 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
542 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
545 if (EQ (font, Vthe_null_font_instance))
548 mswindows_update_dc (hdc, font, cachel->foreground,
549 NILP(bg_pmap) ? cachel->background : Qnil, Qnil);
551 this_width = mswindows_text_width_single_run (hdc, cachel, runs + i);
553 /* cope with fonts taller than lines */
554 if ((int) fi->height < (int) (height + dl->clip))
556 int clear_start = max (xpos, clip_start);
557 int clear_end = min (xpos + this_width, clip_end);
560 redisplay_clear_region (window, findex, clear_start,
561 dl->ypos - dl->ascent,
562 clear_end - clear_start,
564 /* output pixmap calls this so we have to recall to get correct
566 cachel = WINDOW_FACE_CACHEL (w, findex);
570 assert (runs[i].dimension == 1); /* #### FIXME: Broken when Mule? */
571 ExtTextOut (hdc, xpos, dl->ypos,
572 NILP(bg_pmap) ? ETO_CLIPPED | ETO_OPAQUE : ETO_CLIPPED,
573 &rect, (char *) runs[i].ptr, runs[i].len, NULL);
575 /* #### X does underline/strikethrough here so we do the same.
576 On mswindows, underline/strikethrough really belongs to the font */
577 if (cachel->underline || cachel->strikethru)
578 mswindows_apply_face_effects (hdc, dl, xpos, this_width, fi,
585 mswindows_output_dibitmap (struct frame *f, struct Lisp_Image_Instance *p,
587 int clip_x, int clip_y,
588 int clip_width, int clip_height,
589 int width, int height, int pixmap_offset,
592 HDC hdc = FRAME_MSWINDOWS_DC (f);
594 COLORREF bgcolor = GetBkColor (hdc);
595 int need_clipping = (clip_x || clip_y);
599 /* do we need to offset the pixmap vertically? this is necessary
600 for background pixmaps. */
603 yoffset = y % IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
604 xoffset = x % IMAGE_INSTANCE_PIXMAP_WIDTH (p);
605 /* the width is handled by mswindows_output_pixmap_region */
612 /* first blt the mask */
613 if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
616 col.rgbBlue = GetBValue (bgcolor);
617 col.rgbRed = GetRValue (bgcolor);
618 col.rgbGreen = GetGValue (bgcolor);
621 old = SelectObject (FRAME_MSWINDOWS_CDC (f),
622 IMAGE_INSTANCE_MSWINDOWS_MASK (p));
624 SetDIBColorTable (FRAME_MSWINDOWS_CDC (f), 1, 1, &col);
629 FRAME_MSWINDOWS_CDC (f),
633 SelectObject (FRAME_MSWINDOWS_CDC (f), old);
636 /* now blt the bitmap itself. */
637 old = SelectObject (FRAME_MSWINDOWS_CDC (f),
638 IMAGE_INSTANCE_MSWINDOWS_BITMAP (p));
643 FRAME_MSWINDOWS_CDC (f),
645 IMAGE_INSTANCE_MSWINDOWS_MASK (p) ? SRCINVERT : SRCCOPY);
647 SelectObject (FRAME_MSWINDOWS_CDC (f),old);
655 * X gc's have this nice property that setting the bg pixmap will
656 * output it offset relative to the window. Windows doesn't have this
657 * feature so we have to emulate this by outputting multiple pixmaps
660 mswindows_output_dibitmap_region (struct frame *f,
661 struct Lisp_Image_Instance *p,
663 int clip_x, int clip_y,
664 int clip_width, int clip_height,
665 int width, int height, int pixmap_offset,
668 int pwidth = min (width, IMAGE_INSTANCE_PIXMAP_WIDTH (p));
669 int pheight = min (height, IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
670 int pxoffset = 0, pyoffset = 0;
672 /* when doing a bg pixmap do a partial pixmap first so that we
673 blt whole pixmaps thereafter */
677 pheight = min (pheight, IMAGE_INSTANCE_PIXMAP_HEIGHT (p) -
678 y % IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
685 pwidth = min (min (width, IMAGE_INSTANCE_PIXMAP_WIDTH (p)),
686 IMAGE_INSTANCE_PIXMAP_WIDTH (p) -
687 x % IMAGE_INSTANCE_PIXMAP_WIDTH (p));
692 mswindows_output_dibitmap (f, p,
693 x + pxoffset, y + pyoffset,
695 clip_width, clip_height,
696 pwidth, pheight, pixmap_offset,
699 pwidth = min ((width-pxoffset),
700 IMAGE_INSTANCE_PIXMAP_WIDTH (p));
703 pheight = min ((height-pyoffset),
704 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
709 mswindows_output_pixmap (struct window *w, struct display_line *dl,
710 Lisp_Object image_instance, int xpos, int xoffset,
711 int start_pixpos, int width, face_index findex,
712 int cursor_start, int cursor_width, int cursor_height,
715 struct frame *f = XFRAME (w->frame);
716 HDC hdc = FRAME_MSWINDOWS_DC (f);
718 struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
721 int lheight = DISPLAY_LINE_HEIGHT (dl);
722 int pheight = ((int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > lheight ? lheight :
723 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
724 int clip_x, clip_y, clip_width, clip_height;
726 /* The pixmap_offset is used to center the pixmap on lines which are
727 shorter than it is. This results in odd effects when scrolling
728 pixmaps off of the bottom. Let's try not using it. */
730 int pixmap_offset = (int) (IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - lheight) / 2;
732 int pixmap_offset = 0;
735 XSETWINDOW (window, w);
737 if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
739 if (start_pixpos > xpos && start_pixpos > xpos + width)
744 if (start_pixpos > xpos)
746 clip_x += (start_pixpos - xpos);
747 clip_width -= (start_pixpos - xpos);
756 /* Place markers for possible future functionality (clipping the top
757 half instead of the bottom half; think pixel scrolling). */
759 clip_height = pheight;
761 /* Clear the area the pixmap is going into. The pixmap itself will
762 always take care of the full width. We don't want to clear where
763 it is going to go in order to avoid flicker. So, all we have to
764 take care of is any area above or below the pixmap. */
765 /* #### We take a shortcut for now. We know that since we have
766 pixmap_offset hardwired to 0 that the pixmap is against the top
767 edge so all we have to worry about is below it. */
768 /* #### Unless the pixmap has a mask in which case we have to clear
769 the whole damn thing since we can't yet clear just the area not
770 included in the mask. */
771 if (((int) (dl->ypos - dl->ascent + pheight) <
772 (int) (dl->ypos + dl->descent - dl->clip))
773 || IMAGE_INSTANCE_MSWINDOWS_MASK (p))
775 int clear_x, clear_y, clear_width, clear_height;
777 if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
779 clear_y = dl->ypos - dl->ascent;
780 clear_height = lheight;
784 clear_y = dl->ypos - dl->ascent + pheight;
785 clear_height = lheight - pheight;
788 if (start_pixpos >= 0 && start_pixpos > xpos)
790 clear_x = start_pixpos;
791 clear_width = xpos + width - start_pixpos;
799 if (!offset_bitmap) /* i.e. not a bg pixmap */
800 redisplay_clear_region (window, findex, clear_x, clear_y,
801 clear_width, clear_height);
804 /* Output the pixmap. Have to do this as many times as is required
805 to fill the given area */
806 mswindows_update_dc (hdc, Qnil,
807 WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
808 WINDOW_FACE_CACHEL_BACKGROUND (w, findex), Qnil);
810 mswindows_output_dibitmap_region (f, p, xpos - xoffset,
811 dl->ypos - dl->ascent,
812 clip_x, clip_y, clip_width, clip_height,
813 width + xoffset, pheight, pixmap_offset,
817 #ifdef HAVE_SCROLLBARS
819 * This function paints window's deadbox, a rectangle between window
820 * borders and two short edges of both scrollbars.
822 * Function checks whether deadbox intersects with the rectangle pointed
823 * to by PRC, and paints only the intersection
826 mswindows_redisplay_deadbox_maybe (struct window *w, CONST RECT* prc)
828 int sbh = window_scrollbar_height (w);
829 int sbw = window_scrollbar_width (w);
830 RECT rect_dead, rect_paint;
831 if (sbh == 0 || sbw == 0)
834 if (!NILP (w->scrollbar_on_left_p))
835 rect_dead.left = WINDOW_LEFT (w);
837 rect_dead.left = WINDOW_TEXT_RIGHT (w);
838 rect_dead.right = rect_dead.left + sbw;
840 if (!NILP (w->scrollbar_on_top_p))
841 rect_dead.top = WINDOW_TOP (w);
843 rect_dead.top = WINDOW_TEXT_BOTTOM (w);
844 rect_dead.bottom = rect_dead.top + sbh;
846 if (IntersectRect (&rect_paint, &rect_dead, prc))
848 struct frame *f = XFRAME (WINDOW_FRAME (w));
849 FillRect (FRAME_MSWINDOWS_DC (f), &rect_paint,
850 (HBRUSH) (COLOR_BTNFACE+1));
854 #endif /* HAVE_SCROLLBARS */
856 /*****************************************************************************
857 mswindows_redraw_exposed_window
859 Given a bounding box for an area that needs to be redrawn, determine
860 what parts of what lines are contained within and re-output their
862 Copied from redisplay-x.c
863 ****************************************************************************/
865 mswindows_redraw_exposed_window (struct window *w, int x, int y, int width,
868 struct frame *f = XFRAME (w->frame);
870 int orig_windows_structure_changed;
871 RECT rect_window = { WINDOW_LEFT (w), WINDOW_TOP (w),
872 WINDOW_RIGHT (w), WINDOW_BOTTOM (w) };
873 RECT rect_expose = { x, y, x + width, y + height };
876 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
878 if (!NILP (w->vchild))
880 mswindows_redraw_exposed_windows (w->vchild, x, y, width, height);
883 else if (!NILP (w->hchild))
885 mswindows_redraw_exposed_windows (w->hchild, x, y, width, height);
889 /* If the window doesn't intersect the exposed region, we're done here. */
890 if (!IntersectRect (&rect_draw, &rect_window, &rect_expose))
893 /* We do this to make sure that the 3D modelines get redrawn if
894 they are in the exposed region. */
895 orig_windows_structure_changed = f->windows_structure_changed;
896 f->windows_structure_changed = 1;
898 if (window_needs_vertical_divider (w))
900 mswindows_output_vertical_divider (w, 0);
903 for (line = 0; line < Dynarr_length (cdla); line++)
905 struct display_line *cdl = Dynarr_atp (cdla, line);
906 int top_y = cdl->ypos - cdl->ascent;
907 int bottom_y = cdl->ypos + cdl->descent;
909 if (bottom_y >= rect_draw.top)
911 if (top_y > rect_draw.bottom)
920 output_display_line (w, 0, cdla, line,
921 rect_draw.left, rect_draw.right);
926 f->windows_structure_changed = orig_windows_structure_changed;
928 /* If there have never been any face cache_elements created, then this
929 expose event doesn't actually have anything to do. */
930 if (Dynarr_largest (w->face_cachels))
931 redisplay_clear_bottom_of_window (w, cdla, rect_draw.top, rect_draw.bottom);
933 #ifdef HAVE_SCROLLBARS
934 mswindows_redisplay_deadbox_maybe (w, &rect_expose);
938 /*****************************************************************************
939 mswindows_redraw_exposed_windows
941 For each window beneath the given window in the window hierarchy,
942 ensure that it is redrawn if necessary after an Expose event.
943 ****************************************************************************/
945 mswindows_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
948 for (; !NILP (window); window = XWINDOW (window)->next)
949 mswindows_redraw_exposed_window (XWINDOW (window), x, y, width, height);
952 /*****************************************************************************
953 mswindows_redraw_exposed_area
955 For each window on the given frame, ensure that any area in the
956 Exposed area is redrawn.
957 ****************************************************************************/
959 mswindows_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
961 /* If any window on the frame has had its face cache reset then the
962 redisplay structures are effectively invalid. If we attempt to
963 use them we'll blow up. We mark the frame as changed to ensure
964 that redisplay will do a full update. This probably isn't
965 necessary but it can't hurt. */
967 /* #### We would rather put these off as well but there is currently
968 no combination of flags which will force an unchanged toolbar to
970 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
973 if (!f->window_face_cache_reset)
975 mswindows_redraw_exposed_windows (f->root_window, x, y, width, height);
979 MARK_FRAME_CHANGED (f);
983 /*****************************************************************************
984 mswindows_bevel_modeline
986 Draw a 3d border around the modeline on window W.
987 ****************************************************************************/
989 mswindows_bevel_modeline (struct window *w, struct display_line *dl)
991 struct frame *f = XFRAME (w->frame);
993 int shadow_width = MODELINE_SHADOW_THICKNESS (w);
994 RECT rect = { WINDOW_MODELINE_LEFT (w),
995 dl->ypos - dl->ascent - shadow_width,
996 WINDOW_MODELINE_RIGHT (w),
997 dl->ypos + dl->descent + shadow_width};
1000 color = WINDOW_FACE_CACHEL_BACKGROUND (w, MODELINE_INDEX);
1001 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, color, Qnil);
1003 if (XINT (w->modeline_shadow_thickness) < 0)
1004 shadow_width = -shadow_width;
1006 if (shadow_width < -1)
1008 else if (shadow_width < 0)
1009 edge = BDR_SUNKENINNER;
1010 else if (shadow_width == 1)
1011 edge = BDR_RAISEDINNER;
1015 DrawEdge (FRAME_MSWINDOWS_DC (f), &rect, edge, BF_RECT);
1019 /*****************************************************************************
1021 *****************************************************************************/
1023 /*****************************************************************************
1024 mswindows_divider_height
1026 Return the height of the horizontal divider.
1027 ****************************************************************************/
1029 mswindows_divider_height (void)
1031 return 1; /* XXX Copied from redisplay-X.c. What is this? */
1034 /*****************************************************************************
1035 mswindows_eol_cursor_width
1037 Return the width of the end-of-line cursor.
1038 ****************************************************************************/
1040 mswindows_eol_cursor_width (void)
1042 return MSWINDOWS_EOL_CURSOR_WIDTH;
1045 /*****************************************************************************
1046 mswindows_output_begin
1048 Perform any necessary initialization prior to an update.
1049 ****************************************************************************/
1051 mswindows_output_begin (struct device *d)
1055 /*****************************************************************************
1056 mswindows_output_end
1058 Perform any necessary flushing of queues when an update has completed.
1059 ****************************************************************************/
1061 mswindows_output_end (struct device *d)
1067 mswindows_flash (struct device *d)
1069 struct frame *f = device_selected_frame (d);
1072 GetClientRect (FRAME_MSWINDOWS_HANDLE (f), &rc);
1073 InvertRect (FRAME_MSWINDOWS_DC (f), &rc);
1076 InvertRect (FRAME_MSWINDOWS_DC (f), &rc);
1082 mswindows_ring_bell (struct device *d, int volume, int pitch, int duration)
1084 /* Beep does not work at all, anyways! -kkm */
1085 MessageBeep (MB_OK);
1088 /*****************************************************************************
1089 mswindows_output_display_block
1091 Given a display line, a block number for that start line, output all
1092 runes between start and end in the specified display block.
1093 Ripped off with minimal thought from the corresponding X routine.
1094 ****************************************************************************/
1096 mswindows_output_display_block (struct window *w, struct display_line *dl, int block,
1097 int start, int end, int start_pixpos, int cursor_start,
1098 int cursor_width, int cursor_height)
1100 struct frame *f = XFRAME (w->frame);
1101 Emchar_dynarr *buf = Dynarr_new (Emchar);
1104 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
1105 rune_dynarr *rba = db->runes;
1111 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
1112 MULE is not defined */
1113 XSETWINDOW (window, w);
1114 rb = Dynarr_atp (rba, start);
1118 /* Nothing to do so don't do anything. */
1123 findex = rb->findex;
1126 if (rb->type == RUNE_CHAR)
1127 charset = CHAR_CHARSET (rb->object.chr.ch);
1131 end = Dynarr_length (rba);
1136 rb = Dynarr_atp (rba, elt);
1138 if (rb->findex == findex && rb->type == RUNE_CHAR
1139 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
1140 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
1142 Dynarr_add (buf, rb->object.chr.ch);
1148 if (Dynarr_length (buf))
1150 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
1158 if (rb->type == RUNE_CHAR)
1160 findex = rb->findex;
1162 charset = CHAR_CHARSET (rb->object.chr.ch);
1164 if (rb->cursor_type == CURSOR_ON)
1166 if (rb->object.chr.ch == '\n')
1168 mswindows_output_cursor (w, dl, xpos, cursor_width,
1173 Dynarr_add (buf, rb->object.chr.ch);
1174 mswindows_output_cursor (w, dl, xpos, cursor_width,
1175 findex, rb->object.chr.ch, 0);
1182 else if (rb->object.chr.ch == '\n')
1184 /* Clear in case a cursor was formerly here. */
1185 int height = DISPLAY_LINE_HEIGHT (dl);
1187 redisplay_clear_region (window, findex, xpos, dl->ypos - dl->ascent,
1192 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
1194 if (rb->type == RUNE_BLANK)
1195 mswindows_output_blank (w, dl, rb, start_pixpos);
1198 /* #### Our flagging of when we need to redraw the
1199 modeline shadows sucks. Since RUNE_HLINE is only used
1200 by the modeline at the moment it is a good bet
1201 that if it gets redrawn then we should also
1202 redraw the shadows. This won't be true forever.
1203 We borrow the shadow_thickness_changed flag for
1205 w->shadow_thickness_changed = 1;
1206 mswindows_output_hline (w, dl, rb);
1209 if (rb->cursor_type == CURSOR_ON)
1210 mswindows_output_cursor (w, dl, xpos, cursor_width, rb->findex, 0, 0);
1215 rb = Dynarr_atp (rba, elt);
1217 findex = rb->findex;
1221 else if (rb->type == RUNE_DGLYPH)
1223 Lisp_Object instance;
1225 XSETWINDOW (window, w);
1226 instance = glyph_image_instance (rb->object.dglyph.glyph,
1227 window, ERROR_ME_NOT, 1);
1228 findex = rb->findex;
1230 if (IMAGE_INSTANCEP (instance))
1231 switch (XIMAGE_INSTANCE_TYPE (instance))
1235 /* #### This is way losing. See the comment in
1236 add_glyph_rune(). */
1237 Lisp_Object string =
1238 XIMAGE_INSTANCE_TEXT_STRING (instance);
1239 convert_bufbyte_string_into_emchar_dynarr
1240 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
1242 if (rb->cursor_type == CURSOR_ON)
1243 mswindows_output_cursor (w, dl, xpos, cursor_width,
1244 findex, Dynarr_at (buf, 0), 0);
1245 else /* #### redisplay-x passes -1 as the width: why ? */
1246 mswindows_output_string (w, dl, buf, xpos,
1247 rb->object.dglyph.xoffset,
1248 start_pixpos, rb->width, findex);
1253 case IMAGE_MONO_PIXMAP:
1254 case IMAGE_COLOR_PIXMAP:
1255 mswindows_output_pixmap (w, dl, instance, xpos,
1256 rb->object.dglyph.xoffset, start_pixpos,
1257 rb->width, findex, cursor_start,
1258 cursor_width, cursor_height, 0);
1259 if (rb->cursor_type == CURSOR_ON)
1260 mswindows_output_cursor (w, dl, xpos, cursor_width,
1267 case IMAGE_SUBWINDOW:
1269 redisplay_output_subwindow (w, dl, instance, xpos,
1270 rb->object.dglyph.xoffset, start_pixpos,
1271 rb->width, findex, cursor_start,
1272 cursor_width, cursor_height);
1273 if (rb->cursor_type == CURSOR_ON)
1274 mswindows_output_cursor (w, dl, xpos, cursor_width,
1279 /* nothing is as nothing does */
1294 if (Dynarr_length (buf))
1295 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex);
1298 && !EQ (Qzero, w->modeline_shadow_thickness)
1300 || f->windows_structure_changed
1301 || w->shadow_thickness_changed))
1302 mswindows_bevel_modeline (w, dl);
1308 /*****************************************************************************
1309 mswindows_output_vertical_divider
1311 Draw a vertical divider down the right side of the given window.
1312 ****************************************************************************/
1314 mswindows_output_vertical_divider (struct window *w, int clear_unused)
1316 struct frame *f = XFRAME (w->frame);
1318 int spacing = XINT (w->vertical_divider_spacing);
1319 int shadow = XINT (w->vertical_divider_shadow_thickness);
1320 int abs_shadow = abs (shadow);
1321 int line_width = XINT (w->vertical_divider_line_width);
1322 int div_left = WINDOW_RIGHT (w) - window_divider_width (w);
1324 /* Clear left and right spacing areas */
1327 rect.top = WINDOW_TOP (w);
1328 rect.bottom = WINDOW_BOTTOM (w);
1329 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
1330 WINDOW_FACE_CACHEL_BACKGROUND (w, DEFAULT_INDEX), Qnil);
1331 rect.right = WINDOW_RIGHT (w);
1332 rect.left = rect.right - spacing;
1333 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
1334 &rect, NULL, 0, NULL);
1335 rect.left = div_left;
1336 rect.right = div_left + spacing;
1337 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
1338 &rect, NULL, 0, NULL);
1341 /* Clear divider face */
1342 rect.top = WINDOW_TOP (w) + abs_shadow;
1343 rect.bottom = WINDOW_BOTTOM (w) - abs_shadow;
1344 rect.left = div_left + spacing + abs_shadow;
1345 rect.right = rect.left + line_width;
1346 if (rect.left < rect.right)
1349 = get_builtin_face_cache_index (w, Vvertical_divider_face);
1350 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
1351 WINDOW_FACE_CACHEL_BACKGROUND (w, div_face), Qnil);
1352 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
1353 &rect, NULL, 0, NULL);
1356 /* Draw a shadow around the divider */
1359 /* #### This will be fixed to support arbitrary thickness */
1360 InflateRect (&rect, abs_shadow, abs_shadow);
1361 DrawEdge (FRAME_MSWINDOWS_DC (f), &rect,
1362 shadow > 0 ? EDGE_RAISED : EDGE_SUNKEN, BF_RECT);
1366 /****************************************************************************
1367 mswindows_text_width
1369 Given a string and a face, return the string's length in pixels when
1370 displayed in the font associated with the face.
1371 ****************************************************************************/
1373 mswindows_text_width (struct frame *f, struct face_cachel *cachel,
1374 CONST Emchar *str, Charcount len)
1376 int width_so_far = 0;
1377 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
1378 textual_run *runs = alloca_array (textual_run, len);
1382 nruns = separate_textual_runs (text_storage, runs, str, len);
1384 for (i = 0; i < nruns; i++)
1385 width_so_far += mswindows_text_width_single_run (FRAME_MSWINDOWS_DC (f),
1388 return width_so_far;
1392 /****************************************************************************
1393 mswindows_clear_region
1395 Clear the area in the box defined by the given parameters using the
1397 ****************************************************************************/
1399 mswindows_clear_region (Lisp_Object locale, struct device* d, struct frame* f,
1400 face_index findex, int x, int y,
1401 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1402 Lisp_Object background_pixmap)
1404 RECT rect = { x, y, x+width, y+height };
1406 if (!NILP (background_pixmap))
1408 mswindows_update_dc (FRAME_MSWINDOWS_DC (f),
1409 Qnil, fcolor, bcolor, background_pixmap);
1411 mswindows_output_dibitmap_region
1412 ( f, XIMAGE_INSTANCE (background_pixmap),
1413 x, y, 0, 0, 0, 0, width, height, 0, TRUE);
1417 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, fcolor, Qnil);
1418 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
1419 &rect, NULL, 0, NULL);
1422 #ifdef HAVE_SCROLLBARS
1423 if (WINDOWP (locale))
1424 mswindows_redisplay_deadbox_maybe (XWINDOW (locale), &rect);
1428 /*****************************************************************************
1429 mswindows_clear_to_window_end
1431 Clear the area between ypos1 and ypos2. Each margin area and the
1432 text area is handled separately since they may each have their own
1434 ****************************************************************************/
1436 mswindows_clear_to_window_end (struct window *w, int ypos1, int ypos2)
1438 int height = ypos2 - ypos1;
1442 struct frame *f = XFRAME (w->frame);
1444 int bflag = (window_needs_vertical_divider (w) ? 0 : 1);
1445 layout_bounds bounds;
1447 bounds = calculate_display_line_boundaries (w, bflag);
1448 XSETWINDOW (window, w);
1450 if (window_is_leftmost (w))
1451 redisplay_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f),
1452 ypos1, FRAME_BORDER_WIDTH (f), height);
1454 if (bounds.left_in - bounds.left_out > 0)
1455 redisplay_clear_region (window,
1456 get_builtin_face_cache_index (w, Vleft_margin_face),
1457 bounds.left_out, ypos1,
1458 bounds.left_in - bounds.left_out, height);
1460 if (bounds.right_in - bounds.left_in > 0)
1461 redisplay_clear_region (window, DEFAULT_INDEX, bounds.left_in, ypos1,
1462 bounds.right_in - bounds.left_in, height);
1464 if (bounds.right_out - bounds.right_in > 0)
1465 redisplay_clear_region (window,
1466 get_builtin_face_cache_index (w, Vright_margin_face),
1467 bounds.right_in, ypos1,
1468 bounds.right_out - bounds.right_in, height);
1470 if (window_is_rightmost (w))
1471 redisplay_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f),
1472 ypos1, FRAME_BORDER_WIDTH (f), height);
1478 /* XXX Implement me! */
1480 mswindows_clear_frame (struct frame *f)
1487 /************************************************************************/
1488 /* initialization */
1489 /************************************************************************/
1492 console_type_create_redisplay_mswindows (void)
1494 /* redisplay methods */
1495 CONSOLE_HAS_METHOD (mswindows, text_width);
1496 CONSOLE_HAS_METHOD (mswindows, output_display_block);
1497 CONSOLE_HAS_METHOD (mswindows, divider_height);
1498 CONSOLE_HAS_METHOD (mswindows, eol_cursor_width);
1499 CONSOLE_HAS_METHOD (mswindows, output_vertical_divider);
1500 CONSOLE_HAS_METHOD (mswindows, clear_to_window_end);
1501 CONSOLE_HAS_METHOD (mswindows, clear_region);
1502 CONSOLE_HAS_METHOD (mswindows, clear_frame);
1503 CONSOLE_HAS_METHOD (mswindows, output_begin);
1504 CONSOLE_HAS_METHOD (mswindows, output_end);
1505 CONSOLE_HAS_METHOD (mswindows, flash);
1506 CONSOLE_HAS_METHOD (mswindows, ring_bell);