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"
45 #include "redisplay.h"
52 #include "character.h"
55 #define MSWINDOWS_EOL_CURSOR_WIDTH 5
58 * Random forward declarations
60 static void mswindows_update_dc (HDC hdc, Lisp_Object font, Lisp_Object fg,
61 Lisp_Object bg, Lisp_Object bg_pmap);
62 static void mswindows_output_vertical_divider (struct window *w, int clear);
63 static void mswindows_redraw_exposed_windows (Lisp_Object window, int x,
64 int y, int width, int height);
65 static void mswindows_output_dibitmap (struct frame *f,
66 struct Lisp_Image_Instance *p,
68 int clip_x, int clip_y,
69 int clip_width, int clip_height,
70 int width, int height,
73 static void mswindows_output_pixmap (struct window *w, struct display_line *dl,
74 Lisp_Object image_instance, int xpos,
75 int xoffset, int start_pixpos, int width,
76 face_index findex, int cursor_start,
77 int cursor_width, int cursor_height,
79 void bevel_modeline (struct window *w, struct display_line *dl);
81 typedef struct textual_run
89 /* Separate out the text in DYN into a series of textual runs of a
90 particular charset. Also convert the characters as necessary into
91 the format needed by XDrawImageString(), XDrawImageString16(), et
92 al. (This means converting to one or two byte format, possibly
93 tweaking the high bits, and possibly running a CCL program.) You
94 must pre-allocate the space used and pass it in. (This is done so
95 you can alloca() the space.) You need to allocate (2 * len) bytes
96 of TEXT_STORAGE and (len * sizeof (textual_run)) bytes of
97 RUN_STORAGE, where LEN is the length of the dynarr.
99 Returns the number of runs actually used. */
102 separate_textual_runs (unsigned char *text_storage,
103 textual_run *run_storage,
104 CONST Emchar *str, Charcount len)
106 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a
107 possible valid charset when
108 MULE is not defined */
112 struct ccl_program char_converter;
113 int need_ccl_conversion = 0;
116 for (i = 0; i < len; i++)
124 BREAKUP_CHAR (ch, charset, byte1, byte2);
125 dimension = XCHARSET_DIMENSION (charset);
126 graphic = XCHARSET_GRAPHIC (charset);
128 if (!EQ (charset, prev_charset))
130 run_storage[runs_so_far].ptr = text_storage;
131 run_storage[runs_so_far].charset = charset;
132 run_storage[runs_so_far].dimension = dimension;
136 run_storage[runs_so_far - 1].len =
137 text_storage - run_storage[runs_so_far - 1].ptr;
138 if (run_storage[runs_so_far - 1].dimension == 2)
139 run_storage[runs_so_far - 1].len >>= 1;
142 prev_charset = charset;
145 Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset);
146 need_ccl_conversion = !NILP (ccl_prog);
147 if (need_ccl_conversion)
148 setup_ccl_program (&char_converter, ccl_prog);
158 else if (graphic == 1)
164 if (need_ccl_conversion)
166 char_converter.reg[0] = XCHARSET_ID (charset);
167 char_converter.reg[1] = byte1;
168 char_converter.reg[2] = byte2;
169 char_converter.ic = 0; /* start at beginning each time */
170 ccl_driver (&char_converter, 0, 0, 0, 0, CCL_MODE_ENCODING);
171 byte1 = char_converter.reg[1];
172 byte2 = char_converter.reg[2];
175 *text_storage++ = (unsigned char) byte1;
177 *text_storage++ = (unsigned char) byte2;
182 run_storage[runs_so_far - 1].len =
183 text_storage - run_storage[runs_so_far - 1].ptr;
184 if (run_storage[runs_so_far - 1].dimension == 2)
185 run_storage[runs_so_far - 1].len >>= 1;
193 mswindows_text_width_single_run (HDC hdc, struct face_cachel *cachel,
196 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
197 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
200 if (!fi->proportional_p || !hdc)
201 return (fi->width * run->len);
204 assert(run->dimension == 1); /* #### FIXME! */
205 mswindows_update_dc (hdc, font_inst, Qnil, Qnil, Qnil);
206 GetTextExtentPoint32 (hdc, run->ptr, run->len, &size);
212 /*****************************************************************************
215 Given a number of parameters munge the DC so it has those properties.
216 ****************************************************************************/
218 mswindows_update_dc (HDC hdc, Lisp_Object font, Lisp_Object fg,
219 Lisp_Object bg, Lisp_Object bg_pmap)
222 SelectObject(hdc, FONT_INSTANCE_MSWINDOWS_HFONT (XFONT_INSTANCE (font)));
227 SetTextColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR
228 (XCOLOR_INSTANCE (fg)));
232 SetBkMode (hdc, OPAQUE);
233 SetBkColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (bg)));
237 SetBkMode (hdc, TRANSPARENT);
242 /*****************************************************************************
243 mswindows_apply_face_effects
245 Draw underline and strikeout as if this was X.
246 #### On mswindows this really should be done as part of drawing the font.
247 The line width used is chosen arbitrarily from the font height.
248 ****************************************************************************/
250 mswindows_apply_face_effects (HDC hdc, struct display_line *dl, int xpos,
251 int width, struct Lisp_Font_Instance *fi,
252 struct face_cachel *cachel,
253 struct face_cachel *color_cachel)
256 HBRUSH brush, oldbrush;
259 brush = CreateSolidBrush (COLOR_INSTANCE_MSWINDOWS_COLOR (
260 XCOLOR_INSTANCE (color_cachel->foreground)));
263 yclip = dl->ypos + dl->descent - dl->clip;
265 rect.right = xpos + width;
266 oldbrush = SelectObject (hdc, brush);
268 if (cachel->underline)
270 rect.top = dl->ypos + dl->descent/2;
271 rect.bottom = rect.top + (fi->height >= 0x20 ? 2 : 1);
272 if (rect.bottom <= yclip)
273 FillRect (hdc, &rect, brush);
275 if (cachel->strikethru)
277 rect.top = dl->ypos + dl->descent - (dl->ascent + dl->descent)/2;
278 rect.bottom = rect.top + (fi->height >= 0x20 ? 2 : 1);
279 if (rect.bottom <= yclip)
280 FillRect (hdc, &rect, brush);
283 SelectObject (hdc, oldbrush);
284 DeleteObject (brush);
289 /*****************************************************************************
290 mswindows_output_hline
292 Output a horizontal line in the foreground of its face.
293 ****************************************************************************/
295 mswindows_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
296 { /* XXX Implement me */
300 /*****************************************************************************
301 mswindows_output_blank
303 Output a blank by clearing the area it covers in the background color
305 ****************************************************************************/
307 mswindows_output_blank (struct window *w, struct display_line *dl, struct rune *rb, int start_pixpos)
309 struct frame *f = XFRAME (w->frame);
310 RECT rect = { rb->xpos, dl->ypos-dl->ascent,
311 rb->xpos+rb->width, dl->ypos+dl->descent-dl->clip };
312 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, rb->findex);
314 Lisp_Object bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
316 if (!IMAGE_INSTANCEP (bg_pmap)
317 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
322 /* blank the background in the appropriate color */
323 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, cachel->foreground,
324 cachel->background, Qnil);
326 mswindows_output_pixmap (w, dl, bg_pmap,
327 rb->xpos, 0 /*rb->object.dglyph.xoffset*/,
328 start_pixpos, rb->width, rb->findex,
333 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
334 cachel->background, Qnil);
336 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
337 &rect, NULL, 0, NULL);
342 /*****************************************************************************
343 mswindows_output_cursor
345 Draw a normal or end-of-line cursor. The end-of-line cursor is
346 narrower than the normal cursor.
347 ****************************************************************************/
349 mswindows_output_cursor (struct window *w, struct display_line *dl, int xpos,
350 int width, face_index findex, Emchar ch, int image_p)
352 struct frame *f = XFRAME (w->frame);
353 struct device *d = XDEVICE (f->device);
354 struct face_cachel *cachel=0;
355 Lisp_Object font = Qnil;
356 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
357 HDC hdc = FRAME_MSWINDOWS_DC (f);
358 unsigned int face_index=0;
362 dl->ypos - dl->ascent,
364 dl->ypos + dl->descent - dl->clip};
365 Lisp_Object bar = symbol_value_in_buffer (Qbar_cursor,
367 int bar_p = image_p || !NILP (bar);
368 int cursor_p = !NILP (w->text_cursor_visible_p);
369 int real_char_p = ch != 0;
373 /* Use the font from the underlying character */
374 cachel = WINDOW_FACE_CACHEL (w, findex);
376 /* #### MULE: Need to know the charset! */
377 font = FACE_CACHEL_FONT (cachel, Vcharset_ascii);
380 if ((focus || bar_p) && real_char_p)
382 p_char = (char*) &ch;
388 struct face_cachel *color_cachel;
390 /* Use cursor fg/bg for block cursor, or character fg/bg for the bar
391 or when we need to erase the cursor. Output nothing at eol if bar
393 face_index = get_builtin_face_cache_index (w, Vtext_cursor_face);
394 color_cachel = WINDOW_FACE_CACHEL (w, ((!cursor_p || bar_p) ?
395 findex : face_index));
396 mswindows_update_dc (hdc, font, color_cachel->foreground,
397 color_cachel->background, Qnil);
398 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE|ETO_CLIPPED, &rect, p_char, n_char, NULL);
399 if (real_char_p && (cachel->underline || cachel->strikethru))
400 mswindows_apply_face_effects (hdc, dl, xpos, width,
401 XFONT_INSTANCE (font),
402 cachel, color_cachel);
410 rect.right = rect.left + (EQ (bar, Qt) ? 1 : min (2, width));
411 face_index = get_builtin_face_cache_index (w, Vtext_cursor_face);
412 cachel = WINDOW_FACE_CACHEL (w, face_index);
413 mswindows_update_dc (hdc, Qnil, Qnil, cachel->background, Qnil);
414 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE, &rect, NULL, 0, NULL);
418 /* Now have real character drawn in its own color. We deflate
419 the rectangle so character cell will be bounded by the
420 previously drawn cursor shape */
421 InflateRect (&rect, -1, -1);
425 p_char = (char*) &ch;
429 face_index = get_builtin_face_cache_index (w, Vdefault_face);
430 cachel = WINDOW_FACE_CACHEL (w, (real_char_p ? findex : face_index));
431 mswindows_update_dc (hdc, Qnil, cachel->foreground,
432 cachel->background, Qnil);
433 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE | ETO_CLIPPED,
434 &rect, p_char, n_char, NULL);
435 if (cachel->underline || cachel->strikethru)
436 mswindows_apply_face_effects (hdc, dl, xpos+1, width-2,
437 XFONT_INSTANCE (font),
443 /*****************************************************************************
444 mswindows_output_string
446 Given a string and a starting position, output that string in the
448 Correctly handles multiple charsets in the string.
450 The meaning of the parameters is something like this:
452 W Window that the text is to be displayed in.
453 DL Display line that this text is on. The values in the
454 structure are used to determine the vertical position and
455 clipping range of the text.
456 BUF Dynamic array of Emchars specifying what is actually to be
458 XPOS X position in pixels where the text should start being drawn.
459 XOFFSET Number of pixels to be chopped off the left side of the
460 text. The effect is as if the text were shifted to the
461 left this many pixels and clipped at XPOS.
462 CLIP_START Clip everything left of this X position.
463 WIDTH Clip everything right of XPOS + WIDTH.
464 FINDEX Index for the face cache element describing how to display
466 ****************************************************************************/
468 mswindows_output_string (struct window *w, struct display_line *dl,
469 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
470 int width, face_index findex)
472 struct frame *f = XFRAME (w->frame);
473 /* struct device *d = XDEVICE (f->device);*/
475 HDC hdc = FRAME_MSWINDOWS_DC (f);
478 int len = Dynarr_length (buf);
479 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
480 textual_run *runs = alloca_array (textual_run, len);
484 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
486 XSETWINDOW (window, w);
488 #if 0 /* #### FIXME? */
489 /* We can't work out the width before we've set the font in the DC */
491 width = mswindows_text_width (cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
496 /* Regularize the variables passed in. */
497 if (clip_start < xpos)
499 clip_end = xpos + width;
500 if (clip_start >= clip_end)
501 /* It's all clipped out. */
506 /* sort out the destination rectangle */
507 height = DISPLAY_LINE_HEIGHT (dl);
508 rect.left = clip_start;
509 rect.top = dl->ypos - dl->ascent;
510 rect.right = clip_end;
511 rect.bottom = height + dl->ypos - dl->ascent;
513 /* output the background pixmap if there is one */
514 bg_pmap = cachel->background_pixmap;
515 if (!IMAGE_INSTANCEP (bg_pmap)
516 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
521 /* blank the background in the appropriate color */
522 mswindows_update_dc (hdc, Qnil, cachel->foreground,
523 cachel->background, Qnil);
525 mswindows_output_pixmap (w, dl, bg_pmap,
527 clip_start, width, findex,
529 /* output pixmap calls this so we have to recall to get correct
531 cachel = WINDOW_FACE_CACHEL (w, findex);
534 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
535 Dynarr_length (buf));
537 for (i = 0; i < nruns; i++)
539 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
540 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
543 if (EQ (font, Vthe_null_font_instance))
546 mswindows_update_dc (hdc, font, cachel->foreground,
547 NILP(bg_pmap) ? cachel->background : Qnil, Qnil);
549 this_width = mswindows_text_width_single_run (hdc, cachel, runs + i);
551 /* cope with fonts taller than lines */
552 if ((int) fi->height < (int) (height + dl->clip))
554 int clear_start = max (xpos, clip_start);
555 int clear_end = min (xpos + this_width, clip_end);
558 redisplay_clear_region (window, findex, clear_start,
559 dl->ypos - dl->ascent,
560 clear_end - clear_start,
562 /* output pixmap calls this so we have to recall to get correct
564 cachel = WINDOW_FACE_CACHEL (w, findex);
568 assert (runs[i].dimension == 1); /* #### FIXME: Broken when Mule? */
569 ExtTextOut (hdc, xpos, dl->ypos,
570 NILP(bg_pmap) ? ETO_CLIPPED | ETO_OPAQUE : ETO_CLIPPED,
571 &rect, (char *) runs[i].ptr, runs[i].len, NULL);
573 /* #### X does underline/strikethrough here so we do the same.
574 On mswindows, underline/strikethrough really belongs to the font */
575 if (cachel->underline || cachel->strikethru)
576 mswindows_apply_face_effects (hdc, dl, xpos, this_width, fi,
583 mswindows_output_dibitmap (struct frame *f, struct Lisp_Image_Instance *p,
585 int clip_x, int clip_y,
586 int clip_width, int clip_height,
587 int width, int height, int pixmap_offset,
590 HDC hdc = FRAME_MSWINDOWS_DC (f);
592 COLORREF bgcolor = GetBkColor (hdc);
593 int need_clipping = (clip_x || clip_y);
597 /* do we need to offset the pixmap vertically? this is necessary
598 for background pixmaps. */
601 yoffset = y % IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
602 xoffset = x % IMAGE_INSTANCE_PIXMAP_WIDTH (p);
603 /* the width is handled by mswindows_output_pixmap_region */
610 /* first blt the mask */
611 if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
614 col.rgbBlue = GetBValue (bgcolor);
615 col.rgbRed = GetRValue (bgcolor);
616 col.rgbGreen = GetGValue (bgcolor);
619 old = SelectObject (FRAME_MSWINDOWS_CDC (f),
620 IMAGE_INSTANCE_MSWINDOWS_MASK (p));
622 SetDIBColorTable (FRAME_MSWINDOWS_CDC (f), 1, 1, &col);
627 FRAME_MSWINDOWS_CDC (f),
631 SelectObject (FRAME_MSWINDOWS_CDC (f), old);
634 /* now blt the bitmap itself. */
635 old = SelectObject (FRAME_MSWINDOWS_CDC (f),
636 IMAGE_INSTANCE_MSWINDOWS_BITMAP (p));
641 FRAME_MSWINDOWS_CDC (f),
643 IMAGE_INSTANCE_MSWINDOWS_MASK (p) ? SRCINVERT : SRCCOPY);
645 SelectObject (FRAME_MSWINDOWS_CDC (f),old);
653 * X gc's have this nice property that setting the bg pixmap will
654 * output it offset relative to the window. Windows doesn't have this
655 * feature so we have to emulate this by outputting multiple pixmaps
658 mswindows_output_dibitmap_region (struct frame *f,
659 struct Lisp_Image_Instance *p,
661 int clip_x, int clip_y,
662 int clip_width, int clip_height,
663 int width, int height, int pixmap_offset,
666 int pwidth = min (width, IMAGE_INSTANCE_PIXMAP_WIDTH (p));
667 int pheight = min (height, IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
668 int pxoffset = 0, pyoffset = 0;
670 /* when doing a bg pixmap do a partial pixmap first so that we
671 blt whole pixmaps thereafter */
675 pheight = min (pheight, IMAGE_INSTANCE_PIXMAP_HEIGHT (p) -
676 y % IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
683 pwidth = min (min (width, IMAGE_INSTANCE_PIXMAP_WIDTH (p)),
684 IMAGE_INSTANCE_PIXMAP_WIDTH (p) -
685 x % IMAGE_INSTANCE_PIXMAP_WIDTH (p));
690 mswindows_output_dibitmap (f, p,
691 x + pxoffset, y + pyoffset,
693 clip_width, clip_height,
694 pwidth, pheight, pixmap_offset,
697 pwidth = min ((width-pxoffset),
698 IMAGE_INSTANCE_PIXMAP_WIDTH (p));
701 pheight = min ((height-pyoffset),
702 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
707 mswindows_output_pixmap (struct window *w, struct display_line *dl,
708 Lisp_Object image_instance, int xpos, int xoffset,
709 int start_pixpos, int width, face_index findex,
710 int cursor_start, int cursor_width, int cursor_height,
713 struct frame *f = XFRAME (w->frame);
714 HDC hdc = FRAME_MSWINDOWS_DC (f);
716 struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
719 int lheight = DISPLAY_LINE_HEIGHT (dl);
720 int pheight = ((int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > lheight ? lheight :
721 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
722 int clip_x, clip_y, clip_width, clip_height;
724 /* The pixmap_offset is used to center the pixmap on lines which are
725 shorter than it is. This results in odd effects when scrolling
726 pixmaps off of the bottom. Let's try not using it. */
728 int pixmap_offset = (int) (IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - lheight) / 2;
730 int pixmap_offset = 0;
733 XSETWINDOW (window, w);
735 if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
737 if (start_pixpos > xpos && start_pixpos > xpos + width)
742 if (start_pixpos > xpos)
744 clip_x += (start_pixpos - xpos);
745 clip_width -= (start_pixpos - xpos);
754 /* Place markers for possible future functionality (clipping the top
755 half instead of the bottom half; think pixel scrolling). */
757 clip_height = pheight;
759 /* Clear the area the pixmap is going into. The pixmap itself will
760 always take care of the full width. We don't want to clear where
761 it is going to go in order to avoid flicker. So, all we have to
762 take care of is any area above or below the pixmap. */
763 /* #### We take a shortcut for now. We know that since we have
764 pixmap_offset hardwired to 0 that the pixmap is against the top
765 edge so all we have to worry about is below it. */
766 /* #### Unless the pixmap has a mask in which case we have to clear
767 the whole damn thing since we can't yet clear just the area not
768 included in the mask. */
769 if (((int) (dl->ypos - dl->ascent + pheight) <
770 (int) (dl->ypos + dl->descent - dl->clip))
771 || IMAGE_INSTANCE_MSWINDOWS_MASK (p))
773 int clear_x, clear_y, clear_width, clear_height;
775 if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
777 clear_y = dl->ypos - dl->ascent;
778 clear_height = lheight;
782 clear_y = dl->ypos - dl->ascent + pheight;
783 clear_height = lheight - pheight;
786 if (start_pixpos >= 0 && start_pixpos > xpos)
788 clear_x = start_pixpos;
789 clear_width = xpos + width - start_pixpos;
797 if (!offset_bitmap) /* i.e. not a bg pixmap */
798 redisplay_clear_region (window, findex, clear_x, clear_y,
799 clear_width, clear_height);
802 /* Output the pixmap. Have to do this as many times as is required
803 to fill the given area */
804 mswindows_update_dc (hdc, Qnil,
805 WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
806 WINDOW_FACE_CACHEL_BACKGROUND (w, findex), Qnil);
808 mswindows_output_dibitmap_region (f, p, xpos - xoffset,
809 dl->ypos - dl->ascent,
810 clip_x, clip_y, clip_width, clip_height,
811 width + xoffset, pheight, pixmap_offset,
815 #ifdef HAVE_SCROLLBARS
817 * This function paints window's deadbox, a rectangle between window
818 * borders and two short edges of both scrollbars.
820 * Function checks whether deadbox intersects with the rectangle pointed
821 * to by PRC, and paints only the intersection
824 mswindows_redisplay_deadbox_maybe (struct window *w, CONST RECT* prc)
826 int sbh = window_scrollbar_height (w);
827 int sbw = window_scrollbar_width (w);
828 RECT rect_dead, rect_paint;
829 if (sbh == 0 || sbw == 0)
832 if (!NILP (w->scrollbar_on_left_p))
833 rect_dead.left = WINDOW_LEFT (w);
835 rect_dead.left = WINDOW_TEXT_RIGHT (w);
836 rect_dead.right = rect_dead.left + sbw;
838 if (!NILP (w->scrollbar_on_top_p))
839 rect_dead.top = WINDOW_TOP (w);
841 rect_dead.top = WINDOW_TEXT_BOTTOM (w);
842 rect_dead.bottom = rect_dead.top + sbh;
844 if (IntersectRect (&rect_paint, &rect_dead, prc))
846 struct frame *f = XFRAME (WINDOW_FRAME (w));
847 FillRect (FRAME_MSWINDOWS_DC (f), &rect_paint,
848 (HBRUSH) (COLOR_BTNFACE+1));
852 #endif /* HAVE_SCROLLBARS */
854 /*****************************************************************************
855 mswindows_redraw_exposed_window
857 Given a bounding box for an area that needs to be redrawn, determine
858 what parts of what lines are contained within and re-output their
860 Copied from redisplay-x.c
861 ****************************************************************************/
863 mswindows_redraw_exposed_window (struct window *w, int x, int y, int width,
866 struct frame *f = XFRAME (w->frame);
868 int orig_windows_structure_changed;
869 RECT rect_window = { WINDOW_LEFT (w), WINDOW_TOP (w),
870 WINDOW_RIGHT (w), WINDOW_BOTTOM (w) };
871 RECT rect_expose = { x, y, x + width, y + height };
874 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
876 if (!NILP (w->vchild))
878 mswindows_redraw_exposed_windows (w->vchild, x, y, width, height);
881 else if (!NILP (w->hchild))
883 mswindows_redraw_exposed_windows (w->hchild, x, y, width, height);
887 /* If the window doesn't intersect the exposed region, we're done here. */
888 if (!IntersectRect (&rect_draw, &rect_window, &rect_expose))
891 /* We do this to make sure that the 3D modelines get redrawn if
892 they are in the exposed region. */
893 orig_windows_structure_changed = f->windows_structure_changed;
894 f->windows_structure_changed = 1;
896 if (window_needs_vertical_divider (w))
898 mswindows_output_vertical_divider (w, 0);
901 for (line = 0; line < Dynarr_length (cdla); line++)
903 struct display_line *cdl = Dynarr_atp (cdla, line);
904 int top_y = cdl->ypos - cdl->ascent;
905 int bottom_y = cdl->ypos + cdl->descent;
907 if (bottom_y >= rect_draw.top)
909 if (top_y > rect_draw.bottom)
918 output_display_line (w, 0, cdla, line,
919 rect_draw.left, rect_draw.right);
924 f->windows_structure_changed = orig_windows_structure_changed;
926 /* If there have never been any face cache_elements created, then this
927 expose event doesn't actually have anything to do. */
928 if (Dynarr_largest (w->face_cachels))
929 redisplay_clear_bottom_of_window (w, cdla, rect_draw.top, rect_draw.bottom);
931 #ifdef HAVE_SCROLLBARS
932 mswindows_redisplay_deadbox_maybe (w, &rect_expose);
936 /*****************************************************************************
937 mswindows_redraw_exposed_windows
939 For each window beneath the given window in the window hierarchy,
940 ensure that it is redrawn if necessary after an Expose event.
941 ****************************************************************************/
943 mswindows_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
946 for (; !NILP (window); window = XWINDOW (window)->next)
947 mswindows_redraw_exposed_window (XWINDOW (window), x, y, width, height);
950 /*****************************************************************************
951 mswindows_redraw_exposed_area
953 For each window on the given frame, ensure that any area in the
954 Exposed area is redrawn.
955 ****************************************************************************/
957 mswindows_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
959 /* If any window on the frame has had its face cache reset then the
960 redisplay structures are effectively invalid. If we attempt to
961 use them we'll blow up. We mark the frame as changed to ensure
962 that redisplay will do a full update. This probably isn't
963 necessary but it can't hurt. */
965 /* #### We would rather put these off as well but there is currently
966 no combination of flags which will force an unchanged toolbar to
968 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
970 redraw_exposed_gutters (f, x, y, width, height);
972 if (!f->window_face_cache_reset)
974 mswindows_redraw_exposed_windows (f->root_window, x, y, width, height);
978 MARK_FRAME_CHANGED (f);
982 /*****************************************************************************
985 Draw a 3d border around the specified area on window W.
986 ****************************************************************************/
988 mswindows_bevel_area (struct window *w, face_index findex, int x, int y,
989 int width, int height, int shadow_thickness)
991 struct frame *f = XFRAME (w->frame);
994 if (shadow_thickness < -1)
996 else if (shadow_thickness < 0)
997 edge = BDR_SUNKENINNER;
998 else if (shadow_thickness == 1)
999 edge = BDR_RAISEDINNER;
1003 if (shadow_thickness < 0)
1004 shadow_thickness = -shadow_thickness;
1007 RECT rect = { x, y, x + width, y + height };
1008 Lisp_Object color = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1009 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, color, Qnil);
1011 DrawEdge (FRAME_MSWINDOWS_DC (f), &rect, edge, BF_RECT);
1016 /*****************************************************************************
1018 *****************************************************************************/
1020 /*****************************************************************************
1021 mswindows_divider_height
1023 Return the height of the horizontal divider.
1024 ****************************************************************************/
1026 mswindows_divider_height (void)
1028 return 1; /* XXX Copied from redisplay-X.c. What is this? */
1031 /*****************************************************************************
1032 mswindows_eol_cursor_width
1034 Return the width of the end-of-line cursor.
1035 ****************************************************************************/
1037 mswindows_eol_cursor_width (void)
1039 return MSWINDOWS_EOL_CURSOR_WIDTH;
1042 /*****************************************************************************
1043 mswindows_output_begin
1045 Perform any necessary initialization prior to an update.
1046 ****************************************************************************/
1048 mswindows_output_begin (struct device *d)
1052 /*****************************************************************************
1053 mswindows_output_end
1055 Perform any necessary flushing of queues when an update has completed.
1056 ****************************************************************************/
1058 mswindows_output_end (struct device *d)
1064 mswindows_flash (struct device *d)
1066 struct frame *f = device_selected_frame (d);
1069 GetClientRect (FRAME_MSWINDOWS_HANDLE (f), &rc);
1070 InvertRect (FRAME_MSWINDOWS_DC (f), &rc);
1073 InvertRect (FRAME_MSWINDOWS_DC (f), &rc);
1079 mswindows_ring_bell (struct device *d, int volume, int pitch, int duration)
1081 /* Beep does not work at all, anyways! -kkm */
1082 MessageBeep (MB_OK);
1085 /*****************************************************************************
1086 mswindows_output_display_block
1088 Given a display line, a block number for that start line, output all
1089 runes between start and end in the specified display block.
1090 Ripped off with minimal thought from the corresponding X routine.
1091 ****************************************************************************/
1093 mswindows_output_display_block (struct window *w, struct display_line *dl, int block,
1094 int start, int end, int start_pixpos, int cursor_start,
1095 int cursor_width, int cursor_height)
1097 struct frame *f = XFRAME (w->frame);
1098 Emchar_dynarr *buf = Dynarr_new (Emchar);
1101 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
1102 rune_dynarr *rba = db->runes;
1108 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
1109 MULE is not defined */
1110 XSETWINDOW (window, w);
1111 rb = Dynarr_atp (rba, start);
1114 /* Nothing to do so don't do anything. */
1117 findex = rb->findex;
1120 if (rb->type == RUNE_CHAR)
1121 charset = CHAR_CHARSET (rb->object.chr.ch);
1124 end = Dynarr_length (rba);
1129 rb = Dynarr_atp (rba, elt);
1131 if (rb->findex == findex && rb->type == RUNE_CHAR
1132 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
1133 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
1135 Dynarr_add (buf, rb->object.chr.ch);
1141 if (Dynarr_length (buf))
1143 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
1151 if (rb->type == RUNE_CHAR)
1153 findex = rb->findex;
1155 charset = CHAR_CHARSET (rb->object.chr.ch);
1157 if (rb->cursor_type == CURSOR_ON)
1159 if (rb->object.chr.ch == '\n')
1161 mswindows_output_cursor (w, dl, xpos, cursor_width,
1166 Dynarr_add (buf, rb->object.chr.ch);
1167 mswindows_output_cursor (w, dl, xpos, cursor_width,
1168 findex, rb->object.chr.ch, 0);
1175 else if (rb->object.chr.ch == '\n')
1177 /* Clear in case a cursor was formerly here. */
1178 int height = DISPLAY_LINE_HEIGHT (dl);
1180 redisplay_clear_region (window, findex, xpos, dl->ypos - dl->ascent,
1185 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
1187 if (rb->type == RUNE_BLANK)
1188 mswindows_output_blank (w, dl, rb, start_pixpos);
1191 /* #### Our flagging of when we need to redraw the
1192 modeline shadows sucks. Since RUNE_HLINE is only used
1193 by the modeline at the moment it is a good bet
1194 that if it gets redrawn then we should also
1195 redraw the shadows. This won't be true forever.
1196 We borrow the shadow_thickness_changed flag for
1198 w->shadow_thickness_changed = 1;
1199 mswindows_output_hline (w, dl, rb);
1202 if (rb->cursor_type == CURSOR_ON)
1203 mswindows_output_cursor (w, dl, xpos, cursor_width, rb->findex, 0, 0);
1208 rb = Dynarr_atp (rba, elt);
1210 findex = rb->findex;
1214 else if (rb->type == RUNE_DGLYPH)
1216 Lisp_Object instance;
1218 XSETWINDOW (window, w);
1219 instance = glyph_image_instance (rb->object.dglyph.glyph,
1220 window, ERROR_ME_NOT, 1);
1221 findex = rb->findex;
1223 if (IMAGE_INSTANCEP (instance))
1224 switch (XIMAGE_INSTANCE_TYPE (instance))
1228 /* #### This is way losing. See the comment in
1229 add_glyph_rune(). */
1230 Lisp_Object string =
1231 XIMAGE_INSTANCE_TEXT_STRING (instance);
1232 convert_bufbyte_string_into_emchar_dynarr
1233 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
1235 if (rb->cursor_type == CURSOR_ON)
1236 mswindows_output_cursor (w, dl, xpos, cursor_width,
1237 findex, Dynarr_at (buf, 0), 0);
1238 else /* #### redisplay-x passes -1 as the width: why ? */
1239 mswindows_output_string (w, dl, buf, xpos,
1240 rb->object.dglyph.xoffset,
1241 start_pixpos, rb->width, findex);
1246 case IMAGE_MONO_PIXMAP:
1247 case IMAGE_COLOR_PIXMAP:
1248 mswindows_output_pixmap (w, dl, instance, xpos,
1249 rb->object.dglyph.xoffset, start_pixpos,
1250 rb->width, findex, cursor_start,
1251 cursor_width, cursor_height, 0);
1252 if (rb->cursor_type == CURSOR_ON)
1253 mswindows_output_cursor (w, dl, xpos, cursor_width,
1260 case IMAGE_SUBWINDOW:
1262 redisplay_output_subwindow (w, dl, instance, xpos,
1263 rb->object.dglyph.xoffset, start_pixpos,
1264 rb->width, findex, cursor_start,
1265 cursor_width, cursor_height);
1266 if (rb->cursor_type == CURSOR_ON)
1267 mswindows_output_cursor (w, dl, xpos, cursor_width,
1272 /* nothing is as nothing does */
1287 if (Dynarr_length (buf))
1288 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex);
1291 && !EQ (Qzero, w->modeline_shadow_thickness)
1293 || f->windows_structure_changed
1294 || w->shadow_thickness_changed))
1295 bevel_modeline (w, dl);
1301 /*****************************************************************************
1302 mswindows_output_vertical_divider
1304 Draw a vertical divider down the right side of the given window.
1305 ****************************************************************************/
1307 mswindows_output_vertical_divider (struct window *w, int clear_unused)
1309 struct frame *f = XFRAME (w->frame);
1311 int spacing = XINT (w->vertical_divider_spacing);
1312 int shadow = XINT (w->vertical_divider_shadow_thickness);
1313 int abs_shadow = abs (shadow);
1314 int line_width = XINT (w->vertical_divider_line_width);
1315 int div_left = WINDOW_RIGHT (w) - window_divider_width (w);
1316 int y1 = WINDOW_TOP (w) + FRAME_TOP_GUTTER_BOUNDS (f);
1317 int y2 = WINDOW_BOTTOM (w) + FRAME_BOTTOM_GUTTER_BOUNDS (f);
1319 /* Clear left and right spacing areas */
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 = y1 + abs_shadow;
1338 rect.bottom = y2 - 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 /* XXX Implement me! */
1425 mswindows_clear_frame (struct frame *f)
1432 /************************************************************************/
1433 /* initialization */
1434 /************************************************************************/
1437 console_type_create_redisplay_mswindows (void)
1439 /* redisplay methods */
1440 CONSOLE_HAS_METHOD (mswindows, text_width);
1441 CONSOLE_HAS_METHOD (mswindows, output_display_block);
1442 CONSOLE_HAS_METHOD (mswindows, divider_height);
1443 CONSOLE_HAS_METHOD (mswindows, eol_cursor_width);
1444 CONSOLE_HAS_METHOD (mswindows, output_vertical_divider);
1445 CONSOLE_HAS_METHOD (mswindows, clear_region);
1446 CONSOLE_HAS_METHOD (mswindows, clear_frame);
1447 CONSOLE_HAS_METHOD (mswindows, output_begin);
1448 CONSOLE_HAS_METHOD (mswindows, output_end);
1449 CONSOLE_HAS_METHOD (mswindows, flash);
1450 CONSOLE_HAS_METHOD (mswindows, ring_bell);
1451 CONSOLE_HAS_METHOD (mswindows, bevel_area);