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 "character.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 if ((!NILP (ccl_prog))
138 && (setup_ccl_program (&char_converter, ccl_prog) >= 0))
139 need_ccl_conversion = 1;
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
205 * a print job. For a print job, page is also started when printer's
206 * device context is first time requested.
209 get_frame_dc (struct frame *f, int start_page_p)
211 if (FRAME_MSWINDOWS_P (f))
212 return FRAME_MSWINDOWS_DC (f);
215 if (start_page_p && !FRAME_MSPRINTER_PAGE_STARTED (f))
216 msprinter_start_page (f);
217 return DEVICE_MSPRINTER_HDC (XDEVICE (FRAME_DEVICE (f)));
222 * Given F, retrieve compatible device context. F can be a display
223 * frame, or a print job.
226 get_frame_compdc (struct frame *f)
228 struct device *d = XDEVICE (FRAME_DEVICE (f));
229 if (DEVICE_MSWINDOWS_P (d))
230 return DEVICE_MSWINDOWS_HCDC (d);
232 return DEVICE_MSPRINTER_HCDC (d);
235 /*****************************************************************************
238 Given a number of parameters munge the DC so it has those properties.
239 ****************************************************************************/
241 mswindows_update_dc (HDC hdc, Lisp_Object fg, Lisp_Object bg,
246 SetTextColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR
247 (XCOLOR_INSTANCE (fg)));
252 SetBkMode (hdc, OPAQUE);
253 SetBkColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (bg)));
257 SetBkMode (hdc, TRANSPARENT);
261 static void mswindows_set_dc_font (HDC hdc, Lisp_Object font,
262 int under, int strike)
264 SelectObject(hdc, mswindows_get_hfont (XFONT_INSTANCE (font),
268 /*****************************************************************************
269 mswindows_output_hline
271 Output a horizontal line in the foreground of its face.
272 ****************************************************************************/
274 mswindows_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
275 { /* XXX Implement me */
279 /*****************************************************************************
280 mswindows_output_blank
282 Output a blank by clearing the area it covers in the background color
284 ****************************************************************************/
286 mswindows_output_blank (struct window *w, struct display_line *dl,
287 struct rune *rb, int start_pixpos)
289 struct frame *f = XFRAME (w->frame);
290 HDC hdc = get_frame_dc (f, 1);
291 RECT rect = { rb->xpos, DISPLAY_LINE_YPOS (dl),
293 DISPLAY_LINE_YEND (dl) };
294 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, rb->findex);
296 Lisp_Object bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
298 /* Unmap all subwindows in the area we are going to blank. */
299 redisplay_unmap_subwindows_maybe (f, rb->xpos, DISPLAY_LINE_YPOS (dl),
300 rb->width, DISPLAY_LINE_HEIGHT (dl));
302 if (!IMAGE_INSTANCEP (bg_pmap)
303 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
308 struct display_box db;
309 struct display_glyph_area dga;
310 redisplay_calculate_display_boxes (dl, rb->xpos,
311 /*rb->object.dglyph.xoffset*/ 0,
312 /*rb->object.dglyph.yoffset*/ 0,
313 start_pixpos, rb->width,
315 /* blank the background in the appropriate color */
316 mswindows_update_dc (hdc, cachel->foreground,
317 cachel->background, Qnil);
318 redisplay_output_pixmap (w, bg_pmap, &db, &dga, rb->findex,
323 mswindows_update_dc (hdc, Qnil, cachel->background, Qnil);
324 ExtTextOut (hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
329 /*****************************************************************************
330 mswindows_output_cursor
332 Draw a normal or end-of-line cursor. The end-of-line cursor is
333 narrower than the normal cursor.
334 ****************************************************************************/
336 mswindows_output_cursor (struct window *w, struct display_line *dl, int xpos,
337 int width, face_index findex, Emchar ch, int image_p)
339 struct frame *f = XFRAME (w->frame);
340 struct device *d = XDEVICE (f->device);
341 struct face_cachel *cachel=0;
342 Lisp_Object font = Qnil;
343 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
344 HDC hdc = get_frame_dc (f, 1);
345 unsigned int local_face_index=0;
349 DISPLAY_LINE_YPOS (dl),
351 DISPLAY_LINE_YEND (dl) };
352 Lisp_Object bar = symbol_value_in_buffer (Qbar_cursor,
354 int bar_p = image_p || !NILP (bar);
355 int cursor_p = !NILP (w->text_cursor_visible_p);
356 int real_char_p = ch != 0;
358 /* Unmap all subwindows in the area we are going to blank. */
359 redisplay_unmap_subwindows_maybe (f, xpos, DISPLAY_LINE_YPOS (dl),
360 width, DISPLAY_LINE_HEIGHT (dl));
364 /* Use the font from the underlying character */
365 cachel = WINDOW_FACE_CACHEL (w, findex);
367 /* #### MULE: Need to know the charset! */
368 font = FACE_CACHEL_FONT (cachel, Vcharset_ascii);
371 if ((focus || bar_p) && real_char_p)
373 p_char = (char*) &ch;
379 struct face_cachel *color_cachel;
381 /* Use cursor fg/bg for block cursor, or character fg/bg for the bar
382 or when we need to erase the cursor. Output nothing at eol if bar
384 local_face_index = get_builtin_face_cache_index (w, Vtext_cursor_face);
385 color_cachel = WINDOW_FACE_CACHEL (w, ((!cursor_p || bar_p) ?
386 findex : local_face_index));
387 mswindows_update_dc (hdc, color_cachel->foreground,
388 color_cachel->background, Qnil);
390 mswindows_set_dc_font (hdc, font,
391 cachel->underline, cachel->strikethru);
393 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE|ETO_CLIPPED, &rect, p_char, n_char, NULL);
401 rect.right = rect.left + (EQ (bar, Qt) ? 1 : min (2, width));
402 local_face_index = get_builtin_face_cache_index (w, Vtext_cursor_face);
403 cachel = WINDOW_FACE_CACHEL (w, local_face_index);
404 mswindows_update_dc (hdc, Qnil, cachel->background, Qnil);
405 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE, &rect, NULL, 0, NULL);
409 /* Now have real character drawn in its own color. We deflate
410 the rectangle so character cell will be bounded by the
411 previously drawn cursor shape */
412 InflateRect (&rect, -1, -1);
416 p_char = (char*) &ch;
420 local_face_index = get_builtin_face_cache_index (w, Vdefault_face);
421 cachel = WINDOW_FACE_CACHEL (w, (real_char_p ? findex : local_face_index));
422 mswindows_update_dc (hdc,
423 cachel->foreground, cachel->background, Qnil);
424 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE | ETO_CLIPPED,
425 &rect, p_char, n_char, NULL);
430 /*****************************************************************************
431 mswindows_output_string
433 Given a string and a starting position, output that string in the
435 Correctly handles multiple charsets in the string.
437 The meaning of the parameters is something like this:
439 W Window that the text is to be displayed in.
440 DL Display line that this text is on. The values in the
441 structure are used to determine the vertical position and
442 clipping range of the text.
443 BUF Dynamic array of Emchars specifying what is actually to be
445 XPOS X position in pixels where the text should start being drawn.
446 XOFFSET Number of pixels to be chopped off the left side of the
447 text. The effect is as if the text were shifted to the
448 left this many pixels and clipped at XPOS.
449 CLIP_START Clip everything left of this X position.
450 WIDTH Clip everything right of XPOS + WIDTH.
451 FINDEX Index for the face cache element describing how to display
453 ****************************************************************************/
455 mswindows_output_string (struct window *w, struct display_line *dl,
456 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
457 int width, face_index findex,
458 int cursor, int cursor_start, int cursor_width,
461 struct frame *f = XFRAME (w->frame);
462 /* struct device *d = XDEVICE (f->device);*/
464 HDC hdc = get_frame_dc (f, 1);
467 int len = Dynarr_length (buf);
468 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
469 textual_run *runs = alloca_array (textual_run, len);
473 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
475 XSETWINDOW (window, w);
477 #if 0 /* #### FIXME? */
478 /* We can't work out the width before we've set the font in the DC */
480 width = mswindows_text_width (cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
485 /* Regularize the variables passed in. */
486 if (clip_start < xpos)
488 clip_end = xpos + width;
489 if (clip_start >= clip_end)
490 /* It's all clipped out. */
495 /* sort out the destination rectangle */
496 height = DISPLAY_LINE_HEIGHT (dl);
497 rect.left = clip_start;
498 rect.top = DISPLAY_LINE_YPOS (dl);
499 rect.right = clip_end;
500 rect.bottom = rect.top + height;
502 /* make sure the area we are about to display is subwindow free. */
503 redisplay_unmap_subwindows_maybe (f, clip_start, DISPLAY_LINE_YPOS (dl),
504 clip_end - clip_start, DISPLAY_LINE_HEIGHT (dl));
506 /* output the background pixmap if there is one */
507 bg_pmap = cachel->background_pixmap;
508 if (!IMAGE_INSTANCEP (bg_pmap)
509 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
514 struct display_box db;
515 struct display_glyph_area dga;
516 redisplay_calculate_display_boxes (dl, xpos + xoffset, 0, 0,
517 clip_start, width, &db, &dga);
518 /* blank the background in the appropriate color */
519 mswindows_update_dc (hdc,
520 cachel->foreground, cachel->background, Qnil);
521 redisplay_output_pixmap (w, bg_pmap, &db, &dga, findex,
523 /* output pixmap calls this so we have to recall to get correct
525 cachel = WINDOW_FACE_CACHEL (w, findex);
528 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
529 Dynarr_length (buf));
531 for (i = 0; i < nruns; i++)
533 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
534 Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
537 if (EQ (font, Vthe_null_font_instance))
540 mswindows_update_dc (hdc, cachel->foreground,
541 NILP(bg_pmap) ? cachel->background : Qnil, Qnil);
542 mswindows_set_dc_font (hdc, font, cachel->underline, cachel->strikethru);
544 this_width = mswindows_text_width_single_run (hdc, cachel, runs + i);
546 /* cope with fonts taller than lines */
547 if ((int) fi->height < (int) (height + dl->clip + dl->top_clip))
549 int clear_start = max (xpos, clip_start);
550 int clear_end = min (xpos + this_width, clip_end);
553 redisplay_clear_region (window, findex, clear_start,
554 DISPLAY_LINE_YPOS (dl),
555 clear_end - clear_start,
557 /* output pixmap calls this so we have to recall to get correct
559 cachel = WINDOW_FACE_CACHEL (w, findex);
563 assert (runs[i].dimension == 1); /* #### FIXME: Broken when Mule? */
564 ExtTextOut (hdc, xpos, dl->ypos,
565 NILP(bg_pmap) ? ETO_CLIPPED | ETO_OPAQUE : ETO_CLIPPED,
566 &rect, (char *) runs[i].ptr, runs[i].len, NULL);
573 mswindows_output_dibitmap (struct frame *f, Lisp_Image_Instance *p,
574 struct display_box* db,
575 struct display_glyph_area* dga)
577 HDC hdc = get_frame_dc (f, 1);
578 HDC hcompdc = get_frame_compdc (f);
580 const int real_x = IMAGE_INSTANCE_MSWINDOWS_BITMAP_REAL_WIDTH (p);
581 const int real_y = IMAGE_INSTANCE_MSWINDOWS_BITMAP_REAL_HEIGHT (p);
582 const int surface_x = IMAGE_INSTANCE_PIXMAP_WIDTH (p);
583 const int surface_y = IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
585 /* first blit the mask */
586 if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
591 old = SelectObject (hcompdc, IMAGE_INSTANCE_MSWINDOWS_MASK (p));
593 if (IMAGE_INSTANCE_TYPE (p) == IMAGE_MONO_PIXMAP)
598 fgcolor = GetTextColor (hdc);
599 fg.rgbBlue = GetBValue (fgcolor);
600 fg.rgbRed = GetRValue (fgcolor);
601 fg.rgbGreen = GetGValue (fgcolor);
603 SetDIBColorTable (hcompdc, 0, 1, &fg);
606 bgcolor = GetBkColor (hdc);
607 bg.rgbBlue = GetBValue (bgcolor);
608 bg.rgbRed = GetRValue (bgcolor);
609 bg.rgbGreen = GetGValue (bgcolor);
611 SetDIBColorTable (hcompdc, 1, 1, &bg);
615 dga->width, dga->height,
617 MulDiv (dga->xoffset, real_x, surface_x),
618 MulDiv (dga->yoffset, real_y, surface_y),
619 MulDiv (dga->width, real_x, surface_x),
620 MulDiv (dga->height, real_y, surface_y),
623 SelectObject (hcompdc, old);
626 /* Now blit the bitmap itself, or one of its slices. */
627 old = SelectObject (hcompdc,
628 IMAGE_INSTANCE_MSWINDOWS_BITMAP_SLICE
629 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)));
633 dga->width, dga->height,
635 MulDiv (dga->xoffset, real_x, surface_x),
636 MulDiv (dga->yoffset, real_y, surface_y),
637 MulDiv (dga->width, real_x, surface_x),
638 MulDiv (dga->height, real_y, surface_y),
639 IMAGE_INSTANCE_MSWINDOWS_MASK (p) ? SRCINVERT : SRCCOPY);
641 SelectObject (hcompdc, old);
644 /* X gc's have this nice property that setting the bg pixmap will
645 * output it offset relative to the window. Windows doesn't have this
646 * feature so we have to emulate this by outputting multiple pixmaps.
647 * This is only used for background pixmaps. Normal pixmaps are
648 * outputted once and are scrollable */
650 mswindows_output_dibitmap_region (struct frame *f,
651 Lisp_Image_Instance *p,
652 struct display_box *db,
653 struct display_glyph_area *dga)
655 struct display_box xdb = { db->xpos, db->ypos, db->width, db->height };
656 struct display_glyph_area xdga
657 = { 0, 0, IMAGE_INSTANCE_PIXMAP_WIDTH (p),
658 IMAGE_INSTANCE_PIXMAP_HEIGHT (p) };
659 int pxoffset = 0, pyoffset = 0;
663 xdga.width = dga->width;
664 xdga.height = dga->height;
666 else if (!redisplay_normalize_glyph_area (&xdb, &xdga))
669 /* when doing a bg pixmap do a partial pixmap first so that we
670 blt whole pixmaps thereafter */
671 xdga.height = min (xdga.height, IMAGE_INSTANCE_PIXMAP_HEIGHT (p) -
672 db->ypos % IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
674 while (xdga.height > 0)
676 xdga.width = min (min (db->width, IMAGE_INSTANCE_PIXMAP_WIDTH (p)),
677 IMAGE_INSTANCE_PIXMAP_WIDTH (p) -
678 db->xpos % IMAGE_INSTANCE_PIXMAP_WIDTH (p));
680 while (xdga.width > 0)
682 xdb.xpos = db->xpos + pxoffset;
683 xdb.ypos = db->ypos + pyoffset;
684 /* do we need to offset the pixmap vertically? this is necessary
685 for background pixmaps. */
686 xdga.yoffset = xdb.ypos % IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
687 xdga.xoffset = xdb.xpos % IMAGE_INSTANCE_PIXMAP_WIDTH (p);
688 /* the width is handled by mswindows_output_pixmap_region */
689 mswindows_output_dibitmap (f, p, &xdb, &xdga);
690 pxoffset += xdga.width;
691 xdga.width = min ((db->width - pxoffset),
692 IMAGE_INSTANCE_PIXMAP_WIDTH (p));
694 pyoffset += xdga.height;
695 xdga.height = min ((db->height - pyoffset),
696 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
700 /* Output a pixmap at the desired location.
701 DB normalized display_box.
702 DGA normalized display_glyph_area. */
704 mswindows_output_pixmap (struct window *w, Lisp_Object image_instance,
705 struct display_box *db, struct display_glyph_area *dga,
706 face_index findex, int cursor_start, int cursor_width,
707 int cursor_height, int bg_pixmap)
709 struct frame *f = XFRAME (w->frame);
710 HDC hdc = get_frame_dc (f, 1);
712 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
715 XSETWINDOW (window, w);
717 /* Output the pixmap. Have to do this as many times as is required
718 to fill the given area */
719 mswindows_update_dc (hdc,
720 WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
721 WINDOW_FACE_CACHEL_BACKGROUND (w, findex), Qnil);
724 mswindows_output_dibitmap_region (f, p, db, dga);
726 mswindows_output_dibitmap (f, p, db, dga);
729 #ifdef HAVE_SCROLLBARS
731 * This function paints window's deadbox, a rectangle between window
732 * borders and two short edges of both scrollbars.
734 * Function checks whether deadbox intersects with the rectangle pointed
735 * to by PRC, and paints only the intersection
738 mswindows_redisplay_deadbox_maybe (struct window *w, const RECT* prc)
740 int sbh = window_scrollbar_height (w);
741 int sbw = window_scrollbar_width (w);
742 RECT rect_dead, rect_paint;
743 if (sbh == 0 || sbw == 0)
746 if (!NILP (w->scrollbar_on_left_p))
747 rect_dead.left = WINDOW_LEFT (w);
749 rect_dead.left = WINDOW_TEXT_RIGHT (w);
750 rect_dead.right = rect_dead.left + sbw;
752 if (!NILP (w->scrollbar_on_top_p))
753 rect_dead.top = WINDOW_TOP (w);
755 rect_dead.top = WINDOW_TEXT_BOTTOM (w);
756 rect_dead.bottom = rect_dead.top + sbh;
758 if (IntersectRect (&rect_paint, &rect_dead, prc))
760 struct frame *f = XFRAME (WINDOW_FRAME (w));
761 FillRect (get_frame_dc (f, 1), &rect_paint,
762 (HBRUSH) (COLOR_BTNFACE+1));
766 #endif /* HAVE_SCROLLBARS */
768 /*****************************************************************************
769 mswindows_redraw_exposed_window
771 Given a bounding box for an area that needs to be redrawn, determine
772 what parts of what lines are contained within and re-output their
774 Copied from redisplay-x.c
775 ****************************************************************************/
777 mswindows_redraw_exposed_window (struct window *w, int x, int y, int width,
780 struct frame *f = XFRAME (w->frame);
782 int orig_windows_structure_changed;
783 RECT rect_window = { WINDOW_LEFT (w), WINDOW_TOP (w),
784 WINDOW_RIGHT (w), WINDOW_BOTTOM (w) };
785 RECT rect_expose = { x, y, x + width, y + height };
788 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
790 if (!NILP (w->vchild))
792 mswindows_redraw_exposed_windows (w->vchild, x, y, width, height);
795 else if (!NILP (w->hchild))
797 mswindows_redraw_exposed_windows (w->hchild, x, y, width, height);
801 /* If the window doesn't intersect the exposed region, we're done here. */
802 if (!IntersectRect (&rect_draw, &rect_window, &rect_expose))
805 /* We do this to make sure that the 3D modelines get redrawn if
806 they are in the exposed region. */
807 orig_windows_structure_changed = f->windows_structure_changed;
808 f->windows_structure_changed = 1;
810 if (window_needs_vertical_divider (w))
812 mswindows_output_vertical_divider (w, 0);
815 for (line = 0; line < Dynarr_length (cdla); line++)
817 struct display_line *cdl = Dynarr_atp (cdla, line);
819 if (DISPLAY_LINE_YPOS (cdl) + DISPLAY_LINE_HEIGHT (cdl)
822 if (DISPLAY_LINE_YPOS (cdl) > rect_draw.bottom)
831 output_display_line (w, 0, cdla, line,
832 rect_draw.left, rect_draw.right);
837 f->windows_structure_changed = orig_windows_structure_changed;
839 /* If there have never been any face cache_elements created, then this
840 expose event doesn't actually have anything to do. */
841 if (Dynarr_largest (w->face_cachels))
842 redisplay_clear_bottom_of_window (w, cdla, rect_draw.top, rect_draw.bottom);
844 #ifdef HAVE_SCROLLBARS
845 mswindows_redisplay_deadbox_maybe (w, &rect_expose);
849 /*****************************************************************************
850 mswindows_redraw_exposed_windows
852 For each window beneath the given window in the window hierarchy,
853 ensure that it is redrawn if necessary after an Expose event.
854 ****************************************************************************/
856 mswindows_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
859 for (; !NILP (window); window = XWINDOW (window)->next)
860 mswindows_redraw_exposed_window (XWINDOW (window), x, y, width, height);
863 /*****************************************************************************
864 mswindows_redraw_exposed_area
866 For each window on the given frame, ensure that any area in the
867 Exposed area is redrawn.
868 ****************************************************************************/
870 mswindows_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
872 /* If any window on the frame has had its face cache reset then the
873 redisplay structures are effectively invalid. If we attempt to
874 use them we'll blow up. We mark the frame as changed to ensure
875 that redisplay will do a full update. This probably isn't
876 necessary but it can't hurt. */
878 /* #### We would rather put these off as well but there is currently
879 no combination of flags which will force an unchanged toolbar to
881 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
883 redraw_exposed_gutters (f, x, y, width, height);
885 if (!f->window_face_cache_reset)
887 mswindows_redraw_exposed_windows (f->root_window, x, y, width, height);
891 MARK_FRAME_CHANGED (f);
895 /*****************************************************************************
898 Draw a 3d border around the specified area on window W.
899 ****************************************************************************/
901 mswindows_bevel_area (struct window *w, face_index findex, int x, int y,
902 int width, int height, int thickness,
903 int edges, enum edge_style style)
905 struct frame *f = XFRAME (w->frame);
909 if (style == EDGE_ETCHED_IN)
911 else if (style == EDGE_ETCHED_OUT)
913 else if (style == EDGE_BEVEL_IN)
916 edge = BDR_SUNKENINNER;
920 else /* EDGE_BEVEL_OUT */
923 edge = BDR_RAISEDINNER;
928 if (edges & EDGE_TOP)
930 if (edges & EDGE_LEFT)
932 if (edges & EDGE_BOTTOM)
934 if (edges & EDGE_RIGHT)
938 RECT rect = { x, y, x + width, y + height };
939 Lisp_Object color = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
940 HDC hdc = get_frame_dc (f, 1);
942 mswindows_update_dc (hdc, Qnil, color, Qnil);
943 DrawEdge (hdc, &rect, edge, border);
948 /*****************************************************************************
950 *****************************************************************************/
952 /*****************************************************************************
953 mswindows_divider_height
955 Return the height of the horizontal divider.
956 ****************************************************************************/
958 mswindows_divider_height (void)
960 return 1; /* XXX Copied from redisplay-X.c. What is this? */
963 /*****************************************************************************
964 mswindows_eol_cursor_width
966 Return the width of the end-of-line cursor.
967 ****************************************************************************/
969 mswindows_eol_cursor_width (void)
971 return MSWINDOWS_EOL_CURSOR_WIDTH;
974 /*****************************************************************************
975 mswindows_frame_output_begin
977 Perform any necessary initialization prior to an update.
978 ****************************************************************************/
980 mswindows_frame_output_begin (struct frame *f)
984 /*****************************************************************************
985 mswindows_frame_output_end
987 Perform any necessary flushing of queues when an update has completed.
988 ****************************************************************************/
990 mswindows_frame_output_end (struct frame *f)
992 #ifdef DEFER_WINDOW_POS
993 HDWP hdwp = FRAME_MSWINDOWS_DATA (f)->hdwp;
997 EndDeferWindowPos (hdwp);
998 FRAME_MSWINDOWS_DATA (f)->hdwp = 0;
1004 /* Printer version is more lightweight. */
1006 msprinter_frame_output_end (struct frame *f)
1012 mswindows_flash (struct device *d)
1014 struct frame *f = device_selected_frame (d);
1015 HDC hdc = get_frame_dc (f, 1);
1018 GetClientRect (FRAME_MSWINDOWS_HANDLE (f), &rc);
1019 InvertRect (hdc, &rc);
1022 InvertRect (hdc, &rc);
1028 mswindows_ring_bell (struct device *d, int volume, int pitch, int duration)
1030 /* Beep does not work at all, anyways! -kkm */
1031 MessageBeep (MB_OK);
1034 /*****************************************************************************
1035 mswindows_output_display_block
1037 Given a display line, a block number for that start line, output all
1038 runes between start and end in the specified display block.
1039 Ripped off with minimal thought from the corresponding X routine.
1040 ****************************************************************************/
1042 mswindows_output_display_block (struct window *w, struct display_line *dl, int block,
1043 int start, int end, int start_pixpos, int cursor_start,
1044 int cursor_width, int cursor_height)
1046 struct frame *f = XFRAME (w->frame);
1047 Emchar_dynarr *buf = Dynarr_new (Emchar);
1050 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
1051 rune_dynarr *rba = db->runes;
1057 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
1058 MULE is not defined */
1059 XSETWINDOW (window, w);
1060 rb = Dynarr_atp (rba, start);
1063 /* Nothing to do so don't do anything. */
1066 findex = rb->findex;
1069 if (rb->type == RUNE_CHAR)
1070 charset = CHAR_CHARSET (rb->object.chr.ch);
1073 end = Dynarr_length (rba);
1078 rb = Dynarr_atp (rba, elt);
1080 if (rb->findex == findex && rb->type == RUNE_CHAR
1081 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
1082 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
1084 Dynarr_add (buf, rb->object.chr.ch);
1090 if (Dynarr_length (buf))
1092 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
1093 findex, 0, 0, 0, 0);
1100 if (rb->type == RUNE_CHAR)
1102 findex = rb->findex;
1104 charset = CHAR_CHARSET (rb->object.chr.ch);
1106 if (rb->cursor_type == CURSOR_ON)
1108 if (rb->object.chr.ch == '\n')
1110 mswindows_output_cursor (w, dl, xpos, cursor_width,
1115 Dynarr_add (buf, rb->object.chr.ch);
1116 mswindows_output_cursor (w, dl, xpos, cursor_width,
1117 findex, rb->object.chr.ch, 0);
1124 else if (rb->object.chr.ch == '\n')
1126 /* Clear in case a cursor was formerly here. */
1127 redisplay_clear_region (window, findex, xpos,
1128 DISPLAY_LINE_YPOS (dl),
1129 rb->width, DISPLAY_LINE_HEIGHT (dl));
1133 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
1135 if (rb->type == RUNE_BLANK)
1136 mswindows_output_blank (w, dl, rb, start_pixpos);
1139 /* #### Our flagging of when we need to redraw the
1140 modeline shadows sucks. Since RUNE_HLINE is only used
1141 by the modeline at the moment it is a good bet
1142 that if it gets redrawn then we should also
1143 redraw the shadows. This won't be true forever.
1144 We borrow the shadow_thickness_changed flag for
1146 w->shadow_thickness_changed = 1;
1147 mswindows_output_hline (w, dl, rb);
1150 if (rb->cursor_type == CURSOR_ON)
1151 mswindows_output_cursor (w, dl, xpos, cursor_width, rb->findex, 0, 0);
1156 rb = Dynarr_atp (rba, elt);
1158 findex = rb->findex;
1162 else if (rb->type == RUNE_DGLYPH)
1164 Lisp_Object instance;
1165 struct display_box dbox;
1166 struct display_glyph_area dga;
1168 redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset,
1169 rb->object.dglyph.yoffset,
1170 start_pixpos, rb->width, &dbox, &dga);
1172 XSETWINDOW (window, w);
1173 instance = glyph_image_instance (rb->object.dglyph.glyph,
1174 window, ERROR_ME_NOT, 1);
1175 findex = rb->findex;
1177 if (IMAGE_INSTANCEP (instance))
1179 switch (XIMAGE_INSTANCE_TYPE (instance))
1181 case IMAGE_MONO_PIXMAP:
1182 case IMAGE_COLOR_PIXMAP:
1183 redisplay_output_pixmap (w, instance, &dbox, &dga, findex,
1184 cursor_start, cursor_width,
1186 if (rb->cursor_type == CURSOR_ON)
1187 mswindows_output_cursor (w, dl, xpos, cursor_width,
1192 if (EQ (XIMAGE_INSTANCE_WIDGET_TYPE (instance),
1195 redisplay_output_layout (window, instance, &dbox, &dga, findex,
1196 cursor_start, cursor_width,
1198 if (rb->cursor_type == CURSOR_ON)
1199 mswindows_output_cursor (w, dl, xpos, cursor_width,
1203 case IMAGE_SUBWINDOW:
1204 redisplay_output_subwindow (w, instance, &dbox, &dga, findex,
1205 cursor_start, cursor_width,
1207 if (rb->cursor_type == CURSOR_ON)
1208 mswindows_output_cursor (w, dl, xpos, cursor_width,
1213 /* nothing is as nothing does */
1221 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
1222 (XIMAGE_INSTANCE (instance)) = 0;
1232 if (Dynarr_length (buf))
1233 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
1237 && !EQ (Qzero, w->modeline_shadow_thickness)
1239 || f->windows_structure_changed
1240 || w->shadow_thickness_changed))
1241 bevel_modeline (w, dl);
1247 /*****************************************************************************
1248 mswindows_output_vertical_divider
1250 Draw a vertical divider down the right side of the given window.
1251 ****************************************************************************/
1253 mswindows_output_vertical_divider (struct window *w, int clear_unused)
1255 struct frame *f = XFRAME (w->frame);
1256 HDC hdc = get_frame_dc (f, 1);
1258 int spacing = XINT (w->vertical_divider_spacing);
1259 int shadow = XINT (w->vertical_divider_shadow_thickness);
1260 int abs_shadow = abs (shadow);
1261 int line_width = XINT (w->vertical_divider_line_width);
1262 int div_left = WINDOW_RIGHT (w) - window_divider_width (w);
1263 int y1 = WINDOW_TOP (w);
1264 int y2 = WINDOW_BOTTOM (w);
1266 /* Clear left and right spacing areas */
1271 mswindows_update_dc (hdc, Qnil,
1272 WINDOW_FACE_CACHEL_BACKGROUND (w, DEFAULT_INDEX), Qnil);
1273 rect.right = WINDOW_RIGHT (w);
1274 rect.left = rect.right - spacing;
1275 ExtTextOut (hdc, 0, 0, ETO_OPAQUE,
1276 &rect, NULL, 0, NULL);
1277 rect.left = div_left;
1278 rect.right = div_left + spacing;
1279 ExtTextOut (hdc, 0, 0, ETO_OPAQUE,
1280 &rect, NULL, 0, NULL);
1283 /* Clear divider face */
1284 rect.top = y1 + abs_shadow;
1285 rect.bottom = y2 - abs_shadow;
1286 rect.left = div_left + spacing + abs_shadow;
1287 rect.right = rect.left + line_width;
1288 if (rect.left < rect.right)
1291 = get_builtin_face_cache_index (w, Vvertical_divider_face);
1292 mswindows_update_dc (hdc, Qnil,
1293 WINDOW_FACE_CACHEL_BACKGROUND (w, div_face), Qnil);
1294 ExtTextOut (hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
1297 /* Draw a shadow around the divider */
1300 /* #### This will be fixed to support arbitrary thickness */
1301 InflateRect (&rect, abs_shadow, abs_shadow);
1302 DrawEdge (hdc, &rect,
1303 shadow > 0 ? EDGE_RAISED : EDGE_SUNKEN, BF_RECT);
1307 /****************************************************************************
1308 mswindows_text_width
1310 Given a string and a face, return the string's length in pixels when
1311 displayed in the font associated with the face.
1312 ****************************************************************************/
1314 mswindows_text_width (struct frame *f, struct face_cachel *cachel,
1315 const Emchar *str, Charcount len)
1317 HDC hdc = get_frame_dc (f, 0);
1318 int width_so_far = 0;
1319 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
1320 textual_run *runs = alloca_array (textual_run, len);
1324 nruns = separate_textual_runs (text_storage, runs, str, len);
1326 for (i = 0; i < nruns; i++)
1327 width_so_far += mswindows_text_width_single_run (hdc,
1330 return width_so_far;
1334 /****************************************************************************
1335 mswindows_clear_region
1337 Clear the area in the box defined by the given parameters using the
1339 ****************************************************************************/
1341 mswindows_clear_region (Lisp_Object locale, struct device* d, struct frame* f,
1342 face_index findex, int x, int y,
1343 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1344 Lisp_Object background_pixmap)
1346 RECT rect = { x, y, x+width, y+height };
1347 HDC hdc = get_frame_dc (f, 1);
1349 if (!NILP (background_pixmap))
1351 struct display_box db = { x, y, width, height };
1352 mswindows_update_dc (hdc,
1353 fcolor, bcolor, background_pixmap);
1354 mswindows_output_dibitmap_region
1355 ( f, XIMAGE_INSTANCE (background_pixmap), &db, 0);
1359 mswindows_update_dc (hdc, Qnil, fcolor, Qnil);
1360 ExtTextOut (hdc, 0, 0, ETO_OPAQUE,
1361 &rect, NULL, 0, NULL);
1364 #ifdef HAVE_SCROLLBARS
1365 if (WINDOWP (locale))
1366 mswindows_redisplay_deadbox_maybe (XWINDOW (locale), &rect);
1370 /* XXX Implement me! */
1372 mswindows_clear_frame (struct frame *f)
1379 /************************************************************************/
1380 /* initialization */
1381 /************************************************************************/
1384 console_type_create_redisplay_mswindows (void)
1386 /* redisplay methods - display*/
1387 CONSOLE_HAS_METHOD (mswindows, text_width);
1388 CONSOLE_HAS_METHOD (mswindows, output_display_block);
1389 CONSOLE_HAS_METHOD (mswindows, divider_height);
1390 CONSOLE_HAS_METHOD (mswindows, eol_cursor_width);
1391 CONSOLE_HAS_METHOD (mswindows, output_vertical_divider);
1392 CONSOLE_HAS_METHOD (mswindows, clear_region);
1393 CONSOLE_HAS_METHOD (mswindows, clear_frame);
1394 CONSOLE_HAS_METHOD (mswindows, frame_output_begin);
1395 CONSOLE_HAS_METHOD (mswindows, frame_output_end);
1396 CONSOLE_HAS_METHOD (mswindows, flash);
1397 CONSOLE_HAS_METHOD (mswindows, ring_bell);
1398 CONSOLE_HAS_METHOD (mswindows, bevel_area);
1399 CONSOLE_HAS_METHOD (mswindows, output_string);
1400 CONSOLE_HAS_METHOD (mswindows, output_pixmap);
1402 /* redisplay methods - printer */
1403 CONSOLE_HAS_METHOD (msprinter, frame_output_end);
1404 CONSOLE_INHERITS_METHOD (msprinter, mswindows, text_width);
1405 CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_display_block);
1406 CONSOLE_INHERITS_METHOD (msprinter, mswindows, divider_height);
1407 CONSOLE_INHERITS_METHOD (msprinter, mswindows, eol_cursor_width);
1408 CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_vertical_divider);
1409 CONSOLE_INHERITS_METHOD (msprinter, mswindows, clear_region);
1410 CONSOLE_INHERITS_METHOD (msprinter, mswindows, clear_frame);
1411 CONSOLE_INHERITS_METHOD (msprinter, mswindows, frame_output_begin);
1412 CONSOLE_INHERITS_METHOD (msprinter, mswindows, bevel_area);
1413 CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_string);
1414 CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_pixmap);