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
30 Partially rewritten for mswindows by Jonathan Harris, November 1997
36 #include "console-msw.h"
37 #include "objects-msw.h"
44 #include "glyphs-msw.h"
46 #include "redisplay.h"
52 #include "mule-charset.h"
55 #define MSWINDOWS_EOL_CURSOR_WIDTH 5
58 * Random forward declarations
60 static void mswindows_update_dc (HDC hdc, Lisp_Object fg, Lisp_Object bg,
62 static void mswindows_set_dc_font (HDC hdc, Lisp_Object font,
63 int under, int strike);
64 static void mswindows_output_vertical_divider (struct window *w, int clear);
65 static void mswindows_redraw_exposed_windows (Lisp_Object window, int x,
66 int y, int width, int height);
67 static void mswindows_output_dibitmap (struct frame *f,
68 Lisp_Image_Instance *p,
69 struct display_box* db,
70 struct display_glyph_area* dga);
72 typedef struct textual_run
80 /* Separate out the text in DYN into a series of textual runs of a
81 particular charset. Also convert the characters as necessary into
82 the format needed by XDrawImageString(), XDrawImageString16(), et
83 al. (This means converting to one or two byte format, possibly
84 tweaking the high bits, and possibly running a CCL program.) You
85 must pre-allocate the space used and pass it in. (This is done so
86 you can alloca() the space.) You need to allocate (2 * len) bytes
87 of TEXT_STORAGE and (len * sizeof (textual_run)) bytes of
88 RUN_STORAGE, where LEN is the length of the dynarr.
90 Returns the number of runs actually used. */
93 separate_textual_runs (unsigned char *text_storage,
94 textual_run *run_storage,
95 const Emchar *str, Charcount len)
97 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a
98 possible valid charset when
99 MULE is not defined */
103 struct ccl_program char_converter;
104 int need_ccl_conversion = 0;
107 for (i = 0; i < len; i++)
115 BREAKUP_CHAR (ch, charset, byte1, byte2);
116 dimension = XCHARSET_DIMENSION (charset);
117 graphic = XCHARSET_GRAPHIC (charset);
119 if (!EQ (charset, prev_charset))
121 run_storage[runs_so_far].ptr = text_storage;
122 run_storage[runs_so_far].charset = charset;
123 run_storage[runs_so_far].dimension = dimension;
127 run_storage[runs_so_far - 1].len =
128 text_storage - run_storage[runs_so_far - 1].ptr;
129 if (run_storage[runs_so_far - 1].dimension == 2)
130 run_storage[runs_so_far - 1].len >>= 1;
133 prev_charset = charset;
136 Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset);
137 need_ccl_conversion = !NILP (ccl_prog);
138 if (need_ccl_conversion)
139 setup_ccl_program (&char_converter, ccl_prog);
149 else if (graphic == 1)
155 if (need_ccl_conversion)
157 char_converter.reg[0] = XCHARSET_ID (charset);
158 char_converter.reg[1] = byte1;
159 char_converter.reg[2] = byte2;
160 char_converter.ic = 0; /* start at beginning each time */
161 ccl_driver (&char_converter, 0, 0, 0, 0, CCL_MODE_ENCODING);
162 byte1 = char_converter.reg[1];
163 byte2 = char_converter.reg[2];
166 *text_storage++ = (unsigned char) byte1;
168 *text_storage++ = (unsigned char) byte2;
173 run_storage[runs_so_far - 1].len =
174 text_storage - run_storage[runs_so_far - 1].ptr;
175 if (run_storage[runs_so_far - 1].dimension == 2)
176 run_storage[runs_so_far - 1].len >>= 1;
184 mswindows_text_width_single_run (HDC hdc, struct face_cachel *cachel,
187 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
188 Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
191 if (!fi->proportional_p || !hdc)
192 return (fi->width * run->len);
195 assert(run->dimension == 1); /* #### FIXME! */
196 mswindows_set_dc_font (hdc, font_inst,
197 cachel->underline, cachel->strikethru);
198 GetTextExtentPoint32 (hdc, run->ptr, run->len, &size);
204 * Given F, retrieve device context. F can be a display frame, or
208 get_frame_dc (struct frame *f)
210 if (FRAME_MSWINDOWS_P (f))
211 return FRAME_MSWINDOWS_DC (f);
214 if (!FRAME_MSPRINTER_PAGE_STARTED (f))
215 msprinter_start_page (f);
216 return DEVICE_MSPRINTER_HDC (XDEVICE (FRAME_DEVICE (f)));
221 * Given F, retrieve compatible device context. F can be a display
222 * frame, or a print job.
225 get_frame_compdc (struct frame *f)
227 if (FRAME_MSWINDOWS_P (f))
228 return FRAME_MSWINDOWS_CDC (f);
230 return FRAME_MSPRINTER_CDC (f);
233 /*****************************************************************************
236 Given a number of parameters munge the DC so it has those properties.
237 ****************************************************************************/
239 mswindows_update_dc (HDC hdc, Lisp_Object fg, Lisp_Object bg,
244 SetTextColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR
245 (XCOLOR_INSTANCE (fg)));
250 SetBkMode (hdc, OPAQUE);
251 SetBkColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (bg)));
255 SetBkMode (hdc, TRANSPARENT);
259 static void mswindows_set_dc_font (HDC hdc, Lisp_Object font,
260 int under, int strike)
262 SelectObject(hdc, mswindows_get_hfont (XFONT_INSTANCE (font),
266 /*****************************************************************************
267 mswindows_output_hline
269 Output a horizontal line in the foreground of its face.
270 ****************************************************************************/
272 mswindows_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
273 { /* XXX Implement me */
277 /*****************************************************************************
278 mswindows_output_blank
280 Output a blank by clearing the area it covers in the background color
282 ****************************************************************************/
284 mswindows_output_blank (struct window *w, struct display_line *dl,
285 struct rune *rb, int start_pixpos)
287 struct frame *f = XFRAME (w->frame);
288 HDC hdc = get_frame_dc (f);
289 RECT rect = { rb->xpos, DISPLAY_LINE_YPOS (dl),
291 DISPLAY_LINE_YEND (dl) };
292 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, rb->findex);
294 Lisp_Object bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
296 /* Unmap all subwindows in the area we are going to blank. */
297 redisplay_unmap_subwindows_maybe (f, rb->xpos, DISPLAY_LINE_YPOS (dl),
298 rb->width, DISPLAY_LINE_HEIGHT (dl));
300 if (!IMAGE_INSTANCEP (bg_pmap)
301 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
306 struct display_box db;
307 struct display_glyph_area dga;
308 redisplay_calculate_display_boxes (dl, rb->xpos,
309 /*rb->object.dglyph.xoffset*/ 0,
310 start_pixpos, rb->width,
312 /* blank the background in the appropriate color */
313 mswindows_update_dc (hdc, cachel->foreground,
314 cachel->background, Qnil);
315 redisplay_output_pixmap (w, bg_pmap, &db, &dga, rb->findex,
320 mswindows_update_dc (hdc, Qnil, cachel->background, Qnil);
321 ExtTextOut (hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
326 /*****************************************************************************
327 mswindows_output_cursor
329 Draw a normal or end-of-line cursor. The end-of-line cursor is
330 narrower than the normal cursor.
331 ****************************************************************************/
333 mswindows_output_cursor (struct window *w, struct display_line *dl, int xpos,
334 int width, face_index findex, Emchar ch, int image_p)
336 struct frame *f = XFRAME (w->frame);
337 struct device *d = XDEVICE (f->device);
338 struct face_cachel *cachel=0;
339 Lisp_Object font = Qnil;
340 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
341 HDC hdc = get_frame_dc (f);
342 unsigned int local_face_index=0;
346 DISPLAY_LINE_YPOS (dl),
348 DISPLAY_LINE_YEND (dl) };
349 Lisp_Object bar = symbol_value_in_buffer (Qbar_cursor,
351 int bar_p = image_p || !NILP (bar);
352 int cursor_p = !NILP (w->text_cursor_visible_p);
353 int real_char_p = ch != 0;
355 /* Unmap all subwindows in the area we are going to blank. */
356 redisplay_unmap_subwindows_maybe (f, xpos, DISPLAY_LINE_YPOS (dl),
357 width, DISPLAY_LINE_HEIGHT (dl));
361 /* Use the font from the underlying character */
362 cachel = WINDOW_FACE_CACHEL (w, findex);
364 /* #### MULE: Need to know the charset! */
365 font = FACE_CACHEL_FONT (cachel, Vcharset_ascii);
368 if ((focus || bar_p) && real_char_p)
370 p_char = (char*) &ch;
376 struct face_cachel *color_cachel;
378 /* Use cursor fg/bg for block cursor, or character fg/bg for the bar
379 or when we need to erase the cursor. Output nothing at eol if bar
381 local_face_index = get_builtin_face_cache_index (w, Vtext_cursor_face);
382 color_cachel = WINDOW_FACE_CACHEL (w, ((!cursor_p || bar_p) ?
383 findex : local_face_index));
384 mswindows_update_dc (hdc, color_cachel->foreground,
385 color_cachel->background, Qnil);
387 mswindows_set_dc_font (hdc, font,
388 cachel->underline, cachel->strikethru);
390 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE|ETO_CLIPPED, &rect, p_char, n_char, NULL);
398 rect.right = rect.left + (EQ (bar, Qt) ? 1 : min (2, width));
399 local_face_index = get_builtin_face_cache_index (w, Vtext_cursor_face);
400 cachel = WINDOW_FACE_CACHEL (w, local_face_index);
401 mswindows_update_dc (hdc, Qnil, cachel->background, Qnil);
402 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE, &rect, NULL, 0, NULL);
406 /* Now have real character drawn in its own color. We deflate
407 the rectangle so character cell will be bounded by the
408 previously drawn cursor shape */
409 InflateRect (&rect, -1, -1);
413 p_char = (char*) &ch;
417 local_face_index = get_builtin_face_cache_index (w, Vdefault_face);
418 cachel = WINDOW_FACE_CACHEL (w, (real_char_p ? findex : local_face_index));
419 mswindows_update_dc (hdc,
420 cachel->foreground, cachel->background, Qnil);
421 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE | ETO_CLIPPED,
422 &rect, p_char, n_char, NULL);
427 /*****************************************************************************
428 mswindows_output_string
430 Given a string and a starting position, output that string in the
432 Correctly handles multiple charsets in the string.
434 The meaning of the parameters is something like this:
436 W Window that the text is to be displayed in.
437 DL Display line that this text is on. The values in the
438 structure are used to determine the vertical position and
439 clipping range of the text.
440 BUF Dynamic array of Emchars specifying what is actually to be
442 XPOS X position in pixels where the text should start being drawn.
443 XOFFSET Number of pixels to be chopped off the left side of the
444 text. The effect is as if the text were shifted to the
445 left this many pixels and clipped at XPOS.
446 CLIP_START Clip everything left of this X position.
447 WIDTH Clip everything right of XPOS + WIDTH.
448 FINDEX Index for the face cache element describing how to display
450 ****************************************************************************/
452 mswindows_output_string (struct window *w, struct display_line *dl,
453 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
454 int width, face_index findex,
455 int cursor, int cursor_start, int cursor_width,
458 struct frame *f = XFRAME (w->frame);
459 /* struct device *d = XDEVICE (f->device);*/
461 HDC hdc = get_frame_dc (f);
464 int len = Dynarr_length (buf);
465 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
466 textual_run *runs = alloca_array (textual_run, len);
470 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
472 XSETWINDOW (window, w);
474 #if 0 /* #### FIXME? */
475 /* We can't work out the width before we've set the font in the DC */
477 width = mswindows_text_width (cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
482 /* Regularize the variables passed in. */
483 if (clip_start < xpos)
485 clip_end = xpos + width;
486 if (clip_start >= clip_end)
487 /* It's all clipped out. */
492 /* sort out the destination rectangle */
493 height = DISPLAY_LINE_HEIGHT (dl);
494 rect.left = clip_start;
495 rect.top = DISPLAY_LINE_YPOS (dl);
496 rect.right = clip_end;
497 rect.bottom = rect.top + height;
499 /* make sure the area we are about to display is subwindow free. */
500 redisplay_unmap_subwindows_maybe (f, clip_start, DISPLAY_LINE_YPOS (dl),
501 clip_end - clip_start, DISPLAY_LINE_HEIGHT (dl));
503 /* output the background pixmap if there is one */
504 bg_pmap = cachel->background_pixmap;
505 if (!IMAGE_INSTANCEP (bg_pmap)
506 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
511 struct display_box db;
512 struct display_glyph_area dga;
513 redisplay_calculate_display_boxes (dl, xpos + xoffset, 0,
514 clip_start, width, &db, &dga);
515 /* blank the background in the appropriate color */
516 mswindows_update_dc (hdc,
517 cachel->foreground, cachel->background, Qnil);
518 redisplay_output_pixmap (w, bg_pmap, &db, &dga, findex,
520 /* output pixmap calls this so we have to recall to get correct
522 cachel = WINDOW_FACE_CACHEL (w, findex);
525 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
526 Dynarr_length (buf));
528 for (i = 0; i < nruns; i++)
530 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
531 Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
534 if (EQ (font, Vthe_null_font_instance))
537 mswindows_update_dc (hdc, cachel->foreground,
538 NILP(bg_pmap) ? cachel->background : Qnil, Qnil);
539 mswindows_set_dc_font (hdc, font, cachel->underline, cachel->strikethru);
541 this_width = mswindows_text_width_single_run (hdc, cachel, runs + i);
543 /* cope with fonts taller than lines */
544 if ((int) fi->height < (int) (height + dl->clip + dl->top_clip))
546 int clear_start = max (xpos, clip_start);
547 int clear_end = min (xpos + this_width, clip_end);
550 redisplay_clear_region (window, findex, clear_start,
551 DISPLAY_LINE_YPOS (dl),
552 clear_end - clear_start,
554 /* output pixmap calls this so we have to recall to get correct
556 cachel = WINDOW_FACE_CACHEL (w, findex);
560 assert (runs[i].dimension == 1); /* #### FIXME: Broken when Mule? */
561 ExtTextOut (hdc, xpos, dl->ypos,
562 NILP(bg_pmap) ? ETO_CLIPPED | ETO_OPAQUE : ETO_CLIPPED,
563 &rect, (char *) runs[i].ptr, runs[i].len, NULL);
570 mswindows_output_dibitmap (struct frame *f, Lisp_Image_Instance *p,
571 struct display_box* db,
572 struct display_glyph_area* dga)
574 HDC hdc = get_frame_dc (f);
575 HDC hcompdc = get_frame_compdc (f);
577 COLORREF bgcolor = GetBkColor (hdc);
579 /* first blt the mask */
580 if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
583 col.rgbBlue = GetBValue (bgcolor);
584 col.rgbRed = GetRValue (bgcolor);
585 col.rgbGreen = GetGValue (bgcolor);
588 old = SelectObject (hcompdc, IMAGE_INSTANCE_MSWINDOWS_MASK (p));
590 SetDIBColorTable (hcompdc, 1, 1, &col);
594 dga->width, dga->height,
596 dga->xoffset, dga->yoffset,
599 SelectObject (hcompdc, old);
602 /* Now blt the bitmap itself, or one of its slices. */
603 old = SelectObject (hcompdc,
604 IMAGE_INSTANCE_MSWINDOWS_BITMAP_SLICE
605 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)));
609 dga->width, dga->height,
611 dga->xoffset, dga->yoffset,
612 IMAGE_INSTANCE_MSWINDOWS_MASK (p) ? SRCINVERT : SRCCOPY);
614 SelectObject (hcompdc, old);
617 /* X gc's have this nice property that setting the bg pixmap will
618 * output it offset relative to the window. Windows doesn't have this
619 * feature so we have to emulate this by outputting multiple pixmaps.
620 * This is only used for background pixmaps. Normal pixmaps are
621 * outputted once and are scrollable */
623 mswindows_output_dibitmap_region (struct frame *f,
624 Lisp_Image_Instance *p,
625 struct display_box *db,
626 struct display_glyph_area *dga)
628 struct display_box xdb = { db->xpos, db->ypos, db->width, db->height };
629 struct display_glyph_area xdga
630 = { 0, 0, IMAGE_INSTANCE_PIXMAP_WIDTH (p),
631 IMAGE_INSTANCE_PIXMAP_HEIGHT (p) };
632 int pxoffset = 0, pyoffset = 0;
636 xdga.width = dga->width;
637 xdga.height = dga->height;
639 else if (!redisplay_normalize_glyph_area (&xdb, &xdga))
642 /* when doing a bg pixmap do a partial pixmap first so that we
643 blt whole pixmaps thereafter */
644 xdga.height = min (xdga.height, IMAGE_INSTANCE_PIXMAP_HEIGHT (p) -
645 db->ypos % IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
647 while (xdga.height > 0)
649 xdga.width = min (min (db->width, IMAGE_INSTANCE_PIXMAP_WIDTH (p)),
650 IMAGE_INSTANCE_PIXMAP_WIDTH (p) -
651 db->xpos % IMAGE_INSTANCE_PIXMAP_WIDTH (p));
653 while (xdga.width > 0)
655 xdb.xpos = db->xpos + pxoffset;
656 xdb.ypos = db->ypos + pyoffset;
657 /* do we need to offset the pixmap vertically? this is necessary
658 for background pixmaps. */
659 xdga.yoffset = xdb.ypos % IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
660 xdga.xoffset = xdb.xpos % IMAGE_INSTANCE_PIXMAP_WIDTH (p);
661 /* the width is handled by mswindows_output_pixmap_region */
662 mswindows_output_dibitmap (f, p, &xdb, &xdga);
663 pxoffset += xdga.width;
664 xdga.width = min ((db->width - pxoffset),
665 IMAGE_INSTANCE_PIXMAP_WIDTH (p));
667 pyoffset += xdga.height;
668 xdga.height = min ((db->height - pyoffset),
669 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
673 /* Output a pixmap at the desired location.
674 DB normalized display_box.
675 DGA normalized display_glyph_area. */
677 mswindows_output_pixmap (struct window *w, Lisp_Object image_instance,
678 struct display_box *db, struct display_glyph_area *dga,
679 face_index findex, int cursor_start, int cursor_width,
680 int cursor_height, int bg_pixmap)
682 struct frame *f = XFRAME (w->frame);
683 HDC hdc = get_frame_dc (f);
685 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
688 XSETWINDOW (window, w);
690 /* Output the pixmap. Have to do this as many times as is required
691 to fill the given area */
692 mswindows_update_dc (hdc,
693 WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
694 WINDOW_FACE_CACHEL_BACKGROUND (w, findex), Qnil);
697 mswindows_output_dibitmap_region (f, p, db, dga);
699 mswindows_output_dibitmap (f, p, db, dga);
702 #ifdef HAVE_SCROLLBARS
704 * This function paints window's deadbox, a rectangle between window
705 * borders and two short edges of both scrollbars.
707 * Function checks whether deadbox intersects with the rectangle pointed
708 * to by PRC, and paints only the intersection
711 mswindows_redisplay_deadbox_maybe (struct window *w, const RECT* prc)
713 int sbh = window_scrollbar_height (w);
714 int sbw = window_scrollbar_width (w);
715 RECT rect_dead, rect_paint;
716 if (sbh == 0 || sbw == 0)
719 if (!NILP (w->scrollbar_on_left_p))
720 rect_dead.left = WINDOW_LEFT (w);
722 rect_dead.left = WINDOW_TEXT_RIGHT (w);
723 rect_dead.right = rect_dead.left + sbw;
725 if (!NILP (w->scrollbar_on_top_p))
726 rect_dead.top = WINDOW_TOP (w);
728 rect_dead.top = WINDOW_TEXT_BOTTOM (w);
729 rect_dead.bottom = rect_dead.top + sbh;
731 if (IntersectRect (&rect_paint, &rect_dead, prc))
733 struct frame *f = XFRAME (WINDOW_FRAME (w));
734 FillRect (get_frame_dc (f), &rect_paint,
735 (HBRUSH) (COLOR_BTNFACE+1));
739 #endif /* HAVE_SCROLLBARS */
741 /*****************************************************************************
742 mswindows_redraw_exposed_window
744 Given a bounding box for an area that needs to be redrawn, determine
745 what parts of what lines are contained within and re-output their
747 Copied from redisplay-x.c
748 ****************************************************************************/
750 mswindows_redraw_exposed_window (struct window *w, int x, int y, int width,
753 struct frame *f = XFRAME (w->frame);
755 int orig_windows_structure_changed;
756 RECT rect_window = { WINDOW_LEFT (w), WINDOW_TOP (w),
757 WINDOW_RIGHT (w), WINDOW_BOTTOM (w) };
758 RECT rect_expose = { x, y, x + width, y + height };
761 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
763 if (!NILP (w->vchild))
765 mswindows_redraw_exposed_windows (w->vchild, x, y, width, height);
768 else if (!NILP (w->hchild))
770 mswindows_redraw_exposed_windows (w->hchild, x, y, width, height);
774 /* If the window doesn't intersect the exposed region, we're done here. */
775 if (!IntersectRect (&rect_draw, &rect_window, &rect_expose))
778 /* We do this to make sure that the 3D modelines get redrawn if
779 they are in the exposed region. */
780 orig_windows_structure_changed = f->windows_structure_changed;
781 f->windows_structure_changed = 1;
783 if (window_needs_vertical_divider (w))
785 mswindows_output_vertical_divider (w, 0);
788 for (line = 0; line < Dynarr_length (cdla); line++)
790 struct display_line *cdl = Dynarr_atp (cdla, line);
792 if (DISPLAY_LINE_YPOS (cdl) + DISPLAY_LINE_HEIGHT (cdl)
795 if (DISPLAY_LINE_YPOS (cdl) > rect_draw.bottom)
804 output_display_line (w, 0, cdla, line,
805 rect_draw.left, rect_draw.right);
810 f->windows_structure_changed = orig_windows_structure_changed;
812 /* If there have never been any face cache_elements created, then this
813 expose event doesn't actually have anything to do. */
814 if (Dynarr_largest (w->face_cachels))
815 redisplay_clear_bottom_of_window (w, cdla, rect_draw.top, rect_draw.bottom);
817 #ifdef HAVE_SCROLLBARS
818 mswindows_redisplay_deadbox_maybe (w, &rect_expose);
822 /*****************************************************************************
823 mswindows_redraw_exposed_windows
825 For each window beneath the given window in the window hierarchy,
826 ensure that it is redrawn if necessary after an Expose event.
827 ****************************************************************************/
829 mswindows_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
832 for (; !NILP (window); window = XWINDOW (window)->next)
833 mswindows_redraw_exposed_window (XWINDOW (window), x, y, width, height);
836 /*****************************************************************************
837 mswindows_redraw_exposed_area
839 For each window on the given frame, ensure that any area in the
840 Exposed area is redrawn.
841 ****************************************************************************/
843 mswindows_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
845 /* If any window on the frame has had its face cache reset then the
846 redisplay structures are effectively invalid. If we attempt to
847 use them we'll blow up. We mark the frame as changed to ensure
848 that redisplay will do a full update. This probably isn't
849 necessary but it can't hurt. */
851 /* #### We would rather put these off as well but there is currently
852 no combination of flags which will force an unchanged toolbar to
854 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
856 redraw_exposed_gutters (f, x, y, width, height);
858 if (!f->window_face_cache_reset)
860 mswindows_redraw_exposed_windows (f->root_window, x, y, width, height);
864 MARK_FRAME_CHANGED (f);
868 /*****************************************************************************
871 Draw a 3d border around the specified area on window W.
872 ****************************************************************************/
874 mswindows_bevel_area (struct window *w, face_index findex, int x, int y,
875 int width, int height, int thickness,
876 int edges, enum edge_style style)
878 struct frame *f = XFRAME (w->frame);
882 if (style == EDGE_ETCHED_IN)
884 else if (style == EDGE_ETCHED_OUT)
886 else if (style == EDGE_BEVEL_IN)
889 edge = BDR_SUNKENINNER;
893 else /* EDGE_BEVEL_OUT */
896 edge = BDR_RAISEDINNER;
901 if (edges & EDGE_TOP)
903 if (edges & EDGE_LEFT)
905 if (edges & EDGE_BOTTOM)
907 if (edges & EDGE_RIGHT)
911 RECT rect = { x, y, x + width, y + height };
912 Lisp_Object color = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
913 HDC hdc = get_frame_dc (f);
915 mswindows_update_dc (hdc, Qnil, color, Qnil);
916 DrawEdge (hdc, &rect, edge, border);
921 /*****************************************************************************
923 *****************************************************************************/
925 /*****************************************************************************
926 mswindows_divider_height
928 Return the height of the horizontal divider.
929 ****************************************************************************/
931 mswindows_divider_height (void)
933 return 1; /* XXX Copied from redisplay-X.c. What is this? */
936 /*****************************************************************************
937 mswindows_eol_cursor_width
939 Return the width of the end-of-line cursor.
940 ****************************************************************************/
942 mswindows_eol_cursor_width (void)
944 return MSWINDOWS_EOL_CURSOR_WIDTH;
947 /*****************************************************************************
948 mswindows_output_begin
950 Perform any necessary initialization prior to an update.
951 ****************************************************************************/
953 mswindows_output_begin (struct device *d)
957 /*****************************************************************************
960 Perform any necessary flushing of queues when an update has completed.
961 ****************************************************************************/
963 mswindows_output_end (struct device *d)
969 mswindows_flash (struct device *d)
971 struct frame *f = device_selected_frame (d);
972 HDC hdc = get_frame_dc (f);
975 GetClientRect (FRAME_MSWINDOWS_HANDLE (f), &rc);
976 InvertRect (hdc, &rc);
979 InvertRect (hdc, &rc);
985 mswindows_ring_bell (struct device *d, int volume, int pitch, int duration)
987 /* Beep does not work at all, anyways! -kkm */
991 /*****************************************************************************
992 mswindows_output_display_block
994 Given a display line, a block number for that start line, output all
995 runes between start and end in the specified display block.
996 Ripped off with minimal thought from the corresponding X routine.
997 ****************************************************************************/
999 mswindows_output_display_block (struct window *w, struct display_line *dl, int block,
1000 int start, int end, int start_pixpos, int cursor_start,
1001 int cursor_width, int cursor_height)
1003 struct frame *f = XFRAME (w->frame);
1004 Emchar_dynarr *buf = Dynarr_new (Emchar);
1007 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
1008 rune_dynarr *rba = db->runes;
1014 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
1015 MULE is not defined */
1016 XSETWINDOW (window, w);
1017 rb = Dynarr_atp (rba, start);
1020 /* Nothing to do so don't do anything. */
1023 findex = rb->findex;
1026 if (rb->type == RUNE_CHAR)
1027 charset = CHAR_CHARSET (rb->object.chr.ch);
1030 end = Dynarr_length (rba);
1035 rb = Dynarr_atp (rba, elt);
1037 if (rb->findex == findex && rb->type == RUNE_CHAR
1038 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
1039 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
1041 Dynarr_add (buf, rb->object.chr.ch);
1047 if (Dynarr_length (buf))
1049 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
1050 findex, 0, 0, 0, 0);
1057 if (rb->type == RUNE_CHAR)
1059 findex = rb->findex;
1061 charset = CHAR_CHARSET (rb->object.chr.ch);
1063 if (rb->cursor_type == CURSOR_ON)
1065 if (rb->object.chr.ch == '\n')
1067 mswindows_output_cursor (w, dl, xpos, cursor_width,
1072 Dynarr_add (buf, rb->object.chr.ch);
1073 mswindows_output_cursor (w, dl, xpos, cursor_width,
1074 findex, rb->object.chr.ch, 0);
1081 else if (rb->object.chr.ch == '\n')
1083 /* Clear in case a cursor was formerly here. */
1084 redisplay_clear_region (window, findex, xpos,
1085 DISPLAY_LINE_YPOS (dl),
1086 rb->width, DISPLAY_LINE_HEIGHT (dl));
1090 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
1092 if (rb->type == RUNE_BLANK)
1093 mswindows_output_blank (w, dl, rb, start_pixpos);
1096 /* #### Our flagging of when we need to redraw the
1097 modeline shadows sucks. Since RUNE_HLINE is only used
1098 by the modeline at the moment it is a good bet
1099 that if it gets redrawn then we should also
1100 redraw the shadows. This won't be true forever.
1101 We borrow the shadow_thickness_changed flag for
1103 w->shadow_thickness_changed = 1;
1104 mswindows_output_hline (w, dl, rb);
1107 if (rb->cursor_type == CURSOR_ON)
1108 mswindows_output_cursor (w, dl, xpos, cursor_width, rb->findex, 0, 0);
1113 rb = Dynarr_atp (rba, elt);
1115 findex = rb->findex;
1119 else if (rb->type == RUNE_DGLYPH)
1121 Lisp_Object instance;
1122 struct display_box dbox;
1123 struct display_glyph_area dga;
1124 redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset,
1125 start_pixpos, rb->width,
1128 XSETWINDOW (window, w);
1129 instance = glyph_image_instance (rb->object.dglyph.glyph,
1130 window, ERROR_ME_NOT, 1);
1131 findex = rb->findex;
1133 if (IMAGE_INSTANCEP (instance))
1134 switch (XIMAGE_INSTANCE_TYPE (instance))
1138 /* #### This is way losing. See the comment in
1139 add_glyph_rune(). */
1140 Lisp_Object string =
1141 XIMAGE_INSTANCE_TEXT_STRING (instance);
1142 convert_bufbyte_string_into_emchar_dynarr
1143 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
1145 if (rb->cursor_type == CURSOR_ON)
1146 mswindows_output_cursor (w, dl, xpos, cursor_width,
1147 findex, Dynarr_at (buf, 0), 0);
1148 else /* #### redisplay-x passes -1 as the width: why ? */
1149 mswindows_output_string (w, dl, buf, xpos,
1150 rb->object.dglyph.xoffset,
1151 start_pixpos, rb->width, findex,
1157 case IMAGE_MONO_PIXMAP:
1158 case IMAGE_COLOR_PIXMAP:
1159 redisplay_output_pixmap (w, instance, &dbox, &dga, findex,
1160 cursor_start, cursor_width,
1162 if (rb->cursor_type == CURSOR_ON)
1163 mswindows_output_cursor (w, dl, xpos, cursor_width,
1170 case IMAGE_SUBWINDOW:
1172 redisplay_output_subwindow (w, instance, &dbox, &dga, findex,
1173 cursor_start, cursor_width,
1175 if (rb->cursor_type == CURSOR_ON)
1176 mswindows_output_cursor (w, dl, xpos, cursor_width,
1181 redisplay_output_layout (w, instance, &dbox, &dga, findex,
1182 cursor_start, cursor_width,
1184 if (rb->cursor_type == CURSOR_ON)
1185 mswindows_output_cursor (w, dl, xpos, cursor_width,
1190 /* nothing is as nothing does */
1205 if (Dynarr_length (buf))
1206 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
1210 && !EQ (Qzero, w->modeline_shadow_thickness)
1212 || f->windows_structure_changed
1213 || w->shadow_thickness_changed))
1214 bevel_modeline (w, dl);
1220 /*****************************************************************************
1221 mswindows_output_vertical_divider
1223 Draw a vertical divider down the right side of the given window.
1224 ****************************************************************************/
1226 mswindows_output_vertical_divider (struct window *w, int clear_unused)
1228 struct frame *f = XFRAME (w->frame);
1229 HDC hdc = get_frame_dc (f);
1231 int spacing = XINT (w->vertical_divider_spacing);
1232 int shadow = XINT (w->vertical_divider_shadow_thickness);
1233 int abs_shadow = abs (shadow);
1234 int line_width = XINT (w->vertical_divider_line_width);
1235 int div_left = WINDOW_RIGHT (w) - window_divider_width (w);
1236 int y1 = WINDOW_TOP (w) + FRAME_TOP_GUTTER_BOUNDS (f);
1237 int y2 = WINDOW_BOTTOM (w) + FRAME_BOTTOM_GUTTER_BOUNDS (f);
1239 /* Clear left and right spacing areas */
1244 mswindows_update_dc (hdc, Qnil,
1245 WINDOW_FACE_CACHEL_BACKGROUND (w, DEFAULT_INDEX), Qnil);
1246 rect.right = WINDOW_RIGHT (w);
1247 rect.left = rect.right - spacing;
1248 ExtTextOut (hdc, 0, 0, ETO_OPAQUE,
1249 &rect, NULL, 0, NULL);
1250 rect.left = div_left;
1251 rect.right = div_left + spacing;
1252 ExtTextOut (hdc, 0, 0, ETO_OPAQUE,
1253 &rect, NULL, 0, NULL);
1256 /* Clear divider face */
1257 rect.top = y1 + abs_shadow;
1258 rect.bottom = y2 - abs_shadow;
1259 rect.left = div_left + spacing + abs_shadow;
1260 rect.right = rect.left + line_width;
1261 if (rect.left < rect.right)
1264 = get_builtin_face_cache_index (w, Vvertical_divider_face);
1265 mswindows_update_dc (hdc, Qnil,
1266 WINDOW_FACE_CACHEL_BACKGROUND (w, div_face), Qnil);
1267 ExtTextOut (hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
1270 /* Draw a shadow around the divider */
1273 /* #### This will be fixed to support arbitrary thickness */
1274 InflateRect (&rect, abs_shadow, abs_shadow);
1275 DrawEdge (hdc, &rect,
1276 shadow > 0 ? EDGE_RAISED : EDGE_SUNKEN, BF_RECT);
1280 /****************************************************************************
1281 mswindows_text_width
1283 Given a string and a face, return the string's length in pixels when
1284 displayed in the font associated with the face.
1285 ****************************************************************************/
1287 mswindows_text_width (struct frame *f, struct face_cachel *cachel,
1288 const Emchar *str, Charcount len)
1290 HDC hdc = get_frame_dc (f);
1291 int width_so_far = 0;
1292 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
1293 textual_run *runs = alloca_array (textual_run, len);
1297 nruns = separate_textual_runs (text_storage, runs, str, len);
1299 for (i = 0; i < nruns; i++)
1300 width_so_far += mswindows_text_width_single_run (hdc,
1303 return width_so_far;
1307 /****************************************************************************
1308 mswindows_clear_region
1310 Clear the area in the box defined by the given parameters using the
1312 ****************************************************************************/
1314 mswindows_clear_region (Lisp_Object locale, struct device* d, struct frame* f,
1315 face_index findex, int x, int y,
1316 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1317 Lisp_Object background_pixmap)
1319 RECT rect = { x, y, x+width, y+height };
1320 HDC hdc = get_frame_dc (f);
1322 if (!NILP (background_pixmap))
1324 struct display_box db = { x, y, width, height };
1325 mswindows_update_dc (hdc,
1326 fcolor, bcolor, background_pixmap);
1327 mswindows_output_dibitmap_region
1328 ( f, XIMAGE_INSTANCE (background_pixmap), &db, 0);
1332 mswindows_update_dc (hdc, Qnil, fcolor, Qnil);
1333 ExtTextOut (hdc, 0, 0, ETO_OPAQUE,
1334 &rect, NULL, 0, NULL);
1337 #ifdef HAVE_SCROLLBARS
1338 if (WINDOWP (locale))
1339 mswindows_redisplay_deadbox_maybe (XWINDOW (locale), &rect);
1343 /* XXX Implement me! */
1345 mswindows_clear_frame (struct frame *f)
1352 /************************************************************************/
1353 /* initialization */
1354 /************************************************************************/
1357 console_type_create_redisplay_mswindows (void)
1359 /* redisplay methods - display*/
1360 CONSOLE_HAS_METHOD (mswindows, text_width);
1361 CONSOLE_HAS_METHOD (mswindows, output_display_block);
1362 CONSOLE_HAS_METHOD (mswindows, divider_height);
1363 CONSOLE_HAS_METHOD (mswindows, eol_cursor_width);
1364 CONSOLE_HAS_METHOD (mswindows, output_vertical_divider);
1365 CONSOLE_HAS_METHOD (mswindows, clear_region);
1366 CONSOLE_HAS_METHOD (mswindows, clear_frame);
1367 CONSOLE_HAS_METHOD (mswindows, output_begin);
1368 CONSOLE_HAS_METHOD (mswindows, output_end);
1369 CONSOLE_HAS_METHOD (mswindows, flash);
1370 CONSOLE_HAS_METHOD (mswindows, ring_bell);
1371 CONSOLE_HAS_METHOD (mswindows, bevel_area);
1372 CONSOLE_HAS_METHOD (mswindows, output_string);
1373 CONSOLE_HAS_METHOD (mswindows, output_pixmap);
1375 /* redisplay methods - printer */
1376 CONSOLE_INHERITS_METHOD (msprinter, mswindows, text_width);
1377 CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_display_block);
1378 CONSOLE_INHERITS_METHOD (msprinter, mswindows, divider_height);
1379 CONSOLE_INHERITS_METHOD (msprinter, mswindows, eol_cursor_width);
1380 CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_vertical_divider);
1381 CONSOLE_INHERITS_METHOD (msprinter, mswindows, clear_region);
1382 CONSOLE_INHERITS_METHOD (msprinter, mswindows, clear_frame);
1383 CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_begin);
1384 CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_end);
1385 CONSOLE_INHERITS_METHOD (msprinter, mswindows, bevel_area);
1386 CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_string);
1387 CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_pixmap);