Mercurial > hg > xemacs-beta
comparison src/redisplay-gtk.c @ 462:0784d089fdc9 r21-2-46
Import from CVS: tag r21-2-46
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:44:37 +0200 |
parents | |
children | fdefd0186b75 |
comparison
equal
deleted
inserted
replaced
461:120ed4009e51 | 462:0784d089fdc9 |
---|---|
1 /* X 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 /* Author: Chuck Thompson */ | |
26 /* Gtk flavor by William Perry */ | |
27 | |
28 /* Lots of work done by Ben Wing for Mule */ | |
29 | |
30 #include <config.h> | |
31 #include "lisp.h" | |
32 | |
33 #include "console-gtk.h" | |
34 #include "gccache-gtk.h" | |
35 #include "glyphs-gtk.h" | |
36 #include "objects-gtk.h" | |
37 | |
38 #include "buffer.h" | |
39 #include "debug.h" | |
40 #include "faces.h" | |
41 #include "frame.h" | |
42 #include "gutter.h" | |
43 #include "redisplay.h" | |
44 #include "sysdep.h" | |
45 #include "window.h" | |
46 | |
47 #include "sysproc.h" /* for select() */ | |
48 | |
49 #ifdef MULE | |
50 #include "mule-ccl.h" | |
51 #include "file-coding.h" /* for CCL conversion */ | |
52 #endif | |
53 | |
54 #define CONST const | |
55 | |
56 #define EOL_CURSOR_WIDTH 5 | |
57 | |
58 static void gtk_output_pixmap (struct window *w, struct display_line *dl, | |
59 Lisp_Object image_instance, int xpos, | |
60 int xoffset, | |
61 int start_pixpos, int width, face_index findex, | |
62 int cursor_start, int cursor_width, | |
63 int cursor_height); | |
64 static void gtk_output_vertical_divider (struct window *w, int clear); | |
65 static void gtk_output_blank (struct window *w, struct display_line *dl, | |
66 struct rune *rb, int start_pixpos, | |
67 int cursor_start, int cursor_width); | |
68 static void gtk_output_hline (struct window *w, struct display_line *dl, | |
69 struct rune *rb); | |
70 static void gtk_redraw_exposed_window (struct window *w, int x, int y, | |
71 int width, int height); | |
72 static void gtk_redraw_exposed_windows (Lisp_Object window, int x, int y, | |
73 int width, int height); | |
74 static void gtk_clear_region (Lisp_Object locale, struct device* d, struct frame* f, | |
75 face_index findex, int x, int y, | |
76 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor, | |
77 Lisp_Object background_pixmap); | |
78 static void gtk_output_eol_cursor (struct window *w, struct display_line *dl, | |
79 int xpos, face_index findex); | |
80 static void gtk_clear_frame (struct frame *f); | |
81 static void gtk_clear_frame_windows (Lisp_Object window); | |
82 static void gtk_bevel_modeline (struct window *w, struct display_line *dl); | |
83 | |
84 #if 0 | |
85 static void __describe_gc (GdkGC *); | |
86 #endif | |
87 | |
88 struct textual_run | |
89 { | |
90 Lisp_Object charset; | |
91 unsigned char *ptr; | |
92 int len; | |
93 int dimension; | |
94 }; | |
95 | |
96 /* Separate out the text in DYN into a series of textual runs of a | |
97 particular charset. Also convert the characters as necessary into | |
98 the format needed by XDrawImageString(), XDrawImageString16(), et | |
99 al. (This means converting to one or two byte format, possibly | |
100 tweaking the high bits, and possibly running a CCL program.) You | |
101 must pre-allocate the space used and pass it in. (This is done so | |
102 you can alloca() the space.) You need to allocate (2 * len) bytes | |
103 of TEXT_STORAGE and (len * sizeof (struct textual_run)) bytes of | |
104 RUN_STORAGE, where LEN is the length of the dynarr. | |
105 | |
106 Returns the number of runs actually used. */ | |
107 | |
108 static int | |
109 separate_textual_runs (unsigned char *text_storage, | |
110 struct textual_run *run_storage, | |
111 CONST Emchar *str, Charcount len) | |
112 { | |
113 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a | |
114 possible valid charset when | |
115 MULE is not defined */ | |
116 int runs_so_far = 0; | |
117 int i; | |
118 #ifdef MULE | |
119 struct ccl_program char_converter; | |
120 int need_ccl_conversion = 0; | |
121 #endif | |
122 | |
123 for (i = 0; i < len; i++) | |
124 { | |
125 Emchar ch = str[i]; | |
126 Lisp_Object charset; | |
127 int byte1, byte2; | |
128 int dimension; | |
129 int graphic; | |
130 | |
131 BREAKUP_CHAR (ch, charset, byte1, byte2); | |
132 dimension = XCHARSET_DIMENSION (charset); | |
133 graphic = XCHARSET_GRAPHIC (charset); | |
134 | |
135 if (!EQ (charset, prev_charset)) | |
136 { | |
137 run_storage[runs_so_far].ptr = text_storage; | |
138 run_storage[runs_so_far].charset = charset; | |
139 run_storage[runs_so_far].dimension = dimension; | |
140 | |
141 if (runs_so_far) | |
142 { | |
143 run_storage[runs_so_far - 1].len = | |
144 text_storage - run_storage[runs_so_far - 1].ptr; | |
145 if (run_storage[runs_so_far - 1].dimension == 2) | |
146 run_storage[runs_so_far - 1].len >>= 1; | |
147 } | |
148 runs_so_far++; | |
149 prev_charset = charset; | |
150 #ifdef MULE | |
151 { | |
152 Lisp_Object ccl_prog = XCHARSET_CCL_PROGRAM (charset); | |
153 need_ccl_conversion = !NILP (ccl_prog); | |
154 if (need_ccl_conversion) | |
155 setup_ccl_program (&char_converter, ccl_prog); | |
156 } | |
157 #endif | |
158 } | |
159 | |
160 if (graphic == 0) | |
161 { | |
162 byte1 &= 0x7F; | |
163 byte2 &= 0x7F; | |
164 } | |
165 else if (graphic == 1) | |
166 { | |
167 byte1 |= 0x80; | |
168 byte2 |= 0x80; | |
169 } | |
170 #ifdef MULE | |
171 if (need_ccl_conversion) | |
172 { | |
173 char_converter.reg[0] = XCHARSET_ID (charset); | |
174 char_converter.reg[1] = byte1; | |
175 char_converter.reg[2] = byte2; | |
176 ccl_driver (&char_converter, 0, 0, 0, 0, CCL_MODE_ENCODING); | |
177 byte1 = char_converter.reg[1]; | |
178 byte2 = char_converter.reg[2]; | |
179 } | |
180 #endif | |
181 *text_storage++ = (unsigned char) byte1; | |
182 if (dimension == 2) | |
183 *text_storage++ = (unsigned char) byte2; | |
184 } | |
185 | |
186 if (runs_so_far) | |
187 { | |
188 run_storage[runs_so_far - 1].len = | |
189 text_storage - run_storage[runs_so_far - 1].ptr; | |
190 if (run_storage[runs_so_far - 1].dimension == 2) | |
191 run_storage[runs_so_far - 1].len >>= 1; | |
192 } | |
193 | |
194 return runs_so_far; | |
195 } | |
196 | |
197 /****************************************************************************/ | |
198 /* */ | |
199 /* Gtk output routines */ | |
200 /* */ | |
201 /****************************************************************************/ | |
202 | |
203 static int | |
204 gtk_text_width_single_run (struct face_cachel *cachel, struct textual_run *run) | |
205 { | |
206 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset); | |
207 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst); | |
208 | |
209 if (!fi->proportional_p) | |
210 { | |
211 return fi->width * run->len; | |
212 } | |
213 else | |
214 { | |
215 if (run->dimension == 2) | |
216 { | |
217 stderr_out ("Measuring wide characters\n"); | |
218 return gdk_text_width_wc (FONT_INSTANCE_GTK_FONT (fi), | |
219 (GdkWChar *) run->ptr, run->len); | |
220 } | |
221 else | |
222 { | |
223 return gdk_text_width (FONT_INSTANCE_GTK_FONT (fi), | |
224 (char *) run->ptr, run->len); | |
225 } | |
226 } | |
227 } | |
228 | |
229 /* | |
230 gtk_text_width | |
231 | |
232 Given a string and a face, return the string's length in pixels when | |
233 displayed in the font associated with the face. | |
234 */ | |
235 | |
236 static int | |
237 gtk_text_width (struct frame *f, struct face_cachel *cachel, CONST Emchar *str, | |
238 Charcount len) | |
239 { | |
240 int width_so_far = 0; | |
241 unsigned char *text_storage = (unsigned char *) alloca (2 * len); | |
242 struct textual_run *runs = alloca_array (struct textual_run, len); | |
243 int nruns; | |
244 int i; | |
245 | |
246 nruns = separate_textual_runs (text_storage, runs, str, len); | |
247 | |
248 for (i = 0; i < nruns; i++) | |
249 width_so_far += gtk_text_width_single_run (cachel, runs + i); | |
250 | |
251 return width_so_far; | |
252 } | |
253 | |
254 /***************************************************************************** | |
255 gtk_divider_height | |
256 | |
257 Return the height of the horizontal divider. This is a function because | |
258 divider_height is a device method. | |
259 | |
260 #### If we add etched horizontal divider lines this will have to get | |
261 smarter. | |
262 ****************************************************************************/ | |
263 static int | |
264 gtk_divider_height (void) | |
265 { | |
266 return 2; | |
267 } | |
268 | |
269 /***************************************************************************** | |
270 gtk_eol_cursor_width | |
271 | |
272 Return the width of the end-of-line cursor. This is a function | |
273 because eol_cursor_width is a device method. | |
274 ****************************************************************************/ | |
275 static int | |
276 gtk_eol_cursor_width (void) | |
277 { | |
278 return EOL_CURSOR_WIDTH; | |
279 } | |
280 | |
281 /***************************************************************************** | |
282 gtk_output_display_block | |
283 | |
284 Given a display line, a block number for that start line, output all | |
285 runes between start and end in the specified display block. | |
286 ****************************************************************************/ | |
287 static void | |
288 gtk_output_display_block (struct window *w, struct display_line *dl, int block, | |
289 int start, int end, int start_pixpos, int cursor_start, | |
290 int cursor_width, int cursor_height) | |
291 { | |
292 struct frame *f = XFRAME (w->frame); | |
293 Emchar_dynarr *buf = Dynarr_new (Emchar); | |
294 Lisp_Object window; | |
295 | |
296 struct display_block *db = Dynarr_atp (dl->display_blocks, block); | |
297 rune_dynarr *rba = db->runes; | |
298 struct rune *rb; | |
299 | |
300 int elt = start; | |
301 face_index findex; | |
302 int xpos, width; | |
303 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when | |
304 MULE is not defined */ | |
305 | |
306 XSETWINDOW (window, w); | |
307 rb = Dynarr_atp (rba, start); | |
308 | |
309 if (!rb) | |
310 { | |
311 /* Nothing to do so don't do anything. */ | |
312 return; | |
313 } | |
314 else | |
315 { | |
316 findex = rb->findex; | |
317 xpos = rb->xpos; | |
318 width = 0; | |
319 if (rb->type == RUNE_CHAR) | |
320 charset = CHAR_CHARSET (rb->object.chr.ch); | |
321 } | |
322 | |
323 if (end < 0) | |
324 end = Dynarr_length (rba); | |
325 Dynarr_reset (buf); | |
326 | |
327 while (elt < end) | |
328 { | |
329 rb = Dynarr_atp (rba, elt); | |
330 | |
331 if (rb->findex == findex && rb->type == RUNE_CHAR | |
332 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON | |
333 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch))) | |
334 { | |
335 Dynarr_add (buf, rb->object.chr.ch); | |
336 width += rb->width; | |
337 elt++; | |
338 } | |
339 else | |
340 { | |
341 if (Dynarr_length (buf)) | |
342 { | |
343 gtk_output_string (w, dl, buf, xpos, 0, start_pixpos, width, | |
344 findex, 0, cursor_start, cursor_width, | |
345 cursor_height); | |
346 xpos = rb->xpos; | |
347 width = 0; | |
348 } | |
349 Dynarr_reset (buf); | |
350 width = 0; | |
351 | |
352 if (rb->type == RUNE_CHAR) | |
353 { | |
354 findex = rb->findex; | |
355 xpos = rb->xpos; | |
356 charset = CHAR_CHARSET (rb->object.chr.ch); | |
357 | |
358 if (rb->cursor_type == CURSOR_ON) | |
359 { | |
360 if (rb->object.chr.ch == '\n') | |
361 { | |
362 gtk_output_eol_cursor (w, dl, xpos, findex); | |
363 } | |
364 else | |
365 { | |
366 Dynarr_add (buf, rb->object.chr.ch); | |
367 gtk_output_string (w, dl, buf, xpos, 0, start_pixpos, | |
368 rb->width, findex, 1, | |
369 cursor_start, cursor_width, | |
370 cursor_height); | |
371 Dynarr_reset (buf); | |
372 } | |
373 | |
374 xpos += rb->width; | |
375 elt++; | |
376 } | |
377 else if (rb->object.chr.ch == '\n') | |
378 { | |
379 /* Clear in case a cursor was formerly here. */ | |
380 int height = dl->ascent + dl->descent - dl->clip; | |
381 | |
382 redisplay_clear_region (window, findex, xpos, dl->ypos - dl->ascent, | |
383 rb->width, height); | |
384 elt++; | |
385 } | |
386 } | |
387 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE) | |
388 { | |
389 if (rb->type == RUNE_BLANK) | |
390 gtk_output_blank (w, dl, rb, start_pixpos, cursor_start, | |
391 cursor_width); | |
392 else | |
393 { | |
394 /* #### Our flagging of when we need to redraw the | |
395 modeline shadows sucks. Since RUNE_HLINE is only used | |
396 by the modeline at the moment it is a good bet | |
397 that if it gets redrawn then we should also | |
398 redraw the shadows. This won't be true forever. | |
399 We borrow the shadow_thickness_changed flag for | |
400 now. */ | |
401 w->shadow_thickness_changed = 1; | |
402 gtk_output_hline (w, dl, rb); | |
403 } | |
404 | |
405 elt++; | |
406 if (elt < end) | |
407 { | |
408 rb = Dynarr_atp (rba, elt); | |
409 | |
410 findex = rb->findex; | |
411 xpos = rb->xpos; | |
412 } | |
413 } | |
414 else if (rb->type == RUNE_DGLYPH) | |
415 { | |
416 Lisp_Object instance; | |
417 struct display_box dbox; | |
418 struct display_glyph_area dga; | |
419 redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset, | |
420 start_pixpos, rb->width, | |
421 &dbox, &dga); | |
422 | |
423 XSETWINDOW (window, w); | |
424 instance = glyph_image_instance (rb->object.dglyph.glyph, | |
425 window, ERROR_ME_NOT, 1); | |
426 findex = rb->findex; | |
427 | |
428 if (IMAGE_INSTANCEP (instance)) | |
429 switch (XIMAGE_INSTANCE_TYPE (instance)) | |
430 { | |
431 case IMAGE_TEXT: | |
432 { | |
433 /* #### This is way losing. See the comment in | |
434 add_glyph_rune(). */ | |
435 Lisp_Object string = | |
436 XIMAGE_INSTANCE_TEXT_STRING (instance); | |
437 convert_bufbyte_string_into_emchar_dynarr | |
438 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf); | |
439 | |
440 gtk_output_string (w, dl, buf, xpos, | |
441 rb->object.dglyph.xoffset, | |
442 start_pixpos, -1, findex, | |
443 (rb->cursor_type == CURSOR_ON), | |
444 cursor_start, cursor_width, | |
445 cursor_height); | |
446 Dynarr_reset (buf); | |
447 } | |
448 break; | |
449 | |
450 case IMAGE_MONO_PIXMAP: | |
451 case IMAGE_COLOR_PIXMAP: | |
452 gtk_output_pixmap (w, dl, instance, xpos, | |
453 rb->object.dglyph.xoffset, start_pixpos, | |
454 rb->width, findex, cursor_start, | |
455 cursor_width, cursor_height); | |
456 break; | |
457 | |
458 case IMAGE_POINTER: | |
459 abort (); | |
460 | |
461 case IMAGE_WIDGET: | |
462 if (EQ (XIMAGE_INSTANCE_WIDGET_TYPE (instance), | |
463 Qlayout)) | |
464 { | |
465 redisplay_output_layout (window, instance, &dbox, | |
466 &dga, findex, | |
467 cursor_start, cursor_width, | |
468 cursor_height); | |
469 break; | |
470 } | |
471 | |
472 case IMAGE_SUBWINDOW: | |
473 redisplay_output_subwindow (w, instance, &dbox, &dga, | |
474 findex, cursor_start, | |
475 cursor_width, cursor_height); | |
476 break; | |
477 | |
478 case IMAGE_NOTHING: | |
479 /* nothing is as nothing does */ | |
480 break; | |
481 | |
482 default: | |
483 abort (); | |
484 } | |
485 | |
486 xpos += rb->width; | |
487 elt++; | |
488 } | |
489 else | |
490 abort (); | |
491 } | |
492 } | |
493 | |
494 if (Dynarr_length (buf)) | |
495 gtk_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex, | |
496 0, cursor_start, cursor_width, cursor_height); | |
497 | |
498 /* #### This is really conditionalized well for optimized | |
499 performance. */ | |
500 if (dl->modeline | |
501 && !EQ (Qzero, w->modeline_shadow_thickness) | |
502 && (f->clear | |
503 || f->windows_structure_changed | |
504 || w->shadow_thickness_changed)) | |
505 gtk_bevel_modeline (w, dl); | |
506 | |
507 Dynarr_free (buf); | |
508 } | |
509 | |
510 /***************************************************************************** | |
511 gtk_bevel_modeline | |
512 | |
513 Draw a 3d border around the modeline on window W. | |
514 ****************************************************************************/ | |
515 static void | |
516 gtk_bevel_modeline (struct window *w, struct display_line *dl) | |
517 { | |
518 struct frame *f = XFRAME (w->frame); | |
519 int shadow_thickness = MODELINE_SHADOW_THICKNESS (w); | |
520 int x,y, width, height; | |
521 | |
522 x = WINDOW_MODELINE_LEFT (w); | |
523 width = WINDOW_MODELINE_RIGHT (w) - x; | |
524 y = dl->ypos - dl->ascent - shadow_thickness; | |
525 height = dl->ascent + dl->descent + 2 * shadow_thickness; | |
526 | |
527 gtk_output_shadows (f, x, y, width, height, shadow_thickness); | |
528 } | |
529 | |
530 /***************************************************************************** | |
531 gtk_get_gc | |
532 | |
533 Given a number of parameters return a GC with those properties. | |
534 ****************************************************************************/ | |
535 GdkGC * | |
536 gtk_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg, | |
537 Lisp_Object bg_pmap, Lisp_Object lwidth) | |
538 { | |
539 GdkGCValues gcv; | |
540 unsigned long mask; | |
541 | |
542 memset (&gcv, ~0, sizeof (gcv)); | |
543 gcv.graphics_exposures = FALSE; | |
544 /* Make absolutely sure that we don't pick up a clipping region in | |
545 the GC returned by this function. */ | |
546 gcv.clip_mask = 0; | |
547 gcv.clip_x_origin = 0; | |
548 gcv.clip_y_origin = 0; | |
549 gcv.fill = GDK_SOLID; | |
550 mask = GDK_GC_EXPOSURES | GDK_GC_CLIP_MASK | GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN; | |
551 mask |= GDK_GC_FILL; | |
552 | |
553 if (!NILP (font)) | |
554 { | |
555 gcv.font = FONT_INSTANCE_GTK_FONT (XFONT_INSTANCE (font)); | |
556 mask |= GDK_GC_FONT; | |
557 } | |
558 | |
559 /* evil kludge! */ | |
560 if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg)) | |
561 { | |
562 /* #### I fixed once case where this was getting it. It was a | |
563 bad macro expansion (compiler bug). */ | |
564 fprintf (stderr, "Help! gtk_get_gc got a bogus fg value! fg = "); | |
565 debug_print (fg); | |
566 fg = Qnil; | |
567 } | |
568 | |
569 if (!NILP (fg)) | |
570 { | |
571 if (COLOR_INSTANCEP (fg)) | |
572 gcv.foreground = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (fg)); | |
573 else | |
574 gcv.foreground.pixel = XINT (fg); | |
575 mask |= GDK_GC_FOREGROUND; | |
576 } | |
577 | |
578 if (!NILP (bg)) | |
579 { | |
580 if (COLOR_INSTANCEP (bg)) | |
581 gcv.background = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (bg)); | |
582 else | |
583 gcv.background.pixel = XINT (fg); | |
584 mask |= GDK_GC_BACKGROUND; | |
585 } | |
586 | |
587 if (IMAGE_INSTANCEP (bg_pmap) | |
588 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap))) | |
589 { | |
590 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0) | |
591 { | |
592 gcv.fill = GDK_OPAQUE_STIPPLED; | |
593 gcv.stipple = XIMAGE_INSTANCE_GTK_PIXMAP (bg_pmap); | |
594 mask |= (GDK_GC_STIPPLE | GDK_GC_FILL); | |
595 } | |
596 else | |
597 { | |
598 gcv.fill = GDK_TILED; | |
599 gcv.tile = XIMAGE_INSTANCE_GTK_PIXMAP (bg_pmap); | |
600 mask |= (GDK_GC_TILE | GDK_GC_FILL); | |
601 } | |
602 } | |
603 | |
604 if (!NILP (lwidth)) | |
605 { | |
606 gcv.line_width = XINT (lwidth); | |
607 mask |= GDK_GC_LINE_WIDTH; | |
608 } | |
609 | |
610 return gc_cache_lookup (DEVICE_GTK_GC_CACHE (d), &gcv, mask); | |
611 } | |
612 | |
613 /***************************************************************************** | |
614 gtk_output_string | |
615 | |
616 Given a string and a starting position, output that string in the | |
617 given face. If cursor is true, draw a cursor around the string. | |
618 Correctly handles multiple charsets in the string. | |
619 | |
620 The meaning of the parameters is something like this: | |
621 | |
622 W Window that the text is to be displayed in. | |
623 DL Display line that this text is on. The values in the | |
624 structure are used to determine the vertical position and | |
625 clipping range of the text. | |
626 BUF Dynamic array of Emchars specifying what is actually to be | |
627 drawn. | |
628 XPOS X position in pixels where the text should start being drawn. | |
629 XOFFSET Number of pixels to be chopped off the left side of the | |
630 text. The effect is as if the text were shifted to the | |
631 left this many pixels and clipped at XPOS. | |
632 CLIP_START Clip everything left of this X position. | |
633 WIDTH Clip everything right of XPOS + WIDTH. | |
634 FINDEX Index for the face cache element describing how to display | |
635 the text. | |
636 CURSOR #### I don't understand this. There's something | |
637 strange and overcomplexified with this variable. | |
638 Chuck, explain please? | |
639 CURSOR_START Starting X position of cursor. | |
640 CURSOR_WIDTH Width of cursor in pixels. | |
641 CURSOR_HEIGHT Height of cursor in pixels. | |
642 | |
643 Starting Y position of cursor is the top of the text line. | |
644 The cursor is drawn sometimes whether or not CURSOR is set. ??? | |
645 ****************************************************************************/ | |
646 void | |
647 gdk_draw_text_image (GdkDrawable *drawable, | |
648 GdkFont *font, | |
649 GdkGC *gc, | |
650 gint x, | |
651 gint y, | |
652 const gchar *text, | |
653 gint text_length); | |
654 | |
655 void | |
656 gtk_output_string (struct window *w, struct display_line *dl, | |
657 Emchar_dynarr *buf, int xpos, int xoffset, int clip_start, | |
658 int width, face_index findex, int cursor, | |
659 int cursor_start, int cursor_width, int cursor_height) | |
660 { | |
661 /* General variables */ | |
662 struct frame *f = XFRAME (w->frame); | |
663 struct device *d = XDEVICE (f->device); | |
664 Lisp_Object device; | |
665 Lisp_Object window; | |
666 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
667 | |
668 int clip_end; | |
669 | |
670 /* Cursor-related variables */ | |
671 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d)); | |
672 int cursor_clip; | |
673 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor, | |
674 WINDOW_BUFFER (w)); | |
675 struct face_cachel *cursor_cachel = 0; | |
676 | |
677 /* Text-related variables */ | |
678 Lisp_Object bg_pmap; | |
679 GdkGC *bgc, *gc; | |
680 int height; | |
681 int len = Dynarr_length (buf); | |
682 unsigned char *text_storage = (unsigned char *) alloca (2 * len); | |
683 struct textual_run *runs = alloca_array (struct textual_run, len); | |
684 int nruns; | |
685 int i; | |
686 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex); | |
687 | |
688 XSETDEVICE (device, d); | |
689 XSETWINDOW (window, w); | |
690 | |
691 if (width < 0) | |
692 width = gtk_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf)); | |
693 height = dl->ascent + dl->descent - dl->clip; | |
694 | |
695 /* Regularize the variables passed in. */ | |
696 | |
697 if (clip_start < xpos) | |
698 clip_start = xpos; | |
699 clip_end = xpos + width; | |
700 if (clip_start >= clip_end) | |
701 /* It's all clipped out. */ | |
702 return; | |
703 | |
704 xpos -= xoffset; | |
705 | |
706 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0), | |
707 Dynarr_length (buf)); | |
708 | |
709 cursor_clip = (cursor_start >= clip_start && | |
710 cursor_start < clip_end); | |
711 | |
712 /* This cursor code is really a mess. */ | |
713 if (!NILP (w->text_cursor_visible_p) | |
714 && (cursor | |
715 || cursor_clip | |
716 || (cursor_width | |
717 && (cursor_start + cursor_width >= clip_start) | |
718 && !NILP (bar_cursor_value)))) | |
719 { | |
720 /* These have to be in separate statements in order to avoid a | |
721 compiler bug. */ | |
722 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face); | |
723 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks); | |
724 | |
725 /* We have to reset this since any call to WINDOW_FACE_CACHEL | |
726 may cause the cache to resize and any pointers to it to | |
727 become invalid. */ | |
728 cachel = WINDOW_FACE_CACHEL (w, findex); | |
729 } | |
730 | |
731 bg_pmap = cachel->background_pixmap; | |
732 if (!IMAGE_INSTANCEP (bg_pmap) | |
733 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap))) | |
734 bg_pmap = Qnil; | |
735 | |
736 if ((cursor && focus && NILP (bar_cursor_value) | |
737 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap)) | |
738 bgc = 0; | |
739 else | |
740 bgc = gtk_get_gc (d, Qnil, cachel->foreground, cachel->background, | |
741 bg_pmap, Qnil); | |
742 | |
743 if (bgc) | |
744 gdk_draw_rectangle (GDK_DRAWABLE (x_win), bgc, TRUE, clip_start, | |
745 dl->ypos - dl->ascent, clip_end - clip_start, | |
746 height); | |
747 | |
748 for (i = 0; i < nruns; i++) | |
749 { | |
750 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset); | |
751 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font); | |
752 GdkFont *gdk_font = FONT_INSTANCE_GTK_FONT (fi); | |
753 int this_width; | |
754 int need_clipping; | |
755 | |
756 if (EQ (font, Vthe_null_font_instance)) | |
757 continue; | |
758 | |
759 this_width = gtk_text_width_single_run (cachel, runs + i); | |
760 need_clipping = (dl->clip || clip_start > xpos || | |
761 clip_end < xpos + this_width); | |
762 | |
763 /* XDrawImageString only clears the area equal to the height of | |
764 the given font. It is possible that a font is being displayed | |
765 on a line taller than it is, so this would cause us to fail to | |
766 clear some areas. */ | |
767 if ((int) fi->height < (int) (height + dl->clip)) | |
768 { | |
769 int clear_start = max (xpos, clip_start); | |
770 int clear_end = min (xpos + this_width, clip_end); | |
771 | |
772 if (cursor) | |
773 { | |
774 int ypos1_line, ypos1_string, ypos2_line, ypos2_string; | |
775 | |
776 ypos1_string = dl->ypos - fi->ascent; | |
777 ypos2_string = dl->ypos + fi->descent; | |
778 ypos1_line = dl->ypos - dl->ascent; | |
779 ypos2_line = dl->ypos + dl->descent - dl->clip; | |
780 | |
781 /* Make sure we don't clear below the real bottom of the | |
782 line. */ | |
783 if (ypos1_string > ypos2_line) | |
784 ypos1_string = ypos2_line; | |
785 if (ypos2_string > ypos2_line) | |
786 ypos2_string = ypos2_line; | |
787 | |
788 if (ypos1_line < ypos1_string) | |
789 { | |
790 redisplay_clear_region (window, findex, clear_start, ypos1_line, | |
791 clear_end - clear_start, | |
792 ypos1_string - ypos1_line); | |
793 } | |
794 | |
795 if (ypos2_line > ypos2_string) | |
796 { | |
797 redisplay_clear_region (window, findex, clear_start, ypos2_string, | |
798 clear_end - clear_start, | |
799 ypos2_line - ypos2_string); | |
800 } | |
801 } | |
802 else | |
803 { | |
804 redisplay_clear_region (window, findex, clear_start, | |
805 dl->ypos - dl->ascent, clear_end - clear_start, | |
806 height); | |
807 } | |
808 } | |
809 | |
810 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value)) | |
811 { | |
812 gc = gtk_get_gc (d, font, cursor_cachel->foreground, | |
813 cursor_cachel->background, Qnil, Qnil); | |
814 } | |
815 else | |
816 { | |
817 gc = gtk_get_gc (d, font, cachel->foreground, cachel->background, | |
818 Qnil, Qnil); | |
819 } | |
820 | |
821 if (need_clipping) | |
822 { | |
823 GdkRectangle clip_box; | |
824 | |
825 clip_box.x = 0; | |
826 clip_box.y = 0; | |
827 clip_box.width = clip_end - clip_start; | |
828 clip_box.height = height; | |
829 | |
830 gdk_gc_set_clip_rectangle (gc, &clip_box); | |
831 gdk_gc_set_clip_origin (gc, clip_start, dl->ypos - dl->ascent); | |
832 } | |
833 | |
834 /* The X specific called different functions (XDraw*String | |
835 vs. XDraw*String16), but apparently gdk_draw_text takes care | |
836 of that for us. | |
837 | |
838 BUT, gdk_draw_text also does too much, by dividing the length | |
839 by 2. So we fake them out my multiplying the length by the | |
840 dimension of the text. This will do the right thing for | |
841 single-dimension runs as well of course. | |
842 */ | |
843 (bgc ? gdk_draw_text : gdk_draw_text_image) (GDK_DRAWABLE (x_win), gdk_font, gc, xpos, | |
844 dl->ypos, (char *) runs[i].ptr, | |
845 runs[i].len * runs[i].dimension); | |
846 | |
847 /* We draw underlines in the same color as the text. */ | |
848 if (cachel->underline) | |
849 { | |
850 unsigned long upos, uthick; | |
851 | |
852 /* Cannot get at font properties in Gtk, so we resort to | |
853 guessing */ | |
854 upos = dl->descent / 2; | |
855 uthick = 1; | |
856 | |
857 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip) | |
858 { | |
859 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip) | |
860 uthick = dl->descent - dl->clip - upos; | |
861 | |
862 if (uthick == 1) | |
863 { | |
864 gdk_draw_line (GDK_DRAWABLE (x_win), gc, xpos, dl->ypos + upos, | |
865 xpos + this_width, dl->ypos + upos); | |
866 } | |
867 else if (uthick > 1) | |
868 { | |
869 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE, xpos, | |
870 dl->ypos + upos, this_width, uthick); | |
871 } | |
872 } | |
873 } | |
874 | |
875 if (cachel->strikethru) { | |
876 unsigned long ascent,descent,upos, uthick; | |
877 GdkFont *gfont = FONT_INSTANCE_GTK_FONT (XFONT_INSTANCE (font)); | |
878 | |
879 /* Cannot get at font properties in Gtk, so we resort to | |
880 guessing */ | |
881 | |
882 ascent = gfont->ascent; | |
883 descent = gfont->descent; | |
884 uthick = 1; | |
885 | |
886 upos = ascent - ((ascent + descent) / 2) + 1; | |
887 | |
888 /* Generally, upos will be positive (above the baseline),so subtract */ | |
889 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip) | |
890 { | |
891 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip) | |
892 uthick = dl->descent - dl->clip + upos; | |
893 | |
894 if (uthick == 1) | |
895 { | |
896 gdk_draw_line (GDK_DRAWABLE (x_win), gc, xpos, dl->ypos - upos, | |
897 xpos + this_width, dl->ypos - upos); | |
898 } | |
899 else if (uthick > 1) | |
900 { | |
901 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE, xpos, dl->ypos + upos, | |
902 this_width, uthick); | |
903 } | |
904 } | |
905 } | |
906 | |
907 /* Restore the GC */ | |
908 if (need_clipping) | |
909 { | |
910 gdk_gc_set_clip_rectangle (gc, NULL); | |
911 gdk_gc_set_clip_origin (gc, 0, 0); | |
912 } | |
913 | |
914 /* If we are actually superimposing the cursor then redraw with just | |
915 the appropriate section highlighted. */ | |
916 if (cursor_clip && !cursor && focus && cursor_cachel) | |
917 { | |
918 GdkGC *cgc; | |
919 GdkRectangle clip_box; | |
920 | |
921 cgc = gtk_get_gc (d, font, cursor_cachel->foreground, | |
922 cursor_cachel->background, Qnil, Qnil); | |
923 | |
924 clip_box.x = 0; | |
925 clip_box.y = 0; | |
926 clip_box.width = cursor_width; | |
927 clip_box.height = height; | |
928 | |
929 gdk_gc_set_clip_rectangle (cgc, &clip_box); | |
930 gdk_gc_set_clip_origin (cgc, cursor_start, dl->ypos - dl->ascent); | |
931 | |
932 /* The X specific called different functions (XDraw*String | |
933 vs. XDraw*String16), but apparently gdk_draw_text takes care | |
934 of that for us. | |
935 | |
936 BUT, gdk_draw_text also does too much, by dividing the | |
937 length by 2. So we fake them out my multiplying the | |
938 length by the dimension of the text. This will do the | |
939 right thing for single-dimension runs as well of course. | |
940 */ | |
941 gdk_draw_text_image (GDK_DRAWABLE (x_win), gdk_font, cgc, xpos, | |
942 dl->ypos, (char *) runs[i].ptr, | |
943 runs[i].len * runs[i].dimension); | |
944 | |
945 gdk_gc_set_clip_rectangle (cgc, NULL); | |
946 gdk_gc_set_clip_origin (cgc, 0, 0); | |
947 } | |
948 | |
949 xpos += this_width; | |
950 } | |
951 | |
952 /* Draw the non-focus box or bar-cursor as needed. */ | |
953 /* Can't this logic be simplified? */ | |
954 if (cursor_cachel | |
955 && ((cursor && !focus && NILP (bar_cursor_value)) | |
956 || (cursor_width | |
957 && (cursor_start + cursor_width >= clip_start) | |
958 && !NILP (bar_cursor_value)))) | |
959 { | |
960 int tmp_height, tmp_y; | |
961 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2; | |
962 int need_clipping = (cursor_start < clip_start | |
963 || clip_end < cursor_start + cursor_width); | |
964 | |
965 /* #### This value is correct (as far as I know) because | |
966 all of the times we need to draw this cursor, we will | |
967 be called with exactly one character, so we know we | |
968 can always use runs[0]. | |
969 | |
970 This is bogus as all hell, however. The cursor handling in | |
971 this function is way bogus and desperately needs to be | |
972 cleaned up. (In particular, the drawing of the cursor should | |
973 really really be separated out of this function. This may be | |
974 a bit tricky now because this function itself does way too | |
975 much stuff, a lot of which needs to be moved into | |
976 redisplay.c) This is the only way to be able to easily add | |
977 new cursor types or (e.g.) make the bar cursor be able to | |
978 span two characters instead of overlaying just one. */ | |
979 int bogusly_obtained_ascent_value = | |
980 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent; | |
981 | |
982 if (!NILP (bar_cursor_value)) | |
983 { | |
984 gc = gtk_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, | |
985 make_int (bar_width)); | |
986 } | |
987 else | |
988 { | |
989 gc = gtk_get_gc (d, Qnil, cursor_cachel->background, | |
990 Qnil, Qnil, Qnil); | |
991 } | |
992 | |
993 tmp_y = dl->ypos - bogusly_obtained_ascent_value; | |
994 tmp_height = cursor_height; | |
995 if (tmp_y + tmp_height > (int) (dl->ypos - dl->ascent + height)) | |
996 { | |
997 tmp_y = dl->ypos - dl->ascent + height - tmp_height; | |
998 if (tmp_y < (int) (dl->ypos - dl->ascent)) | |
999 tmp_y = dl->ypos - dl->ascent; | |
1000 tmp_height = dl->ypos - dl->ascent + height - tmp_y; | |
1001 } | |
1002 | |
1003 if (need_clipping) | |
1004 { | |
1005 GdkRectangle clip_box; | |
1006 clip_box.x = 0; | |
1007 clip_box.y = 0; | |
1008 clip_box.width = clip_end - clip_start; | |
1009 clip_box.height = tmp_height; | |
1010 | |
1011 gdk_gc_set_clip_rectangle (gc, &clip_box); | |
1012 gdk_gc_set_clip_origin (gc, clip_start, tmp_y); | |
1013 } | |
1014 | |
1015 if (!focus && NILP (bar_cursor_value)) | |
1016 { | |
1017 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, FALSE, | |
1018 cursor_start, tmp_y, | |
1019 cursor_width - 1, tmp_height - 1); | |
1020 } | |
1021 else if (focus && !NILP (bar_cursor_value)) | |
1022 { | |
1023 gdk_draw_line (GDK_DRAWABLE (x_win), gc, | |
1024 cursor_start + bar_width - 1, tmp_y, | |
1025 cursor_start + bar_width - 1, tmp_y + tmp_height - 1); | |
1026 } | |
1027 | |
1028 /* Restore the GC */ | |
1029 if (need_clipping) | |
1030 { | |
1031 gdk_gc_set_clip_rectangle (gc, NULL); | |
1032 gdk_gc_set_clip_origin (gc, 0, 0); | |
1033 } | |
1034 } | |
1035 } | |
1036 | |
1037 static void | |
1038 our_draw_bitmap (GdkDrawable *drawable, | |
1039 GdkGC *gc, | |
1040 GdkPixmap *src, | |
1041 gint xsrc, | |
1042 gint ysrc, | |
1043 gint xdest, | |
1044 gint ydest, | |
1045 gint width, | |
1046 gint height); | |
1047 | |
1048 void | |
1049 gtk_output_gdk_pixmap (struct frame *f, struct Lisp_Image_Instance *p, int x, | |
1050 int y, int clip_x, int clip_y, int clip_width, | |
1051 int clip_height, int width, int height, int pixmap_offset, | |
1052 GdkColor *fg, GdkColor *bg, GdkGC *override_gc) | |
1053 { | |
1054 struct device *d = XDEVICE (f->device); | |
1055 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
1056 | |
1057 GdkGC *gc; | |
1058 GdkGCValues gcv; | |
1059 unsigned long pixmap_mask; | |
1060 int need_clipping = (clip_x || clip_y); | |
1061 | |
1062 if (!override_gc) | |
1063 { | |
1064 memset (&gcv, ~0, sizeof (gcv)); | |
1065 gcv.graphics_exposures = FALSE; | |
1066 gcv.foreground = *fg; | |
1067 gcv.background = *bg; | |
1068 pixmap_mask = GDK_GC_FOREGROUND | GDK_GC_BACKGROUND | GDK_GC_EXPOSURES; | |
1069 | |
1070 if (IMAGE_INSTANCE_GTK_MASK (p)) | |
1071 { | |
1072 gcv.function = GDK_COPY; | |
1073 gcv.clip_mask = IMAGE_INSTANCE_GTK_MASK (p); | |
1074 gcv.clip_x_origin = x; | |
1075 gcv.clip_y_origin = y - pixmap_offset; | |
1076 pixmap_mask |= (GDK_GC_FUNCTION | GDK_GC_CLIP_MASK | GDK_GC_CLIP_X_ORIGIN | | |
1077 GDK_GC_CLIP_Y_ORIGIN); | |
1078 /* Can't set a clip rectangle below because we already have a mask. | |
1079 We could conceivably create a new clipmask by zeroing out | |
1080 everything outside the clip region. Is it worth it? | |
1081 Is it possible to get an equivalent effect by changing the | |
1082 args to XCopyArea below rather than messing with a clip box? | |
1083 - dkindred@cs.cmu.edu */ | |
1084 need_clipping = 0; | |
1085 } | |
1086 | |
1087 gc = gc_cache_lookup (DEVICE_GTK_GC_CACHE (d), &gcv, pixmap_mask); | |
1088 } | |
1089 else | |
1090 { | |
1091 gc = override_gc; | |
1092 /* override_gc might have a mask already--we don't want to nuke it. | |
1093 Maybe we can insist that override_gc have no mask, or use | |
1094 one of the suggestions above. */ | |
1095 need_clipping = 0; | |
1096 } | |
1097 | |
1098 if (need_clipping) | |
1099 { | |
1100 GdkRectangle clip_box; | |
1101 | |
1102 clip_box.x = clip_x; | |
1103 clip_box.y = clip_y; | |
1104 clip_box.width = clip_width; | |
1105 clip_box.height = clip_height; | |
1106 | |
1107 gdk_gc_set_clip_rectangle (gc, &clip_box); | |
1108 gdk_gc_set_clip_origin (gc, x, y); | |
1109 } | |
1110 | |
1111 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0) | |
1112 { | |
1113 gdk_draw_pixmap (GDK_DRAWABLE (x_win), gc, | |
1114 IMAGE_INSTANCE_GTK_PIXMAP (p), | |
1115 0, pixmap_offset, x, y, width, height); | |
1116 } | |
1117 else | |
1118 { | |
1119 our_draw_bitmap (GDK_DRAWABLE (x_win), gc, | |
1120 IMAGE_INSTANCE_GTK_PIXMAP (p), | |
1121 0, pixmap_offset, x, y, width, height); | |
1122 } | |
1123 | |
1124 if (need_clipping) | |
1125 { | |
1126 gdk_gc_set_clip_rectangle (gc, NULL); | |
1127 gdk_gc_set_clip_origin (gc, 0, 0); | |
1128 } | |
1129 } | |
1130 | |
1131 static void | |
1132 gtk_output_pixmap (struct window *w, struct display_line *dl, | |
1133 Lisp_Object image_instance, int xpos, int xoffset, | |
1134 int start_pixpos, int width, face_index findex, | |
1135 int cursor_start, int cursor_width, int cursor_height) | |
1136 { | |
1137 struct frame *f = XFRAME (w->frame); | |
1138 struct device *d = XDEVICE (f->device); | |
1139 struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance); | |
1140 Lisp_Object window; | |
1141 | |
1142 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
1143 int lheight = dl->ascent + dl->descent - dl->clip; | |
1144 int pheight = ((int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > lheight ? lheight : | |
1145 IMAGE_INSTANCE_PIXMAP_HEIGHT (p)); | |
1146 int pwidth = min (width + xoffset, (int) IMAGE_INSTANCE_PIXMAP_WIDTH (p)); | |
1147 int clip_x, clip_y, clip_width, clip_height; | |
1148 | |
1149 /* The pixmap_offset is used to center the pixmap on lines which are | |
1150 shorter than it is. This results in odd effects when scrolling | |
1151 pixmaps off of the bottom. Let's try not using it. */ | |
1152 #if 0 | |
1153 int pixmap_offset = (int) (IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - lheight) / 2; | |
1154 #else | |
1155 int pixmap_offset = 0; | |
1156 #endif | |
1157 | |
1158 XSETWINDOW (window, w); | |
1159 | |
1160 if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset) | |
1161 { | |
1162 if (start_pixpos > xpos && start_pixpos > xpos + width) | |
1163 return; | |
1164 | |
1165 clip_x = xoffset; | |
1166 clip_width = width; | |
1167 if (start_pixpos > xpos) | |
1168 { | |
1169 clip_x += (start_pixpos - xpos); | |
1170 clip_width -= (start_pixpos - xpos); | |
1171 } | |
1172 } | |
1173 else | |
1174 { | |
1175 clip_x = 0; | |
1176 clip_width = 0; | |
1177 } | |
1178 | |
1179 /* Place markers for possible future functionality (clipping the top | |
1180 half instead of the bottom half; think pixel scrolling). */ | |
1181 clip_y = 0; | |
1182 clip_height = pheight; | |
1183 | |
1184 /* Clear the area the pixmap is going into. The pixmap itself will | |
1185 always take care of the full width. We don't want to clear where | |
1186 it is going to go in order to avoid flicker. So, all we have to | |
1187 take care of is any area above or below the pixmap. */ | |
1188 /* #### We take a shortcut for now. We know that since we have | |
1189 pixmap_offset hardwired to 0 that the pixmap is against the top | |
1190 edge so all we have to worry about is below it. */ | |
1191 /* #### Unless the pixmap has a mask in which case we have to clear | |
1192 the whole damn thing since we can't yet clear just the area not | |
1193 included in the mask. */ | |
1194 if (((int) (dl->ypos - dl->ascent + pheight) < | |
1195 (int) (dl->ypos + dl->descent - dl->clip)) | |
1196 || IMAGE_INSTANCE_GTK_MASK (p)) | |
1197 { | |
1198 int clear_x, clear_y, clear_width, clear_height; | |
1199 | |
1200 if (IMAGE_INSTANCE_GTK_MASK (p)) | |
1201 { | |
1202 clear_y = dl->ypos - dl->ascent; | |
1203 clear_height = lheight; | |
1204 } | |
1205 else | |
1206 { | |
1207 clear_y = dl->ypos - dl->ascent + pheight; | |
1208 clear_height = lheight - pheight; | |
1209 } | |
1210 | |
1211 if (start_pixpos >= 0 && start_pixpos > xpos) | |
1212 { | |
1213 clear_x = start_pixpos; | |
1214 clear_width = xpos + width - start_pixpos; | |
1215 } | |
1216 else | |
1217 { | |
1218 clear_x = xpos; | |
1219 clear_width = width; | |
1220 } | |
1221 | |
1222 redisplay_clear_region (window, findex, clear_x, clear_y, | |
1223 clear_width, clear_height); | |
1224 } | |
1225 | |
1226 /* Output the pixmap. */ | |
1227 { | |
1228 Lisp_Object tmp_pixel; | |
1229 GdkColor *tmp_bcolor, *tmp_fcolor; | |
1230 | |
1231 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex); | |
1232 tmp_fcolor = COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (tmp_pixel)); | |
1233 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex); | |
1234 tmp_bcolor = COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (tmp_pixel)); | |
1235 | |
1236 gtk_output_gdk_pixmap (f, p, xpos - xoffset, dl->ypos - dl->ascent, clip_x, | |
1237 clip_y, clip_width, clip_height, | |
1238 pwidth, pheight, pixmap_offset, | |
1239 tmp_fcolor, tmp_bcolor, 0); | |
1240 } | |
1241 | |
1242 /* Draw a cursor over top of the pixmap. */ | |
1243 if (cursor_width && cursor_height && (cursor_start >= xpos) | |
1244 && !NILP (w->text_cursor_visible_p) | |
1245 && (cursor_start < xpos + pwidth)) | |
1246 { | |
1247 GdkGC *gc; | |
1248 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d)); | |
1249 int y = dl->ypos - dl->ascent; | |
1250 struct face_cachel *cursor_cachel = | |
1251 WINDOW_FACE_CACHEL (w, | |
1252 get_builtin_face_cache_index | |
1253 (w, Vtext_cursor_face)); | |
1254 | |
1255 gc = gtk_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil); | |
1256 | |
1257 if (cursor_width > xpos + pwidth - cursor_start) | |
1258 cursor_width = xpos + pwidth - cursor_start; | |
1259 | |
1260 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, focus ? TRUE : FALSE, | |
1261 cursor_start, y, cursor_width, | |
1262 cursor_height); | |
1263 } | |
1264 } | |
1265 | |
1266 /***************************************************************************** | |
1267 gtk_output_vertical_divider | |
1268 | |
1269 Draw a vertical divider down the right side of the given window. | |
1270 ****************************************************************************/ | |
1271 static void | |
1272 gtk_output_vertical_divider (struct window *w, int clear) | |
1273 { | |
1274 struct frame *f = XFRAME (w->frame); | |
1275 struct device *d = XDEVICE (f->device); | |
1276 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
1277 GdkGC *background_gc; | |
1278 Lisp_Object tmp_pixel; | |
1279 GdkGCValues gcv; | |
1280 unsigned long mask; | |
1281 int x, y1, y2, width, shadow_thickness, spacing, line_width; | |
1282 face_index div_face = get_builtin_face_cache_index (w, Vvertical_divider_face); | |
1283 | |
1284 width = window_divider_width (w); | |
1285 shadow_thickness = XINT (w->vertical_divider_shadow_thickness); | |
1286 spacing = XINT (w->vertical_divider_spacing); | |
1287 line_width = XINT (w->vertical_divider_line_width); | |
1288 x = WINDOW_RIGHT (w) - width; | |
1289 y1 = WINDOW_TOP (w); | |
1290 y2 = WINDOW_BOTTOM (w); | |
1291 | |
1292 memset (&gcv, ~0, sizeof (gcv)); | |
1293 | |
1294 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face); | |
1295 | |
1296 gcv.background = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (tmp_pixel)); | |
1297 gcv.foreground = gcv.background; | |
1298 gcv.graphics_exposures = FALSE; | |
1299 mask = GDK_GC_FOREGROUND | GDK_GC_BACKGROUND | GDK_GC_EXPOSURES; | |
1300 | |
1301 background_gc = gc_cache_lookup (DEVICE_GTK_GC_CACHE (d), &gcv, mask); | |
1302 | |
1303 /* Clear the divider area first. This needs to be done when a | |
1304 window split occurs. */ | |
1305 /* if (clear) */ | |
1306 gdk_draw_rectangle (GDK_DRAWABLE (x_win), background_gc, TRUE, | |
1307 x, y1, width, y2 - y1); | |
1308 | |
1309 #if 0 | |
1310 /* Draw the divider line. */ | |
1311 gdk_draw_rectangle (GDK_DRAWABLE (x_win), background_gc, TRUE, | |
1312 x + spacing + shadow_thickness, y1, | |
1313 line_width, y2 - y1); | |
1314 #endif | |
1315 | |
1316 /* Draw the shadows around the divider line */ | |
1317 gtk_output_shadows (f, x + spacing, y1, | |
1318 width - 2 * spacing, y2 - y1, | |
1319 shadow_thickness); | |
1320 } | |
1321 | |
1322 /***************************************************************************** | |
1323 gtk_output_blank | |
1324 | |
1325 Output a blank by clearing the area it covers in the foreground color | |
1326 of its face. | |
1327 ****************************************************************************/ | |
1328 static void | |
1329 gtk_output_blank (struct window *w, struct display_line *dl, struct rune *rb, | |
1330 int start_pixpos, int cursor_start, int cursor_width) | |
1331 { | |
1332 struct frame *f = XFRAME (w->frame); | |
1333 struct device *d = XDEVICE (f->device); | |
1334 | |
1335 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
1336 GdkGC *gc; | |
1337 struct face_cachel *cursor_cachel = | |
1338 WINDOW_FACE_CACHEL (w, | |
1339 get_builtin_face_cache_index | |
1340 (w, Vtext_cursor_face)); | |
1341 Lisp_Object bg_pmap; | |
1342 Lisp_Object buffer = WINDOW_BUFFER (w); | |
1343 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor, | |
1344 buffer); | |
1345 | |
1346 int x = rb->xpos; | |
1347 int y = dl->ypos - dl->ascent; | |
1348 int width = rb->width; | |
1349 int height = dl->ascent + dl->descent - dl->clip; | |
1350 | |
1351 if (start_pixpos > x) | |
1352 { | |
1353 if (start_pixpos >= (x + width)) | |
1354 return; | |
1355 else | |
1356 { | |
1357 width -= (start_pixpos - x); | |
1358 x = start_pixpos; | |
1359 } | |
1360 } | |
1361 | |
1362 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex); | |
1363 if (!IMAGE_INSTANCEP (bg_pmap) | |
1364 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap))) | |
1365 bg_pmap = Qnil; | |
1366 | |
1367 if (NILP (bg_pmap)) | |
1368 gc = gtk_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), | |
1369 Qnil, Qnil, Qnil); | |
1370 else | |
1371 gc = gtk_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex), | |
1372 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap, | |
1373 Qnil); | |
1374 | |
1375 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE, x, y, width, height); | |
1376 | |
1377 /* If this rune is marked as having the cursor, then it is actually | |
1378 representing a tab. */ | |
1379 if (!NILP (w->text_cursor_visible_p) | |
1380 && (rb->cursor_type == CURSOR_ON | |
1381 || (cursor_width | |
1382 && (cursor_start + cursor_width > x) | |
1383 && cursor_start < (x + width)))) | |
1384 { | |
1385 int cursor_height, cursor_y; | |
1386 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d)); | |
1387 struct Lisp_Font_Instance *fi; | |
1388 | |
1389 fi = XFONT_INSTANCE (FACE_CACHEL_FONT | |
1390 (WINDOW_FACE_CACHEL (w, rb->findex), | |
1391 Vcharset_ascii)); | |
1392 | |
1393 gc = gtk_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil); | |
1394 | |
1395 cursor_y = dl->ypos - fi->ascent; | |
1396 cursor_height = fi->height; | |
1397 if (cursor_y + cursor_height > y + height) | |
1398 cursor_height = y + height - cursor_y; | |
1399 | |
1400 if (focus) | |
1401 { | |
1402 if (NILP (bar_cursor_value)) | |
1403 { | |
1404 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE, | |
1405 cursor_start, cursor_y, | |
1406 fi->width, cursor_height); | |
1407 } | |
1408 else | |
1409 { | |
1410 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2; | |
1411 | |
1412 gc = gtk_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, | |
1413 make_int (bar_width)); | |
1414 gdk_draw_line (GDK_DRAWABLE (x_win), gc, cursor_start + bar_width - 1, | |
1415 cursor_y, cursor_start + bar_width - 1, | |
1416 cursor_y + cursor_height - 1); | |
1417 } | |
1418 } | |
1419 else if (NILP (bar_cursor_value)) | |
1420 { | |
1421 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, FALSE, | |
1422 cursor_start, cursor_y, | |
1423 fi->width - 1, cursor_height - 1); | |
1424 } | |
1425 } | |
1426 } | |
1427 | |
1428 /***************************************************************************** | |
1429 gtk_output_hline | |
1430 | |
1431 Output a horizontal line in the foreground of its face. | |
1432 ****************************************************************************/ | |
1433 static void | |
1434 gtk_output_hline (struct window *w, struct display_line *dl, struct rune *rb) | |
1435 { | |
1436 struct frame *f = XFRAME (w->frame); | |
1437 struct device *d = XDEVICE (f->device); | |
1438 GtkStyle *style = FRAME_GTK_TEXT_WIDGET (f)->style; | |
1439 | |
1440 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
1441 GdkGC *gc; | |
1442 | |
1443 int x = rb->xpos; | |
1444 int width = rb->width; | |
1445 int height = dl->ascent + dl->descent - dl->clip; | |
1446 | |
1447 int ypos1, ypos2, ypos3, ypos4; | |
1448 | |
1449 ypos1 = dl->ypos - dl->ascent; | |
1450 ypos2 = ypos1 + rb->object.hline.yoffset; | |
1451 ypos3 = ypos2 + rb->object.hline.thickness; | |
1452 ypos4 = dl->ypos + dl->descent - dl->clip; | |
1453 | |
1454 /* First clear the area not covered by the line. */ | |
1455 if (height - rb->object.hline.thickness > 0) | |
1456 { | |
1457 gc = gtk_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex), | |
1458 Qnil, Qnil, Qnil); | |
1459 | |
1460 if (ypos2 - ypos1 > 0) | |
1461 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE, x, ypos1, width, ypos2 - ypos1); | |
1462 if (ypos4 - ypos3 > 0) | |
1463 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE, x, ypos1, width, ypos2 - ypos1); | |
1464 } | |
1465 | |
1466 gtk_paint_hline (style, x_win, GTK_STATE_NORMAL, NULL, FRAME_GTK_TEXT_WIDGET (f), | |
1467 "hline", x, x + width, ypos2); | |
1468 #if 0 | |
1469 /* Now draw the line. */ | |
1470 gc = gtk_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), | |
1471 Qnil, Qnil, Qnil); | |
1472 | |
1473 if (ypos2 < ypos1) | |
1474 ypos2 = ypos1; | |
1475 if (ypos3 > ypos4) | |
1476 ypos3 = ypos4; | |
1477 | |
1478 if (ypos3 - ypos2 > 0) | |
1479 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE, x, ypos2, width, ypos3 - ypos2); | |
1480 #endif | |
1481 } | |
1482 | |
1483 /***************************************************************************** | |
1484 gtk_output_shadows | |
1485 | |
1486 Draw a shadow around the given area using the standard theme engine routines. | |
1487 ****************************************************************************/ | |
1488 void | |
1489 gtk_output_shadows (struct frame *f, int x, int y, int width, int height, | |
1490 int shadow_thickness) | |
1491 { | |
1492 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
1493 GtkStyle *style = FRAME_GTK_TEXT_WIDGET (f)->style; | |
1494 GtkShadowType stype = GTK_SHADOW_OUT; | |
1495 | |
1496 if (shadow_thickness < 0) | |
1497 { | |
1498 stype = GTK_SHADOW_IN; | |
1499 } | |
1500 else if (shadow_thickness == 0) | |
1501 { | |
1502 stype = GTK_SHADOW_NONE; | |
1503 } | |
1504 | |
1505 /* Do we want to have some magic constants to set | |
1506 GTK_SHADOW_ETCHED_IN or GTK_SHADOW_ETCHED_OUT? */ | |
1507 | |
1508 gtk_paint_shadow (style, x_win, GTK_STATE_NORMAL, stype, NULL, | |
1509 FRAME_GTK_TEXT_WIDGET (f), "modeline", | |
1510 x, y, width, height); | |
1511 } | |
1512 | |
1513 /***************************************************************************** | |
1514 gtk_clear_to_window_end | |
1515 | |
1516 Clear the area between ypos1 and ypos2. Each margin area and the | |
1517 text area is handled separately since they may each have their own | |
1518 background color. | |
1519 ****************************************************************************/ | |
1520 static void | |
1521 gtk_clear_to_window_end (struct window *w, int ypos1, int ypos2) | |
1522 { | |
1523 int height = ypos2 - ypos1; | |
1524 | |
1525 if (height) | |
1526 { | |
1527 struct frame *f = XFRAME (w->frame); | |
1528 Lisp_Object window; | |
1529 int bflag = (window_needs_vertical_divider (w) ? 0 : 1); | |
1530 layout_bounds bounds; | |
1531 | |
1532 bounds = calculate_display_line_boundaries (w, bflag); | |
1533 XSETWINDOW (window, w); | |
1534 | |
1535 if (window_is_leftmost (w)) | |
1536 redisplay_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f), | |
1537 ypos1, FRAME_BORDER_WIDTH (f), height); | |
1538 | |
1539 if (bounds.left_in - bounds.left_out > 0) | |
1540 redisplay_clear_region (window, | |
1541 get_builtin_face_cache_index (w, Vleft_margin_face), | |
1542 bounds.left_out, ypos1, | |
1543 bounds.left_in - bounds.left_out, height); | |
1544 | |
1545 if (bounds.right_in - bounds.left_in > 0) | |
1546 redisplay_clear_region (window, DEFAULT_INDEX, bounds.left_in, ypos1, | |
1547 bounds.right_in - bounds.left_in, height); | |
1548 | |
1549 if (bounds.right_out - bounds.right_in > 0) | |
1550 redisplay_clear_region (window, | |
1551 get_builtin_face_cache_index (w, Vright_margin_face), | |
1552 bounds.right_in, ypos1, | |
1553 bounds.right_out - bounds.right_in, height); | |
1554 | |
1555 if (window_is_rightmost (w)) | |
1556 redisplay_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f), | |
1557 ypos1, FRAME_BORDER_WIDTH (f), height); | |
1558 } | |
1559 } | |
1560 | |
1561 /***************************************************************************** | |
1562 gtk_redraw_exposed_window | |
1563 | |
1564 Given a bounding box for an area that needs to be redrawn, determine | |
1565 what parts of what lines are contained within and re-output their | |
1566 contents. | |
1567 ****************************************************************************/ | |
1568 static void | |
1569 gtk_redraw_exposed_window (struct window *w, int x, int y, int width, int height) | |
1570 { | |
1571 struct frame *f = XFRAME (w->frame); | |
1572 int line; | |
1573 int start_x, start_y, end_x, end_y; | |
1574 int orig_windows_structure_changed; | |
1575 | |
1576 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP); | |
1577 | |
1578 if (!NILP (w->vchild)) | |
1579 { | |
1580 gtk_redraw_exposed_windows (w->vchild, x, y, width, height); | |
1581 return; | |
1582 } | |
1583 else if (!NILP (w->hchild)) | |
1584 { | |
1585 gtk_redraw_exposed_windows (w->hchild, x, y, width, height); | |
1586 return; | |
1587 } | |
1588 | |
1589 /* If the window doesn't intersect the exposed region, we're done here. */ | |
1590 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w) | |
1591 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w)) | |
1592 { | |
1593 return; | |
1594 } | |
1595 else | |
1596 { | |
1597 start_x = max (WINDOW_LEFT (w), x); | |
1598 end_x = min (WINDOW_RIGHT (w), (x + width)); | |
1599 start_y = max (WINDOW_TOP (w), y); | |
1600 end_y = min (WINDOW_BOTTOM (w), y + height); | |
1601 | |
1602 /* We do this to make sure that the 3D modelines get redrawn if | |
1603 they are in the exposed region. */ | |
1604 orig_windows_structure_changed = f->windows_structure_changed; | |
1605 f->windows_structure_changed = 1; | |
1606 } | |
1607 | |
1608 if (window_needs_vertical_divider (w)) | |
1609 { | |
1610 gtk_output_vertical_divider (w, 0); | |
1611 } | |
1612 | |
1613 for (line = 0; line < Dynarr_length (cdla); line++) | |
1614 { | |
1615 struct display_line *cdl = Dynarr_atp (cdla, line); | |
1616 int top_y = cdl->ypos - cdl->ascent; | |
1617 int bottom_y = cdl->ypos + cdl->descent; | |
1618 | |
1619 if (bottom_y >= start_y) | |
1620 { | |
1621 if (top_y > end_y) | |
1622 { | |
1623 if (line == 0) | |
1624 continue; | |
1625 else | |
1626 break; | |
1627 } | |
1628 else | |
1629 { | |
1630 output_display_line (w, 0, cdla, line, start_x, end_x); | |
1631 } | |
1632 } | |
1633 } | |
1634 | |
1635 f->windows_structure_changed = orig_windows_structure_changed; | |
1636 | |
1637 /* If there have never been any face cache_elements created, then this | |
1638 expose event doesn't actually have anything to do. */ | |
1639 if (Dynarr_largest (w->face_cachels)) | |
1640 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y); | |
1641 } | |
1642 | |
1643 /***************************************************************************** | |
1644 gtk_redraw_exposed_windows | |
1645 | |
1646 For each window beneath the given window in the window hierarchy, | |
1647 ensure that it is redrawn if necessary after an Expose event. | |
1648 ****************************************************************************/ | |
1649 static void | |
1650 gtk_redraw_exposed_windows (Lisp_Object window, int x, int y, int width, | |
1651 int height) | |
1652 { | |
1653 for (; !NILP (window); window = XWINDOW (window)->next) | |
1654 gtk_redraw_exposed_window (XWINDOW (window), x, y, width, height); | |
1655 } | |
1656 | |
1657 /***************************************************************************** | |
1658 gtk_redraw_exposed_area | |
1659 | |
1660 For each window on the given frame, ensure that any area in the | |
1661 Exposed area is redrawn. | |
1662 ****************************************************************************/ | |
1663 void | |
1664 gtk_redraw_exposed_area (struct frame *f, int x, int y, int width, int height) | |
1665 { | |
1666 /* If any window on the frame has had its face cache reset then the | |
1667 redisplay structures are effectively invalid. If we attempt to | |
1668 use them we'll blow up. We mark the frame as changed to ensure | |
1669 that redisplay will do a full update. This probably isn't | |
1670 necessary but it can't hurt. */ | |
1671 | |
1672 #ifdef HAVE_TOOLBARS | |
1673 /* #### We would rather put these off as well but there is currently | |
1674 no combination of flags which will force an unchanged toolbar to | |
1675 redraw anyhow. */ | |
1676 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height)); | |
1677 #endif | |
1678 redraw_exposed_gutters (f, x, y, width, height); | |
1679 | |
1680 if (!f->window_face_cache_reset) | |
1681 { | |
1682 gtk_redraw_exposed_windows (f->root_window, x, y, width, height); | |
1683 } | |
1684 else | |
1685 MARK_FRAME_CHANGED (f); | |
1686 } | |
1687 | |
1688 /**************************************************************************** | |
1689 gtk_clear_region | |
1690 | |
1691 Clear the area in the box defined by the given parameters using the | |
1692 given face. | |
1693 ****************************************************************************/ | |
1694 static void | |
1695 gtk_clear_region (Lisp_Object locale, struct device* d, struct frame* f, face_index findex, | |
1696 int x, int y, | |
1697 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor, | |
1698 Lisp_Object background_pixmap) | |
1699 { | |
1700 GdkWindow *x_win; | |
1701 GdkGC *gc = NULL; | |
1702 | |
1703 x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
1704 | |
1705 if (!UNBOUNDP (background_pixmap)) | |
1706 { | |
1707 gc = gtk_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil); | |
1708 } | |
1709 | |
1710 if (gc) | |
1711 { | |
1712 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc,TRUE, | |
1713 x, y, width, height); | |
1714 } | |
1715 else | |
1716 { | |
1717 gdk_window_clear_area (x_win, x, y, width, height); | |
1718 } | |
1719 } | |
1720 | |
1721 /***************************************************************************** | |
1722 gtk_output_eol_cursor | |
1723 | |
1724 Draw a cursor at the end of a line. The end-of-line cursor is | |
1725 narrower than the normal cursor. | |
1726 ****************************************************************************/ | |
1727 static void | |
1728 gtk_output_eol_cursor (struct window *w, struct display_line *dl, int xpos, | |
1729 face_index findex) | |
1730 { | |
1731 struct frame *f = XFRAME (w->frame); | |
1732 struct device *d = XDEVICE (f->device); | |
1733 Lisp_Object window; | |
1734 | |
1735 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
1736 GdkGC *gc; | |
1737 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face); | |
1738 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt); | |
1739 | |
1740 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d)); | |
1741 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor, | |
1742 WINDOW_BUFFER (w)); | |
1743 | |
1744 int x = xpos; | |
1745 int y = dl->ypos - dl->ascent; | |
1746 int width = EOL_CURSOR_WIDTH; | |
1747 int height = dl->ascent + dl->descent - dl->clip; | |
1748 int cursor_height, cursor_y; | |
1749 int defheight, defascent; | |
1750 | |
1751 XSETWINDOW (window, w); | |
1752 redisplay_clear_region (window, findex, x, y, width, height); | |
1753 | |
1754 if (NILP (w->text_cursor_visible_p)) | |
1755 return; | |
1756 | |
1757 gc = gtk_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil); | |
1758 | |
1759 default_face_font_info (window, &defascent, 0, &defheight, 0, 0); | |
1760 | |
1761 /* make sure the cursor is entirely contained between y and y+height */ | |
1762 cursor_height = min (defheight, height); | |
1763 cursor_y = max (y, min (y + height - cursor_height, | |
1764 dl->ypos - defascent)); | |
1765 | |
1766 if (focus) | |
1767 { | |
1768 if (NILP (bar_cursor_value)) | |
1769 { | |
1770 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE, x, cursor_y, width, cursor_height); | |
1771 } | |
1772 else | |
1773 { | |
1774 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2; | |
1775 | |
1776 gc = gtk_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, | |
1777 make_int (bar_width)); | |
1778 gdk_draw_line (GDK_DRAWABLE (x_win), gc, x + bar_width - 1, cursor_y, | |
1779 x + bar_width - 1, cursor_y + cursor_height - 1); | |
1780 } | |
1781 } | |
1782 else if (NILP (bar_cursor_value)) | |
1783 { | |
1784 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, FALSE, x, cursor_y, width - 1, | |
1785 cursor_height - 1); | |
1786 } | |
1787 } | |
1788 | |
1789 static void | |
1790 gtk_clear_frame_window (Lisp_Object window) | |
1791 { | |
1792 struct window *w = XWINDOW (window); | |
1793 | |
1794 if (!NILP (w->vchild)) | |
1795 { | |
1796 gtk_clear_frame_windows (w->vchild); | |
1797 return; | |
1798 } | |
1799 | |
1800 if (!NILP (w->hchild)) | |
1801 { | |
1802 gtk_clear_frame_windows (w->hchild); | |
1803 return; | |
1804 } | |
1805 | |
1806 gtk_clear_to_window_end (w, WINDOW_TEXT_TOP (w), WINDOW_TEXT_BOTTOM (w)); | |
1807 } | |
1808 | |
1809 static void | |
1810 gtk_clear_frame_windows (Lisp_Object window) | |
1811 { | |
1812 for (; !NILP (window); window = XWINDOW (window)->next) | |
1813 gtk_clear_frame_window (window); | |
1814 } | |
1815 | |
1816 static void | |
1817 gtk_clear_frame (struct frame *f) | |
1818 { | |
1819 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
1820 int x, y, width, height; | |
1821 Lisp_Object frame; | |
1822 | |
1823 x = FRAME_LEFT_BORDER_START (f); | |
1824 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) - | |
1825 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) - | |
1826 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) - | |
1827 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f)); | |
1828 /* #### This adjustment by 1 should be being done in the macros. | |
1829 There is some small differences between when the menubar is on | |
1830 and off that we still need to deal with. */ | |
1831 y = FRAME_TOP_BORDER_START (f) - 1; | |
1832 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) - | |
1833 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) - | |
1834 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) - | |
1835 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1; | |
1836 | |
1837 gdk_window_clear_area (x_win, x, y, width, height); | |
1838 | |
1839 XSETFRAME (frame, f); | |
1840 | |
1841 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame)) | |
1842 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame)) | |
1843 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame))) | |
1844 { | |
1845 gtk_clear_frame_windows (f->root_window); | |
1846 } | |
1847 } | |
1848 | |
1849 static int | |
1850 gtk_flash (struct device *d) | |
1851 { | |
1852 GdkGCValues gcv; | |
1853 GdkGC *gc; | |
1854 GdkColor tmp_fcolor, tmp_bcolor; | |
1855 Lisp_Object tmp_pixel, frame; | |
1856 struct frame *f = device_selected_frame (d); | |
1857 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f)); | |
1858 | |
1859 XSETFRAME (frame, f); | |
1860 | |
1861 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame); | |
1862 tmp_fcolor = * (COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (tmp_pixel))); | |
1863 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame); | |
1864 tmp_bcolor = * (COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (tmp_pixel))); | |
1865 | |
1866 memset (&gcv, ~0, sizeof (gcv)); /* initialize all slots to ~0 */ | |
1867 gcv.foreground.pixel = (tmp_fcolor.pixel ^ tmp_bcolor.pixel); | |
1868 gcv.function = GDK_XOR; | |
1869 gcv.graphics_exposures = FALSE; | |
1870 gc = gc_cache_lookup (DEVICE_GTK_GC_CACHE (XDEVICE (f->device)), &gcv, | |
1871 GDK_GC_FOREGROUND | GDK_GC_FUNCTION | GDK_GC_EXPOSURES); | |
1872 | |
1873 gdk_draw_rectangle (GDK_DRAWABLE (GET_GTK_WIDGET_WINDOW (FRAME_GTK_SHELL_WIDGET (f))), | |
1874 gc, TRUE, w->pixel_left, w->pixel_top, | |
1875 w->pixel_width, w->pixel_height); | |
1876 | |
1877 gdk_flush (); | |
1878 | |
1879 #ifdef HAVE_POLL | |
1880 poll (0, 0, 100); | |
1881 #else /* !HAVE_POLL */ | |
1882 #ifdef HAVE_SELECT | |
1883 { | |
1884 int usecs = 100000; | |
1885 struct timeval tv; | |
1886 tv.tv_sec = usecs / 1000000L; | |
1887 tv.tv_usec = usecs % 1000000L; | |
1888 /* I'm sure someone is going to complain about this... */ | |
1889 select (0, 0, 0, 0, &tv); | |
1890 } | |
1891 #else | |
1892 bite me | |
1893 #endif /* HAVE_POLL */ | |
1894 #endif /* HAVE_SELECT */ | |
1895 | |
1896 gdk_draw_rectangle (GDK_DRAWABLE (GET_GTK_WIDGET_WINDOW (FRAME_GTK_SHELL_WIDGET (f))), | |
1897 gc, TRUE, w->pixel_left, w->pixel_top, | |
1898 w->pixel_width, w->pixel_height); | |
1899 | |
1900 gdk_flush (); | |
1901 | |
1902 return 1; | |
1903 } | |
1904 | |
1905 static void | |
1906 gtk_bevel_area (struct window *w, face_index findex, | |
1907 int x, int y, int width, int height, | |
1908 int shadow_thickness, int edges, enum edge_style style) | |
1909 { | |
1910 struct frame *f = XFRAME (w->frame); | |
1911 struct device *d = XDEVICE (f->device); | |
1912 | |
1913 gtk_output_shadows (f, x, y, width, height, shadow_thickness); | |
1914 } | |
1915 | |
1916 | |
1917 | |
1918 /* Make audible bell. */ | |
1919 static void | |
1920 gtk_ring_bell (struct device *d, int volume, int pitch, int duration) | |
1921 { | |
1922 /* Gdk does not allow us to control the duration / pitch / volume */ | |
1923 gdk_beep (); | |
1924 } | |
1925 | |
1926 | |
1927 /************************************************************************/ | |
1928 /* initialization */ | |
1929 /************************************************************************/ | |
1930 | |
1931 void | |
1932 console_type_create_redisplay_gtk (void) | |
1933 { | |
1934 /* redisplay methods */ | |
1935 CONSOLE_HAS_METHOD (gtk, text_width); | |
1936 CONSOLE_HAS_METHOD (gtk, output_display_block); | |
1937 CONSOLE_HAS_METHOD (gtk, divider_height); | |
1938 CONSOLE_HAS_METHOD (gtk, eol_cursor_width); | |
1939 CONSOLE_HAS_METHOD (gtk, output_vertical_divider); | |
1940 CONSOLE_HAS_METHOD (gtk, clear_to_window_end); | |
1941 CONSOLE_HAS_METHOD (gtk, clear_region); | |
1942 CONSOLE_HAS_METHOD (gtk, clear_frame); | |
1943 CONSOLE_HAS_METHOD (gtk, flash); | |
1944 CONSOLE_HAS_METHOD (gtk, ring_bell); | |
1945 CONSOLE_HAS_METHOD (gtk, bevel_area); | |
1946 CONSOLE_HAS_METHOD (gtk, output_string); | |
1947 /* CONSOLE_HAS_METHOD (gtk, output_pixmap); */ | |
1948 } | |
1949 | |
1950 /* This makes me feel incredibly dirty... but there is no other way to | |
1951 get this done right other than calling clear_area before every | |
1952 single $#!%@ing piece of text, which I do NOT want to do. */ | |
1953 #define USE_X_SPECIFIC_DRAW_ROUTINES 1 | |
1954 | |
1955 #include <gdk/gdkx.h> | |
1956 | |
1957 void | |
1958 gdk_draw_text_image (GdkDrawable *drawable, | |
1959 GdkFont *font, | |
1960 GdkGC *gc, | |
1961 gint x, | |
1962 gint y, | |
1963 const gchar *text, | |
1964 gint text_length) | |
1965 { | |
1966 #if !USE_X_SPECIFIC_DRAW_ROUTINES | |
1967 int width = gdk_text_measure (font, text, text_length); | |
1968 int height = gdk_text_height (font, text, text_length); | |
1969 | |
1970 gdk_draw_rectangle (drawable, gc, TRUE, x, y, width, height); | |
1971 gdk_draw_text (drawable, font, gc, x, y, text, text_length); | |
1972 #else | |
1973 GdkWindowPrivate *drawable_private; | |
1974 GdkFontPrivate *font_private; | |
1975 GdkGCPrivate *gc_private; | |
1976 | |
1977 g_return_if_fail (drawable != NULL); | |
1978 g_return_if_fail (font != NULL); | |
1979 g_return_if_fail (gc != NULL); | |
1980 g_return_if_fail (text != NULL); | |
1981 | |
1982 drawable_private = (GdkWindowPrivate*) drawable; | |
1983 if (drawable_private->destroyed) | |
1984 return; | |
1985 gc_private = (GdkGCPrivate*) gc; | |
1986 font_private = (GdkFontPrivate*) font; | |
1987 | |
1988 if (font->type == GDK_FONT_FONT) | |
1989 { | |
1990 XFontStruct *xfont = (XFontStruct *) font_private->xfont; | |
1991 XSetFont(drawable_private->xdisplay, gc_private->xgc, xfont->fid); | |
1992 if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) | |
1993 { | |
1994 XDrawImageString (drawable_private->xdisplay, drawable_private->xwindow, | |
1995 gc_private->xgc, x, y, text, text_length); | |
1996 } | |
1997 else | |
1998 { | |
1999 XDrawImageString16 (drawable_private->xdisplay, drawable_private->xwindow, | |
2000 gc_private->xgc, x, y, (XChar2b *) text, text_length / 2); | |
2001 } | |
2002 } | |
2003 else if (font->type == GDK_FONT_FONTSET) | |
2004 { | |
2005 XFontSet fontset = (XFontSet) font_private->xfont; | |
2006 XmbDrawImageString (drawable_private->xdisplay, drawable_private->xwindow, | |
2007 fontset, gc_private->xgc, x, y, text, text_length); | |
2008 } | |
2009 else | |
2010 g_error("undefined font type\n"); | |
2011 #endif | |
2012 } | |
2013 | |
2014 static void | |
2015 our_draw_bitmap (GdkDrawable *drawable, | |
2016 GdkGC *gc, | |
2017 GdkPixmap *src, | |
2018 gint xsrc, | |
2019 gint ysrc, | |
2020 gint xdest, | |
2021 gint ydest, | |
2022 gint width, | |
2023 gint height) | |
2024 { | |
2025 GdkWindowPrivate *drawable_private; | |
2026 GdkWindowPrivate *src_private; | |
2027 GdkGCPrivate *gc_private; | |
2028 | |
2029 g_return_if_fail (drawable != NULL); | |
2030 g_return_if_fail (src != NULL); | |
2031 g_return_if_fail (gc != NULL); | |
2032 | |
2033 drawable_private = (GdkWindowPrivate*) drawable; | |
2034 src_private = (GdkWindowPrivate*) src; | |
2035 if (drawable_private->destroyed || src_private->destroyed) | |
2036 return; | |
2037 gc_private = (GdkGCPrivate*) gc; | |
2038 | |
2039 if (width == -1) | |
2040 width = src_private->width; | |
2041 if (height == -1) | |
2042 height = src_private->height; | |
2043 | |
2044 XCopyPlane (drawable_private->xdisplay, | |
2045 src_private->xwindow, | |
2046 drawable_private->xwindow, | |
2047 gc_private->xgc, | |
2048 xsrc, ysrc, | |
2049 width, height, | |
2050 xdest, ydest, 1L); | |
2051 } |