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 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 start_pixpos, rb->width,
314 /* blank the background in the appropriate color */
315 mswindows_update_dc (hdc, cachel->foreground,
316 cachel->background, Qnil);
317 redisplay_output_pixmap (w, bg_pmap, &db, &dga, rb->findex,
322 mswindows_update_dc (hdc, Qnil, cachel->background, Qnil);
323 ExtTextOut (hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
328 /*****************************************************************************
329 mswindows_output_cursor
331 Draw a normal or end-of-line cursor. The end-of-line cursor is
332 narrower than the normal cursor.
333 ****************************************************************************/
335 mswindows_output_cursor (struct window *w, struct display_line *dl, int xpos,
336 int width, face_index findex, Emchar ch, int image_p)
338 struct frame *f = XFRAME (w->frame);
339 struct device *d = XDEVICE (f->device);
340 struct face_cachel *cachel=0;
341 Lisp_Object font = Qnil;
342 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
343 HDC hdc = get_frame_dc (f, 1);
344 unsigned int local_face_index=0;
348 DISPLAY_LINE_YPOS (dl),
350 DISPLAY_LINE_YEND (dl) };
351 Lisp_Object bar = symbol_value_in_buffer (Qbar_cursor,
353 int bar_p = image_p || !NILP (bar);
354 int cursor_p = !NILP (w->text_cursor_visible_p);
355 int real_char_p = ch != 0;
357 /* Unmap all subwindows in the area we are going to blank. */
358 redisplay_unmap_subwindows_maybe (f, xpos, DISPLAY_LINE_YPOS (dl),
359 width, DISPLAY_LINE_HEIGHT (dl));
363 /* Use the font from the underlying character */
364 cachel = WINDOW_FACE_CACHEL (w, findex);
366 /* #### MULE: Need to know the charset! */
367 font = FACE_CACHEL_FONT (cachel, Vcharset_ascii);
370 if ((focus || bar_p) && real_char_p)
372 p_char = (char*) &ch;
378 struct face_cachel *color_cachel;
380 /* Use cursor fg/bg for block cursor, or character fg/bg for the bar
381 or when we need to erase the cursor. Output nothing at eol if bar
383 local_face_index = get_builtin_face_cache_index (w, Vtext_cursor_face);
384 color_cachel = WINDOW_FACE_CACHEL (w, ((!cursor_p || bar_p) ?
385 findex : local_face_index));
386 mswindows_update_dc (hdc, color_cachel->foreground,
387 color_cachel->background, Qnil);
389 mswindows_set_dc_font (hdc, font,
390 cachel->underline, cachel->strikethru);
392 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE|ETO_CLIPPED, &rect, p_char, n_char, NULL);
400 rect.right = rect.left + (EQ (bar, Qt) ? 1 : min (2, width));
401 local_face_index = get_builtin_face_cache_index (w, Vtext_cursor_face);
402 cachel = WINDOW_FACE_CACHEL (w, local_face_index);
403 mswindows_update_dc (hdc, Qnil, cachel->background, Qnil);
404 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE, &rect, NULL, 0, NULL);
408 /* Now have real character drawn in its own color. We deflate
409 the rectangle so character cell will be bounded by the
410 previously drawn cursor shape */
411 InflateRect (&rect, -1, -1);
415 p_char = (char*) &ch;
419 local_face_index = get_builtin_face_cache_index (w, Vdefault_face);
420 cachel = WINDOW_FACE_CACHEL (w, (real_char_p ? findex : local_face_index));
421 mswindows_update_dc (hdc,
422 cachel->foreground, cachel->background, Qnil);
423 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE | ETO_CLIPPED,
424 &rect, p_char, n_char, NULL);
429 /*****************************************************************************
430 mswindows_output_string
432 Given a string and a starting position, output that string in the
434 Correctly handles multiple charsets in the string.
436 The meaning of the parameters is something like this:
438 W Window that the text is to be displayed in.
439 DL Display line that this text is on. The values in the
440 structure are used to determine the vertical position and
441 clipping range of the text.
442 BUF Dynamic array of Emchars specifying what is actually to be
444 XPOS X position in pixels where the text should start being drawn.
445 XOFFSET Number of pixels to be chopped off the left side of the
446 text. The effect is as if the text were shifted to the
447 left this many pixels and clipped at XPOS.
448 CLIP_START Clip everything left of this X position.
449 WIDTH Clip everything right of XPOS + WIDTH.
450 FINDEX Index for the face cache element describing how to display
452 ****************************************************************************/
454 mswindows_output_string (struct window *w, struct display_line *dl,
455 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
456 int width, face_index findex,
457 int cursor, int cursor_start, int cursor_width,
460 struct frame *f = XFRAME (w->frame);
461 /* struct device *d = XDEVICE (f->device);*/
463 HDC hdc = get_frame_dc (f, 1);
466 int len = Dynarr_length (buf);
467 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
468 textual_run *runs = alloca_array (textual_run, len);
472 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
474 XSETWINDOW (window, w);
476 #if 0 /* #### FIXME? */
477 /* We can't work out the width before we've set the font in the DC */
479 width = mswindows_text_width (cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
484 /* Regularize the variables passed in. */
485 if (clip_start < xpos)
487 clip_end = xpos + width;
488 if (clip_start >= clip_end)
489 /* It's all clipped out. */
494 /* sort out the destination rectangle */
495 height = DISPLAY_LINE_HEIGHT (dl);
496 rect.left = clip_start;
497 rect.top = DISPLAY_LINE_YPOS (dl);
498 rect.right = clip_end;
499 rect.bottom = rect.top + height;
501 /* make sure the area we are about to display is subwindow free. */
502 redisplay_unmap_subwindows_maybe (f, clip_start, DISPLAY_LINE_YPOS (dl),
503 clip_end - clip_start, DISPLAY_LINE_HEIGHT (dl));
505 /* output the background pixmap if there is one */
506 bg_pmap = cachel->background_pixmap;
507 if (!IMAGE_INSTANCEP (bg_pmap)
508 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
513 struct display_box db;
514 struct display_glyph_area dga;
515 redisplay_calculate_display_boxes (dl, xpos + xoffset, 0,
516 clip_start, width, &db, &dga);
517 /* blank the background in the appropriate color */
518 mswindows_update_dc (hdc,
519 cachel->foreground, cachel->background, Qnil);
520 redisplay_output_pixmap (w, bg_pmap, &db, &dga, findex,
522 /* output pixmap calls this so we have to recall to get correct
524 cachel = WINDOW_FACE_CACHEL (w, findex);
527 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
528 Dynarr_length (buf));
530 for (i = 0; i < nruns; i++)
532 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
533 Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
536 if (EQ (font, Vthe_null_font_instance))
539 mswindows_update_dc (hdc, cachel->foreground,
540 NILP(bg_pmap) ? cachel->background : Qnil, Qnil);
541 mswindows_set_dc_font (hdc, font, cachel->underline, cachel->strikethru);
543 this_width = mswindows_text_width_single_run (hdc, cachel, runs + i);
545 /* cope with fonts taller than lines */
546 if ((int) fi->height < (int) (height + dl->clip + dl->top_clip))
548 int clear_start = max (xpos, clip_start);
549 int clear_end = min (xpos + this_width, clip_end);
552 redisplay_clear_region (window, findex, clear_start,
553 DISPLAY_LINE_YPOS (dl),
554 clear_end - clear_start,
556 /* output pixmap calls this so we have to recall to get correct
558 cachel = WINDOW_FACE_CACHEL (w, findex);
562 assert (runs[i].dimension == 1); /* #### FIXME: Broken when Mule? */
563 ExtTextOut (hdc, xpos, dl->ypos,
564 NILP(bg_pmap) ? ETO_CLIPPED | ETO_OPAQUE : ETO_CLIPPED,
565 &rect, (char *) runs[i].ptr, runs[i].len, NULL);
572 mswindows_output_dibitmap (struct frame *f, Lisp_Image_Instance *p,
573 struct display_box* db,
574 struct display_glyph_area* dga)
576 HDC hdc = get_frame_dc (f, 1);
577 HDC hcompdc = get_frame_compdc (f);
579 const int real_x = IMAGE_INSTANCE_MSWINDOWS_BITMAP_REAL_WIDTH (p);
580 const int real_y = IMAGE_INSTANCE_MSWINDOWS_BITMAP_REAL_HEIGHT (p);
581 const int surface_x = IMAGE_INSTANCE_PIXMAP_WIDTH (p);
582 const int surface_y = IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
584 /* first blit the mask */
585 if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
590 old = SelectObject (hcompdc, IMAGE_INSTANCE_MSWINDOWS_MASK (p));
592 if (IMAGE_INSTANCE_TYPE (p) == IMAGE_MONO_PIXMAP)
597 fgcolor = GetTextColor (hdc);
598 fg.rgbBlue = GetBValue (fgcolor);
599 fg.rgbRed = GetRValue (fgcolor);
600 fg.rgbGreen = GetGValue (fgcolor);
602 SetDIBColorTable (hcompdc, 0, 1, &fg);
605 bgcolor = GetBkColor (hdc);
606 bg.rgbBlue = GetBValue (bgcolor);
607 bg.rgbRed = GetRValue (bgcolor);
608 bg.rgbGreen = GetGValue (bgcolor);
610 SetDIBColorTable (hcompdc, 1, 1, &bg);
614 dga->width, dga->height,
616 MulDiv (dga->xoffset, real_x, surface_x),
617 MulDiv (dga->yoffset, real_y, surface_y),
618 MulDiv (dga->width, real_x, surface_x),
619 MulDiv (dga->height, real_y, surface_y),
622 SelectObject (hcompdc, old);
625 /* Now blit the bitmap itself, or one of its slices. */
626 old = SelectObject (hcompdc,
627 IMAGE_INSTANCE_MSWINDOWS_BITMAP_SLICE
628 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)));
632 dga->width, dga->height,
634 MulDiv (dga->xoffset, real_x, surface_x),
635 MulDiv (dga->yoffset, real_y, surface_y),
636 MulDiv (dga->width, real_x, surface_x),
637 MulDiv (dga->height, real_y, surface_y),
638 IMAGE_INSTANCE_MSWINDOWS_MASK (p) ? SRCINVERT : SRCCOPY);
640 SelectObject (hcompdc, old);
643 /* X gc's have this nice property that setting the bg pixmap will
644 * output it offset relative to the window. Windows doesn't have this
645 * feature so we have to emulate this by outputting multiple pixmaps.
646 * This is only used for background pixmaps. Normal pixmaps are
647 * outputted once and are scrollable */
649 mswindows_output_dibitmap_region (struct frame *f,
650 Lisp_Image_Instance *p,
651 struct display_box *db,
652 struct display_glyph_area *dga)
654 struct display_box xdb = { db->xpos, db->ypos, db->width, db->height };
655 struct display_glyph_area xdga
656 = { 0, 0, IMAGE_INSTANCE_PIXMAP_WIDTH (p),
657 IMAGE_INSTANCE_PIXMAP_HEIGHT (p) };
658 int pxoffset = 0, pyoffset = 0;
662 xdga.width = dga->width;
663 xdga.height = dga->height;
665 else if (!redisplay_normalize_glyph_area (&xdb, &xdga))
668 /* when doing a bg pixmap do a partial pixmap first so that we
669 blt whole pixmaps thereafter */
670 xdga.height = min (xdga.height, IMAGE_INSTANCE_PIXMAP_HEIGHT (p) -
671 db->ypos % IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
673 while (xdga.height > 0)
675 xdga.width = min (min (db->width, IMAGE_INSTANCE_PIXMAP_WIDTH (p)),
676 IMAGE_INSTANCE_PIXMAP_WIDTH (p) -
677 db->xpos % IMAGE_INSTANCE_PIXMAP_WIDTH (p));
679 while (xdga.width > 0)
681 xdb.xpos = db->xpos + pxoffset;
682 xdb.ypos = db->ypos + pyoffset;
683 /* do we need to offset the pixmap vertically? this is necessary
684 for background pixmaps. */
685 xdga.yoffset = xdb.ypos % IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
686 xdga.xoffset = xdb.xpos % IMAGE_INSTANCE_PIXMAP_WIDTH (p);
687 /* the width is handled by mswindows_output_pixmap_region */
688 mswindows_output_dibitmap (f, p, &xdb, &xdga);
689 pxoffset += xdga.width;
690 xdga.width = min ((db->width - pxoffset),
691 IMAGE_INSTANCE_PIXMAP_WIDTH (p));
693 pyoffset += xdga.height;
694 xdga.height = min ((db->height - pyoffset),
695 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
699 /* Output a pixmap at the desired location.
700 DB normalized display_box.
701 DGA normalized display_glyph_area. */
703 mswindows_output_pixmap (struct window *w, Lisp_Object image_instance,
704 struct display_box *db, struct display_glyph_area *dga,
705 face_index findex, int cursor_start, int cursor_width,
706 int cursor_height, int bg_pixmap)
708 struct frame *f = XFRAME (w->frame);
709 HDC hdc = get_frame_dc (f, 1);
711 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
714 XSETWINDOW (window, w);
716 /* Output the pixmap. Have to do this as many times as is required
717 to fill the given area */
718 mswindows_update_dc (hdc,
719 WINDOW_FACE_CACHEL_FOREGROUND (w, findex),
720 WINDOW_FACE_CACHEL_BACKGROUND (w, findex), Qnil);
723 mswindows_output_dibitmap_region (f, p, db, dga);
725 mswindows_output_dibitmap (f, p, db, dga);
728 #ifdef HAVE_SCROLLBARS
730 * This function paints window's deadbox, a rectangle between window
731 * borders and two short edges of both scrollbars.
733 * Function checks whether deadbox intersects with the rectangle pointed
734 * to by PRC, and paints only the intersection
737 mswindows_redisplay_deadbox_maybe (struct window *w, const RECT* prc)
739 int sbh = window_scrollbar_height (w);
740 int sbw = window_scrollbar_width (w);
741 RECT rect_dead, rect_paint;
742 if (sbh == 0 || sbw == 0)
745 if (!NILP (w->scrollbar_on_left_p))
746 rect_dead.left = WINDOW_LEFT (w);
748 rect_dead.left = WINDOW_TEXT_RIGHT (w);
749 rect_dead.right = rect_dead.left + sbw;
751 if (!NILP (w->scrollbar_on_top_p))
752 rect_dead.top = WINDOW_TOP (w);
754 rect_dead.top = WINDOW_TEXT_BOTTOM (w);
755 rect_dead.bottom = rect_dead.top + sbh;
757 if (IntersectRect (&rect_paint, &rect_dead, prc))
759 struct frame *f = XFRAME (WINDOW_FRAME (w));
760 FillRect (get_frame_dc (f, 1), &rect_paint,
761 (HBRUSH) (COLOR_BTNFACE+1));
765 #endif /* HAVE_SCROLLBARS */
767 /*****************************************************************************
768 mswindows_redraw_exposed_window
770 Given a bounding box for an area that needs to be redrawn, determine
771 what parts of what lines are contained within and re-output their
773 Copied from redisplay-x.c
774 ****************************************************************************/
776 mswindows_redraw_exposed_window (struct window *w, int x, int y, int width,
779 struct frame *f = XFRAME (w->frame);
781 int orig_windows_structure_changed;
782 RECT rect_window = { WINDOW_LEFT (w), WINDOW_TOP (w),
783 WINDOW_RIGHT (w), WINDOW_BOTTOM (w) };
784 RECT rect_expose = { x, y, x + width, y + height };
787 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
789 if (!NILP (w->vchild))
791 mswindows_redraw_exposed_windows (w->vchild, x, y, width, height);
794 else if (!NILP (w->hchild))
796 mswindows_redraw_exposed_windows (w->hchild, x, y, width, height);
800 /* If the window doesn't intersect the exposed region, we're done here. */
801 if (!IntersectRect (&rect_draw, &rect_window, &rect_expose))
804 /* We do this to make sure that the 3D modelines get redrawn if
805 they are in the exposed region. */
806 orig_windows_structure_changed = f->windows_structure_changed;
807 f->windows_structure_changed = 1;
809 if (window_needs_vertical_divider (w))
811 mswindows_output_vertical_divider (w, 0);
814 for (line = 0; line < Dynarr_length (cdla); line++)
816 struct display_line *cdl = Dynarr_atp (cdla, line);
818 if (DISPLAY_LINE_YPOS (cdl) + DISPLAY_LINE_HEIGHT (cdl)
821 if (DISPLAY_LINE_YPOS (cdl) > rect_draw.bottom)
830 output_display_line (w, 0, cdla, line,
831 rect_draw.left, rect_draw.right);
836 f->windows_structure_changed = orig_windows_structure_changed;
838 /* If there have never been any face cache_elements created, then this
839 expose event doesn't actually have anything to do. */
840 if (Dynarr_largest (w->face_cachels))
841 redisplay_clear_bottom_of_window (w, cdla, rect_draw.top, rect_draw.bottom);
843 #ifdef HAVE_SCROLLBARS
844 mswindows_redisplay_deadbox_maybe (w, &rect_expose);
848 /*****************************************************************************
849 mswindows_redraw_exposed_windows
851 For each window beneath the given window in the window hierarchy,
852 ensure that it is redrawn if necessary after an Expose event.
853 ****************************************************************************/
855 mswindows_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
858 for (; !NILP (window); window = XWINDOW (window)->next)
859 mswindows_redraw_exposed_window (XWINDOW (window), x, y, width, height);
862 /*****************************************************************************
863 mswindows_redraw_exposed_area
865 For each window on the given frame, ensure that any area in the
866 Exposed area is redrawn.
867 ****************************************************************************/
869 mswindows_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
871 /* If any window on the frame has had its face cache reset then the
872 redisplay structures are effectively invalid. If we attempt to
873 use them we'll blow up. We mark the frame as changed to ensure
874 that redisplay will do a full update. This probably isn't
875 necessary but it can't hurt. */
877 /* #### We would rather put these off as well but there is currently
878 no combination of flags which will force an unchanged toolbar to
880 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
882 redraw_exposed_gutters (f, x, y, width, height);
884 if (!f->window_face_cache_reset)
886 mswindows_redraw_exposed_windows (f->root_window, x, y, width, height);
890 MARK_FRAME_CHANGED (f);
894 /*****************************************************************************
897 Draw a 3d border around the specified area on window W.
898 ****************************************************************************/
900 mswindows_bevel_area (struct window *w, face_index findex, int x, int y,
901 int width, int height, int thickness,
902 int edges, enum edge_style style)
904 struct frame *f = XFRAME (w->frame);
908 if (style == EDGE_ETCHED_IN)
910 else if (style == EDGE_ETCHED_OUT)
912 else if (style == EDGE_BEVEL_IN)
915 edge = BDR_SUNKENINNER;
919 else /* EDGE_BEVEL_OUT */
922 edge = BDR_RAISEDINNER;
927 if (edges & EDGE_TOP)
929 if (edges & EDGE_LEFT)
931 if (edges & EDGE_BOTTOM)
933 if (edges & EDGE_RIGHT)
937 RECT rect = { x, y, x + width, y + height };
938 Lisp_Object color = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
939 HDC hdc = get_frame_dc (f, 1);
941 mswindows_update_dc (hdc, Qnil, color, Qnil);
942 DrawEdge (hdc, &rect, edge, border);
947 /*****************************************************************************
949 *****************************************************************************/
951 /*****************************************************************************
952 mswindows_divider_height
954 Return the height of the horizontal divider.
955 ****************************************************************************/
957 mswindows_divider_height (void)
959 return 1; /* XXX Copied from redisplay-X.c. What is this? */
962 /*****************************************************************************
963 mswindows_eol_cursor_width
965 Return the width of the end-of-line cursor.
966 ****************************************************************************/
968 mswindows_eol_cursor_width (void)
970 return MSWINDOWS_EOL_CURSOR_WIDTH;
973 /*****************************************************************************
974 mswindows_frame_output_begin
976 Perform any necessary initialization prior to an update.
977 ****************************************************************************/
979 mswindows_frame_output_begin (struct frame *f)
983 /*****************************************************************************
984 mswindows_frame_output_end
986 Perform any necessary flushing of queues when an update has completed.
987 ****************************************************************************/
989 mswindows_frame_output_end (struct frame *f)
991 #ifdef DEFER_WINDOW_POS
992 HDWP hdwp = FRAME_MSWINDOWS_DATA (f)->hdwp;
996 EndDeferWindowPos (hdwp);
997 FRAME_MSWINDOWS_DATA (f)->hdwp = 0;
1003 /* Printer version is more lightweight. */
1005 msprinter_frame_output_end (struct frame *f)
1011 mswindows_flash (struct device *d)
1013 struct frame *f = device_selected_frame (d);
1014 HDC hdc = get_frame_dc (f, 1);
1017 GetClientRect (FRAME_MSWINDOWS_HANDLE (f), &rc);
1018 InvertRect (hdc, &rc);
1021 InvertRect (hdc, &rc);
1027 mswindows_ring_bell (struct device *d, int volume, int pitch, int duration)
1029 /* Beep does not work at all, anyways! -kkm */
1030 MessageBeep (MB_OK);
1033 /*****************************************************************************
1034 mswindows_output_display_block
1036 Given a display line, a block number for that start line, output all
1037 runes between start and end in the specified display block.
1038 Ripped off with minimal thought from the corresponding X routine.
1039 ****************************************************************************/
1041 mswindows_output_display_block (struct window *w, struct display_line *dl, int block,
1042 int start, int end, int start_pixpos, int cursor_start,
1043 int cursor_width, int cursor_height)
1045 struct frame *f = XFRAME (w->frame);
1046 Emchar_dynarr *buf = Dynarr_new (Emchar);
1049 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
1050 rune_dynarr *rba = db->runes;
1056 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
1057 MULE is not defined */
1058 XSETWINDOW (window, w);
1059 rb = Dynarr_atp (rba, start);
1062 /* Nothing to do so don't do anything. */
1065 findex = rb->findex;
1068 if (rb->type == RUNE_CHAR)
1069 charset = CHAR_CHARSET (rb->object.chr.ch);
1072 end = Dynarr_length (rba);
1077 rb = Dynarr_atp (rba, elt);
1079 if (rb->findex == findex && rb->type == RUNE_CHAR
1080 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
1081 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
1083 Dynarr_add (buf, rb->object.chr.ch);
1089 if (Dynarr_length (buf))
1091 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
1092 findex, 0, 0, 0, 0);
1099 if (rb->type == RUNE_CHAR)
1101 findex = rb->findex;
1103 charset = CHAR_CHARSET (rb->object.chr.ch);
1105 if (rb->cursor_type == CURSOR_ON)
1107 if (rb->object.chr.ch == '\n')
1109 mswindows_output_cursor (w, dl, xpos, cursor_width,
1114 Dynarr_add (buf, rb->object.chr.ch);
1115 mswindows_output_cursor (w, dl, xpos, cursor_width,
1116 findex, rb->object.chr.ch, 0);
1123 else if (rb->object.chr.ch == '\n')
1125 /* Clear in case a cursor was formerly here. */
1126 redisplay_clear_region (window, findex, xpos,
1127 DISPLAY_LINE_YPOS (dl),
1128 rb->width, DISPLAY_LINE_HEIGHT (dl));
1132 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
1134 if (rb->type == RUNE_BLANK)
1135 mswindows_output_blank (w, dl, rb, start_pixpos);
1138 /* #### Our flagging of when we need to redraw the
1139 modeline shadows sucks. Since RUNE_HLINE is only used
1140 by the modeline at the moment it is a good bet
1141 that if it gets redrawn then we should also
1142 redraw the shadows. This won't be true forever.
1143 We borrow the shadow_thickness_changed flag for
1145 w->shadow_thickness_changed = 1;
1146 mswindows_output_hline (w, dl, rb);
1149 if (rb->cursor_type == CURSOR_ON)
1150 mswindows_output_cursor (w, dl, xpos, cursor_width, rb->findex, 0, 0);
1155 rb = Dynarr_atp (rba, elt);
1157 findex = rb->findex;
1161 else if (rb->type == RUNE_DGLYPH)
1163 Lisp_Object instance;
1164 struct display_box dbox;
1165 struct display_glyph_area dga;
1167 redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset,
1168 start_pixpos, rb->width,
1171 XSETWINDOW (window, w);
1172 instance = glyph_image_instance (rb->object.dglyph.glyph,
1173 window, ERROR_ME_NOT, 1);
1174 findex = rb->findex;
1176 if (IMAGE_INSTANCEP (instance))
1178 switch (XIMAGE_INSTANCE_TYPE (instance))
1180 case IMAGE_MONO_PIXMAP:
1181 case IMAGE_COLOR_PIXMAP:
1182 redisplay_output_pixmap (w, instance, &dbox, &dga, findex,
1183 cursor_start, cursor_width,
1185 if (rb->cursor_type == CURSOR_ON)
1186 mswindows_output_cursor (w, dl, xpos, cursor_width,
1191 if (EQ (XIMAGE_INSTANCE_WIDGET_TYPE (instance),
1194 redisplay_output_layout (window, instance, &dbox, &dga, findex,
1195 cursor_start, cursor_width,
1197 if (rb->cursor_type == CURSOR_ON)
1198 mswindows_output_cursor (w, dl, xpos, cursor_width,
1202 case IMAGE_SUBWINDOW:
1203 redisplay_output_subwindow (w, instance, &dbox, &dga, findex,
1204 cursor_start, cursor_width,
1206 if (rb->cursor_type == CURSOR_ON)
1207 mswindows_output_cursor (w, dl, xpos, cursor_width,
1212 /* nothing is as nothing does */
1220 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
1221 (XIMAGE_INSTANCE (instance)) = 0;
1231 if (Dynarr_length (buf))
1232 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
1236 && !EQ (Qzero, w->modeline_shadow_thickness)
1238 || f->windows_structure_changed
1239 || w->shadow_thickness_changed))
1240 bevel_modeline (w, dl);
1246 /*****************************************************************************
1247 mswindows_output_vertical_divider
1249 Draw a vertical divider down the right side of the given window.
1250 ****************************************************************************/
1252 mswindows_output_vertical_divider (struct window *w, int clear_unused)
1254 struct frame *f = XFRAME (w->frame);
1255 HDC hdc = get_frame_dc (f, 1);
1257 int spacing = XINT (w->vertical_divider_spacing);
1258 int shadow = XINT (w->vertical_divider_shadow_thickness);
1259 int abs_shadow = abs (shadow);
1260 int line_width = XINT (w->vertical_divider_line_width);
1261 int div_left = WINDOW_RIGHT (w) - window_divider_width (w);
1262 int y1 = WINDOW_TOP (w);
1263 int y2 = WINDOW_BOTTOM (w);
1265 /* Clear left and right spacing areas */
1270 mswindows_update_dc (hdc, Qnil,
1271 WINDOW_FACE_CACHEL_BACKGROUND (w, DEFAULT_INDEX), Qnil);
1272 rect.right = WINDOW_RIGHT (w);
1273 rect.left = rect.right - spacing;
1274 ExtTextOut (hdc, 0, 0, ETO_OPAQUE,
1275 &rect, NULL, 0, NULL);
1276 rect.left = div_left;
1277 rect.right = div_left + spacing;
1278 ExtTextOut (hdc, 0, 0, ETO_OPAQUE,
1279 &rect, NULL, 0, NULL);
1282 /* Clear divider face */
1283 rect.top = y1 + abs_shadow;
1284 rect.bottom = y2 - abs_shadow;
1285 rect.left = div_left + spacing + abs_shadow;
1286 rect.right = rect.left + line_width;
1287 if (rect.left < rect.right)
1290 = get_builtin_face_cache_index (w, Vvertical_divider_face);
1291 mswindows_update_dc (hdc, Qnil,
1292 WINDOW_FACE_CACHEL_BACKGROUND (w, div_face), Qnil);
1293 ExtTextOut (hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
1296 /* Draw a shadow around the divider */
1299 /* #### This will be fixed to support arbitrary thickness */
1300 InflateRect (&rect, abs_shadow, abs_shadow);
1301 DrawEdge (hdc, &rect,
1302 shadow > 0 ? EDGE_RAISED : EDGE_SUNKEN, BF_RECT);
1306 /****************************************************************************
1307 mswindows_text_width
1309 Given a string and a face, return the string's length in pixels when
1310 displayed in the font associated with the face.
1311 ****************************************************************************/
1313 mswindows_text_width (struct frame *f, struct face_cachel *cachel,
1314 const Emchar *str, Charcount len)
1316 HDC hdc = get_frame_dc (f, 0);
1317 int width_so_far = 0;
1318 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
1319 textual_run *runs = alloca_array (textual_run, len);
1323 nruns = separate_textual_runs (text_storage, runs, str, len);
1325 for (i = 0; i < nruns; i++)
1326 width_so_far += mswindows_text_width_single_run (hdc,
1329 return width_so_far;
1333 /****************************************************************************
1334 mswindows_clear_region
1336 Clear the area in the box defined by the given parameters using the
1338 ****************************************************************************/
1340 mswindows_clear_region (Lisp_Object locale, struct device* d, struct frame* f,
1341 face_index findex, int x, int y,
1342 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1343 Lisp_Object background_pixmap)
1345 RECT rect = { x, y, x+width, y+height };
1346 HDC hdc = get_frame_dc (f, 1);
1348 if (!NILP (background_pixmap))
1350 struct display_box db = { x, y, width, height };
1351 mswindows_update_dc (hdc,
1352 fcolor, bcolor, background_pixmap);
1353 mswindows_output_dibitmap_region
1354 ( f, XIMAGE_INSTANCE (background_pixmap), &db, 0);
1358 mswindows_update_dc (hdc, Qnil, fcolor, Qnil);
1359 ExtTextOut (hdc, 0, 0, ETO_OPAQUE,
1360 &rect, NULL, 0, NULL);
1363 #ifdef HAVE_SCROLLBARS
1364 if (WINDOWP (locale))
1365 mswindows_redisplay_deadbox_maybe (XWINDOW (locale), &rect);
1369 /* XXX Implement me! */
1371 mswindows_clear_frame (struct frame *f)
1378 /************************************************************************/
1379 /* initialization */
1380 /************************************************************************/
1383 console_type_create_redisplay_mswindows (void)
1385 /* redisplay methods - display*/
1386 CONSOLE_HAS_METHOD (mswindows, text_width);
1387 CONSOLE_HAS_METHOD (mswindows, output_display_block);
1388 CONSOLE_HAS_METHOD (mswindows, divider_height);
1389 CONSOLE_HAS_METHOD (mswindows, eol_cursor_width);
1390 CONSOLE_HAS_METHOD (mswindows, output_vertical_divider);
1391 CONSOLE_HAS_METHOD (mswindows, clear_region);
1392 CONSOLE_HAS_METHOD (mswindows, clear_frame);
1393 CONSOLE_HAS_METHOD (mswindows, frame_output_begin);
1394 CONSOLE_HAS_METHOD (mswindows, frame_output_end);
1395 CONSOLE_HAS_METHOD (mswindows, flash);
1396 CONSOLE_HAS_METHOD (mswindows, ring_bell);
1397 CONSOLE_HAS_METHOD (mswindows, bevel_area);
1398 CONSOLE_HAS_METHOD (mswindows, output_string);
1399 CONSOLE_HAS_METHOD (mswindows, output_pixmap);
1401 /* redisplay methods - printer */
1402 CONSOLE_HAS_METHOD (msprinter, frame_output_end);
1403 CONSOLE_INHERITS_METHOD (msprinter, mswindows, text_width);
1404 CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_display_block);
1405 CONSOLE_INHERITS_METHOD (msprinter, mswindows, divider_height);
1406 CONSOLE_INHERITS_METHOD (msprinter, mswindows, eol_cursor_width);
1407 CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_vertical_divider);
1408 CONSOLE_INHERITS_METHOD (msprinter, mswindows, clear_region);
1409 CONSOLE_INHERITS_METHOD (msprinter, mswindows, clear_frame);
1410 CONSOLE_INHERITS_METHOD (msprinter, mswindows, frame_output_begin);
1411 CONSOLE_INHERITS_METHOD (msprinter, mswindows, bevel_area);
1412 CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_string);
1413 CONSOLE_INHERITS_METHOD (msprinter, mswindows, output_pixmap);