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 delarations
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_clear_region (Lisp_Object locale, face_index findex,
62 int x, int y, int width, int height);
63 static void mswindows_output_vertical_divider (struct window *w, int clear);
64 static void mswindows_redraw_exposed_windows (Lisp_Object window, int x,
65 int y, int width, int height);
66 static void mswindows_output_dibitmap (struct frame *f,
67 struct Lisp_Image_Instance *p,
69 int clip_x, int clip_y,
70 int clip_width, int clip_height,
71 int width, int height,
74 static void mswindows_output_pixmap (struct window *w, struct display_line *dl,
75 Lisp_Object image_instance, int xpos,
76 int xoffset, int start_pixpos, int width,
77 face_index findex, int cursor_start,
78 int cursor_width, int cursor_height,
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);
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;
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 = dl->ascent + dl->descent - dl->clip;
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 mswindows_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);
596 /* do we need to offset the pixmap vertically? this is necessary
597 for background pixmaps. */
600 yoffset = y % IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
601 xoffset = x % IMAGE_INSTANCE_PIXMAP_WIDTH (p);
602 /* the width is handled by mswindows_output_pixmap_region */
609 /* first blt the mask */
610 if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
613 col.rgbBlue = GetBValue (bgcolor);
614 col.rgbRed = GetRValue (bgcolor);
615 col.rgbGreen = GetGValue (bgcolor);
618 old = SelectObject (FRAME_MSWINDOWS_CDC (f),
619 IMAGE_INSTANCE_MSWINDOWS_MASK (p));
621 SetDIBColorTable (FRAME_MSWINDOWS_CDC (f), 1, 1, &col);
626 FRAME_MSWINDOWS_CDC (f),
630 SelectObject (FRAME_MSWINDOWS_CDC (f), old);
633 /* now blt the bitmap itself. */
634 old = SelectObject (FRAME_MSWINDOWS_CDC (f),
635 IMAGE_INSTANCE_MSWINDOWS_BITMAP (p));
640 FRAME_MSWINDOWS_CDC (f),
642 IMAGE_INSTANCE_MSWINDOWS_MASK (p) ? SRCINVERT : SRCCOPY);
644 SelectObject (FRAME_MSWINDOWS_CDC (f),old);
652 * X gc's have this nice property that setting the bg pixmap will
653 * output it offset relative to the window. Windows doesn't have this
654 * feature so we have to emulate this by outputting multiple pixmaps
657 mswindows_output_dibitmap_region (struct frame *f,
658 struct Lisp_Image_Instance *p,
660 int clip_x, int clip_y,
661 int clip_width, int clip_height,
662 int width, int height, int pixmap_offset,
665 int pwidth = min (width, IMAGE_INSTANCE_PIXMAP_WIDTH (p));
666 int pheight = min (height, IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
667 int pxoffset = 0, pyoffset = 0;
669 /* when doing a bg pixmap do a partial pixmap first so that we
670 blt whole pixmaps thereafter */
674 pheight = min (pheight, IMAGE_INSTANCE_PIXMAP_HEIGHT (p) -
675 y % IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
682 pwidth = min (min (width, IMAGE_INSTANCE_PIXMAP_WIDTH (p)),
683 IMAGE_INSTANCE_PIXMAP_WIDTH (p) -
684 x % IMAGE_INSTANCE_PIXMAP_WIDTH (p));
689 mswindows_output_dibitmap (f, p,
690 x + pxoffset, y + pyoffset,
692 clip_width, clip_height,
693 pwidth, pheight, pixmap_offset,
696 pwidth = min ((width-pxoffset),
697 IMAGE_INSTANCE_PIXMAP_WIDTH (p));
700 pheight = min ((height-pyoffset),
701 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
706 mswindows_output_pixmap (struct window *w, struct display_line *dl,
707 Lisp_Object image_instance, int xpos, int xoffset,
708 int start_pixpos, int width, face_index findex,
709 int cursor_start, int cursor_width, int cursor_height,
712 struct frame *f = XFRAME (w->frame);
713 HDC hdc = FRAME_MSWINDOWS_DC (f);
715 struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
718 int lheight = dl->ascent + dl->descent - dl->clip;
719 int pheight = ((int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > lheight ? lheight :
720 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
721 int clip_x, clip_y, clip_width, clip_height;
723 /* The pixmap_offset is used to center the pixmap on lines which are
724 shorter than it is. This results in odd effects when scrolling
725 pixmaps off of the bottom. Let's try not using it. */
727 int pixmap_offset = (int) (IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - lheight) / 2;
729 int pixmap_offset = 0;
732 XSETWINDOW (window, w);
734 if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
736 if (start_pixpos > xpos && start_pixpos > xpos + width)
741 if (start_pixpos > xpos)
743 clip_x += (start_pixpos - xpos);
744 clip_width -= (start_pixpos - xpos);
753 /* Place markers for possible future functionality (clipping the top
754 half instead of the bottom half; think pixel scrolling). */
756 clip_height = pheight;
758 /* Clear the area the pixmap is going into. The pixmap itself will
759 always take care of the full width. We don't want to clear where
760 it is going to go in order to avoid flicker. So, all we have to
761 take care of is any area above or below the pixmap. */
762 /* #### We take a shortcut for now. We know that since we have
763 pixmap_offset hardwired to 0 that the pixmap is against the top
764 edge so all we have to worry about is below it. */
765 /* #### Unless the pixmap has a mask in which case we have to clear
766 the whole damn thing since we can't yet clear just the area not
767 included in the mask. */
768 if (((int) (dl->ypos - dl->ascent + pheight) <
769 (int) (dl->ypos + dl->descent - dl->clip))
770 || IMAGE_INSTANCE_MSWINDOWS_MASK (p))
772 int clear_x, clear_y, clear_width, clear_height;
774 if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
776 clear_y = dl->ypos - dl->ascent;
777 clear_height = lheight;
781 clear_y = dl->ypos - dl->ascent + pheight;
782 clear_height = lheight - pheight;
785 if (start_pixpos >= 0 && start_pixpos > xpos)
787 clear_x = start_pixpos;
788 clear_width = xpos + width - start_pixpos;
796 if (!offset_bitmap) /* i.e. not a bg pixmap */
797 mswindows_clear_region (window, findex, clear_x, clear_y,
798 clear_width, clear_height);
801 /* Output the pixmap. Have to do this as many times as is required
802 to fill the given area */
803 mswindows_update_dc (hdc, Qnil,
804 WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
805 WINDOW_FACE_CACHEL_BACKGROUND (w, findex), Qnil);
807 mswindows_output_dibitmap_region (f, p, xpos - xoffset,
808 dl->ypos - dl->ascent,
809 clip_x, clip_y, clip_width, clip_height,
810 width + xoffset, pheight, pixmap_offset,
814 #ifdef HAVE_SCROLLBARS
816 * This function paints window's deadbox, a rectangle between window
817 * borders and two short edges of both scrollbars.
819 * Function checks whether deadbox intersects with the rectangle pointed
820 * to by PRC, and paints only the intersection
823 mswindows_redisplay_deadbox_maybe (struct window *w, CONST RECT* prc)
825 int sbh = window_scrollbar_height (w);
826 int sbw = window_scrollbar_width (w);
827 RECT rect_dead, rect_paint;
828 if (sbh == 0 || sbw == 0)
831 if (!NILP (w->scrollbar_on_left_p))
832 rect_dead.left = WINDOW_LEFT (w);
834 rect_dead.left = WINDOW_TEXT_RIGHT (w);
835 rect_dead.right = rect_dead.left + sbw;
837 if (!NILP (w->scrollbar_on_top_p))
838 rect_dead.top = WINDOW_TOP (w);
840 rect_dead.top = WINDOW_TEXT_BOTTOM (w);
841 rect_dead.bottom = rect_dead.top + sbh;
843 if (IntersectRect (&rect_paint, &rect_dead, prc))
845 struct frame *f = XFRAME (WINDOW_FRAME (w));
846 FillRect (FRAME_MSWINDOWS_DC (f), &rect_paint,
847 (HBRUSH) (COLOR_BTNFACE+1));
851 #endif /* HAVE_SCROLLBARS */
853 /*****************************************************************************
854 mswindows_redraw_exposed_window
856 Given a bounding box for an area that needs to be redrawn, determine
857 what parts of what lines are contained within and re-output their
859 Copied from redisplay-x.c
860 ****************************************************************************/
862 mswindows_redraw_exposed_window (struct window *w, int x, int y, int width,
865 struct frame *f = XFRAME (w->frame);
867 int orig_windows_structure_changed;
868 RECT rect_window = { WINDOW_LEFT (w), WINDOW_TOP (w),
869 WINDOW_RIGHT (w), WINDOW_BOTTOM (w) };
870 RECT rect_expose = { x, y, x + width, y + height };
873 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
875 if (!NILP (w->vchild))
877 mswindows_redraw_exposed_windows (w->vchild, x, y, width, height);
880 else if (!NILP (w->hchild))
882 mswindows_redraw_exposed_windows (w->hchild, x, y, width, height);
886 /* If the window doesn't intersect the exposed region, we're done here. */
887 if (!IntersectRect (&rect_draw, &rect_window, &rect_expose))
890 /* We do this to make sure that the 3D modelines get redrawn if
891 they are in the exposed region. */
892 orig_windows_structure_changed = f->windows_structure_changed;
893 f->windows_structure_changed = 1;
895 if (window_needs_vertical_divider (w))
897 mswindows_output_vertical_divider (w, 0);
900 for (line = 0; line < Dynarr_length (cdla); line++)
902 struct display_line *cdl = Dynarr_atp (cdla, line);
903 int top_y = cdl->ypos - cdl->ascent;
904 int bottom_y = cdl->ypos + cdl->descent;
906 if (bottom_y >= rect_draw.top)
908 if (top_y > rect_draw.bottom)
917 output_display_line (w, 0, cdla, line,
918 rect_draw.left, rect_draw.right);
923 f->windows_structure_changed = orig_windows_structure_changed;
925 /* If there have never been any face cache_elements created, then this
926 expose event doesn't actually have anything to do. */
927 if (Dynarr_largest (w->face_cachels))
928 redisplay_clear_bottom_of_window (w, cdla, rect_draw.top, rect_draw.bottom);
930 #ifdef HAVE_SCROLLBARS
931 mswindows_redisplay_deadbox_maybe (w, &rect_expose);
935 /*****************************************************************************
936 mswindows_redraw_exposed_windows
938 For each window beneath the given window in the window hierarchy,
939 ensure that it is redrawn if necessary after an Expose event.
940 ****************************************************************************/
942 mswindows_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
945 for (; !NILP (window); window = XWINDOW (window)->next)
946 mswindows_redraw_exposed_window (XWINDOW (window), x, y, width, height);
949 /*****************************************************************************
950 mswindows_redraw_exposed_area
952 For each window on the given frame, ensure that any area in the
953 Exposed area is redrawn.
954 ****************************************************************************/
956 mswindows_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
958 /* If any window on the frame has had its face cache reset then the
959 redisplay structures are effectively invalid. If we attempt to
960 use them we'll blow up. We mark the frame as changed to ensure
961 that redisplay will do a full update. This probably isn't
962 necessary but it can't hurt. */
964 /* #### We would rather put these off as well but there is currently
965 no combination of flags which will force an unchanged toolbar to
967 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
970 if (!f->window_face_cache_reset)
972 mswindows_redraw_exposed_windows (f->root_window, x, y, width, height);
976 MARK_FRAME_CHANGED (f);
980 /*****************************************************************************
981 mswindows_bevel_modeline
983 Draw a 3d border around the modeline on window W.
984 ****************************************************************************/
986 mswindows_bevel_modeline (struct window *w, struct display_line *dl)
988 struct frame *f = XFRAME (w->frame);
990 int shadow_width = MODELINE_SHADOW_THICKNESS (w);
991 RECT rect = { WINDOW_MODELINE_LEFT (w),
992 dl->ypos - dl->ascent - shadow_width,
993 WINDOW_MODELINE_RIGHT (w),
994 dl->ypos + dl->descent + shadow_width};
997 color = WINDOW_FACE_CACHEL_BACKGROUND (w, MODELINE_INDEX);
998 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, color, Qnil);
1000 if (XINT (w->modeline_shadow_thickness) < 0)
1001 shadow_width = -shadow_width;
1003 if (shadow_width < -1)
1005 else if (shadow_width < 0)
1006 edge = BDR_SUNKENINNER;
1007 else if (shadow_width == 1)
1008 edge = BDR_RAISEDINNER;
1012 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 mininmal 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);
1115 /* Nothing to do so don't do anything. */
1120 findex = rb->findex;
1123 if (rb->type == RUNE_CHAR)
1124 charset = CHAR_CHARSET (rb->object.chr.ch);
1128 end = Dynarr_length (rba);
1133 rb = Dynarr_atp (rba, elt);
1135 if (rb->findex == findex && rb->type == RUNE_CHAR
1136 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
1137 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
1139 Dynarr_add (buf, rb->object.chr.ch);
1145 if (Dynarr_length (buf))
1147 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
1155 if (rb->type == RUNE_CHAR)
1157 findex = rb->findex;
1159 charset = CHAR_CHARSET (rb->object.chr.ch);
1161 if (rb->cursor_type == CURSOR_ON)
1163 if (rb->object.chr.ch == '\n')
1165 mswindows_output_cursor (w, dl, xpos, cursor_width,
1170 Dynarr_add (buf, rb->object.chr.ch);
1171 mswindows_output_cursor (w, dl, xpos, cursor_width,
1172 findex, rb->object.chr.ch, 0);
1179 else if (rb->object.chr.ch == '\n')
1181 /* Clear in case a cursor was formerly here. */
1182 int height = dl->ascent + dl->descent - dl->clip;
1184 mswindows_clear_region (window, findex, xpos, dl->ypos - dl->ascent,
1189 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
1191 if (rb->type == RUNE_BLANK)
1192 mswindows_output_blank (w, dl, rb, start_pixpos);
1195 /* #### Our flagging of when we need to redraw the
1196 modeline shadows sucks. Since RUNE_HLINE is only used
1197 by the modeline at the moment it is a good bet
1198 that if it gets redrawn then we should also
1199 redraw the shadows. This won't be true forever.
1200 We borrow the shadow_thickness_changed flag for
1202 w->shadow_thickness_changed = 1;
1203 mswindows_output_hline (w, dl, rb);
1206 if (rb->cursor_type == CURSOR_ON)
1207 mswindows_output_cursor (w, dl, xpos, cursor_width, rb->findex, 0, 0);
1212 rb = Dynarr_atp (rba, elt);
1214 findex = rb->findex;
1218 else if (rb->type == RUNE_DGLYPH)
1220 Lisp_Object instance;
1222 XSETWINDOW (window, w);
1223 instance = glyph_image_instance (rb->object.dglyph.glyph,
1224 window, ERROR_ME_NOT, 1);
1225 findex = rb->findex;
1227 if (IMAGE_INSTANCEP (instance))
1228 switch (XIMAGE_INSTANCE_TYPE (instance))
1232 /* #### This is way losing. See the comment in
1233 add_glyph_rune(). */
1234 Lisp_Object string =
1235 XIMAGE_INSTANCE_TEXT_STRING (instance);
1236 convert_bufbyte_string_into_emchar_dynarr
1237 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
1239 if (rb->cursor_type == CURSOR_ON)
1240 mswindows_output_cursor (w, dl, xpos, cursor_width,
1241 findex, Dynarr_at (buf, 0), 0);
1242 else /* #### redisplay-x passes -1 as the width: why ? */
1243 mswindows_output_string (w, dl, buf, xpos,
1244 rb->object.dglyph.xoffset,
1245 start_pixpos, rb->width, findex);
1250 case IMAGE_MONO_PIXMAP:
1251 case IMAGE_COLOR_PIXMAP:
1252 mswindows_output_pixmap (w, dl, instance, xpos,
1253 rb->object.dglyph.xoffset, start_pixpos,
1254 rb->width, findex, cursor_start,
1255 cursor_width, cursor_height, 0);
1256 if (rb->cursor_type == CURSOR_ON)
1257 mswindows_output_cursor (w, dl, xpos, cursor_width,
1264 case IMAGE_SUBWINDOW:
1265 /* #### implement me */
1269 /* nothing is as nothing does */
1284 if (Dynarr_length (buf))
1285 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex);
1288 && !EQ (Qzero, w->modeline_shadow_thickness)
1290 || f->windows_structure_changed
1291 || w->shadow_thickness_changed))
1292 mswindows_bevel_modeline (w, dl);
1298 /*****************************************************************************
1299 mswindows_output_vertical_divider
1301 Draw a vertical divider down the right side of the given window.
1302 ****************************************************************************/
1304 mswindows_output_vertical_divider (struct window *w, int clear_unused)
1306 struct frame *f = XFRAME (w->frame);
1308 int spacing = XINT (w->vertical_divider_spacing);
1309 int shadow = XINT (w->vertical_divider_shadow_thickness);
1310 int abs_shadow = abs (shadow);
1311 int line_width = XINT (w->vertical_divider_line_width);
1312 int div_left = WINDOW_RIGHT (w) - window_divider_width (w);
1314 /* Clear left and right spacing areas */
1317 rect.top = WINDOW_TOP (w);
1318 rect.bottom = WINDOW_BOTTOM (w);
1319 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
1320 WINDOW_FACE_CACHEL_BACKGROUND (w, DEFAULT_INDEX), Qnil);
1321 rect.right = WINDOW_RIGHT (w);
1322 rect.left = rect.right - spacing;
1323 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
1324 &rect, NULL, 0, NULL);
1325 rect.left = div_left;
1326 rect.right = div_left + spacing;
1327 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
1328 &rect, NULL, 0, NULL);
1331 /* Clear divider face */
1332 rect.top = WINDOW_TOP (w) + abs_shadow;
1333 rect.bottom = WINDOW_BOTTOM (w) - abs_shadow;
1334 rect.left = div_left + spacing + abs_shadow;
1335 rect.right = rect.left + line_width;
1336 if (rect.left < rect.right)
1339 = get_builtin_face_cache_index (w, Vvertical_divider_face);
1340 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil,
1341 WINDOW_FACE_CACHEL_BACKGROUND (w, div_face), Qnil);
1342 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE,
1343 &rect, NULL, 0, NULL);
1346 /* Draw a shadow around the divider */
1349 /* #### This will be fixed to support arbitrary thichkness */
1350 InflateRect (&rect, abs_shadow, abs_shadow);
1351 DrawEdge (FRAME_MSWINDOWS_DC (f), &rect,
1352 shadow > 0 ? EDGE_RAISED : EDGE_SUNKEN, BF_RECT);
1356 /****************************************************************************
1357 mswindows_text_width
1359 Given a string and a face, return the string's length in pixels when
1360 displayed in the font associated with the face.
1361 ****************************************************************************/
1363 mswindows_text_width (struct frame *f, struct face_cachel *cachel,
1364 CONST Emchar *str, Charcount len)
1366 int width_so_far = 0;
1367 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
1368 textual_run *runs = alloca_array (textual_run, len);
1372 nruns = separate_textual_runs (text_storage, runs, str, len);
1374 for (i = 0; i < nruns; i++)
1375 width_so_far += mswindows_text_width_single_run (FRAME_MSWINDOWS_DC (f),
1378 return width_so_far;
1382 /****************************************************************************
1383 mswindows_clear_region
1385 Clear the area in the box defined by the given parameters using the
1387 ****************************************************************************/
1389 mswindows_clear_region (Lisp_Object locale, face_index findex, int x, int y,
1390 int width, int height)
1394 Lisp_Object background_pixmap = Qunbound;
1396 RECT rect = { x, y, x+width, y+height };
1398 if (!(width && height)) /* We often seem to get called with width==0 */
1401 if (WINDOWP (locale))
1403 w = XWINDOW (locale);
1404 f = XFRAME (w->frame);
1406 else if (FRAMEP (locale))
1409 f = XFRAME (locale);
1416 temp = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, findex);
1418 if (IMAGE_INSTANCEP (temp)
1419 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
1421 /* #### maybe we could implement such that a string
1422 can be a background pixmap? */
1423 background_pixmap = temp;
1428 temp = FACE_BACKGROUND_PIXMAP (Vdefault_face, locale);
1430 if (IMAGE_INSTANCEP (temp)
1431 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
1433 background_pixmap = temp;
1437 if (!UNBOUNDP (background_pixmap))
1439 Lisp_Object fcolor, bcolor;
1443 fcolor = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1444 bcolor = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1448 fcolor = FACE_FOREGROUND (Vdefault_face, locale);
1449 bcolor = FACE_BACKGROUND (Vdefault_face, locale);
1452 mswindows_update_dc (FRAME_MSWINDOWS_DC (f),
1453 Qnil, fcolor, bcolor, background_pixmap);
1455 mswindows_output_dibitmap_region
1456 ( f, XIMAGE_INSTANCE (background_pixmap),
1457 x, y, 0, 0, 0, 0, width, height, 0, TRUE);
1461 Lisp_Object color = (w ? WINDOW_FACE_CACHEL_BACKGROUND (w, findex) :
1462 FACE_BACKGROUND (Vdefault_face, locale));
1463 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, color, Qnil);
1464 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
1467 #ifdef HAVE_SCROLLBARS
1468 if (WINDOWP (locale))
1469 mswindows_redisplay_deadbox_maybe (w, &rect);
1473 /*****************************************************************************
1474 mswindows_clear_to_window_end
1476 Clear the area between ypos1 and ypos2. Each margin area and the
1477 text area is handled separately since they may each have their own
1479 ****************************************************************************/
1481 mswindows_clear_to_window_end (struct window *w, int ypos1, int ypos2)
1483 int height = ypos2 - ypos1;
1487 struct frame *f = XFRAME (w->frame);
1489 int bflag = (window_needs_vertical_divider (w) ? 0 : 1);
1490 layout_bounds bounds;
1492 bounds = calculate_display_line_boundaries (w, bflag);
1493 XSETWINDOW (window, w);
1495 if (window_is_leftmost (w))
1496 mswindows_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f),
1497 ypos1, FRAME_BORDER_WIDTH (f), height);
1499 if (bounds.left_in - bounds.left_out > 0)
1500 mswindows_clear_region (window,
1501 get_builtin_face_cache_index (w, Vleft_margin_face),
1502 bounds.left_out, ypos1,
1503 bounds.left_in - bounds.left_out, height);
1505 if (bounds.right_in - bounds.left_in > 0)
1506 mswindows_clear_region (window, DEFAULT_INDEX, bounds.left_in, ypos1,
1507 bounds.right_in - bounds.left_in, height);
1509 if (bounds.right_out - bounds.right_in > 0)
1510 mswindows_clear_region (window,
1511 get_builtin_face_cache_index (w, Vright_margin_face),
1512 bounds.right_in, ypos1,
1513 bounds.right_out - bounds.right_in, height);
1515 if (window_is_rightmost (w))
1516 mswindows_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f),
1517 ypos1, FRAME_BORDER_WIDTH (f), height);
1523 /* XXX Implement me! */
1525 mswindows_clear_frame (struct frame *f)
1532 /************************************************************************/
1533 /* initialization */
1534 /************************************************************************/
1537 console_type_create_redisplay_mswindows (void)
1539 /* redisplay methods */
1540 CONSOLE_HAS_METHOD (mswindows, text_width);
1541 CONSOLE_HAS_METHOD (mswindows, output_display_block);
1542 CONSOLE_HAS_METHOD (mswindows, divider_height);
1543 CONSOLE_HAS_METHOD (mswindows, eol_cursor_width);
1544 CONSOLE_HAS_METHOD (mswindows, output_vertical_divider);
1545 CONSOLE_HAS_METHOD (mswindows, clear_to_window_end);
1546 CONSOLE_HAS_METHOD (mswindows, clear_region);
1547 CONSOLE_HAS_METHOD (mswindows, clear_frame);
1548 CONSOLE_HAS_METHOD (mswindows, output_begin);
1549 CONSOLE_HAS_METHOD (mswindows, output_end);
1550 CONSOLE_HAS_METHOD (mswindows, flash);
1551 CONSOLE_HAS_METHOD (mswindows, ring_bell);