Mercurial > hg > xemacs-beta
comparison src/redisplay-msw.c @ 213:78f53ef88e17 r20-4b5
Import from CVS: tag r20-4b5
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:06:47 +0200 |
parents | |
children | 1f0dabaa0855 |
comparison
equal
deleted
inserted
replaced
212:d8688acf4c5b | 213:78f53ef88e17 |
---|---|
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 20.4. | |
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.h" /* XXX FIXME: Should be glyphs-mswindows when we make one */ | |
44 #include "redisplay.h" | |
45 #include "sysdep.h" | |
46 #include "window.h" | |
47 | |
48 #include "windows.h" | |
49 | |
50 /* MSWINDOWS_DIVIDER_LINE_WIDTH is the width of the line drawn in the gutter. | |
51 MSWINDOWS_DIVIDER_SPACING is the amount of blank space on each side of the line. | |
52 MSWINDOWS_DIVIDER_WIDTH = MSWINDOWS_DIVIDER_LINE_WIDTH + 2*MSWINDOWS_DIVIDER_SPACING | |
53 */ | |
54 #define MSWINDOWS_DIVIDER_LINE_WIDTH 7 | |
55 #define MSWINDOWS_DIVIDER_SPACING 0 | |
56 #define MSWINDOWS_DIVIDER_WIDTH (MSWINDOWS_DIVIDER_LINE_WIDTH + 2 * MSWINDOWS_DIVIDER_SPACING) | |
57 | |
58 #define MSWINDOWS_EOL_CURSOR_WIDTH 5 | |
59 | |
60 /* | |
61 * Random forward delarations | |
62 */ | |
63 static void mswindows_clear_region (Lisp_Object locale, face_index findex, | |
64 int x, int y, int width, int height); | |
65 static void mswindows_output_vertical_divider (struct window *w, int clear); | |
66 static void mswindows_redraw_exposed_windows (Lisp_Object window, int x, | |
67 int y, int width, int height); | |
68 | |
69 | |
70 | |
71 typedef struct textual_run | |
72 { | |
73 Lisp_Object charset; | |
74 unsigned char *ptr; | |
75 int len; | |
76 int dimension; | |
77 } textual_run; | |
78 | |
79 /* Separate out the text in DYN into a series of textual runs of a | |
80 particular charset. Also convert the characters as necessary into | |
81 the format needed by XDrawImageString(), XDrawImageString16(), et | |
82 al. (This means converting to one or two byte format, possibly | |
83 tweaking the high bits, and possibly running a CCL program.) You | |
84 must pre-allocate the space used and pass it in. (This is done so | |
85 you can alloca() the space.) You need to allocate (2 * len) bytes | |
86 of TEXT_STORAGE and (len * sizeof (textual_run)) bytes of | |
87 RUN_STORAGE, where LEN is the length of the dynarr. | |
88 | |
89 Returns the number of runs actually used. */ | |
90 | |
91 static int | |
92 separate_textual_runs (unsigned char *text_storage, | |
93 textual_run *run_storage, | |
94 CONST Emchar *str, Charcount len) | |
95 { | |
96 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a | |
97 possible valid charset when | |
98 MULE is not defined */ | |
99 int runs_so_far = 0; | |
100 int i; | |
101 #ifdef MULE | |
102 struct ccl_program char_converter; | |
103 int need_ccl_conversion = 0; | |
104 #endif | |
105 | |
106 for (i = 0; i < len; i++) | |
107 { | |
108 Emchar ch = str[i]; | |
109 Lisp_Object charset; | |
110 int byte1, byte2; | |
111 int dimension; | |
112 int graphic; | |
113 | |
114 BREAKUP_CHAR (ch, charset, byte1, byte2); | |
115 dimension = XCHARSET_DIMENSION (charset); | |
116 graphic = XCHARSET_GRAPHIC (charset); | |
117 | |
118 if (!EQ (charset, prev_charset)) | |
119 { | |
120 run_storage[runs_so_far].ptr = text_storage; | |
121 run_storage[runs_so_far].charset = charset; | |
122 run_storage[runs_so_far].dimension = dimension; | |
123 | |
124 if (runs_so_far) | |
125 { | |
126 run_storage[runs_so_far - 1].len = | |
127 text_storage - run_storage[runs_so_far - 1].ptr; | |
128 if (run_storage[runs_so_far - 1].dimension == 2) | |
129 run_storage[runs_so_far - 1].len >>= 1; | |
130 } | |
131 runs_so_far++; | |
132 prev_charset = charset; | |
133 #ifdef MULE | |
134 { | |
135 Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset); | |
136 need_ccl_conversion = !NILP (ccl_prog); | |
137 if (need_ccl_conversion) | |
138 setup_ccl_program (&char_converter, ccl_prog); | |
139 } | |
140 #endif | |
141 } | |
142 | |
143 if (graphic == 0) | |
144 { | |
145 byte1 &= 0x7F; | |
146 byte2 &= 0x7F; | |
147 } | |
148 else if (graphic == 1) | |
149 { | |
150 byte1 |= 0x80; | |
151 byte2 |= 0x80; | |
152 } | |
153 #ifdef MULE | |
154 if (need_ccl_conversion) | |
155 { | |
156 char_converter.reg[0] = XCHARSET_ID (charset); | |
157 char_converter.reg[1] = byte1; | |
158 char_converter.reg[2] = byte2; | |
159 char_converter.ic = 0; /* start at beginning each time */ | |
160 ccl_driver (&char_converter, 0, 0, 0, 0); | |
161 byte1 = char_converter.reg[1]; | |
162 byte2 = char_converter.reg[2]; | |
163 } | |
164 #endif | |
165 *text_storage++ = (unsigned char) byte1; | |
166 if (dimension == 2) | |
167 *text_storage++ = (unsigned char) byte2; | |
168 } | |
169 | |
170 if (runs_so_far) | |
171 { | |
172 run_storage[runs_so_far - 1].len = | |
173 text_storage - run_storage[runs_so_far - 1].ptr; | |
174 if (run_storage[runs_so_far - 1].dimension == 2) | |
175 run_storage[runs_so_far - 1].len >>= 1; | |
176 } | |
177 | |
178 return runs_so_far; | |
179 } | |
180 | |
181 | |
182 static int | |
183 mswindows_text_width_single_run (HDC hdc, struct face_cachel *cachel, | |
184 textual_run *run) | |
185 { | |
186 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset); | |
187 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst); | |
188 SIZE size; | |
189 | |
190 #if 0 /* XXX HACK: mswindows_text_width is broken and will pass in a NULL hdc */ | |
191 if (!fi->proportional_p) | |
192 #else | |
193 if (!fi->proportional_p || !hdc) | |
194 #endif | |
195 return (fi->width * run->len); | |
196 else | |
197 { | |
198 assert(run->dimension == 1); /* XXX FIXME! */ | |
199 GetTextExtentPoint32(hdc, run->ptr, run->len, &size); | |
200 return(size.cx); | |
201 } | |
202 } | |
203 | |
204 | |
205 /***************************************************************************** | |
206 mswindows_update_gc | |
207 | |
208 Given a number of parameters munge the GC so it has those properties. | |
209 ****************************************************************************/ | |
210 static void | |
211 mswindows_update_gc (HDC hdc, Lisp_Object font, Lisp_Object fg, Lisp_Object bg, | |
212 Lisp_Object bg_pmap, Lisp_Object lwidth) | |
213 { | |
214 if (!NILP (font)) | |
215 SelectObject(hdc, (XFONT_INSTANCE (font))->data); | |
216 | |
217 /* evil kludge! - XXX do we need this? */ | |
218 if (!NILP (fg) && !COLOR_INSTANCEP (fg)) | |
219 { | |
220 fprintf (stderr, "Help! mswindows_update_gc got a bogus fg value! fg = "); | |
221 debug_print (fg); | |
222 fg = Qnil; | |
223 } | |
224 | |
225 if (!NILP (fg)) | |
226 SetTextColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (fg))); | |
227 | |
228 if (!NILP (bg)) | |
229 SetBkColor (hdc, COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (bg))); | |
230 | |
231 #if 0 /* XXX Implement me */ | |
232 /* I expect that the Lisp_Image_Instance's data will point to a brush */ | |
233 if (IMAGE_INSTANCEP (bg_pmap) | |
234 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap))) | |
235 { | |
236 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0) | |
237 { | |
238 gcv.fill_style = FillOpaqueStippled; | |
239 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap); | |
240 mask |= (GCStipple | GCFillStyle); | |
241 } | |
242 else | |
243 { | |
244 gcv.fill_style = FillTiled; | |
245 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap); | |
246 mask |= (GCTile | GCFillStyle); | |
247 } | |
248 } | |
249 #endif | |
250 | |
251 #if 0 /* XXX FIXME */ | |
252 if (!NILP (lwidth)) | |
253 { | |
254 gcv.line_width = XINT (lwidth); | |
255 mask |= GCLineWidth; | |
256 } | |
257 #endif | |
258 } | |
259 | |
260 | |
261 /***************************************************************************** | |
262 mswindows_output_hline | |
263 | |
264 Output a horizontal line in the foreground of its face. | |
265 ****************************************************************************/ | |
266 static void | |
267 mswindows_output_hline (struct window *w, struct display_line *dl, struct rune *rb) | |
268 { /* XXX Implement me */ | |
269 } | |
270 | |
271 | |
272 /***************************************************************************** | |
273 mswindows_output_blank | |
274 | |
275 Output a blank by clearing the area it covers in the background color | |
276 of its face. | |
277 ****************************************************************************/ | |
278 static void | |
279 mswindows_output_blank (struct window *w, struct display_line *dl, struct rune *rb) | |
280 { | |
281 struct frame *f = XFRAME (w->frame); | |
282 RECT rect = { rb->xpos, dl->ypos-dl->ascent, | |
283 rb->xpos+rb->width, dl->ypos+dl->descent-dl->clip }; | |
284 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, rb->findex); | |
285 | |
286 Lisp_Object bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex); | |
287 | |
288 if (!IMAGE_INSTANCEP (bg_pmap) | |
289 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap))) | |
290 bg_pmap = Qnil; | |
291 | |
292 FillRect (FRAME_MSWINDOWS_DC (f), &rect, | |
293 COLOR_INSTANCE_MSWINDOWS_BRUSH (XCOLOR_INSTANCE (cachel->background))); | |
294 } | |
295 | |
296 | |
297 /***************************************************************************** | |
298 mswindows_output_cursor | |
299 | |
300 Draw a normal or end-of-line cursor. The end-of-line cursor is | |
301 narrower than the normal cursor. | |
302 ****************************************************************************/ | |
303 static void | |
304 mswindows_output_cursor (struct window *w, struct display_line *dl, int xpos, | |
305 int width, struct rune *rb) | |
306 { | |
307 struct frame *f = XFRAME (w->frame); | |
308 struct device *d = XDEVICE (f->device); | |
309 struct face_cachel *cachel; | |
310 Lisp_Object font; | |
311 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d)); | |
312 HBRUSH brush; | |
313 HDC hdc = FRAME_MSWINDOWS_DC (f); | |
314 int real_char_p = (rb->type == RUNE_CHAR && rb->object.chr.ch != '\n'); | |
315 RECT rect = { xpos, | |
316 dl->ypos - dl->ascent, | |
317 xpos + width, | |
318 dl->ypos + dl->descent - dl->clip}; | |
319 | |
320 #if 0 /* XXX FIXME: Whar about the bar_cursor? */ | |
321 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor, | |
322 WINDOW_BUFFER (w)); | |
323 #endif | |
324 | |
325 if (real_char_p) | |
326 { | |
327 /* Use the font from the underlying character */ | |
328 cachel = WINDOW_FACE_CACHEL (w, rb->findex); | |
329 | |
330 /* XXX MULE: Need to know the charset! */ | |
331 font = FACE_CACHEL_FONT (cachel, Vcharset_ascii); | |
332 } | |
333 | |
334 /* Clear the area */ | |
335 if (focus) | |
336 cachel = WINDOW_FACE_CACHEL (w, | |
337 get_builtin_face_cache_index (w, Vtext_cursor_face)); | |
338 else if (!real_char_p) | |
339 cachel = WINDOW_FACE_CACHEL (w, rb->findex); | |
340 | |
341 brush = COLOR_INSTANCE_MSWINDOWS_BRUSH (XCOLOR_INSTANCE (cachel->background)); | |
342 FillRect (hdc, &rect, brush); | |
343 | |
344 if (real_char_p) | |
345 { | |
346 /* XXX FIXME: Need to clip if dl->clip!=0. How rare is this case? */ | |
347 /* Output the underlying character */ | |
348 mswindows_update_gc (hdc, font, cachel->foreground, | |
349 cachel->background, Qnil, Qnil); | |
350 TextOut(hdc, xpos, dl->ypos, (char*) &rb->object.chr.ch, 1); | |
351 } | |
352 | |
353 if (!focus) | |
354 { | |
355 /* Draw hollow rectangle in cursor's background color */ | |
356 cachel = WINDOW_FACE_CACHEL (w, | |
357 get_builtin_face_cache_index (w, Vtext_cursor_face)); | |
358 brush = COLOR_INSTANCE_MSWINDOWS_BRUSH (XCOLOR_INSTANCE (cachel->background)); | |
359 FrameRect (hdc, &rect, brush); | |
360 } | |
361 } | |
362 | |
363 | |
364 /***************************************************************************** | |
365 mswindows_output_string | |
366 | |
367 Given a string and a starting position, output that string in the | |
368 given face. | |
369 Correctly handles multiple charsets in the string. | |
370 | |
371 The meaning of the parameters is something like this: | |
372 | |
373 W Window that the text is to be displayed in. | |
374 DL Display line that this text is on. The values in the | |
375 structure are used to determine the vertical position and | |
376 clipping range of the text. | |
377 BUF Dynamic array of Emchars specifying what is actually to be | |
378 drawn. | |
379 XPOS X position in pixels where the text should start being drawn. | |
380 XOFFSET Number of pixels to be chopped off the left side of the | |
381 text. The effect is as if the text were shifted to the | |
382 left this many pixels and clipped at XPOS. | |
383 CLIP_START Clip everything left of this X position. | |
384 WIDTH Clip everything right of XPOS + WIDTH. | |
385 FINDEX Index for the face cache element describing how to display | |
386 the text. | |
387 ****************************************************************************/ | |
388 void | |
389 mswindows_output_string (struct window *w, struct display_line *dl, | |
390 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start, | |
391 int width, face_index findex) | |
392 { | |
393 struct frame *f = XFRAME (w->frame); | |
394 struct device *d = XDEVICE (f->device); | |
395 Lisp_Object window = Qnil; | |
396 HDC hdc; | |
397 int clip_end; | |
398 Lisp_Object bg_pmap; | |
399 int len = Dynarr_length (buf); | |
400 unsigned char *text_storage = (unsigned char *) alloca (2 * len); | |
401 textual_run *runs = alloca_array (textual_run, len); | |
402 int nruns; | |
403 int i; | |
404 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex); | |
405 | |
406 XSETWINDOW (window, w); | |
407 hdc = FRAME_MSWINDOWS_DC(f); | |
408 | |
409 #if 0 /* XXX: FIXME? */ | |
410 /* We can't work out the width before we've set the font in the DC */ | |
411 if (width < 0) | |
412 width = mswindows_text_width (cachel, Dynarr_atp (buf, 0), Dynarr_length (buf)); | |
413 #else | |
414 assert(width>=0); | |
415 #endif | |
416 | |
417 /* Regularize the variables passed in. */ | |
418 if (clip_start < xpos) | |
419 clip_start = xpos; | |
420 clip_end = xpos + width; | |
421 if (clip_start >= clip_end) | |
422 /* It's all clipped out. */ | |
423 return; | |
424 | |
425 xpos -= xoffset; | |
426 | |
427 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0), | |
428 Dynarr_length (buf)); | |
429 | |
430 bg_pmap = cachel->background_pixmap; | |
431 if (!IMAGE_INSTANCEP (bg_pmap) | |
432 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap))) | |
433 bg_pmap = Qnil; | |
434 | |
435 for (i = 0; i < nruns; i++) | |
436 { | |
437 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset); | |
438 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font); | |
439 int this_width; | |
440 int need_clipping; | |
441 RECT rect = { clip_start, dl->ypos - dl->ascent, | |
442 clip_end, dl->ypos + dl->descent - dl->clip }; | |
443 HRGN region; | |
444 | |
445 if (EQ (font, Vthe_null_font_instance)) | |
446 continue; | |
447 | |
448 mswindows_update_gc (hdc, font, cachel->foreground, | |
449 cachel->background, Qnil, Qnil); | |
450 | |
451 this_width = mswindows_text_width_single_run (hdc, cachel, runs + i); | |
452 need_clipping = (dl->clip || clip_start > xpos || | |
453 clip_end < xpos + this_width); | |
454 | |
455 if (need_clipping) | |
456 { | |
457 region = CreateRectRgn (rect.left, rect.top, | |
458 rect.right, rect.bottom); | |
459 SelectClipRgn (hdc, region); | |
460 } | |
461 | |
462 /* TextOut only clears the area equal to the height of | |
463 the given font. It is possible that a font is being displayed | |
464 on a line taller than it is, so this would cause us to fail to | |
465 clear some areas. */ | |
466 if (fi->ascent < dl->ascent || fi->descent < dl->descent-dl->clip) | |
467 FillRect (hdc, &rect, | |
468 COLOR_INSTANCE_MSWINDOWS_BRUSH (XCOLOR_INSTANCE (cachel->background))); | |
469 | |
470 assert (runs[i].dimension == 1); /* XXX FIXME */ | |
471 TextOut(hdc, xpos, dl->ypos, (char *) runs[i].ptr, runs[i].len); | |
472 | |
473 /* XXX FIXME? X does underline/strikethrough here | |
474 we will do it as part of face's font */ | |
475 | |
476 if (need_clipping) | |
477 { | |
478 SelectClipRgn (hdc, NULL); | |
479 DeleteObject (region); | |
480 } | |
481 | |
482 xpos += this_width; | |
483 } | |
484 } | |
485 | |
486 /***************************************************************************** | |
487 mswindows_redraw_exposed_window | |
488 | |
489 Given a bounding box for an area that needs to be redrawn, determine | |
490 what parts of what lines are contained within and re-output their | |
491 contents. | |
492 Copied from redisplay-x.c | |
493 ****************************************************************************/ | |
494 static void | |
495 mswindows_redraw_exposed_window (struct window *w, int x, int y, int width, | |
496 int height) | |
497 { | |
498 struct frame *f = XFRAME (w->frame); | |
499 int line; | |
500 int start_x, start_y, end_x, end_y; | |
501 int orig_windows_structure_changed; | |
502 | |
503 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP); | |
504 | |
505 if (!NILP (w->vchild)) | |
506 { | |
507 mswindows_redraw_exposed_windows (w->vchild, x, y, width, height); | |
508 return; | |
509 } | |
510 else if (!NILP (w->hchild)) | |
511 { | |
512 mswindows_redraw_exposed_windows (w->hchild, x, y, width, height); | |
513 return; | |
514 } | |
515 | |
516 /* If the window doesn't intersect the exposed region, we're done here. */ | |
517 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w) | |
518 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w)) | |
519 { | |
520 return; | |
521 } | |
522 else | |
523 { | |
524 start_x = max (WINDOW_LEFT (w), x); | |
525 end_x = min (WINDOW_RIGHT (w), (x + width)); | |
526 start_y = max (WINDOW_TOP (w), y); | |
527 end_y = min (WINDOW_BOTTOM (w), y + height); | |
528 | |
529 /* We do this to make sure that the 3D modelines get redrawn if | |
530 they are in the exposed region. */ | |
531 orig_windows_structure_changed = f->windows_structure_changed; | |
532 f->windows_structure_changed = 1; | |
533 } | |
534 | |
535 if (window_needs_vertical_divider (w)) | |
536 { | |
537 mswindows_output_vertical_divider (w, 0); | |
538 } | |
539 | |
540 for (line = 0; line < Dynarr_length (cdla); line++) | |
541 { | |
542 struct display_line *cdl = Dynarr_atp (cdla, line); | |
543 int top_y = cdl->ypos - cdl->ascent; | |
544 int bottom_y = cdl->ypos + cdl->descent; | |
545 | |
546 if (bottom_y >= start_y) | |
547 { | |
548 if (top_y > end_y) | |
549 { | |
550 if (line == 0) | |
551 continue; | |
552 else | |
553 break; | |
554 } | |
555 else | |
556 { | |
557 output_display_line (w, 0, cdla, line, start_x, end_x); | |
558 } | |
559 } | |
560 } | |
561 | |
562 f->windows_structure_changed = orig_windows_structure_changed; | |
563 | |
564 /* If there have never been any face cache_elements created, then this | |
565 expose event doesn't actually have anything to do. */ | |
566 if (Dynarr_largest (w->face_cachels)) | |
567 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y); | |
568 } | |
569 | |
570 /***************************************************************************** | |
571 mswindows_redraw_exposed_windows | |
572 | |
573 For each window beneath the given window in the window hierarchy, | |
574 ensure that it is redrawn if necessary after an Expose event. | |
575 ****************************************************************************/ | |
576 static void | |
577 mswindows_redraw_exposed_windows (Lisp_Object window, int x, int y, int width, | |
578 int height) | |
579 { | |
580 for (; !NILP (window); window = XWINDOW (window)->next) | |
581 mswindows_redraw_exposed_window (XWINDOW (window), x, y, width, height); | |
582 } | |
583 | |
584 /***************************************************************************** | |
585 mswindows_redraw_exposed_area | |
586 | |
587 For each window on the given frame, ensure that any area in the | |
588 Exposed area is redrawn. | |
589 ****************************************************************************/ | |
590 void | |
591 mswindows_redraw_exposed_area (struct frame *f, int x, int y, int width, int height) | |
592 { | |
593 /* If any window on the frame has had its face cache reset then the | |
594 redisplay structures are effectively invalid. If we attempt to | |
595 use them we'll blow up. We mark the frame as changed to ensure | |
596 that redisplay will do a full update. This probably isn't | |
597 necessary but it can't hurt. */ | |
598 | |
599 if (!f->window_face_cache_reset) | |
600 mswindows_redraw_exposed_windows (f->root_window, x, y, width, height); | |
601 else | |
602 MARK_FRAME_CHANGED (f); | |
603 } | |
604 | |
605 | |
606 /***************************************************************************** | |
607 mswindows_bevel_modeline | |
608 | |
609 Draw a 3d border around the modeline on window W. | |
610 ****************************************************************************/ | |
611 static void | |
612 mswindows_bevel_modeline (struct window *w, struct display_line *dl) | |
613 { | |
614 struct frame *f = XFRAME (w->frame); | |
615 Lisp_Object color; | |
616 int shadow_width = MODELINE_SHADOW_THICKNESS (w); | |
617 RECT rect = { WINDOW_MODELINE_LEFT (w), | |
618 dl->ypos - dl->ascent - shadow_width, | |
619 WINDOW_MODELINE_RIGHT (w), | |
620 dl->ypos + dl->descent + shadow_width}; | |
621 | |
622 | |
623 color = WINDOW_FACE_CACHEL_BACKGROUND (w, MODELINE_INDEX); | |
624 mswindows_update_gc(FRAME_MSWINDOWS_DC(f), Qnil, Qnil, color, Qnil, Qnil); | |
625 | |
626 #if 0 /* XXX Eh? */ | |
627 if (shadow_width < 0) | |
628 { | |
629 GC temp; | |
630 | |
631 temp = top_shadow_gc; | |
632 top_shadow_gc = bottom_shadow_gc; | |
633 bottom_shadow_gc = temp; | |
634 } | |
635 #endif | |
636 | |
637 DrawEdge (FRAME_MSWINDOWS_DC(f), &rect, shadow_width==1 ? BDR_RAISEDINNER : | |
638 EDGE_RAISED, BF_RECT); | |
639 } | |
640 | |
641 | |
642 /***************************************************************************** | |
643 #### Display methods | |
644 /***************************************************************************** | |
645 | |
646 /***************************************************************************** | |
647 mswindows_divider_width | |
648 | |
649 Return the width of the vertical divider. | |
650 ****************************************************************************/ | |
651 static int | |
652 mswindows_divider_width (void) | |
653 { | |
654 return MSWINDOWS_DIVIDER_WIDTH; | |
655 } | |
656 | |
657 /***************************************************************************** | |
658 mswindows_divider_height | |
659 | |
660 Return the height of the horizontal divider. | |
661 ****************************************************************************/ | |
662 static int | |
663 mswindows_divider_height (void) | |
664 { | |
665 return 1; /* XXX Copied from redisplay-X.c. What is this? */ | |
666 } | |
667 | |
668 /***************************************************************************** | |
669 mswindows_eol_cursor_width | |
670 | |
671 Return the width of the end-of-line cursor. | |
672 ****************************************************************************/ | |
673 static int | |
674 mswindows_eol_cursor_width (void) | |
675 { | |
676 return MSWINDOWS_EOL_CURSOR_WIDTH; | |
677 } | |
678 | |
679 /***************************************************************************** | |
680 mswindows_output_begin | |
681 | |
682 Perform any necessary initialization prior to an update. | |
683 ****************************************************************************/ | |
684 static void | |
685 mswindows_output_begin (struct device *d) | |
686 { | |
687 } | |
688 | |
689 /***************************************************************************** | |
690 mswindows_output_end | |
691 | |
692 Perform any necessary flushing of queues when an update has completed. | |
693 ****************************************************************************/ | |
694 static void | |
695 mswindows_output_end (struct device *d) | |
696 { | |
697 } | |
698 | |
699 static int | |
700 mswindows_flash (struct device *d) | |
701 { | |
702 struct frame *f = device_selected_frame (d); | |
703 | |
704 /* XXX FIXME: Do something more visible here, maybe involving a timer */ | |
705 FlashWindow (FRAME_MSWINDOWS_HANDLE (f), TRUE); | |
706 FlashWindow (FRAME_MSWINDOWS_HANDLE (f), FALSE); | |
707 } | |
708 | |
709 static void | |
710 mswindows_ring_bell (struct device *d, int volume, int pitch, int duration) | |
711 { | |
712 /* XXX FIXME: I'm guessing pitch=Hz and duration is milliseconds */ | |
713 | |
714 if ((pitch|duration) == -1) /* Pitch and/or duration may be bogus */ | |
715 MessageBeep(-1); /* Default system sound via speaker */ | |
716 else | |
717 Beep(pitch, duration); | |
718 } | |
719 | |
720 | |
721 /***************************************************************************** | |
722 mswindows_output_display_block | |
723 | |
724 Given a display line, a block number for that start line, output all | |
725 runes between start and end in the specified display block. | |
726 Ripped off with mininmal thought from the corresponding X routine. | |
727 ****************************************************************************/ | |
728 static void | |
729 mswindows_output_display_block (struct window *w, struct display_line *dl, int block, | |
730 int start, int end, int start_pixpos, int cursor_start, | |
731 int cursor_width, int cursor_height) | |
732 { | |
733 struct frame *f = XFRAME (w->frame); | |
734 Emchar_dynarr *buf = Dynarr_new (Emchar); | |
735 Lisp_Object window; | |
736 | |
737 struct display_block *db = Dynarr_atp (dl->display_blocks, block); | |
738 rune_dynarr *rba = db->runes; | |
739 struct rune *rb; | |
740 | |
741 int elt = start; | |
742 face_index findex; | |
743 int xpos, width; | |
744 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when | |
745 MULE is not defined */ | |
746 XSETWINDOW (window, w); | |
747 rb = Dynarr_atp (rba, start); | |
748 | |
749 if (!rb) | |
750 { | |
751 /* Nothing to do so don't do anything. */ | |
752 return; | |
753 } | |
754 else | |
755 { | |
756 findex = rb->findex; | |
757 xpos = rb->xpos; | |
758 width = 0; | |
759 if (rb->type == RUNE_CHAR) | |
760 charset = CHAR_CHARSET (rb->object.chr.ch); | |
761 } | |
762 | |
763 if (end < 0) | |
764 end = Dynarr_length (rba); | |
765 Dynarr_reset (buf); | |
766 | |
767 while (elt < end) | |
768 { | |
769 rb = Dynarr_atp (rba, elt); | |
770 | |
771 if (rb->findex == findex && rb->type == RUNE_CHAR | |
772 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON | |
773 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch))) | |
774 { | |
775 Dynarr_add (buf, rb->object.chr.ch); | |
776 width += rb->width; | |
777 elt++; | |
778 } | |
779 else | |
780 { | |
781 if (Dynarr_length (buf)) | |
782 { | |
783 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width, | |
784 findex); | |
785 xpos = rb->xpos; | |
786 width = 0; | |
787 } | |
788 Dynarr_reset (buf); | |
789 width = 0; | |
790 | |
791 if (rb->type == RUNE_CHAR) | |
792 { | |
793 findex = rb->findex; | |
794 xpos = rb->xpos; | |
795 charset = CHAR_CHARSET (rb->object.chr.ch); | |
796 | |
797 if (rb->cursor_type == CURSOR_ON) | |
798 { | |
799 if (rb->object.chr.ch == '\n') | |
800 { | |
801 mswindows_output_cursor (w, dl, xpos, cursor_width, rb); | |
802 } | |
803 else | |
804 { | |
805 Dynarr_add (buf, rb->object.chr.ch); | |
806 #if 0 | |
807 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, | |
808 rb->width, findex, 1, | |
809 cursor_start, cursor_width, | |
810 cursor_height); | |
811 #else | |
812 mswindows_output_cursor (w, dl, xpos, cursor_width, rb); | |
813 #endif | |
814 Dynarr_reset (buf); | |
815 } | |
816 | |
817 xpos += rb->width; | |
818 elt++; | |
819 } | |
820 else if (rb->object.chr.ch == '\n') | |
821 { | |
822 /* Clear in case a cursor was formerly here. */ | |
823 int height = dl->ascent + dl->descent - dl->clip; | |
824 | |
825 mswindows_clear_region (window, findex, xpos, dl->ypos - dl->ascent, | |
826 rb->width, height); | |
827 elt++; | |
828 } | |
829 } | |
830 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE) | |
831 { | |
832 if (rb->type == RUNE_BLANK) | |
833 mswindows_output_blank (w, dl, rb); | |
834 else | |
835 { | |
836 /* #### Our flagging of when we need to redraw the | |
837 modeline shadows sucks. Since RUNE_HLINE is only used | |
838 by the modeline at the moment it is a good bet | |
839 that if it gets redrawn then we should also | |
840 redraw the shadows. This won't be true forever. | |
841 We borrow the shadow_thickness_changed flag for | |
842 now. */ | |
843 w->shadow_thickness_changed = 1; | |
844 mswindows_output_hline (w, dl, rb); | |
845 } | |
846 | |
847 if (rb->cursor_type == CURSOR_ON) | |
848 mswindows_output_cursor (w, dl, xpos, cursor_width, rb); | |
849 | |
850 elt++; | |
851 if (elt < end) | |
852 { | |
853 rb = Dynarr_atp (rba, elt); | |
854 | |
855 findex = rb->findex; | |
856 xpos = rb->xpos; | |
857 } | |
858 } | |
859 else if (rb->type == RUNE_DGLYPH) | |
860 { | |
861 Lisp_Object instance; | |
862 | |
863 XSETWINDOW (window, w); | |
864 instance = glyph_image_instance (rb->object.dglyph.glyph, | |
865 window, ERROR_ME_NOT, 1); | |
866 findex = rb->findex; | |
867 | |
868 if (IMAGE_INSTANCEP (instance)) | |
869 switch (XIMAGE_INSTANCE_TYPE (instance)) | |
870 { | |
871 case IMAGE_TEXT: | |
872 { | |
873 /* #### This is way losing. See the comment in | |
874 add_glyph_rune(). */ | |
875 Lisp_Object string = | |
876 XIMAGE_INSTANCE_TEXT_STRING (instance); | |
877 convert_bufbyte_string_into_emchar_dynarr | |
878 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf); | |
879 | |
880 if (rb->cursor_type == CURSOR_ON) | |
881 mswindows_output_cursor (w, dl, xpos, cursor_width, rb); | |
882 else | |
883 mswindows_output_string (w, dl, buf, xpos, | |
884 rb->object.dglyph.xoffset, | |
885 start_pixpos, -1, findex); | |
886 Dynarr_reset (buf); | |
887 } | |
888 break; | |
889 | |
890 case IMAGE_MONO_PIXMAP: | |
891 case IMAGE_COLOR_PIXMAP: | |
892 #if 0 | |
893 mswindows_output_pixmap (w, dl, instance, xpos, | |
894 rb->object.dglyph.xoffset, start_pixpos, | |
895 rb->width, findex, cursor_start, | |
896 cursor_width, cursor_height); | |
897 #endif | |
898 break; | |
899 | |
900 case IMAGE_POINTER: | |
901 abort (); | |
902 | |
903 case IMAGE_SUBWINDOW: | |
904 /* #### implement me */ | |
905 break; | |
906 | |
907 case IMAGE_NOTHING: | |
908 /* nothing is as nothing does */ | |
909 break; | |
910 | |
911 default: | |
912 abort (); | |
913 } | |
914 | |
915 xpos += rb->width; | |
916 elt++; | |
917 } | |
918 else | |
919 abort (); | |
920 } | |
921 } | |
922 | |
923 if (Dynarr_length (buf)) | |
924 mswindows_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex); | |
925 | |
926 if (dl->modeline | |
927 && !EQ (Qzero, w->modeline_shadow_thickness) | |
928 && (f->clear | |
929 || f->windows_structure_changed | |
930 || w->shadow_thickness_changed)) | |
931 mswindows_bevel_modeline (w, dl); | |
932 | |
933 Dynarr_free (buf); | |
934 | |
935 } | |
936 | |
937 | |
938 /***************************************************************************** | |
939 mswindows_output_vertical_divider | |
940 | |
941 Draw a vertical divider down the left side of the given window. | |
942 ****************************************************************************/ | |
943 static void | |
944 mswindows_output_vertical_divider (struct window *w, int clear) | |
945 { | |
946 struct frame *f = XFRAME (w->frame); | |
947 Lisp_Object color; | |
948 RECT rect; | |
949 HBRUSH brush; | |
950 int shadow_width = MODELINE_SHADOW_THICKNESS (w); | |
951 | |
952 /* We don't use the normal gutter measurements here because the | |
953 horizontal scrollbars and toolbars do not stretch completely over | |
954 to the right edge of the window. Only the modeline does. */ | |
955 int modeline_height = window_modeline_height (w); | |
956 | |
957 assert(!MSWINDOWS_DIVIDER_SPACING); /* This code doesn't handle this */ | |
958 | |
959 /* XXX Not sure about this */ | |
960 #ifdef HAVE_SCROLLBARS | |
961 if (f->scrollbar_on_left) | |
962 rect.left = WINDOW_LEFT (w); | |
963 else | |
964 rect.left = WINDOW_RIGHT (w) - MSWINDOWS_DIVIDER_WIDTH; | |
965 #else | |
966 rect.left = WINDOW_LEFT (w); | |
967 #endif | |
968 rect.right = rect.left + MSWINDOWS_DIVIDER_WIDTH; | |
969 | |
970 #ifdef HAVE_SCROLLBARS | |
971 if (f->scrollbar_on_top) | |
972 rect.top = WINDOW_TOP (w); | |
973 else | |
974 #endif | |
975 rect.top = WINDOW_TEXT_TOP (w); | |
976 rect.bottom = WINDOW_BOTTOM (w) - modeline_height; | |
977 | |
978 /* Draw the divider line */ | |
979 color = WINDOW_FACE_CACHEL_BACKGROUND (w, MODELINE_INDEX); | |
980 mswindows_update_gc(FRAME_MSWINDOWS_DC(f), Qnil, Qnil, color, Qnil, Qnil); | |
981 brush = COLOR_INSTANCE_MSWINDOWS_BRUSH (XCOLOR_INSTANCE (color)); | |
982 FillRect (FRAME_MSWINDOWS_DC(f), &rect, brush); | |
983 if (shadow_width) | |
984 DrawEdge (FRAME_MSWINDOWS_DC(f), &rect, | |
985 shadow_width==1 ? BDR_RAISEDINNER : EDGE_RAISED, | |
986 BF_TOP|BF_RIGHT|BF_LEFT); | |
987 } | |
988 | |
989 | |
990 /**************************************************************************** | |
991 mswindows_text_width | |
992 | |
993 Given a string and a face, return the string's length in pixels when | |
994 displayed in the font associated with the face. | |
995 XXX FIXME: get redisplay_text_width_emchar_string() etc to pass in the | |
996 window so we can get hold of the window's frame's gc | |
997 ****************************************************************************/ | |
998 static int | |
999 mswindows_text_width (struct face_cachel *cachel, CONST Emchar *str, | |
1000 Charcount len) | |
1001 { | |
1002 int width_so_far = 0; | |
1003 unsigned char *text_storage = (unsigned char *) alloca (2 * len); | |
1004 textual_run *runs = alloca_array (textual_run, len); | |
1005 int nruns; | |
1006 int i; | |
1007 HDC hdc=NULL; /* XXXXX FIXME! only works for non-proportional fonts! */ | |
1008 | |
1009 nruns = separate_textual_runs (text_storage, runs, str, len); | |
1010 | |
1011 for (i = 0; i < nruns; i++) | |
1012 width_so_far += mswindows_text_width_single_run (hdc, cachel, runs + i); | |
1013 | |
1014 return width_so_far; | |
1015 } | |
1016 | |
1017 | |
1018 /**************************************************************************** | |
1019 mswindows_clear_region | |
1020 | |
1021 Clear the area in the box defined by the given parameters using the | |
1022 given face. | |
1023 ****************************************************************************/ | |
1024 static void | |
1025 mswindows_clear_region (Lisp_Object locale, face_index findex, int x, int y, | |
1026 int width, int height) | |
1027 { | |
1028 struct window *w; | |
1029 struct frame *f; | |
1030 Lisp_Object background_pixmap = Qunbound; | |
1031 Lisp_Object temp; | |
1032 RECT rect = { x, y, x+width, y+height }; | |
1033 HBRUSH brush; | |
1034 | |
1035 if (!(width && height)) /* We often seem to get called with width==0 */ | |
1036 return; | |
1037 | |
1038 if (WINDOWP (locale)) | |
1039 { | |
1040 w = XWINDOW (locale); | |
1041 f = XFRAME (w->frame); | |
1042 } | |
1043 else if (FRAMEP (locale)) | |
1044 { | |
1045 w = NULL; | |
1046 f = XFRAME (locale); | |
1047 } | |
1048 else | |
1049 abort (); | |
1050 | |
1051 if (w) | |
1052 { | |
1053 temp = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, findex); | |
1054 | |
1055 if (IMAGE_INSTANCEP (temp) | |
1056 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp))) | |
1057 { | |
1058 /* #### maybe we could implement such that a string | |
1059 can be a background pixmap? */ | |
1060 background_pixmap = temp; | |
1061 } | |
1062 } | |
1063 else | |
1064 { | |
1065 temp = FACE_BACKGROUND_PIXMAP (Vdefault_face, locale); | |
1066 | |
1067 if (IMAGE_INSTANCEP (temp) | |
1068 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp))) | |
1069 { | |
1070 background_pixmap = temp; | |
1071 } | |
1072 } | |
1073 | |
1074 if (!UNBOUNDP (background_pixmap)) | |
1075 { | |
1076 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (background_pixmap) == 0) | |
1077 { | |
1078 Lisp_Object fcolor, bcolor; | |
1079 | |
1080 if (w) | |
1081 { | |
1082 fcolor = WINDOW_FACE_CACHEL_FOREGROUND (w, findex); | |
1083 bcolor = WINDOW_FACE_CACHEL_BACKGROUND (w, findex); | |
1084 } | |
1085 else | |
1086 { | |
1087 fcolor = FACE_FOREGROUND (Vdefault_face, locale); | |
1088 bcolor = FACE_BACKGROUND (Vdefault_face, locale); | |
1089 } | |
1090 | |
1091 mswindows_update_gc (FRAME_MSWINDOWS_DC(f), Qnil, fcolor, bcolor, background_pixmap, Qnil); | |
1092 } | |
1093 | |
1094 /* XX FIXME: Get brush from background_pixmap here */ | |
1095 assert(0); | |
1096 } | |
1097 else | |
1098 { | |
1099 Lisp_Object color = (w ? WINDOW_FACE_CACHEL_BACKGROUND (w, findex) : | |
1100 FACE_BACKGROUND (Vdefault_face, locale)); | |
1101 brush = COLOR_INSTANCE_MSWINDOWS_BRUSH (XCOLOR_INSTANCE (color)); | |
1102 } | |
1103 | |
1104 FillRect (FRAME_MSWINDOWS_DC(f), &rect, brush); | |
1105 } | |
1106 | |
1107 | |
1108 /***************************************************************************** | |
1109 mswindows_clear_to_window_end | |
1110 | |
1111 Clear the area between ypos1 and ypos2. Each margin area and the | |
1112 text area is handled separately since they may each have their own | |
1113 background color. | |
1114 ****************************************************************************/ | |
1115 static void | |
1116 mswindows_clear_to_window_end (struct window *w, int ypos1, int ypos2) | |
1117 { | |
1118 int height = ypos2 - ypos1; | |
1119 | |
1120 if (height) | |
1121 { | |
1122 struct frame *f = XFRAME (w->frame); | |
1123 Lisp_Object window; | |
1124 int bflag = (window_needs_vertical_divider (w) ? 0 : 1); | |
1125 layout_bounds bounds; | |
1126 | |
1127 bounds = calculate_display_line_boundaries (w, bflag); | |
1128 XSETWINDOW (window, w); | |
1129 | |
1130 if (window_is_leftmost (w)) | |
1131 mswindows_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f), | |
1132 ypos1, FRAME_BORDER_WIDTH (f), height); | |
1133 | |
1134 if (bounds.left_in - bounds.left_out > 0) | |
1135 mswindows_clear_region (window, | |
1136 get_builtin_face_cache_index (w, Vleft_margin_face), | |
1137 bounds.left_out, ypos1, | |
1138 bounds.left_in - bounds.left_out, height); | |
1139 | |
1140 if (bounds.right_in - bounds.left_in > 0) | |
1141 mswindows_clear_region (window, DEFAULT_INDEX, bounds.left_in, ypos1, | |
1142 bounds.right_in - bounds.left_in, height); | |
1143 | |
1144 if (bounds.right_out - bounds.right_in > 0) | |
1145 mswindows_clear_region (window, | |
1146 get_builtin_face_cache_index (w, Vright_margin_face), | |
1147 bounds.right_in, ypos1, | |
1148 bounds.right_out - bounds.right_in, height); | |
1149 | |
1150 if (window_is_rightmost (w)) | |
1151 mswindows_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f), | |
1152 ypos1, FRAME_BORDER_WIDTH (f), height); | |
1153 } | |
1154 | |
1155 } | |
1156 | |
1157 | |
1158 static void | |
1159 mswindows_clear_frame (struct frame *f) | |
1160 { | |
1161 } | |
1162 | |
1163 | |
1164 | |
1165 | |
1166 /************************************************************************/ | |
1167 /* initialization */ | |
1168 /************************************************************************/ | |
1169 | |
1170 void | |
1171 console_type_create_redisplay_mswindows (void) | |
1172 { | |
1173 /* redisplay methods */ | |
1174 CONSOLE_HAS_METHOD (mswindows, text_width); | |
1175 CONSOLE_HAS_METHOD (mswindows, output_display_block); | |
1176 CONSOLE_HAS_METHOD (mswindows, divider_width); | |
1177 CONSOLE_HAS_METHOD (mswindows, divider_height); | |
1178 CONSOLE_HAS_METHOD (mswindows, eol_cursor_width); | |
1179 CONSOLE_HAS_METHOD (mswindows, output_vertical_divider); | |
1180 CONSOLE_HAS_METHOD (mswindows, clear_to_window_end); | |
1181 CONSOLE_HAS_METHOD (mswindows, clear_region); | |
1182 CONSOLE_HAS_METHOD (mswindows, clear_frame); | |
1183 CONSOLE_HAS_METHOD (mswindows, output_begin); | |
1184 CONSOLE_HAS_METHOD (mswindows, output_end); | |
1185 CONSOLE_HAS_METHOD (mswindows, flash); | |
1186 CONSOLE_HAS_METHOD (mswindows, ring_bell); | |
1187 } |