Mercurial > hg > xemacs-beta
comparison src/redisplay-msw.c @ 428:3ecd8885ac67 r21-2-22
Import from CVS: tag r21-2-22
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:28:15 +0200 |
parents | |
children | 8de8e3f6228a |
comparison
equal
deleted
inserted
replaced
427:0a0253eac470 | 428:3ecd8885ac67 |
---|---|
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. | |
5 | |
6 This file is part of XEmacs. | |
7 | |
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 | |
11 later version. | |
12 | |
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 | |
16 for more details. | |
17 | |
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. */ | |
22 | |
23 /* Synched up with: Not in FSF. */ | |
24 | |
25 /* Authorship: | |
26 | |
27 Chuck Thompson | |
28 Lots of work done by Ben Wing for Mule | |
29 Partially rewritten for mswindows by Jonathan Harris, November 1997 for 21.0. | |
30 */ | |
31 | |
32 #include <config.h> | |
33 #include "lisp.h" | |
34 | |
35 #include "console-msw.h" | |
36 #include "objects-msw.h" | |
37 | |
38 #include "buffer.h" | |
39 #include "debug.h" | |
40 #include "events.h" | |
41 #include "faces.h" | |
42 #include "frame.h" | |
43 #include "glyphs-msw.h" | |
44 #include "gutter.h" | |
45 #include "redisplay.h" | |
46 #include "sysdep.h" | |
47 #include "window.h" | |
48 | |
49 #include "windows.h" | |
50 #ifdef MULE | |
51 #include "mule-ccl.h" | |
52 #include "mule-charset.h" | |
53 #endif | |
54 | |
55 #define MSWINDOWS_EOL_CURSOR_WIDTH 5 | |
56 | |
57 /* | |
58 * Random forward declarations | |
59 */ | |
60 static void mswindows_update_dc (HDC hdc, Lisp_Object font, Lisp_Object fg, | |
61 Lisp_Object bg, Lisp_Object bg_pmap); | |
62 static void mswindows_output_vertical_divider (struct window *w, int clear); | |
63 static void mswindows_redraw_exposed_windows (Lisp_Object window, int x, | |
64 int y, int width, int height); | |
65 static void mswindows_output_dibitmap (struct frame *f, | |
66 struct Lisp_Image_Instance *p, | |
67 struct display_box* db, | |
68 struct display_glyph_area* dga); | |
69 | |
70 typedef struct textual_run | |
71 { | |
72 Lisp_Object charset; | |
73 unsigned char *ptr; | |
74 int len; | |
75 int dimension; | |
76 } textual_run; | |
77 | |
78 /* Separate out the text in DYN into a series of textual runs of a | |
79 particular charset. Also convert the characters as necessary into | |
80 the format needed by XDrawImageString(), XDrawImageString16(), et | |
81 al. (This means converting to one or two byte format, possibly | |
82 tweaking the high bits, and possibly running a CCL program.) You | |
83 must pre-allocate the space used and pass it in. (This is done so | |
84 you can alloca() the space.) You need to allocate (2 * len) bytes | |
85 of TEXT_STORAGE and (len * sizeof (textual_run)) bytes of | |
86 RUN_STORAGE, where LEN is the length of the dynarr. | |
87 | |
88 Returns the number of runs actually used. */ | |
89 | |
90 static int | |
91 separate_textual_runs (unsigned char *text_storage, | |
92 textual_run *run_storage, | |
93 CONST Emchar *str, Charcount len) | |
94 { | |
95 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a | |
96 possible valid charset when | |
97 MULE is not defined */ | |
98 int runs_so_far = 0; | |
99 int i; | |
100 #ifdef MULE | |
101 struct ccl_program char_converter; | |
102 int need_ccl_conversion = 0; | |
103 #endif | |
104 | |
105 for (i = 0; i < len; i++) | |
106 { | |
107 Emchar ch = str[i]; | |
108 Lisp_Object charset; | |
109 int byte1, byte2; | |
110 int dimension; | |
111 int graphic; | |
112 | |
113 BREAKUP_CHAR (ch, charset, byte1, byte2); | |
114 dimension = XCHARSET_DIMENSION (charset); | |
115 graphic = XCHARSET_GRAPHIC (charset); | |
116 | |
117 if (!EQ (charset, prev_charset)) | |
118 { | |
119 run_storage[runs_so_far].ptr = text_storage; | |
120 run_storage[runs_so_far].charset = charset; | |
121 run_storage[runs_so_far].dimension = dimension; | |
122 | |
123 if (runs_so_far) | |
124 { | |
125 run_storage[runs_so_far - 1].len = | |
126 text_storage - run_storage[runs_so_far - 1].ptr; | |
127 if (run_storage[runs_so_far - 1].dimension == 2) | |
128 run_storage[runs_so_far - 1].len >>= 1; | |
129 } | |
130 runs_so_far++; | |
131 prev_charset = charset; | |
132 #ifdef MULE | |
133 { | |
134 Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset); | |
135 need_ccl_conversion = !NILP (ccl_prog); | |
136 if (need_ccl_conversion) | |
137 setup_ccl_program (&char_converter, ccl_prog); | |
138 } | |
139 #endif | |
140 } | |
141 | |
142 if (graphic == 0) | |
143 { | |
144 byte1 &= 0x7F; | |
145 byte2 &= 0x7F; | |
146 } | |
147 else if (graphic == 1) | |
148 { | |
149 byte1 |= 0x80; | |
150 byte2 |= 0x80; | |
151 } | |
152 #ifdef MULE | |
153 if (need_ccl_conversion) | |
154 { | |
155 char_converter.reg[0] = XCHARSET_ID (charset); | |
156 char_converter.reg[1] = byte1; | |
157 char_converter.reg[2] = byte2; | |
158 char_converter.ic = 0; /* start at beginning each time */ | |
159 ccl_driver (&char_converter, 0, 0, 0, 0, CCL_MODE_ENCODING); | |
160 byte1 = char_converter.reg[1]; | |
161 byte2 = char_converter.reg[2]; | |
162 } | |
163 #endif | |
164 *text_storage++ = (unsigned char) byte1; | |
165 if (dimension == 2) | |
166 *text_storage++ = (unsigned char) byte2; | |
167 } | |
168 | |
169 if (runs_so_far) | |
170 { | |
171 run_storage[runs_so_far - 1].len = | |
172 text_storage - run_storage[runs_so_far - 1].ptr; | |
173 if (run_storage[runs_so_far - 1].dimension == 2) | |
174 run_storage[runs_so_far - 1].len >>= 1; | |
175 } | |
176 | |
177 return runs_so_far; | |
178 } | |
179 | |
180 | |
181 static int | |
182 mswindows_text_width_single_run (HDC hdc, struct face_cachel *cachel, | |
183 textual_run *run) | |
184 { | |
185 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset); | |
186 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst); | |
187 SIZE size; | |
188 | |
189 if (!fi->proportional_p || !hdc) | |
190 return (fi->width * run->len); | |
191 else | |
192 { | |
193 assert(run->dimension == 1); /* #### FIXME! */ | |
194 mswindows_update_dc (hdc, font_inst, Qnil, Qnil, Qnil); | |
195 GetTextExtentPoint32 (hdc, run->ptr, run->len, &size); | |
196 return(size.cx); | |
197 } | |
198 } | |
199 | |
200 | |
201 /***************************************************************************** | |
202 mswindows_update_dc | |
203 | |
204 Given a number of parameters munge the DC so it has those properties. | |
205 ****************************************************************************/ | |
206 static void | |
207 mswindows_update_dc (HDC hdc, Lisp_Object font, Lisp_Object fg, | |
208 Lisp_Object bg, Lisp_Object bg_pmap) | |
209 { | |
210 if (!NILP (font)) | |
211 SelectObject(hdc, FONT_INSTANCE_MSWINDOWS_HFONT (XFONT_INSTANCE (font))); | |
212 | |
213 | |
214 if (!NILP (fg)) | |
215 { | |
216 SetTextColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR | |
217 (XCOLOR_INSTANCE (fg))); | |
218 } | |
219 if (!NILP (bg)) | |
220 { | |
221 SetBkMode (hdc, OPAQUE); | |
222 SetBkColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (bg))); | |
223 } | |
224 else | |
225 { | |
226 SetBkMode (hdc, TRANSPARENT); | |
227 } | |
228 } | |
229 | |
230 | |
231 /***************************************************************************** | |
232 mswindows_apply_face_effects | |
233 | |
234 Draw underline and strikeout as if this was X. | |
235 #### On mswindows this really should be done as part of drawing the font. | |
236 The line width used is chosen arbitrarily from the font height. | |
237 ****************************************************************************/ | |
238 static void | |
239 mswindows_apply_face_effects (HDC hdc, struct display_line *dl, int xpos, | |
240 int width, struct Lisp_Font_Instance *fi, | |
241 struct face_cachel *cachel, | |
242 struct face_cachel *color_cachel) | |
243 { | |
244 int yclip; | |
245 HBRUSH brush, oldbrush; | |
246 RECT rect; | |
247 | |
248 brush = CreateSolidBrush (COLOR_INSTANCE_MSWINDOWS_COLOR ( | |
249 XCOLOR_INSTANCE (color_cachel->foreground))); | |
250 if (brush) | |
251 { | |
252 yclip = dl->ypos + dl->descent - dl->clip; | |
253 rect.left = xpos; | |
254 rect.right = xpos + width; | |
255 oldbrush = SelectObject (hdc, brush); | |
256 | |
257 if (cachel->underline) | |
258 { | |
259 rect.top = dl->ypos + dl->descent/2; | |
260 rect.bottom = rect.top + (fi->height >= 0x20 ? 2 : 1); | |
261 if (rect.bottom <= yclip) | |
262 FillRect (hdc, &rect, brush); | |
263 } | |
264 if (cachel->strikethru) | |
265 { | |
266 rect.top = dl->ypos + dl->descent - (dl->ascent + dl->descent)/2; | |
267 rect.bottom = rect.top + (fi->height >= 0x20 ? 2 : 1); | |
268 if (rect.bottom <= yclip) | |
269 FillRect (hdc, &rect, brush); | |
270 } | |
271 | |
272 SelectObject (hdc, oldbrush); | |
273 DeleteObject (brush); | |
274 } | |
275 } | |
276 | |
277 | |
278 /***************************************************************************** | |
279 mswindows_output_hline | |
280 | |
281 Output a horizontal line in the foreground of its face. | |
282 ****************************************************************************/ | |
283 static void | |
284 mswindows_output_hline (struct window *w, struct display_line *dl, struct rune *rb) | |
285 { /* XXX Implement me */ | |
286 } | |
287 | |
288 | |
289 /***************************************************************************** | |
290 mswindows_output_blank | |
291 | |
292 Output a blank by clearing the area it covers in the background color | |
293 of its face. | |
294 ****************************************************************************/ | |
295 static void | |
296 mswindows_output_blank (struct window *w, struct display_line *dl, | |
297 struct rune *rb, int start_pixpos) | |
298 { | |
299 struct frame *f = XFRAME (w->frame); | |
300 RECT rect = { rb->xpos, DISPLAY_LINE_YPOS (dl), | |
301 rb->xpos+rb->width, | |
302 DISPLAY_LINE_YEND (dl) }; | |
303 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, rb->findex); | |
304 | |
305 Lisp_Object bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex); | |
306 | |
307 /* Unmap all subwindows in the area we are going to blank. */ | |
308 redisplay_unmap_subwindows_maybe (f, rb->xpos, DISPLAY_LINE_YPOS (dl), | |
309 rb->width, DISPLAY_LINE_HEIGHT (dl)); | |
310 | |
311 if (!IMAGE_INSTANCEP (bg_pmap) | |
312 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap))) | |
313 bg_pmap = Qnil; | |
314 | |
315 if (!NILP(bg_pmap)) | |
316 { | |
317 struct display_box db; | |
318 struct display_glyph_area dga; | |
319 redisplay_calculate_display_boxes (dl, rb->xpos, | |
320 /*rb->object.dglyph.xoffset*/ 0, | |
321 start_pixpos, rb->width, | |
322 &db, &dga); | |
323 /* blank the background in the appropriate color */ | |
324 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, cachel->foreground, | |
325 cachel->background, Qnil); | |
326 redisplay_output_pixmap (w, bg_pmap, &db, &dga, rb->findex, | |
327 0, 0, 0, TRUE); | |
328 } | |
329 else | |
330 { | |
331 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, | |
332 cachel->background, Qnil); | |
333 | |
334 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, | |
335 &rect, NULL, 0, NULL); | |
336 } | |
337 } | |
338 | |
339 | |
340 /***************************************************************************** | |
341 mswindows_output_cursor | |
342 | |
343 Draw a normal or end-of-line cursor. The end-of-line cursor is | |
344 narrower than the normal cursor. | |
345 ****************************************************************************/ | |
346 static void | |
347 mswindows_output_cursor (struct window *w, struct display_line *dl, int xpos, | |
348 int width, face_index findex, Emchar ch, int image_p) | |
349 { | |
350 struct frame *f = XFRAME (w->frame); | |
351 struct device *d = XDEVICE (f->device); | |
352 struct face_cachel *cachel=0; | |
353 Lisp_Object font = Qnil; | |
354 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d)); | |
355 HDC hdc = FRAME_MSWINDOWS_DC (f); | |
356 unsigned int face_index=0; | |
357 char *p_char = NULL; | |
358 int n_char = 0; | |
359 RECT rect = { xpos, | |
360 DISPLAY_LINE_YPOS (dl), | |
361 xpos + width, | |
362 DISPLAY_LINE_YEND (dl) }; | |
363 Lisp_Object bar = symbol_value_in_buffer (Qbar_cursor, | |
364 WINDOW_BUFFER (w)); | |
365 int bar_p = image_p || !NILP (bar); | |
366 int cursor_p = !NILP (w->text_cursor_visible_p); | |
367 int real_char_p = ch != 0; | |
368 | |
369 /* Unmap all subwindows in the area we are going to blank. */ | |
370 redisplay_unmap_subwindows_maybe (f, xpos, DISPLAY_LINE_YPOS (dl), | |
371 width, DISPLAY_LINE_HEIGHT (dl)); | |
372 | |
373 if (real_char_p) | |
374 { | |
375 /* Use the font from the underlying character */ | |
376 cachel = WINDOW_FACE_CACHEL (w, findex); | |
377 | |
378 /* #### MULE: Need to know the charset! */ | |
379 font = FACE_CACHEL_FONT (cachel, Vcharset_ascii); | |
380 } | |
381 | |
382 if ((focus || bar_p) && real_char_p) | |
383 { | |
384 p_char = (char*) &ch; | |
385 n_char = 1; | |
386 } | |
387 | |
388 if (!image_p) | |
389 { | |
390 struct face_cachel *color_cachel; | |
391 | |
392 /* Use cursor fg/bg for block cursor, or character fg/bg for the bar | |
393 or when we need to erase the cursor. Output nothing at eol if bar | |
394 cursor */ | |
395 face_index = get_builtin_face_cache_index (w, Vtext_cursor_face); | |
396 color_cachel = WINDOW_FACE_CACHEL (w, ((!cursor_p || bar_p) ? | |
397 findex : face_index)); | |
398 mswindows_update_dc (hdc, font, color_cachel->foreground, | |
399 color_cachel->background, Qnil); | |
400 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE|ETO_CLIPPED, &rect, p_char, n_char, NULL); | |
401 if (real_char_p && (cachel->underline || cachel->strikethru)) | |
402 mswindows_apply_face_effects (hdc, dl, xpos, width, | |
403 XFONT_INSTANCE (font), | |
404 cachel, color_cachel); | |
405 } | |
406 | |
407 if (!cursor_p) | |
408 return; | |
409 | |
410 if (focus && bar_p) | |
411 { | |
412 rect.right = rect.left + (EQ (bar, Qt) ? 1 : min (2, width)); | |
413 face_index = get_builtin_face_cache_index (w, Vtext_cursor_face); | |
414 cachel = WINDOW_FACE_CACHEL (w, face_index); | |
415 mswindows_update_dc (hdc, Qnil, Qnil, cachel->background, Qnil); | |
416 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE, &rect, NULL, 0, NULL); | |
417 } | |
418 else if (!focus) | |
419 { | |
420 /* Now have real character drawn in its own color. We deflate | |
421 the rectangle so character cell will be bounded by the | |
422 previously drawn cursor shape */ | |
423 InflateRect (&rect, -1, -1); | |
424 | |
425 if (real_char_p) | |
426 { | |
427 p_char = (char*) &ch; | |
428 n_char = 1; | |
429 } | |
430 | |
431 face_index = get_builtin_face_cache_index (w, Vdefault_face); | |
432 cachel = WINDOW_FACE_CACHEL (w, (real_char_p ? findex : face_index)); | |
433 mswindows_update_dc (hdc, Qnil, cachel->foreground, | |
434 cachel->background, Qnil); | |
435 ExtTextOut (hdc, xpos, dl->ypos, ETO_OPAQUE | ETO_CLIPPED, | |
436 &rect, p_char, n_char, NULL); | |
437 if (cachel->underline || cachel->strikethru) | |
438 mswindows_apply_face_effects (hdc, dl, xpos+1, width-2, | |
439 XFONT_INSTANCE (font), | |
440 cachel, cachel); | |
441 } | |
442 } | |
443 | |
444 | |
445 /***************************************************************************** | |
446 mswindows_output_string | |
447 | |
448 Given a string and a starting position, output that string in the | |
449 given face. | |
450 Correctly handles multiple charsets in the string. | |
451 | |
452 The meaning of the parameters is something like this: | |
453 | |
454 W Window that the text is to be displayed in. | |
455 DL Display line that this text is on. The values in the | |
456 structure are used to determine the vertical position and | |
457 clipping range of the text. | |
458 BUF Dynamic array of Emchars specifying what is actually to be | |
459 drawn. | |
460 XPOS X position in pixels where the text should start being drawn. | |
461 XOFFSET Number of pixels to be chopped off the left side of the | |
462 text. The effect is as if the text were shifted to the | |
463 left this many pixels and clipped at XPOS. | |
464 CLIP_START Clip everything left of this X position. | |
465 WIDTH Clip everything right of XPOS + WIDTH. | |
466 FINDEX Index for the face cache element describing how to display | |
467 the text. | |
468 ****************************************************************************/ | |
469 void | |
470 mswindows_output_string (struct window *w, struct display_line *dl, | |
471 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start, | |
472 int width, face_index findex, | |
473 int cursor, int cursor_start, int cursor_width, | |
474 int cursor_height) | |
475 { | |
476 struct frame *f = XFRAME (w->frame); | |
477 /* struct device *d = XDEVICE (f->device);*/ | |
478 Lisp_Object window; | |
479 HDC hdc = FRAME_MSWINDOWS_DC (f); | |
480 int clip_end; | |
481 Lisp_Object bg_pmap; | |
482 int len = Dynarr_length (buf); | |
483 unsigned char *text_storage = (unsigned char *) alloca (2 * len); | |
484 textual_run *runs = alloca_array (textual_run, len); | |
485 int nruns; | |
486 int i, height; | |
487 RECT rect; | |
488 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex); | |
489 | |
490 XSETWINDOW (window, w); | |
491 | |
492 #if 0 /* #### FIXME? */ | |
493 /* We can't work out the width before we've set the font in the DC */ | |
494 if (width < 0) | |
495 width = mswindows_text_width (cachel, Dynarr_atp (buf, 0), Dynarr_length (buf)); | |
496 #else | |
497 assert(width>=0); | |
498 #endif | |
499 | |
500 /* Regularize the variables passed in. */ | |
501 if (clip_start < xpos) | |
502 clip_start = xpos; | |
503 clip_end = xpos + width; | |
504 if (clip_start >= clip_end) | |
505 /* It's all clipped out. */ | |
506 return; | |
507 | |
508 xpos -= xoffset; | |
509 | |
510 /* sort out the destination rectangle */ | |
511 height = DISPLAY_LINE_HEIGHT (dl); | |
512 rect.left = clip_start; | |
513 rect.top = DISPLAY_LINE_YPOS (dl); | |
514 rect.right = clip_end; | |
515 rect.bottom = rect.top + height; | |
516 | |
517 /* make sure the area we are about to display is subwindow free. */ | |
518 redisplay_unmap_subwindows_maybe (f, clip_start, DISPLAY_LINE_YPOS (dl), | |
519 clip_end - clip_start, DISPLAY_LINE_HEIGHT (dl)); | |
520 | |
521 /* output the background pixmap if there is one */ | |
522 bg_pmap = cachel->background_pixmap; | |
523 if (!IMAGE_INSTANCEP (bg_pmap) | |
524 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap))) | |
525 bg_pmap = Qnil; | |
526 | |
527 if (!NILP(bg_pmap)) | |
528 { | |
529 struct display_box db; | |
530 struct display_glyph_area dga; | |
531 redisplay_calculate_display_boxes (dl, xpos + xoffset, 0, | |
532 clip_start, width, &db, &dga); | |
533 /* blank the background in the appropriate color */ | |
534 mswindows_update_dc (hdc, Qnil, cachel->foreground, | |
535 cachel->background, Qnil); | |
536 redisplay_output_pixmap (w, bg_pmap, &db, &dga, findex, | |
537 0, 0, 0, TRUE); | |
538 /* output pixmap calls this so we have to recall to get correct | |
539 references */ | |
540 cachel = WINDOW_FACE_CACHEL (w, findex); | |
541 } | |
542 | |
543 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0), | |
544 Dynarr_length (buf)); | |
545 | |
546 for (i = 0; i < nruns; i++) | |
547 { | |
548 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset); | |
549 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font); | |
550 int this_width; | |
551 | |
552 if (EQ (font, Vthe_null_font_instance)) | |
553 continue; | |
554 | |
555 mswindows_update_dc (hdc, font, cachel->foreground, | |
556 NILP(bg_pmap) ? cachel->background : Qnil, Qnil); | |
557 | |
558 this_width = mswindows_text_width_single_run (hdc, cachel, runs + i); | |
559 | |
560 /* cope with fonts taller than lines */ | |
561 if ((int) fi->height < (int) (height + dl->clip + dl->top_clip)) | |
562 { | |
563 int clear_start = max (xpos, clip_start); | |
564 int clear_end = min (xpos + this_width, clip_end); | |
565 | |
566 { | |
567 redisplay_clear_region (window, findex, clear_start, | |
568 DISPLAY_LINE_YPOS (dl), | |
569 clear_end - clear_start, | |
570 height); | |
571 /* output pixmap calls this so we have to recall to get correct | |
572 references */ | |
573 cachel = WINDOW_FACE_CACHEL (w, findex); | |
574 } | |
575 } | |
576 | |
577 assert (runs[i].dimension == 1); /* #### FIXME: Broken when Mule? */ | |
578 ExtTextOut (hdc, xpos, dl->ypos, | |
579 NILP(bg_pmap) ? ETO_CLIPPED | ETO_OPAQUE : ETO_CLIPPED, | |
580 &rect, (char *) runs[i].ptr, runs[i].len, NULL); | |
581 | |
582 /* #### X does underline/strikethrough here so we do the same. | |
583 On mswindows, underline/strikethrough really belongs to the font */ | |
584 if (cachel->underline || cachel->strikethru) | |
585 mswindows_apply_face_effects (hdc, dl, xpos, this_width, fi, | |
586 cachel, cachel); | |
587 xpos += this_width; | |
588 } | |
589 } | |
590 | |
591 static void | |
592 mswindows_output_dibitmap (struct frame *f, struct Lisp_Image_Instance *p, | |
593 struct display_box* db, | |
594 struct display_glyph_area* dga) | |
595 { | |
596 HDC hdc = FRAME_MSWINDOWS_DC (f); | |
597 HGDIOBJ old=NULL; | |
598 COLORREF bgcolor = GetBkColor (hdc); | |
599 | |
600 /* first blt the mask */ | |
601 if (IMAGE_INSTANCE_MSWINDOWS_MASK (p)) | |
602 { | |
603 RGBQUAD col; | |
604 col.rgbBlue = GetBValue (bgcolor); | |
605 col.rgbRed = GetRValue (bgcolor); | |
606 col.rgbGreen = GetGValue (bgcolor); | |
607 col.rgbReserved = 0; | |
608 | |
609 old = SelectObject (FRAME_MSWINDOWS_CDC (f), | |
610 IMAGE_INSTANCE_MSWINDOWS_MASK (p)); | |
611 | |
612 SetDIBColorTable (FRAME_MSWINDOWS_CDC (f), 1, 1, &col); | |
613 | |
614 BitBlt (hdc, | |
615 db->xpos, db->ypos, | |
616 dga->width, dga->height, | |
617 FRAME_MSWINDOWS_CDC (f), | |
618 dga->xoffset, dga->yoffset, | |
619 SRCCOPY); | |
620 | |
621 SelectObject (FRAME_MSWINDOWS_CDC (f), old); | |
622 } | |
623 | |
624 /* Now blt the bitmap itself, or one of its slices. */ | |
625 old = SelectObject (FRAME_MSWINDOWS_CDC (f), | |
626 IMAGE_INSTANCE_MSWINDOWS_BITMAP_SLICE | |
627 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p))); | |
628 | |
629 BitBlt (hdc, | |
630 db->xpos, db->ypos, | |
631 dga->width, dga->height, | |
632 FRAME_MSWINDOWS_CDC (f), | |
633 dga->xoffset, dga->yoffset, | |
634 IMAGE_INSTANCE_MSWINDOWS_MASK (p) ? SRCINVERT : SRCCOPY); | |
635 | |
636 SelectObject (FRAME_MSWINDOWS_CDC (f),old); | |
637 } | |
638 | |
639 /* X gc's have this nice property that setting the bg pixmap will | |
640 * output it offset relative to the window. Windows doesn't have this | |
641 * feature so we have to emulate this by outputting multiple pixmaps. | |
642 * This is only used for background pixmaps. Normal pixmaps are | |
643 * outputted once and are scrollable */ | |
644 static void | |
645 mswindows_output_dibitmap_region (struct frame *f, | |
646 struct Lisp_Image_Instance *p, | |
647 struct display_box *db, | |
648 struct display_glyph_area *dga) | |
649 { | |
650 struct display_box xdb = { db->xpos, db->ypos, db->width, db->height }; | |
651 struct display_glyph_area xdga | |
652 = { 0, 0, IMAGE_INSTANCE_PIXMAP_WIDTH (p), | |
653 IMAGE_INSTANCE_PIXMAP_HEIGHT (p) }; | |
654 int pxoffset = 0, pyoffset = 0; | |
655 | |
656 if (dga) | |
657 { | |
658 xdga.width = dga->width; | |
659 xdga.height = dga->height; | |
660 } | |
661 else if (!redisplay_normalize_glyph_area (&xdb, &xdga)) | |
662 return; | |
663 | |
664 /* when doing a bg pixmap do a partial pixmap first so that we | |
665 blt whole pixmaps thereafter */ | |
666 xdga.height = min (xdga.height, IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - | |
667 db->ypos % IMAGE_INSTANCE_PIXMAP_HEIGHT (p)); | |
668 | |
669 while (xdga.height > 0) | |
670 { | |
671 xdga.width = min (min (db->width, IMAGE_INSTANCE_PIXMAP_WIDTH (p)), | |
672 IMAGE_INSTANCE_PIXMAP_WIDTH (p) - | |
673 db->xpos % IMAGE_INSTANCE_PIXMAP_WIDTH (p)); | |
674 pxoffset = 0; | |
675 while (xdga.width > 0) | |
676 { | |
677 xdb.xpos = db->xpos + pxoffset; | |
678 xdb.ypos = db->ypos + pyoffset; | |
679 /* do we need to offset the pixmap vertically? this is necessary | |
680 for background pixmaps. */ | |
681 xdga.yoffset = xdb.ypos % IMAGE_INSTANCE_PIXMAP_HEIGHT (p); | |
682 xdga.xoffset = xdb.xpos % IMAGE_INSTANCE_PIXMAP_WIDTH (p); | |
683 /* the width is handled by mswindows_output_pixmap_region */ | |
684 mswindows_output_dibitmap (f, p, &xdb, &xdga); | |
685 pxoffset += xdga.width; | |
686 xdga.width = min ((db->width - pxoffset), | |
687 IMAGE_INSTANCE_PIXMAP_WIDTH (p)); | |
688 } | |
689 pyoffset += xdga.height; | |
690 xdga.height = min ((db->height - pyoffset), | |
691 IMAGE_INSTANCE_PIXMAP_HEIGHT (p)); | |
692 } | |
693 } | |
694 | |
695 /* Output a pixmap at the desired location. | |
696 DB normalized display_box. | |
697 DGA normalized display_glyph_area. */ | |
698 static void | |
699 mswindows_output_pixmap (struct window *w, Lisp_Object image_instance, | |
700 struct display_box *db, struct display_glyph_area *dga, | |
701 face_index findex, int cursor_start, int cursor_width, | |
702 int cursor_height, int bg_pixmap) | |
703 { | |
704 struct frame *f = XFRAME (w->frame); | |
705 HDC hdc = FRAME_MSWINDOWS_DC (f); | |
706 | |
707 struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance); | |
708 Lisp_Object window; | |
709 | |
710 XSETWINDOW (window, w); | |
711 | |
712 /* Output the pixmap. Have to do this as many times as is required | |
713 to fill the given area */ | |
714 mswindows_update_dc (hdc, Qnil, | |
715 WINDOW_FACE_CACHEL_FOREGROUND (w, findex), | |
716 WINDOW_FACE_CACHEL_BACKGROUND (w, findex), Qnil); | |
717 | |
718 if (bg_pixmap) | |
719 mswindows_output_dibitmap_region (f, p, db, dga); | |
720 else | |
721 mswindows_output_dibitmap (f, p, db, dga); | |
722 } | |
723 | |
724 #ifdef HAVE_SCROLLBARS | |
725 /* | |
726 * This function paints window's deadbox, a rectangle between window | |
727 * borders and two short edges of both scrollbars. | |
728 * | |
729 * Function checks whether deadbox intersects with the rectangle pointed | |
730 * to by PRC, and paints only the intersection | |
731 */ | |
732 static void | |
733 mswindows_redisplay_deadbox_maybe (struct window *w, CONST RECT* prc) | |
734 { | |
735 int sbh = window_scrollbar_height (w); | |
736 int sbw = window_scrollbar_width (w); | |
737 RECT rect_dead, rect_paint; | |
738 if (sbh == 0 || sbw == 0) | |
739 return; | |
740 | |
741 if (!NILP (w->scrollbar_on_left_p)) | |
742 rect_dead.left = WINDOW_LEFT (w); | |
743 else | |
744 rect_dead.left = WINDOW_TEXT_RIGHT (w); | |
745 rect_dead.right = rect_dead.left + sbw; | |
746 | |
747 if (!NILP (w->scrollbar_on_top_p)) | |
748 rect_dead.top = WINDOW_TOP (w); | |
749 else | |
750 rect_dead.top = WINDOW_TEXT_BOTTOM (w); | |
751 rect_dead.bottom = rect_dead.top + sbh; | |
752 | |
753 if (IntersectRect (&rect_paint, &rect_dead, prc)) | |
754 { | |
755 struct frame *f = XFRAME (WINDOW_FRAME (w)); | |
756 FillRect (FRAME_MSWINDOWS_DC (f), &rect_paint, | |
757 (HBRUSH) (COLOR_BTNFACE+1)); | |
758 } | |
759 } | |
760 | |
761 #endif /* HAVE_SCROLLBARS */ | |
762 | |
763 /***************************************************************************** | |
764 mswindows_redraw_exposed_window | |
765 | |
766 Given a bounding box for an area that needs to be redrawn, determine | |
767 what parts of what lines are contained within and re-output their | |
768 contents. | |
769 Copied from redisplay-x.c | |
770 ****************************************************************************/ | |
771 static void | |
772 mswindows_redraw_exposed_window (struct window *w, int x, int y, int width, | |
773 int height) | |
774 { | |
775 struct frame *f = XFRAME (w->frame); | |
776 int line; | |
777 int orig_windows_structure_changed; | |
778 RECT rect_window = { WINDOW_LEFT (w), WINDOW_TOP (w), | |
779 WINDOW_RIGHT (w), WINDOW_BOTTOM (w) }; | |
780 RECT rect_expose = { x, y, x + width, y + height }; | |
781 RECT rect_draw; | |
782 | |
783 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP); | |
784 | |
785 if (!NILP (w->vchild)) | |
786 { | |
787 mswindows_redraw_exposed_windows (w->vchild, x, y, width, height); | |
788 return; | |
789 } | |
790 else if (!NILP (w->hchild)) | |
791 { | |
792 mswindows_redraw_exposed_windows (w->hchild, x, y, width, height); | |
793 return; | |
794 } | |
795 | |
796 /* If the window doesn't intersect the exposed region, we're done here. */ | |
797 if (!IntersectRect (&rect_draw, &rect_window, &rect_expose)) | |
798 return; | |
799 | |
800 /* We do this to make sure that the 3D modelines get redrawn if | |
801 they are in the exposed region. */ | |
802 orig_windows_structure_changed = f->windows_structure_changed; | |
803 f->windows_structure_changed = 1; | |
804 | |
805 if (window_needs_vertical_divider (w)) | |
806 { | |
807 mswindows_output_vertical_divider (w, 0); | |
808 } | |
809 | |
810 for (line = 0; line < Dynarr_length (cdla); line++) | |
811 { | |
812 struct display_line *cdl = Dynarr_atp (cdla, line); | |
813 | |
814 if (DISPLAY_LINE_YPOS (cdl) + DISPLAY_LINE_HEIGHT (cdl) | |
815 >= rect_draw.top) | |
816 { | |
817 if (DISPLAY_LINE_YPOS (cdl) > rect_draw.bottom) | |
818 { | |
819 if (line == 0) | |
820 continue; | |
821 else | |
822 break; | |
823 } | |
824 else | |
825 { | |
826 output_display_line (w, 0, cdla, line, | |
827 rect_draw.left, rect_draw.right); | |
828 } | |
829 } | |
830 } | |
831 | |
832 f->windows_structure_changed = orig_windows_structure_changed; | |
833 | |
834 /* If there have never been any face cache_elements created, then this | |
835 expose event doesn't actually have anything to do. */ | |
836 if (Dynarr_largest (w->face_cachels)) | |
837 redisplay_clear_bottom_of_window (w, cdla, rect_draw.top, rect_draw.bottom); | |
838 | |
839 #ifdef HAVE_SCROLLBARS | |
840 mswindows_redisplay_deadbox_maybe (w, &rect_expose); | |
841 #endif | |
842 } | |
843 | |
844 /***************************************************************************** | |
845 mswindows_redraw_exposed_windows | |
846 | |
847 For each window beneath the given window in the window hierarchy, | |
848 ensure that it is redrawn if necessary after an Expose event. | |
849 ****************************************************************************/ | |
850 static void | |
851 mswindows_redraw_exposed_windows (Lisp_Object window, int x, int y, int width, | |
852 int height) | |
853 { | |
854 for (; !NILP (window); window = XWINDOW (window)->next) | |
855 mswindows_redraw_exposed_window (XWINDOW (window), x, y, width, height); | |
856 } | |
857 | |
858 /***************************************************************************** | |
859 mswindows_redraw_exposed_area | |
860 | |
861 For each window on the given frame, ensure that any area in the | |
862 Exposed area is redrawn. | |
863 ****************************************************************************/ | |
864 void | |
865 mswindows_redraw_exposed_area (struct frame *f, int x, int y, int width, int height) | |
866 { | |
867 /* If any window on the frame has had its face cache reset then the | |
868 redisplay structures are effectively invalid. If we attempt to | |
869 use them we'll blow up. We mark the frame as changed to ensure | |
870 that redisplay will do a full update. This probably isn't | |
871 necessary but it can't hurt. */ | |
872 #ifdef HAVE_TOOLBARS | |
873 /* #### We would rather put these off as well but there is currently | |
874 no combination of flags which will force an unchanged toolbar to | |
875 redraw anyhow. */ | |
876 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height)); | |
877 #endif | |
878 redraw_exposed_gutters (f, x, y, width, height); | |
879 | |
880 if (!f->window_face_cache_reset) | |
881 { | |
882 mswindows_redraw_exposed_windows (f->root_window, x, y, width, height); | |
883 GdiFlush(); | |
884 } | |
885 else | |
886 MARK_FRAME_CHANGED (f); | |
887 } | |
888 | |
889 | |
890 /***************************************************************************** | |
891 mswindows_bevel_area | |
892 | |
893 Draw a 3d border around the specified area on window W. | |
894 ****************************************************************************/ | |
895 static void | |
896 mswindows_bevel_area (struct window *w, face_index findex, int x, int y, | |
897 int width, int height, int thickness, | |
898 int edges, enum edge_style style) | |
899 { | |
900 struct frame *f = XFRAME (w->frame); | |
901 UINT edge; | |
902 UINT border = 0; | |
903 | |
904 if (style == EDGE_ETCHED_IN) | |
905 edge = EDGE_ETCHED; | |
906 else if (style == EDGE_ETCHED_OUT) | |
907 edge = EDGE_BUMP; | |
908 else if (style == EDGE_BEVEL_IN) | |
909 { | |
910 if (thickness == 1) | |
911 edge = BDR_SUNKENINNER; | |
912 else | |
913 edge = EDGE_SUNKEN; | |
914 } | |
915 else /* EDGE_BEVEL_OUT */ | |
916 { | |
917 if (thickness == 1) | |
918 edge = BDR_RAISEDINNER; | |
919 else | |
920 edge = EDGE_RAISED; | |
921 } | |
922 | |
923 if (edges & EDGE_TOP) | |
924 border |= BF_TOP; | |
925 if (edges & EDGE_LEFT) | |
926 border |= BF_LEFT; | |
927 if (edges & EDGE_BOTTOM) | |
928 border |= BF_BOTTOM; | |
929 if (edges & EDGE_RIGHT) | |
930 border |= BF_RIGHT; | |
931 | |
932 { | |
933 RECT rect = { x, y, x + width, y + height }; | |
934 Lisp_Object color = WINDOW_FACE_CACHEL_BACKGROUND (w, findex); | |
935 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, color, Qnil); | |
936 | |
937 DrawEdge (FRAME_MSWINDOWS_DC (f), &rect, edge, border); | |
938 } | |
939 } | |
940 | |
941 | |
942 /***************************************************************************** | |
943 Display methods | |
944 *****************************************************************************/ | |
945 | |
946 /***************************************************************************** | |
947 mswindows_divider_height | |
948 | |
949 Return the height of the horizontal divider. | |
950 ****************************************************************************/ | |
951 static int | |
952 mswindows_divider_height (void) | |
953 { | |
954 return 1; /* XXX Copied from redisplay-X.c. What is this? */ | |
955 } | |
956 | |
957 /***************************************************************************** | |
958 mswindows_eol_cursor_width | |
959 | |
960 Return the width of the end-of-line cursor. | |
961 ****************************************************************************/ | |
962 static int | |
963 mswindows_eol_cursor_width (void) | |
964 { | |
965 return MSWINDOWS_EOL_CURSOR_WIDTH; | |
966 } | |
967 | |
968 /***************************************************************************** | |
969 mswindows_output_begin | |
970 | |
971 Perform any necessary initialization prior to an update. | |
972 ****************************************************************************/ | |
973 static void | |
974 mswindows_output_begin (struct device *d) | |
975 { | |
976 } | |
977 | |
978 /***************************************************************************** | |
979 mswindows_output_end | |
980 | |
981 Perform any necessary flushing of queues when an update has completed. | |
982 ****************************************************************************/ | |
983 static void | |
984 mswindows_output_end (struct device *d) | |
985 { | |
986 GdiFlush(); | |
987 } | |
988 | |
989 static int | |
990 mswindows_flash (struct device *d) | |
991 { | |
992 struct frame *f = device_selected_frame (d); | |
993 RECT rc; | |
994 | |
995 GetClientRect (FRAME_MSWINDOWS_HANDLE (f), &rc); | |
996 InvertRect (FRAME_MSWINDOWS_DC (f), &rc); | |
997 GdiFlush (); | |
998 Sleep (25); | |
999 InvertRect (FRAME_MSWINDOWS_DC (f), &rc); | |
1000 | |
1001 return 1; | |
1002 } | |
1003 | |
1004 static void | |
1005 mswindows_ring_bell (struct device *d, int volume, int pitch, int duration) | |
1006 { | |
1007 /* Beep does not work at all, anyways! -kkm */ | |
1008 MessageBeep (MB_OK); | |
1009 } | |
1010 | |
1011 /***************************************************************************** | |
1012 mswindows_output_display_block | |
1013 | |
1014 Given a display line, a block number for that start line, output all | |
1015 runes between start and end in the specified display block. | |
1016 Ripped off with minimal thought from the corresponding X routine. | |
1017 ****************************************************************************/ | |
1018 static void | |
1019 mswindows_output_display_block (struct window *w, struct display_line *dl, int block, | |
1020 int start, int end, int start_pixpos, int cursor_start, | |
1021 int cursor_width, int cursor_height) | |
1022 { | |
1023 struct frame *f = XFRAME (w->frame); | |
1024 Emchar_dynarr *buf = Dynarr_new (Emchar); | |
1025 Lisp_Object window; | |
1026 | |
1027 struct display_block *db = Dynarr_atp (dl->display_blocks, block); | |
1028 rune_dynarr *rba = db->runes; | |
1029 struct rune *rb; | |
1030 | |
1031 int elt = start; | |
1032 face_index findex; | |
1033 int xpos, width; | |
1034 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when | |
1035 MULE is not defined */ | |
1036 XSETWINDOW (window, w); | |
1037 rb = Dynarr_atp (rba, start); | |
1038 | |
1039 if (!rb) | |
1040 /* Nothing to do so don't do anything. */ | |
1041 return; | |
1042 | |
1043 findex = rb->findex; | |
1044 xpos = rb->xpos; | |
1045 width = 0; | |
1046 if (rb->type == RUNE_CHAR) | |
1047 charset = CHAR_CHARSET (rb->object.chr.ch); | |
1048 | |
1049 if (end < 0) | |
1050 end = Dynarr_length (rba); | |
1051 Dynarr_reset (buf); | |
1052 | |
1053 while (elt < end) | |
1054 { | |
1055 rb = Dynarr_atp (rba, elt); | |
1056 | |
1057 if (rb->findex == findex && rb->type == RUNE_CHAR | |
1058 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON | |
1059 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch))) | |
1060 { | |
1061 Dynarr_add (buf, rb->object.chr.ch); | |
1062 width += rb->width; | |
1063 elt++; | |
1064 } | |
1065 else | |
1066 { | |
1067 if (Dynarr_length (buf)) | |
1068 { | |
1069 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width, | |
1070 findex, 0, 0, 0, 0); | |
1071 xpos = rb->xpos; | |
1072 width = 0; | |
1073 } | |
1074 Dynarr_reset (buf); | |
1075 width = 0; | |
1076 | |
1077 if (rb->type == RUNE_CHAR) | |
1078 { | |
1079 findex = rb->findex; | |
1080 xpos = rb->xpos; | |
1081 charset = CHAR_CHARSET (rb->object.chr.ch); | |
1082 | |
1083 if (rb->cursor_type == CURSOR_ON) | |
1084 { | |
1085 if (rb->object.chr.ch == '\n') | |
1086 { | |
1087 mswindows_output_cursor (w, dl, xpos, cursor_width, | |
1088 findex, 0, 0); | |
1089 } | |
1090 else | |
1091 { | |
1092 Dynarr_add (buf, rb->object.chr.ch); | |
1093 mswindows_output_cursor (w, dl, xpos, cursor_width, | |
1094 findex, rb->object.chr.ch, 0); | |
1095 Dynarr_reset (buf); | |
1096 } | |
1097 | |
1098 xpos += rb->width; | |
1099 elt++; | |
1100 } | |
1101 else if (rb->object.chr.ch == '\n') | |
1102 { | |
1103 /* Clear in case a cursor was formerly here. */ | |
1104 redisplay_clear_region (window, findex, xpos, | |
1105 DISPLAY_LINE_YPOS (dl), | |
1106 rb->width, DISPLAY_LINE_HEIGHT (dl)); | |
1107 elt++; | |
1108 } | |
1109 } | |
1110 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE) | |
1111 { | |
1112 if (rb->type == RUNE_BLANK) | |
1113 mswindows_output_blank (w, dl, rb, start_pixpos); | |
1114 else | |
1115 { | |
1116 /* #### Our flagging of when we need to redraw the | |
1117 modeline shadows sucks. Since RUNE_HLINE is only used | |
1118 by the modeline at the moment it is a good bet | |
1119 that if it gets redrawn then we should also | |
1120 redraw the shadows. This won't be true forever. | |
1121 We borrow the shadow_thickness_changed flag for | |
1122 now. */ | |
1123 w->shadow_thickness_changed = 1; | |
1124 mswindows_output_hline (w, dl, rb); | |
1125 } | |
1126 | |
1127 if (rb->cursor_type == CURSOR_ON) | |
1128 mswindows_output_cursor (w, dl, xpos, cursor_width, rb->findex, 0, 0); | |
1129 | |
1130 elt++; | |
1131 if (elt < end) | |
1132 { | |
1133 rb = Dynarr_atp (rba, elt); | |
1134 | |
1135 findex = rb->findex; | |
1136 xpos = rb->xpos; | |
1137 } | |
1138 } | |
1139 else if (rb->type == RUNE_DGLYPH) | |
1140 { | |
1141 Lisp_Object instance; | |
1142 struct display_box db; | |
1143 struct display_glyph_area dga; | |
1144 redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset, | |
1145 start_pixpos, rb->width, | |
1146 &db, &dga); | |
1147 | |
1148 XSETWINDOW (window, w); | |
1149 instance = glyph_image_instance (rb->object.dglyph.glyph, | |
1150 window, ERROR_ME_NOT, 1); | |
1151 findex = rb->findex; | |
1152 | |
1153 if (IMAGE_INSTANCEP (instance)) | |
1154 switch (XIMAGE_INSTANCE_TYPE (instance)) | |
1155 { | |
1156 case IMAGE_TEXT: | |
1157 { | |
1158 /* #### This is way losing. See the comment in | |
1159 add_glyph_rune(). */ | |
1160 Lisp_Object string = | |
1161 XIMAGE_INSTANCE_TEXT_STRING (instance); | |
1162 convert_bufbyte_string_into_emchar_dynarr | |
1163 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf); | |
1164 | |
1165 if (rb->cursor_type == CURSOR_ON) | |
1166 mswindows_output_cursor (w, dl, xpos, cursor_width, | |
1167 findex, Dynarr_at (buf, 0), 0); | |
1168 else /* #### redisplay-x passes -1 as the width: why ? */ | |
1169 mswindows_output_string (w, dl, buf, xpos, | |
1170 rb->object.dglyph.xoffset, | |
1171 start_pixpos, rb->width, findex, | |
1172 0, 0, 0, 0); | |
1173 Dynarr_reset (buf); | |
1174 } | |
1175 break; | |
1176 | |
1177 case IMAGE_MONO_PIXMAP: | |
1178 case IMAGE_COLOR_PIXMAP: | |
1179 redisplay_output_pixmap (w, instance, &db, &dga, findex, | |
1180 cursor_start, cursor_width, | |
1181 cursor_height, 0); | |
1182 if (rb->cursor_type == CURSOR_ON) | |
1183 mswindows_output_cursor (w, dl, xpos, cursor_width, | |
1184 findex, 0, 1); | |
1185 break; | |
1186 | |
1187 case IMAGE_POINTER: | |
1188 abort (); | |
1189 | |
1190 case IMAGE_SUBWINDOW: | |
1191 case IMAGE_WIDGET: | |
1192 redisplay_output_subwindow (w, instance, &db, &dga, findex, | |
1193 cursor_start, cursor_width, | |
1194 cursor_height); | |
1195 if (rb->cursor_type == CURSOR_ON) | |
1196 mswindows_output_cursor (w, dl, xpos, cursor_width, | |
1197 findex, 0, 1); | |
1198 break; | |
1199 | |
1200 case IMAGE_LAYOUT: | |
1201 redisplay_output_layout (w, instance, &db, &dga, findex, | |
1202 cursor_start, cursor_width, | |
1203 cursor_height); | |
1204 if (rb->cursor_type == CURSOR_ON) | |
1205 mswindows_output_cursor (w, dl, xpos, cursor_width, | |
1206 findex, 0, 1); | |
1207 break; | |
1208 | |
1209 case IMAGE_NOTHING: | |
1210 /* nothing is as nothing does */ | |
1211 break; | |
1212 | |
1213 default: | |
1214 abort (); | |
1215 } | |
1216 | |
1217 xpos += rb->width; | |
1218 elt++; | |
1219 } | |
1220 else | |
1221 abort (); | |
1222 } | |
1223 } | |
1224 | |
1225 if (Dynarr_length (buf)) | |
1226 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex, | |
1227 0, 0, 0, 0); | |
1228 | |
1229 if (dl->modeline | |
1230 && !EQ (Qzero, w->modeline_shadow_thickness) | |
1231 && (f->clear | |
1232 || f->windows_structure_changed | |
1233 || w->shadow_thickness_changed)) | |
1234 bevel_modeline (w, dl); | |
1235 | |
1236 Dynarr_free (buf); | |
1237 } | |
1238 | |
1239 | |
1240 /***************************************************************************** | |
1241 mswindows_output_vertical_divider | |
1242 | |
1243 Draw a vertical divider down the right side of the given window. | |
1244 ****************************************************************************/ | |
1245 static void | |
1246 mswindows_output_vertical_divider (struct window *w, int clear_unused) | |
1247 { | |
1248 struct frame *f = XFRAME (w->frame); | |
1249 RECT rect; | |
1250 int spacing = XINT (w->vertical_divider_spacing); | |
1251 int shadow = XINT (w->vertical_divider_shadow_thickness); | |
1252 int abs_shadow = abs (shadow); | |
1253 int line_width = XINT (w->vertical_divider_line_width); | |
1254 int div_left = WINDOW_RIGHT (w) - window_divider_width (w); | |
1255 int y1 = WINDOW_TOP (w) + FRAME_TOP_GUTTER_BOUNDS (f); | |
1256 int y2 = WINDOW_BOTTOM (w) + FRAME_BOTTOM_GUTTER_BOUNDS (f); | |
1257 | |
1258 /* Clear left and right spacing areas */ | |
1259 if (spacing) | |
1260 { | |
1261 rect.top = y1; | |
1262 rect.bottom = y2; | |
1263 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, | |
1264 WINDOW_FACE_CACHEL_BACKGROUND (w, DEFAULT_INDEX), Qnil); | |
1265 rect.right = WINDOW_RIGHT (w); | |
1266 rect.left = rect.right - spacing; | |
1267 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, | |
1268 &rect, NULL, 0, NULL); | |
1269 rect.left = div_left; | |
1270 rect.right = div_left + spacing; | |
1271 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, | |
1272 &rect, NULL, 0, NULL); | |
1273 } | |
1274 | |
1275 /* Clear divider face */ | |
1276 rect.top = y1 + abs_shadow; | |
1277 rect.bottom = y2 - abs_shadow; | |
1278 rect.left = div_left + spacing + abs_shadow; | |
1279 rect.right = rect.left + line_width; | |
1280 if (rect.left < rect.right) | |
1281 { | |
1282 face_index div_face | |
1283 = get_builtin_face_cache_index (w, Vvertical_divider_face); | |
1284 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, | |
1285 WINDOW_FACE_CACHEL_BACKGROUND (w, div_face), Qnil); | |
1286 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, | |
1287 &rect, NULL, 0, NULL); | |
1288 } | |
1289 | |
1290 /* Draw a shadow around the divider */ | |
1291 if (shadow != 0) | |
1292 { | |
1293 /* #### This will be fixed to support arbitrary thickness */ | |
1294 InflateRect (&rect, abs_shadow, abs_shadow); | |
1295 DrawEdge (FRAME_MSWINDOWS_DC (f), &rect, | |
1296 shadow > 0 ? EDGE_RAISED : EDGE_SUNKEN, BF_RECT); | |
1297 } | |
1298 } | |
1299 | |
1300 /**************************************************************************** | |
1301 mswindows_text_width | |
1302 | |
1303 Given a string and a face, return the string's length in pixels when | |
1304 displayed in the font associated with the face. | |
1305 ****************************************************************************/ | |
1306 static int | |
1307 mswindows_text_width (struct frame *f, struct face_cachel *cachel, | |
1308 CONST Emchar *str, Charcount len) | |
1309 { | |
1310 int width_so_far = 0; | |
1311 unsigned char *text_storage = (unsigned char *) alloca (2 * len); | |
1312 textual_run *runs = alloca_array (textual_run, len); | |
1313 int nruns; | |
1314 int i; | |
1315 | |
1316 nruns = separate_textual_runs (text_storage, runs, str, len); | |
1317 | |
1318 for (i = 0; i < nruns; i++) | |
1319 width_so_far += mswindows_text_width_single_run (FRAME_MSWINDOWS_DC (f), | |
1320 cachel, runs + i); | |
1321 | |
1322 return width_so_far; | |
1323 } | |
1324 | |
1325 | |
1326 /**************************************************************************** | |
1327 mswindows_clear_region | |
1328 | |
1329 Clear the area in the box defined by the given parameters using the | |
1330 given face. | |
1331 ****************************************************************************/ | |
1332 static void | |
1333 mswindows_clear_region (Lisp_Object locale, struct device* d, struct frame* f, | |
1334 face_index findex, int x, int y, | |
1335 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor, | |
1336 Lisp_Object background_pixmap) | |
1337 { | |
1338 RECT rect = { x, y, x+width, y+height }; | |
1339 | |
1340 if (!NILP (background_pixmap)) | |
1341 { | |
1342 struct display_box db = { x, y, width, height }; | |
1343 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), | |
1344 Qnil, fcolor, bcolor, background_pixmap); | |
1345 mswindows_output_dibitmap_region | |
1346 ( f, XIMAGE_INSTANCE (background_pixmap), &db, 0); | |
1347 } | |
1348 else | |
1349 { | |
1350 mswindows_update_dc (FRAME_MSWINDOWS_DC (f), Qnil, Qnil, fcolor, Qnil); | |
1351 ExtTextOut (FRAME_MSWINDOWS_DC (f), 0, 0, ETO_OPAQUE, | |
1352 &rect, NULL, 0, NULL); | |
1353 } | |
1354 | |
1355 #ifdef HAVE_SCROLLBARS | |
1356 if (WINDOWP (locale)) | |
1357 mswindows_redisplay_deadbox_maybe (XWINDOW (locale), &rect); | |
1358 #endif | |
1359 } | |
1360 | |
1361 /* XXX Implement me! */ | |
1362 static void | |
1363 mswindows_clear_frame (struct frame *f) | |
1364 { | |
1365 GdiFlush(); | |
1366 } | |
1367 | |
1368 | |
1369 | |
1370 /************************************************************************/ | |
1371 /* initialization */ | |
1372 /************************************************************************/ | |
1373 | |
1374 void | |
1375 console_type_create_redisplay_mswindows (void) | |
1376 { | |
1377 /* redisplay methods */ | |
1378 CONSOLE_HAS_METHOD (mswindows, text_width); | |
1379 CONSOLE_HAS_METHOD (mswindows, output_display_block); | |
1380 CONSOLE_HAS_METHOD (mswindows, divider_height); | |
1381 CONSOLE_HAS_METHOD (mswindows, eol_cursor_width); | |
1382 CONSOLE_HAS_METHOD (mswindows, output_vertical_divider); | |
1383 CONSOLE_HAS_METHOD (mswindows, clear_region); | |
1384 CONSOLE_HAS_METHOD (mswindows, clear_frame); | |
1385 CONSOLE_HAS_METHOD (mswindows, output_begin); | |
1386 CONSOLE_HAS_METHOD (mswindows, output_end); | |
1387 CONSOLE_HAS_METHOD (mswindows, flash); | |
1388 CONSOLE_HAS_METHOD (mswindows, ring_bell); | |
1389 CONSOLE_HAS_METHOD (mswindows, bevel_area); | |
1390 CONSOLE_HAS_METHOD (mswindows, output_string); | |
1391 CONSOLE_HAS_METHOD (mswindows, output_pixmap); | |
1392 } |