Mercurial > hg > xemacs-beta
comparison src/redisplay-gtk.c @ 4882:eab9498ecc0e
merge most of rest of redisplay-x.c and redisplay-gtk.c into redisplay-xlike-inc.c
-------------------- ChangeLog entries follow: --------------------
src/ChangeLog addition:
2010-01-18 Ben Wing <ben@xemacs.org>
* redisplay-gtk.c:
* redisplay-gtk.c (gtk_bevel_area):
* redisplay-x.c:
* redisplay-x.c (THIS_IS_X):
* redisplay-xlike-inc.c:
* redisplay-xlike-inc.c (XLIKE_text_width_single_run):
* redisplay-xlike-inc.c (XLIKE_text_width):
* redisplay-xlike-inc.c (XLIKE_output_display_block):
* redisplay-xlike-inc.c (XLIKE_get_gc):
* redisplay-xlike-inc.c (XLIKE_output_string):
* redisplay-xlike-inc.c (XLIKE_OUTPUT_XLIKE_PIXMAP):
* redisplay-xlike-inc.c (XLIKE_output_pixmap):
* redisplay-xlike-inc.c (XLIKE_output_vertical_divider):
* redisplay-xlike-inc.c (XLIKE_output_blank):
* redisplay-xlike-inc.c (XLIKE_output_horizontal_line):
* redisplay-xlike-inc.c (XLIKE_clear_region):
* redisplay-xlike-inc.c (XLIKE_output_eol_cursor):
* redisplay-xlike-inc.c (XLIKE_clear_frame_window):
* redisplay-xlike-inc.c (XLIKE_clear_frame):
* redisplay-xlike-inc.c (XLIKE_flash):
* redisplay-xlike-inc.c (console_type_create_redisplay_XLIKE):
Move lots more code into redisplay-xlike-inc.c. Use macros to
isolate the code that differs among X vs. GTK, to reduce the need
for ifdefs in the middle of the code. Now, redisplay-x.c and
redisplay-gtk.c only contain a few functions whose implementation
is completely different from one to the other, or which are not
present at all in one of them.
GTK code not currently tested, but it has bitrotted somewhat
any. Doing this will help keep it less bitrotty.
* depend: Regenerate.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Mon, 18 Jan 2010 08:44:49 -0600 |
parents | a4322ac49e37 |
children | b3ce27ca7647 |
comparison
equal
deleted
inserted
replaced
4881:a4322ac49e37 | 4882:eab9498ecc0e |
---|---|
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
22 Boston, MA 02111-1307, USA. */ | 22 Boston, MA 02111-1307, USA. */ |
23 | 23 |
24 /* Synched up with: Not in FSF. */ | 24 /* Synched up with: Not in FSF. */ |
25 | 25 |
26 /* Author: Chuck Thompson */ | |
27 /* Gtk flavor by William Perry */ | |
28 | |
29 /* Lots of work done by Ben Wing for Mule */ | |
30 | |
31 #include <config.h> | |
32 #include "lisp.h" | |
33 | |
34 #include "buffer.h" | |
35 #include "debug.h" | |
36 #include "device-impl.h" | |
37 #include "faces.h" | |
38 #include "file-coding.h" | |
39 #include "frame-impl.h" | |
40 #include "gutter.h" | |
41 #include "redisplay.h" | |
42 #include "sysdep.h" | |
43 #include "window.h" | |
44 | |
45 #include "console-gtk-impl.h" | |
46 #include "gccache-gtk.h" | |
47 #include "glyphs-gtk.h" | |
48 #include "objects-gtk-impl.h" | |
49 | |
50 #include "sysproc.h" /* for select() */ | |
51 | |
52 #ifdef MULE | |
53 #include "mule-ccl.h" | |
54 #endif | |
55 | |
56 #define CONST const | |
57 | |
58 #define EOL_CURSOR_WIDTH 5 | |
59 | |
60 static void gtk_output_pixmap (struct window *w, | |
61 Lisp_Object image_instance, | |
62 struct display_box *db, | |
63 struct display_glyph_area *dga, | |
64 face_index findex, | |
65 int cursor_start, | |
66 int cursor_width, | |
67 int cursor_height, | |
68 int bgpixmap); | |
69 static void gtk_output_vertical_divider (struct window *w, int clear); | |
70 static void gtk_output_blank (struct window *w, struct display_line *dl, | |
71 struct rune *rb, int start_pixpos, | |
72 int cursor_start, int cursor_width); | |
73 static void gtk_output_horizontal_line (struct window *w, | |
74 struct display_line *dl, | |
75 struct rune *rb); | |
76 static void gtk_clear_region (Lisp_Object locale, struct device* d, struct frame* f, | |
77 face_index findex, int x, int y, | |
78 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor, | |
79 Lisp_Object background_pixmap); | |
80 static void gtk_output_eol_cursor (struct window *w, struct display_line *dl, | |
81 int xpos, face_index findex); | |
82 static void gtk_clear_frame (struct frame *f); | |
83 static void gtk_clear_frame_windows (Lisp_Object window); | |
84 static void gtk_bevel_modeline (struct window *w, struct display_line *dl); | |
85 | |
86 #if 0 | |
87 static void __describe_gc (GdkGC *); | |
88 #endif | |
89 | |
90 #include "redisplay-xlike-inc.c" | 26 #include "redisplay-xlike-inc.c" |
91 | |
92 /****************************************************************************/ | |
93 /* */ | |
94 /* Gtk output routines */ | |
95 /* */ | |
96 /****************************************************************************/ | |
97 | |
98 static int | |
99 gtk_text_width_single_run (struct face_cachel *cachel, struct textual_run *run) | |
100 { | |
101 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset); | |
102 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst); | |
103 | |
104 if (!fi->proportional_p) | |
105 { | |
106 return fi->width * run->len; | |
107 } | |
108 else | |
109 { | |
110 if (run->dimension == 2) | |
111 { | |
112 stderr_out ("Measuring wide characters\n"); | |
113 return gdk_text_width_wc (FONT_INSTANCE_GTK_FONT (fi), | |
114 (GdkWChar *) run->ptr, run->len); | |
115 } | |
116 else | |
117 { | |
118 return gdk_text_width (FONT_INSTANCE_GTK_FONT (fi), | |
119 (char *) run->ptr, run->len); | |
120 } | |
121 } | |
122 } | |
123 | |
124 /* | |
125 gtk_text_width | |
126 | |
127 Given a string and a face, return the string's length in pixels when | |
128 displayed in the font associated with the face. | |
129 */ | |
130 | |
131 static int | |
132 gtk_text_width (struct frame *UNUSED (f), struct face_cachel *cachel, | |
133 CONST Ichar *str, Charcount len) | |
134 { | |
135 /* !!#### */ | |
136 int width_so_far = 0; | |
137 unsigned char *text_storage = (unsigned char *) ALLOCA (2 * len); | |
138 struct textual_run *runs = alloca_array (struct textual_run, len); | |
139 int nruns; | |
140 int i; | |
141 | |
142 nruns = separate_textual_runs (text_storage, runs, str, len); | |
143 | |
144 for (i = 0; i < nruns; i++) | |
145 width_so_far += gtk_text_width_single_run (cachel, runs + i); | |
146 | |
147 return width_so_far; | |
148 } | |
149 | |
150 /***************************************************************************** | |
151 gtk_divider_height | |
152 | |
153 Return the height of the horizontal divider. This is a function because | |
154 divider_height is a device method. | |
155 | |
156 #### If we add etched horizontal divider lines this will have to get | |
157 smarter. | |
158 ****************************************************************************/ | |
159 static int | |
160 gtk_divider_height (void) | |
161 { | |
162 return 2; | |
163 } | |
164 | |
165 /***************************************************************************** | |
166 gtk_eol_cursor_width | |
167 | |
168 Return the width of the end-of-line cursor. This is a function | |
169 because eol_cursor_width is a device method. | |
170 ****************************************************************************/ | |
171 static int | |
172 gtk_eol_cursor_width (void) | |
173 { | |
174 return EOL_CURSOR_WIDTH; | |
175 } | |
176 | |
177 /***************************************************************************** | |
178 gtk_output_display_block | |
179 | |
180 Given a display line, a block number for that start line, output all | |
181 runes between start and end in the specified display block. | |
182 ****************************************************************************/ | |
183 static void | |
184 gtk_output_display_block (struct window *w, struct display_line *dl, int block, | |
185 int start, int end, int start_pixpos, int cursor_start, | |
186 int cursor_width, int cursor_height) | |
187 { | |
188 struct frame *f = XFRAME (w->frame); | |
189 Ichar_dynarr *buf; | |
190 Lisp_Object window; | |
191 | |
192 struct display_block *db = Dynarr_atp (dl->display_blocks, block); | |
193 rune_dynarr *rba = db->runes; | |
194 struct rune *rb; | |
195 | |
196 int elt = start; | |
197 face_index findex; | |
198 int xpos, width; | |
199 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when | |
200 MULE is not defined */ | |
201 | |
202 window = wrap_window (w); | |
203 rb = Dynarr_atp (rba, start); | |
204 | |
205 if (!rb) | |
206 { | |
207 /* Nothing to do so don't do anything. */ | |
208 return; | |
209 } | |
210 else | |
211 { | |
212 findex = rb->findex; | |
213 xpos = rb->xpos; | |
214 width = 0; | |
215 if (rb->type == RUNE_CHAR) | |
216 charset = ichar_charset (rb->object.chr.ch); | |
217 } | |
218 | |
219 if (end < 0) | |
220 end = Dynarr_length (rba); | |
221 buf = Dynarr_new (Ichar); | |
222 | |
223 while (elt < end) | |
224 { | |
225 rb = Dynarr_atp (rba, elt); | |
226 | |
227 if (rb->findex == findex && rb->type == RUNE_CHAR | |
228 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON | |
229 && EQ (charset, ichar_charset (rb->object.chr.ch))) | |
230 { | |
231 Dynarr_add (buf, rb->object.chr.ch); | |
232 width += rb->width; | |
233 elt++; | |
234 } | |
235 else | |
236 { | |
237 if (Dynarr_length (buf)) | |
238 { | |
239 gtk_output_string (w, dl, buf, xpos, 0, start_pixpos, width, | |
240 findex, 0, cursor_start, cursor_width, | |
241 cursor_height); | |
242 xpos = rb->xpos; | |
243 width = 0; | |
244 } | |
245 Dynarr_reset (buf); | |
246 width = 0; | |
247 | |
248 if (rb->type == RUNE_CHAR) | |
249 { | |
250 findex = rb->findex; | |
251 xpos = rb->xpos; | |
252 charset = ichar_charset (rb->object.chr.ch); | |
253 | |
254 if (rb->cursor_type == CURSOR_ON) | |
255 { | |
256 if (rb->object.chr.ch == '\n') | |
257 { | |
258 gtk_output_eol_cursor (w, dl, xpos, findex); | |
259 } | |
260 else | |
261 { | |
262 Dynarr_add (buf, rb->object.chr.ch); | |
263 gtk_output_string (w, dl, buf, xpos, 0, start_pixpos, | |
264 rb->width, findex, 1, | |
265 cursor_start, cursor_width, | |
266 cursor_height); | |
267 Dynarr_reset (buf); | |
268 } | |
269 | |
270 xpos += rb->width; | |
271 elt++; | |
272 } | |
273 else if (rb->object.chr.ch == '\n') | |
274 { | |
275 /* Clear in case a cursor was formerly here. */ | |
276 int height = dl->ascent + dl->descent - dl->clip; | |
277 | |
278 redisplay_clear_region (window, findex, xpos, dl->ypos - dl->ascent, | |
279 rb->width, height); | |
280 elt++; | |
281 } | |
282 } | |
283 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE) | |
284 { | |
285 if (rb->type == RUNE_BLANK) | |
286 gtk_output_blank (w, dl, rb, start_pixpos, cursor_start, | |
287 cursor_width); | |
288 else | |
289 { | |
290 /* #### Our flagging of when we need to redraw the | |
291 modeline shadows sucks. Since RUNE_HLINE is only used | |
292 by the modeline at the moment it is a good bet | |
293 that if it gets redrawn then we should also | |
294 redraw the shadows. This won't be true forever. | |
295 We borrow the shadow_thickness_changed flag for | |
296 now. */ | |
297 w->shadow_thickness_changed = 1; | |
298 gtk_output_horizontal_line (w, dl, rb); | |
299 } | |
300 | |
301 elt++; | |
302 if (elt < end) | |
303 { | |
304 rb = Dynarr_atp (rba, elt); | |
305 | |
306 findex = rb->findex; | |
307 xpos = rb->xpos; | |
308 } | |
309 } | |
310 else if (rb->type == RUNE_DGLYPH) | |
311 { | |
312 Lisp_Object instance; | |
313 struct display_box dbox; | |
314 struct display_glyph_area dga; | |
315 redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset, | |
316 rb->object.dglyph.yoffset ,start_pixpos, | |
317 rb->width, &dbox, &dga); | |
318 | |
319 window = wrap_window (w); | |
320 instance = glyph_image_instance (rb->object.dglyph.glyph, | |
321 window, ERROR_ME_DEBUG_WARN, 1); | |
322 findex = rb->findex; | |
323 | |
324 if (IMAGE_INSTANCEP (instance)) | |
325 switch (XIMAGE_INSTANCE_TYPE (instance)) | |
326 { | |
327 case IMAGE_TEXT: | |
328 { | |
329 /* #### This is way losing. See the comment in | |
330 add_glyph_rune(). */ | |
331 Lisp_Object string = | |
332 XIMAGE_INSTANCE_TEXT_STRING (instance); | |
333 convert_ibyte_string_into_ichar_dynarr | |
334 (XSTRING_DATA (string), XSTRING_LENGTH (string), buf); | |
335 | |
336 gtk_output_string (w, dl, buf, xpos, | |
337 rb->object.dglyph.xoffset, | |
338 start_pixpos, -1, findex, | |
339 (rb->cursor_type == CURSOR_ON), | |
340 cursor_start, cursor_width, | |
341 cursor_height); | |
342 Dynarr_reset (buf); | |
343 } | |
344 break; | |
345 | |
346 case IMAGE_MONO_PIXMAP: | |
347 case IMAGE_COLOR_PIXMAP: | |
348 redisplay_output_pixmap (w, instance, &dbox, &dga, | |
349 findex,cursor_start, | |
350 cursor_width, cursor_height, 0); | |
351 break; | |
352 | |
353 case IMAGE_POINTER: | |
354 ABORT (); | |
355 | |
356 case IMAGE_WIDGET: | |
357 if (EQ (XIMAGE_INSTANCE_WIDGET_TYPE (instance), | |
358 Qlayout)) | |
359 { | |
360 redisplay_output_layout (window, instance, &dbox, | |
361 &dga, findex, | |
362 cursor_start, cursor_width, | |
363 cursor_height); | |
364 break; | |
365 } | |
366 | |
367 case IMAGE_SUBWINDOW: | |
368 redisplay_output_subwindow (w, instance, &dbox, &dga, | |
369 findex, cursor_start, | |
370 cursor_width, cursor_height); | |
371 break; | |
372 | |
373 case IMAGE_NOTHING: | |
374 /* nothing is as nothing does */ | |
375 break; | |
376 | |
377 default: | |
378 ABORT (); | |
379 } | |
380 | |
381 xpos += rb->width; | |
382 elt++; | |
383 } | |
384 else | |
385 ABORT (); | |
386 } | |
387 } | |
388 | |
389 if (Dynarr_length (buf)) | |
390 gtk_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex, | |
391 0, cursor_start, cursor_width, cursor_height); | |
392 | |
393 /* #### This is really conditionalized well for optimized | |
394 performance. */ | |
395 if (dl->modeline | |
396 && !EQ (Qzero, w->modeline_shadow_thickness) | |
397 && (f->clear | |
398 || f->windows_structure_changed | |
399 || w->shadow_thickness_changed)) | |
400 gtk_bevel_modeline (w, dl); | |
401 | |
402 Dynarr_free (buf); | |
403 } | |
404 | 27 |
405 /***************************************************************************** | 28 /***************************************************************************** |
406 gtk_bevel_modeline | 29 gtk_bevel_modeline |
407 | 30 |
408 Draw a 3d border around the modeline on window W. | 31 Draw a 3d border around the modeline on window W. |
418 width = WINDOW_MODELINE_RIGHT (w) - x; | 41 width = WINDOW_MODELINE_RIGHT (w) - x; |
419 y = dl->ypos - dl->ascent - shadow_thickness; | 42 y = dl->ypos - dl->ascent - shadow_thickness; |
420 height = dl->ascent + dl->descent + 2 * shadow_thickness; | 43 height = dl->ascent + dl->descent + 2 * shadow_thickness; |
421 | 44 |
422 gtk_output_shadows (f, x, y, width, height, shadow_thickness); | 45 gtk_output_shadows (f, x, y, width, height, shadow_thickness); |
423 } | |
424 | |
425 /***************************************************************************** | |
426 gtk_get_gc | |
427 | |
428 Given a number of parameters return a GC with those properties. | |
429 ****************************************************************************/ | |
430 GdkGC * | |
431 gtk_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg, | |
432 Lisp_Object bg_pmap, Lisp_Object lwidth) | |
433 { | |
434 GdkGCValues gcv; | |
435 unsigned long mask; | |
436 | |
437 memset (&gcv, ~0, sizeof (gcv)); | |
438 gcv.graphics_exposures = FALSE; | |
439 /* Make absolutely sure that we don't pick up a clipping region in | |
440 the GC returned by this function. */ | |
441 gcv.clip_mask = 0; | |
442 gcv.clip_x_origin = 0; | |
443 gcv.clip_y_origin = 0; | |
444 gcv.fill = GDK_SOLID; | |
445 mask = GDK_GC_EXPOSURES | GDK_GC_CLIP_MASK | GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN; | |
446 mask |= GDK_GC_FILL; | |
447 | |
448 if (!NILP (font)) | |
449 { | |
450 gcv.font = FONT_INSTANCE_GTK_FONT (XFONT_INSTANCE (font)); | |
451 mask |= GDK_GC_FONT; | |
452 } | |
453 | |
454 /* evil kludge! */ | |
455 if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg)) | |
456 { | |
457 /* #### I fixed once case where this was getting it. It was a | |
458 bad macro expansion (compiler bug). */ | |
459 fprintf (stderr, "Help! gtk_get_gc got a bogus fg value! fg = "); | |
460 debug_print (fg); | |
461 fg = Qnil; | |
462 } | |
463 | |
464 if (!NILP (fg)) | |
465 { | |
466 if (COLOR_INSTANCEP (fg)) | |
467 gcv.foreground = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (fg)); | |
468 else | |
469 gcv.foreground.pixel = XINT (fg); | |
470 mask |= GDK_GC_FOREGROUND; | |
471 } | |
472 | |
473 if (!NILP (bg)) | |
474 { | |
475 if (COLOR_INSTANCEP (bg)) | |
476 gcv.background = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (bg)); | |
477 else | |
478 gcv.background.pixel = XINT (fg); | |
479 mask |= GDK_GC_BACKGROUND; | |
480 } | |
481 | |
482 if (IMAGE_INSTANCEP (bg_pmap) | |
483 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap))) | |
484 { | |
485 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0) | |
486 { | |
487 gcv.fill = GDK_OPAQUE_STIPPLED; | |
488 gcv.stipple = XIMAGE_INSTANCE_GTK_PIXMAP (bg_pmap); | |
489 mask |= (GDK_GC_STIPPLE | GDK_GC_FILL); | |
490 } | |
491 else | |
492 { | |
493 gcv.fill = GDK_TILED; | |
494 gcv.tile = XIMAGE_INSTANCE_GTK_PIXMAP (bg_pmap); | |
495 mask |= (GDK_GC_TILE | GDK_GC_FILL); | |
496 } | |
497 } | |
498 | |
499 if (!NILP (lwidth)) | |
500 { | |
501 gcv.line_width = XINT (lwidth); | |
502 mask |= GDK_GC_LINE_WIDTH; | |
503 } | |
504 | |
505 return gc_cache_lookup (DEVICE_GTK_GC_CACHE (d), &gcv, (GdkGCValuesMask) mask); | |
506 } | |
507 | |
508 /***************************************************************************** | |
509 gtk_output_string | |
510 | |
511 Given a string and a starting position, output that string in the | |
512 given face. If cursor is true, draw a cursor around the string. | |
513 Correctly handles multiple charsets in the string. | |
514 | |
515 The meaning of the parameters is something like this: | |
516 | |
517 W Window that the text is to be displayed in. | |
518 DL Display line that this text is on. The values in the | |
519 structure are used to determine the vertical position and | |
520 clipping range of the text. | |
521 BUF Dynamic array of Ichars specifying what is actually to be | |
522 drawn. | |
523 XPOS X position in pixels where the text should start being drawn. | |
524 XOFFSET Number of pixels to be chopped off the left side of the | |
525 text. The effect is as if the text were shifted to the | |
526 left this many pixels and clipped at XPOS. | |
527 CLIP_START Clip everything left of this X position. | |
528 WIDTH Clip everything right of XPOS + WIDTH. | |
529 FINDEX Index for the face cache element describing how to display | |
530 the text. | |
531 CURSOR #### I don't understand this. There's something | |
532 strange and overcomplexified with this variable. | |
533 Chuck, explain please? | |
534 CURSOR_START Starting X position of cursor. | |
535 CURSOR_WIDTH Width of cursor in pixels. | |
536 CURSOR_HEIGHT Height of cursor in pixels. | |
537 | |
538 Starting Y position of cursor is the top of the text line. | |
539 The cursor is drawn sometimes whether or not CURSOR is set. ??? | |
540 ****************************************************************************/ | |
541 static | |
542 void gdk_draw_text_image (GdkDrawable *drawable, | |
543 GdkFont *font, | |
544 GdkGC *gc, | |
545 gint x, | |
546 gint y, | |
547 const gchar *text, | |
548 gint text_length); | |
549 | |
550 void | |
551 gtk_output_string (struct window *w, struct display_line *dl, | |
552 Ichar_dynarr *buf, int xpos, int xoffset, int clip_start, | |
553 int width, face_index findex, int cursor, | |
554 int cursor_start, int cursor_width, int cursor_height) | |
555 { | |
556 /* !!#### Needs review */ | |
557 /* General variables */ | |
558 struct frame *f = XFRAME (w->frame); | |
559 struct device *d = XDEVICE (f->device); | |
560 Lisp_Object device; | |
561 Lisp_Object window; | |
562 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
563 | |
564 int clip_end; | |
565 | |
566 /* Cursor-related variables */ | |
567 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d)); | |
568 int cursor_clip; | |
569 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor, | |
570 WINDOW_BUFFER (w)); | |
571 struct face_cachel *cursor_cachel = 0; | |
572 | |
573 /* Text-related variables */ | |
574 Lisp_Object bg_pmap; | |
575 GdkGC *bgc, *gc; | |
576 int height; | |
577 int len = Dynarr_length (buf); | |
578 unsigned char *text_storage = (unsigned char *) ALLOCA (2 * len); | |
579 struct textual_run *runs = alloca_array (struct textual_run, len); | |
580 int nruns; | |
581 int i; | |
582 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex); | |
583 | |
584 device = wrap_device (d); | |
585 window = wrap_window (w); | |
586 | |
587 if (width < 0) | |
588 width = gtk_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf)); | |
589 height = dl->ascent + dl->descent - dl->clip; | |
590 | |
591 /* Regularize the variables passed in. */ | |
592 | |
593 if (clip_start < xpos) | |
594 clip_start = xpos; | |
595 clip_end = xpos + width; | |
596 if (clip_start >= clip_end) | |
597 /* It's all clipped out. */ | |
598 return; | |
599 | |
600 xpos -= xoffset; | |
601 | |
602 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0), | |
603 Dynarr_length (buf)); | |
604 | |
605 cursor_clip = (cursor_start >= clip_start && | |
606 cursor_start < clip_end); | |
607 | |
608 /* This cursor code is really a mess. */ | |
609 if (!NILP (w->text_cursor_visible_p) | |
610 && (cursor | |
611 || cursor_clip | |
612 || (cursor_width | |
613 && (cursor_start + cursor_width >= clip_start) | |
614 && !NILP (bar_cursor_value)))) | |
615 { | |
616 /* These have to be in separate statements in order to avoid a | |
617 compiler bug. */ | |
618 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face); | |
619 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks); | |
620 | |
621 /* We have to reset this since any call to WINDOW_FACE_CACHEL | |
622 may cause the cache to resize and any pointers to it to | |
623 become invalid. */ | |
624 cachel = WINDOW_FACE_CACHEL (w, findex); | |
625 } | |
626 | |
627 bg_pmap = cachel->background_pixmap; | |
628 if (!IMAGE_INSTANCEP (bg_pmap) | |
629 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap))) | |
630 bg_pmap = Qnil; | |
631 | |
632 if ((cursor && focus && NILP (bar_cursor_value) | |
633 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap)) | |
634 bgc = 0; | |
635 else | |
636 bgc = gtk_get_gc (d, Qnil, cachel->foreground, cachel->background, | |
637 bg_pmap, Qnil); | |
638 | |
639 if (bgc) | |
640 gdk_draw_rectangle (GDK_DRAWABLE (x_win), bgc, TRUE, clip_start, | |
641 dl->ypos - dl->ascent, clip_end - clip_start, | |
642 height); | |
643 | |
644 for (i = 0; i < nruns; i++) | |
645 { | |
646 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset); | |
647 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font); | |
648 GdkFont *gdk_font = FONT_INSTANCE_GTK_FONT (fi); | |
649 int this_width; | |
650 int need_clipping; | |
651 | |
652 if (EQ (font, Vthe_null_font_instance)) | |
653 continue; | |
654 | |
655 this_width = gtk_text_width_single_run (cachel, runs + i); | |
656 need_clipping = (dl->clip || clip_start > xpos || | |
657 clip_end < xpos + this_width); | |
658 | |
659 /* XDrawImageString only clears the area equal to the height of | |
660 the given font. It is possible that a font is being displayed | |
661 on a line taller than it is, so this would cause us to fail to | |
662 clear some areas. */ | |
663 if ((int) fi->height < (int) (height + dl->clip)) | |
664 { | |
665 int clear_start = max (xpos, clip_start); | |
666 int clear_end = min (xpos + this_width, clip_end); | |
667 | |
668 if (cursor) | |
669 { | |
670 int ypos1_line, ypos1_string, ypos2_line, ypos2_string; | |
671 | |
672 ypos1_string = dl->ypos - fi->ascent; | |
673 ypos2_string = dl->ypos + fi->descent; | |
674 ypos1_line = dl->ypos - dl->ascent; | |
675 ypos2_line = dl->ypos + dl->descent - dl->clip; | |
676 | |
677 /* Make sure we don't clear below the real bottom of the | |
678 line. */ | |
679 if (ypos1_string > ypos2_line) | |
680 ypos1_string = ypos2_line; | |
681 if (ypos2_string > ypos2_line) | |
682 ypos2_string = ypos2_line; | |
683 | |
684 if (ypos1_line < ypos1_string) | |
685 { | |
686 redisplay_clear_region (window, findex, clear_start, ypos1_line, | |
687 clear_end - clear_start, | |
688 ypos1_string - ypos1_line); | |
689 } | |
690 | |
691 if (ypos2_line > ypos2_string) | |
692 { | |
693 redisplay_clear_region (window, findex, clear_start, ypos2_string, | |
694 clear_end - clear_start, | |
695 ypos2_line - ypos2_string); | |
696 } | |
697 } | |
698 else | |
699 { | |
700 redisplay_clear_region (window, findex, clear_start, | |
701 dl->ypos - dl->ascent, clear_end - clear_start, | |
702 height); | |
703 } | |
704 } | |
705 | |
706 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value)) | |
707 { | |
708 gc = gtk_get_gc (d, font, cursor_cachel->foreground, | |
709 cursor_cachel->background, Qnil, Qnil); | |
710 } | |
711 else | |
712 { | |
713 gc = gtk_get_gc (d, font, cachel->foreground, cachel->background, | |
714 Qnil, Qnil); | |
715 } | |
716 | |
717 if (need_clipping) | |
718 { | |
719 GdkRectangle clip_box; | |
720 | |
721 clip_box.x = 0; | |
722 clip_box.y = 0; | |
723 clip_box.width = clip_end - clip_start; | |
724 clip_box.height = height; | |
725 | |
726 gdk_gc_set_clip_rectangle (gc, &clip_box); | |
727 gdk_gc_set_clip_origin (gc, clip_start, dl->ypos - dl->ascent); | |
728 } | |
729 | |
730 /* The X specific called different functions (XDraw*String | |
731 vs. XDraw*String16), but apparently gdk_draw_text takes care | |
732 of that for us. | |
733 | |
734 BUT, gdk_draw_text also does too much, by dividing the length | |
735 by 2. So we fake them out my multiplying the length by the | |
736 dimension of the text. This will do the right thing for | |
737 single-dimension runs as well of course. | |
738 */ | |
739 (bgc ? gdk_draw_text : gdk_draw_text_image) (GDK_DRAWABLE (x_win), gdk_font, gc, xpos, | |
740 dl->ypos, (char *) runs[i].ptr, | |
741 runs[i].len * runs[i].dimension); | |
742 | |
743 /* We draw underlines in the same color as the text. */ | |
744 if (cachel->underline) | |
745 { | |
746 int upos, uthick; | |
747 | |
748 /* Cannot get at font properties in Gtk, so we resort to | |
749 guessing */ | |
750 upos = dl->descent / 2; | |
751 uthick = 1; | |
752 | |
753 if ((dl->ypos + upos) < (dl->ypos + dl->descent - dl->clip)) | |
754 { | |
755 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip) | |
756 uthick = dl->descent - dl->clip - upos; | |
757 | |
758 if (uthick == 1) | |
759 { | |
760 gdk_draw_line (GDK_DRAWABLE (x_win), gc, xpos, dl->ypos + upos, | |
761 xpos + this_width, dl->ypos + upos); | |
762 } | |
763 else if (uthick > 1) | |
764 { | |
765 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE, xpos, | |
766 dl->ypos + upos, this_width, uthick); | |
767 } | |
768 } | |
769 } | |
770 | |
771 if (cachel->strikethru) { | |
772 gint ascent,descent,upos, uthick; | |
773 GdkFont *gfont = FONT_INSTANCE_GTK_FONT (XFONT_INSTANCE (font)); | |
774 | |
775 /* Cannot get at font properties in Gtk, so we resort to | |
776 guessing */ | |
777 | |
778 ascent = gfont->ascent; | |
779 descent = gfont->descent; | |
780 uthick = 1; | |
781 | |
782 upos = ascent - ((ascent + descent) / 2) + 1; | |
783 | |
784 /* Generally, upos will be positive (above the baseline),so subtract */ | |
785 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip) | |
786 { | |
787 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip) | |
788 uthick = dl->descent - dl->clip + upos; | |
789 | |
790 if (uthick == 1) | |
791 { | |
792 gdk_draw_line (GDK_DRAWABLE (x_win), gc, xpos, dl->ypos - upos, | |
793 xpos + this_width, dl->ypos - upos); | |
794 } | |
795 else if (uthick > 1) | |
796 { | |
797 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE, xpos, dl->ypos + upos, | |
798 this_width, uthick); | |
799 } | |
800 } | |
801 } | |
802 | |
803 /* Restore the GC */ | |
804 if (need_clipping) | |
805 { | |
806 gdk_gc_set_clip_rectangle (gc, NULL); | |
807 gdk_gc_set_clip_origin (gc, 0, 0); | |
808 } | |
809 | |
810 /* If we are actually superimposing the cursor then redraw with just | |
811 the appropriate section highlighted. */ | |
812 if (cursor_clip && !cursor && focus && cursor_cachel) | |
813 { | |
814 GdkGC *cgc; | |
815 GdkRectangle clip_box; | |
816 | |
817 cgc = gtk_get_gc (d, font, cursor_cachel->foreground, | |
818 cursor_cachel->background, Qnil, Qnil); | |
819 | |
820 clip_box.x = 0; | |
821 clip_box.y = 0; | |
822 clip_box.width = cursor_width; | |
823 clip_box.height = height; | |
824 | |
825 gdk_gc_set_clip_rectangle (cgc, &clip_box); | |
826 gdk_gc_set_clip_origin (cgc, cursor_start, dl->ypos - dl->ascent); | |
827 | |
828 /* The X specific called different functions (XDraw*String | |
829 vs. XDraw*String16), but apparently gdk_draw_text takes care | |
830 of that for us. | |
831 | |
832 BUT, gdk_draw_text also does too much, by dividing the | |
833 length by 2. So we fake them out my multiplying the | |
834 length by the dimension of the text. This will do the | |
835 right thing for single-dimension runs as well of course. | |
836 */ | |
837 gdk_draw_text_image (GDK_DRAWABLE (x_win), gdk_font, cgc, xpos, | |
838 dl->ypos, (char *) runs[i].ptr, | |
839 runs[i].len * runs[i].dimension); | |
840 | |
841 gdk_gc_set_clip_rectangle (cgc, NULL); | |
842 gdk_gc_set_clip_origin (cgc, 0, 0); | |
843 } | |
844 | |
845 xpos += this_width; | |
846 } | |
847 | |
848 /* Draw the non-focus box or bar-cursor as needed. */ | |
849 /* Can't this logic be simplified? */ | |
850 if (cursor_cachel | |
851 && ((cursor && !focus && NILP (bar_cursor_value)) | |
852 || (cursor_width | |
853 && (cursor_start + cursor_width >= clip_start) | |
854 && !NILP (bar_cursor_value)))) | |
855 { | |
856 int tmp_height, tmp_y; | |
857 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2; | |
858 int need_clipping = (cursor_start < clip_start | |
859 || clip_end < cursor_start + cursor_width); | |
860 | |
861 /* #### This value is correct (as far as I know) because | |
862 all of the times we need to draw this cursor, we will | |
863 be called with exactly one character, so we know we | |
864 can always use runs[0]. | |
865 | |
866 This is bogus as all hell, however. The cursor handling in | |
867 this function is way bogus and desperately needs to be | |
868 cleaned up. (In particular, the drawing of the cursor should | |
869 really really be separated out of this function. This may be | |
870 a bit tricky now because this function itself does way too | |
871 much stuff, a lot of which needs to be moved into | |
872 redisplay.c) This is the only way to be able to easily add | |
873 new cursor types or (e.g.) make the bar cursor be able to | |
874 span two characters instead of overlaying just one. */ | |
875 int bogusly_obtained_ascent_value = | |
876 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent; | |
877 | |
878 if (!NILP (bar_cursor_value)) | |
879 { | |
880 gc = gtk_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, | |
881 make_int (bar_width)); | |
882 } | |
883 else | |
884 { | |
885 gc = gtk_get_gc (d, Qnil, cursor_cachel->background, | |
886 Qnil, Qnil, Qnil); | |
887 } | |
888 | |
889 tmp_y = dl->ypos - bogusly_obtained_ascent_value; | |
890 tmp_height = cursor_height; | |
891 if (tmp_y + tmp_height > (int) (dl->ypos - dl->ascent + height)) | |
892 { | |
893 tmp_y = dl->ypos - dl->ascent + height - tmp_height; | |
894 if (tmp_y < (int) (dl->ypos - dl->ascent)) | |
895 tmp_y = dl->ypos - dl->ascent; | |
896 tmp_height = dl->ypos - dl->ascent + height - tmp_y; | |
897 } | |
898 | |
899 if (need_clipping) | |
900 { | |
901 GdkRectangle clip_box; | |
902 clip_box.x = 0; | |
903 clip_box.y = 0; | |
904 clip_box.width = clip_end - clip_start; | |
905 clip_box.height = tmp_height; | |
906 | |
907 gdk_gc_set_clip_rectangle (gc, &clip_box); | |
908 gdk_gc_set_clip_origin (gc, clip_start, tmp_y); | |
909 } | |
910 | |
911 if (!focus && NILP (bar_cursor_value)) | |
912 { | |
913 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, FALSE, | |
914 cursor_start, tmp_y, | |
915 cursor_width - 1, tmp_height - 1); | |
916 } | |
917 else if (focus && !NILP (bar_cursor_value)) | |
918 { | |
919 gdk_draw_line (GDK_DRAWABLE (x_win), gc, | |
920 cursor_start + bar_width - 1, tmp_y, | |
921 cursor_start + bar_width - 1, tmp_y + tmp_height - 1); | |
922 } | |
923 | |
924 /* Restore the GC */ | |
925 if (need_clipping) | |
926 { | |
927 gdk_gc_set_clip_rectangle (gc, NULL); | |
928 gdk_gc_set_clip_origin (gc, 0, 0); | |
929 } | |
930 } | |
931 } | |
932 | |
933 static void | |
934 our_draw_bitmap (GdkDrawable *drawable, | |
935 GdkGC *gc, | |
936 GdkPixmap *src, | |
937 gint xsrc, | |
938 gint ysrc, | |
939 gint xdest, | |
940 gint ydest, | |
941 gint width, | |
942 gint height); | |
943 | |
944 static void | |
945 gtk_output_gdk_pixmap (struct frame *f, struct Lisp_Image_Instance *p, int x, | |
946 int y, int xoffset, int yoffset, | |
947 int width, int height, | |
948 GdkColor *fg, GdkColor *bg, GdkGC *override_gc) | |
949 { | |
950 struct device *d = XDEVICE (f->device); | |
951 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
952 | |
953 GdkGC *gc; | |
954 GdkGCValues gcv; | |
955 unsigned long pixmap_mask; | |
956 | |
957 if (!override_gc) | |
958 { | |
959 memset (&gcv, ~0, sizeof (gcv)); | |
960 gcv.graphics_exposures = FALSE; | |
961 gcv.foreground = *fg; | |
962 gcv.background = *bg; | |
963 pixmap_mask = GDK_GC_FOREGROUND | GDK_GC_BACKGROUND | GDK_GC_EXPOSURES; | |
964 | |
965 if (IMAGE_INSTANCE_GTK_MASK (p)) | |
966 { | |
967 gcv.function = GDK_COPY; | |
968 gcv.clip_mask = IMAGE_INSTANCE_GTK_MASK (p); | |
969 gcv.clip_x_origin = x - xoffset; | |
970 gcv.clip_y_origin = y - yoffset; | |
971 pixmap_mask |= (GDK_GC_FUNCTION | GDK_GC_CLIP_MASK | GDK_GC_CLIP_X_ORIGIN | | |
972 GDK_GC_CLIP_Y_ORIGIN); | |
973 /* Can't set a clip rectangle below because we already have a mask. | |
974 We could conceivably create a new clipmask by zeroing out | |
975 everything outside the clip region. Is it worth it? | |
976 Is it possible to get an equivalent effect by changing the | |
977 args to XCopyArea below rather than messing with a clip box? | |
978 - dkindred@cs.cmu.edu | |
979 Yes. We don't clip at all now - andy@xemacs.org | |
980 */ | |
981 } | |
982 | |
983 gc = gc_cache_lookup (DEVICE_GTK_GC_CACHE (d), &gcv, pixmap_mask); | |
984 } | |
985 else | |
986 { | |
987 gc = override_gc; | |
988 /* override_gc might have a mask already--we don't want to nuke it. | |
989 Maybe we can insist that override_gc have no mask, or use | |
990 one of the suggestions above. */ | |
991 } | |
992 | |
993 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0) | |
994 { | |
995 gdk_draw_pixmap (GDK_DRAWABLE (x_win), gc, | |
996 IMAGE_INSTANCE_GTK_PIXMAP (p), | |
997 xoffset, yoffset, x, y, width, height); | |
998 } | |
999 else | |
1000 { | |
1001 our_draw_bitmap (GDK_DRAWABLE (x_win), gc, | |
1002 IMAGE_INSTANCE_GTK_PIXMAP (p), | |
1003 xoffset, yoffset, x, y, width, height); | |
1004 } | |
1005 } | |
1006 | |
1007 static void | |
1008 gtk_output_pixmap (struct window *w, | |
1009 Lisp_Object image_instance, | |
1010 struct display_box *db, | |
1011 struct display_glyph_area *dga, | |
1012 face_index findex, | |
1013 int cursor_start, | |
1014 int cursor_width, | |
1015 int cursor_height, | |
1016 int UNUSED (bg_pixmap)) | |
1017 { | |
1018 struct frame *f = XFRAME (w->frame); | |
1019 struct device *d = XDEVICE (f->device); | |
1020 struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance); | |
1021 Lisp_Object window; | |
1022 | |
1023 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
1024 | |
1025 window = wrap_window (w); | |
1026 | |
1027 /* Output the pixmap. */ | |
1028 { | |
1029 Lisp_Object tmp_pixel; | |
1030 GdkColor *tmp_bcolor, *tmp_fcolor; | |
1031 | |
1032 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex); | |
1033 tmp_fcolor = COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (tmp_pixel)); | |
1034 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex); | |
1035 tmp_bcolor = COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (tmp_pixel)); | |
1036 | |
1037 gtk_output_gdk_pixmap (f, p, db->xpos, db->ypos, | |
1038 dga->xoffset, dga->yoffset, | |
1039 dga->width, dga->height, | |
1040 tmp_fcolor, tmp_bcolor, NULL); | |
1041 } | |
1042 | |
1043 /* Draw a cursor over top of the pixmap. */ | |
1044 if (cursor_width && cursor_height && (cursor_start >= db->xpos) | |
1045 && !NILP (w->text_cursor_visible_p) | |
1046 && (cursor_start < (db->xpos + dga->width))) | |
1047 { | |
1048 GdkGC *gc; | |
1049 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d)); | |
1050 struct face_cachel *cursor_cachel = | |
1051 WINDOW_FACE_CACHEL (w, | |
1052 get_builtin_face_cache_index | |
1053 (w, Vtext_cursor_face)); | |
1054 | |
1055 gc = gtk_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil); | |
1056 | |
1057 if (cursor_width > db->xpos + dga->width - cursor_start) | |
1058 cursor_width = db->xpos + dga->width - cursor_start; | |
1059 | |
1060 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, focus ? TRUE : FALSE, | |
1061 cursor_start, db->ypos, cursor_width, | |
1062 cursor_height); | |
1063 } | |
1064 } | |
1065 | |
1066 /***************************************************************************** | |
1067 gtk_output_vertical_divider | |
1068 | |
1069 Draw a vertical divider down the right side of the given window. | |
1070 ****************************************************************************/ | |
1071 static void | |
1072 gtk_output_vertical_divider (struct window *w, int UNUSED(clear)) | |
1073 { | |
1074 struct frame *f = XFRAME (w->frame); | |
1075 struct device *d = XDEVICE (f->device); | |
1076 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
1077 GdkGC *background_gc; | |
1078 Lisp_Object tmp_pixel; | |
1079 GdkGCValues gcv; | |
1080 unsigned long mask; | |
1081 int x, y1, y2, width, shadow_thickness, spacing, line_width; | |
1082 face_index div_face = get_builtin_face_cache_index (w, Vvertical_divider_face); | |
1083 | |
1084 width = window_divider_width (w); | |
1085 shadow_thickness = XINT (w->vertical_divider_shadow_thickness); | |
1086 spacing = XINT (w->vertical_divider_spacing); | |
1087 line_width = XINT (w->vertical_divider_line_width); | |
1088 x = WINDOW_RIGHT (w) - width; | |
1089 y1 = WINDOW_TOP (w); | |
1090 y2 = WINDOW_BOTTOM (w); | |
1091 | |
1092 memset (&gcv, ~0, sizeof (gcv)); | |
1093 | |
1094 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face); | |
1095 | |
1096 gcv.background = * COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (tmp_pixel)); | |
1097 gcv.foreground = gcv.background; | |
1098 gcv.graphics_exposures = FALSE; | |
1099 mask = GDK_GC_FOREGROUND | GDK_GC_BACKGROUND | GDK_GC_EXPOSURES; | |
1100 | |
1101 background_gc = gc_cache_lookup (DEVICE_GTK_GC_CACHE (d), &gcv, mask); | |
1102 | |
1103 /* Clear the divider area first. This needs to be done when a | |
1104 window split occurs. */ | |
1105 /* if (clear) */ | |
1106 gdk_draw_rectangle (GDK_DRAWABLE (x_win), background_gc, TRUE, | |
1107 x, y1, width, y2 - y1); | |
1108 | |
1109 #if 0 | |
1110 /* Draw the divider line. */ | |
1111 gdk_draw_rectangle (GDK_DRAWABLE (x_win), background_gc, TRUE, | |
1112 x + spacing + shadow_thickness, y1, | |
1113 line_width, y2 - y1); | |
1114 #endif | |
1115 | |
1116 /* Draw the shadows around the divider line */ | |
1117 gtk_output_shadows (f, x + spacing, y1, | |
1118 width - 2 * spacing, y2 - y1, | |
1119 shadow_thickness); | |
1120 } | |
1121 | |
1122 /***************************************************************************** | |
1123 gtk_output_blank | |
1124 | |
1125 Output a blank by clearing the area it covers in the foreground color | |
1126 of its face. | |
1127 ****************************************************************************/ | |
1128 static void | |
1129 gtk_output_blank (struct window *w, struct display_line *dl, struct rune *rb, | |
1130 int start_pixpos, int cursor_start, int cursor_width) | |
1131 { | |
1132 struct frame *f = XFRAME (w->frame); | |
1133 struct device *d = XDEVICE (f->device); | |
1134 | |
1135 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
1136 GdkGC *gc; | |
1137 struct face_cachel *cursor_cachel = | |
1138 WINDOW_FACE_CACHEL (w, | |
1139 get_builtin_face_cache_index | |
1140 (w, Vtext_cursor_face)); | |
1141 Lisp_Object bg_pmap; | |
1142 Lisp_Object buffer = WINDOW_BUFFER (w); | |
1143 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor, | |
1144 buffer); | |
1145 | |
1146 int x = rb->xpos; | |
1147 int y = dl->ypos - dl->ascent; | |
1148 int width = rb->width; | |
1149 int height = dl->ascent + dl->descent - dl->clip; | |
1150 | |
1151 if (start_pixpos > x) | |
1152 { | |
1153 if (start_pixpos >= (x + width)) | |
1154 return; | |
1155 else | |
1156 { | |
1157 width -= (start_pixpos - x); | |
1158 x = start_pixpos; | |
1159 } | |
1160 } | |
1161 | |
1162 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex); | |
1163 if (!IMAGE_INSTANCEP (bg_pmap) | |
1164 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap))) | |
1165 bg_pmap = Qnil; | |
1166 | |
1167 if (NILP (bg_pmap)) | |
1168 gc = gtk_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), | |
1169 Qnil, Qnil, Qnil); | |
1170 else | |
1171 gc = gtk_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex), | |
1172 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap, | |
1173 Qnil); | |
1174 | |
1175 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE, x, y, width, height); | |
1176 | |
1177 /* If this rune is marked as having the cursor, then it is actually | |
1178 representing a tab. */ | |
1179 if (!NILP (w->text_cursor_visible_p) | |
1180 && (rb->cursor_type == CURSOR_ON | |
1181 || (cursor_width | |
1182 && (cursor_start + cursor_width > x) | |
1183 && cursor_start < (x + width)))) | |
1184 { | |
1185 int cursor_height, cursor_y; | |
1186 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d)); | |
1187 struct Lisp_Font_Instance *fi; | |
1188 | |
1189 fi = XFONT_INSTANCE (FACE_CACHEL_FONT | |
1190 (WINDOW_FACE_CACHEL (w, rb->findex), | |
1191 Vcharset_ascii)); | |
1192 | |
1193 gc = gtk_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil); | |
1194 | |
1195 cursor_y = dl->ypos - fi->ascent; | |
1196 cursor_height = fi->height; | |
1197 if (cursor_y + cursor_height > y + height) | |
1198 cursor_height = y + height - cursor_y; | |
1199 | |
1200 if (focus) | |
1201 { | |
1202 if (NILP (bar_cursor_value)) | |
1203 { | |
1204 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE, | |
1205 cursor_start, cursor_y, | |
1206 fi->width, cursor_height); | |
1207 } | |
1208 else | |
1209 { | |
1210 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2; | |
1211 | |
1212 gc = gtk_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, | |
1213 make_int (bar_width)); | |
1214 gdk_draw_line (GDK_DRAWABLE (x_win), gc, cursor_start + bar_width - 1, | |
1215 cursor_y, cursor_start + bar_width - 1, | |
1216 cursor_y + cursor_height - 1); | |
1217 } | |
1218 } | |
1219 else if (NILP (bar_cursor_value)) | |
1220 { | |
1221 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, FALSE, | |
1222 cursor_start, cursor_y, | |
1223 fi->width - 1, cursor_height - 1); | |
1224 } | |
1225 } | |
1226 } | |
1227 | |
1228 /***************************************************************************** | |
1229 gtk_output_horizontal_line | |
1230 | |
1231 Output a horizontal line in the foreground of its face. | |
1232 ****************************************************************************/ | |
1233 static void | |
1234 gtk_output_horizontal_line (struct window *w, | |
1235 struct display_line *dl, | |
1236 struct rune *rb) | |
1237 { | |
1238 struct frame *f = XFRAME (w->frame); | |
1239 struct device *d = XDEVICE (f->device); | |
1240 GtkStyle *style = FRAME_GTK_TEXT_WIDGET (f)->style; | |
1241 | |
1242 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
1243 GdkGC *gc; | |
1244 | |
1245 int x = rb->xpos; | |
1246 int width = rb->width; | |
1247 int height = dl->ascent + dl->descent - dl->clip; | |
1248 | |
1249 int ypos1, ypos2, ypos3, ypos4; | |
1250 | |
1251 ypos1 = dl->ypos - dl->ascent; | |
1252 ypos2 = ypos1 + rb->object.hline.yoffset; | |
1253 ypos3 = ypos2 + rb->object.hline.thickness; | |
1254 ypos4 = dl->ypos + dl->descent - dl->clip; | |
1255 | |
1256 /* First clear the area not covered by the line. */ | |
1257 if (height - rb->object.hline.thickness > 0) | |
1258 { | |
1259 gc = gtk_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex), | |
1260 Qnil, Qnil, Qnil); | |
1261 | |
1262 if (ypos2 - ypos1 > 0) | |
1263 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE, x, ypos1, width, ypos2 - ypos1); | |
1264 if (ypos4 - ypos3 > 0) | |
1265 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE, x, ypos1, width, ypos2 - ypos1); | |
1266 } | |
1267 | |
1268 gtk_paint_hline (style, x_win, GTK_STATE_NORMAL, NULL, FRAME_GTK_TEXT_WIDGET (f), | |
1269 "hline", x, x + width, ypos2); | |
1270 #if 0 | |
1271 /* Now draw the line. */ | |
1272 gc = gtk_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), | |
1273 Qnil, Qnil, Qnil); | |
1274 | |
1275 if (ypos2 < ypos1) | |
1276 ypos2 = ypos1; | |
1277 if (ypos3 > ypos4) | |
1278 ypos3 = ypos4; | |
1279 | |
1280 if (ypos3 - ypos2 > 0) | |
1281 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE, x, ypos2, width, ypos3 - ypos2); | |
1282 #endif | |
1283 } | 46 } |
1284 | 47 |
1285 /***************************************************************************** | 48 /***************************************************************************** |
1286 gtk_output_shadows | 49 gtk_output_shadows |
1287 | 50 |
1310 gtk_paint_shadow (style, x_win, GTK_STATE_NORMAL, stype, NULL, | 73 gtk_paint_shadow (style, x_win, GTK_STATE_NORMAL, stype, NULL, |
1311 FRAME_GTK_TEXT_WIDGET (f), "modeline", | 74 FRAME_GTK_TEXT_WIDGET (f), "modeline", |
1312 x, y, width, height); | 75 x, y, width, height); |
1313 } | 76 } |
1314 | 77 |
1315 /***************************************************************************** | |
1316 gtk_clear_to_window_end | |
1317 | |
1318 Clear the area between ypos1 and ypos2. Each margin area and the | |
1319 text area is handled separately since they may each have their own | |
1320 background color. | |
1321 ****************************************************************************/ | |
1322 static void | |
1323 gtk_clear_to_window_end (struct window *w, int ypos1, int ypos2) | |
1324 { | |
1325 int height = ypos2 - ypos1; | |
1326 | |
1327 if (height) | |
1328 { | |
1329 struct frame *f = XFRAME (w->frame); | |
1330 Lisp_Object window; | |
1331 int bflag = (window_needs_vertical_divider (w) ? 0 : 1); | |
1332 layout_bounds bounds; | |
1333 | |
1334 bounds = calculate_display_line_boundaries (w, bflag); | |
1335 window = wrap_window (w); | |
1336 | |
1337 if (window_is_leftmost (w)) | |
1338 redisplay_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f), | |
1339 ypos1, FRAME_BORDER_WIDTH (f), height); | |
1340 | |
1341 if (bounds.left_in - bounds.left_out > 0) | |
1342 redisplay_clear_region (window, | |
1343 get_builtin_face_cache_index (w, Vleft_margin_face), | |
1344 bounds.left_out, ypos1, | |
1345 bounds.left_in - bounds.left_out, height); | |
1346 | |
1347 if (bounds.right_in - bounds.left_in > 0) | |
1348 redisplay_clear_region (window, DEFAULT_INDEX, bounds.left_in, ypos1, | |
1349 bounds.right_in - bounds.left_in, height); | |
1350 | |
1351 if (bounds.right_out - bounds.right_in > 0) | |
1352 redisplay_clear_region (window, | |
1353 get_builtin_face_cache_index (w, Vright_margin_face), | |
1354 bounds.right_in, ypos1, | |
1355 bounds.right_out - bounds.right_in, height); | |
1356 | |
1357 if (window_is_rightmost (w)) | |
1358 redisplay_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f), | |
1359 ypos1, FRAME_BORDER_WIDTH (f), height); | |
1360 } | |
1361 } | |
1362 | |
1363 /**************************************************************************** | |
1364 gtk_clear_region | |
1365 | |
1366 Clear the area in the box defined by the given parameters using the | |
1367 given face. | |
1368 ****************************************************************************/ | |
1369 static void | |
1370 gtk_clear_region (Lisp_Object UNUSED (locale), struct device* d, | |
1371 struct frame* f, face_index UNUSED (findex), int x, int y, | |
1372 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor, | |
1373 Lisp_Object background_pixmap) | |
1374 { | |
1375 GdkWindow *x_win; | |
1376 GdkGC *gc = NULL; | |
1377 | |
1378 x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
1379 | |
1380 if (!UNBOUNDP (background_pixmap)) | |
1381 { | |
1382 gc = gtk_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil); | |
1383 } | |
1384 | |
1385 if (gc) | |
1386 { | |
1387 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc,TRUE, | |
1388 x, y, width, height); | |
1389 } | |
1390 else | |
1391 { | |
1392 gdk_window_clear_area (x_win, x, y, width, height); | |
1393 } | |
1394 } | |
1395 | |
1396 /***************************************************************************** | |
1397 gtk_output_eol_cursor | |
1398 | |
1399 Draw a cursor at the end of a line. The end-of-line cursor is | |
1400 narrower than the normal cursor. | |
1401 ****************************************************************************/ | |
1402 static void | |
1403 gtk_output_eol_cursor (struct window *w, struct display_line *dl, int xpos, | |
1404 face_index findex) | |
1405 { | |
1406 struct frame *f = XFRAME (w->frame); | |
1407 struct device *d = XDEVICE (f->device); | |
1408 Lisp_Object window; | |
1409 | |
1410 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
1411 GdkGC *gc; | |
1412 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face); | |
1413 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt); | |
1414 | |
1415 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d)); | |
1416 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor, | |
1417 WINDOW_BUFFER (w)); | |
1418 | |
1419 int x = xpos; | |
1420 int y = dl->ypos - dl->ascent; | |
1421 int width = EOL_CURSOR_WIDTH; | |
1422 int height = dl->ascent + dl->descent - dl->clip; | |
1423 int cursor_height, cursor_y; | |
1424 int defheight, defascent; | |
1425 | |
1426 window = wrap_window (w); | |
1427 redisplay_clear_region (window, findex, x, y, width, height); | |
1428 | |
1429 if (NILP (w->text_cursor_visible_p)) | |
1430 return; | |
1431 | |
1432 gc = gtk_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil); | |
1433 | |
1434 default_face_font_info (window, &defascent, 0, &defheight, 0, 0); | |
1435 | |
1436 /* make sure the cursor is entirely contained between y and y+height */ | |
1437 cursor_height = min (defheight, height); | |
1438 cursor_y = max (y, min (y + height - cursor_height, | |
1439 dl->ypos - defascent)); | |
1440 | |
1441 if (focus) | |
1442 { | |
1443 if (NILP (bar_cursor_value)) | |
1444 { | |
1445 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, TRUE, x, cursor_y, width, cursor_height); | |
1446 } | |
1447 else | |
1448 { | |
1449 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2; | |
1450 | |
1451 gc = gtk_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, | |
1452 make_int (bar_width)); | |
1453 gdk_draw_line (GDK_DRAWABLE (x_win), gc, x + bar_width - 1, cursor_y, | |
1454 x + bar_width - 1, cursor_y + cursor_height - 1); | |
1455 } | |
1456 } | |
1457 else if (NILP (bar_cursor_value)) | |
1458 { | |
1459 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, FALSE, x, cursor_y, width - 1, | |
1460 cursor_height - 1); | |
1461 } | |
1462 } | |
1463 | |
1464 static void | |
1465 gtk_clear_frame_window (Lisp_Object window) | |
1466 { | |
1467 struct window *w = XWINDOW (window); | |
1468 | |
1469 if (!NILP (w->vchild)) | |
1470 { | |
1471 gtk_clear_frame_windows (w->vchild); | |
1472 return; | |
1473 } | |
1474 | |
1475 if (!NILP (w->hchild)) | |
1476 { | |
1477 gtk_clear_frame_windows (w->hchild); | |
1478 return; | |
1479 } | |
1480 | |
1481 gtk_clear_to_window_end (w, WINDOW_TEXT_TOP (w), WINDOW_TEXT_BOTTOM (w)); | |
1482 } | |
1483 | |
1484 static void | |
1485 gtk_clear_frame_windows (Lisp_Object window) | |
1486 { | |
1487 for (; !NILP (window); window = XWINDOW (window)->next) | |
1488 gtk_clear_frame_window (window); | |
1489 } | |
1490 | |
1491 static void | |
1492 gtk_clear_frame (struct frame *f) | |
1493 { | |
1494 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
1495 int x, y, width, height; | |
1496 Lisp_Object frame; | |
1497 | |
1498 x = FRAME_LEFT_BORDER_START (f); | |
1499 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) - | |
1500 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) - | |
1501 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) - | |
1502 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f)); | |
1503 /* #### This adjustment by 1 should be being done in the macros. | |
1504 There is some small differences between when the menubar is on | |
1505 and off that we still need to deal with. */ | |
1506 y = FRAME_TOP_BORDER_START (f) - 1; | |
1507 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) - | |
1508 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) - | |
1509 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) - | |
1510 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1; | |
1511 | |
1512 gdk_window_clear_area (x_win, x, y, width, height); | |
1513 | |
1514 frame = wrap_frame (f); | |
1515 | |
1516 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame)) | |
1517 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame)) | |
1518 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame))) | |
1519 { | |
1520 gtk_clear_frame_windows (f->root_window); | |
1521 } | |
1522 } | |
1523 | |
1524 static int | |
1525 gtk_flash (struct device *d) | |
1526 { | |
1527 GdkGCValues gcv; | |
1528 GdkGC *gc; | |
1529 GdkColor tmp_fcolor, tmp_bcolor; | |
1530 Lisp_Object tmp_pixel, frame; | |
1531 struct frame *f = device_selected_frame (d); | |
1532 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f)); | |
1533 | |
1534 frame = wrap_frame (f); | |
1535 | |
1536 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame); | |
1537 tmp_fcolor = * (COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (tmp_pixel))); | |
1538 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame); | |
1539 tmp_bcolor = * (COLOR_INSTANCE_GTK_COLOR (XCOLOR_INSTANCE (tmp_pixel))); | |
1540 | |
1541 memset (&gcv, ~0, sizeof (gcv)); /* initialize all slots to ~0 */ | |
1542 gcv.foreground.pixel = (tmp_fcolor.pixel ^ tmp_bcolor.pixel); | |
1543 gcv.function = GDK_XOR; | |
1544 gcv.graphics_exposures = FALSE; | |
1545 gc = gc_cache_lookup (DEVICE_GTK_GC_CACHE (XDEVICE (f->device)), &gcv, | |
1546 GDK_GC_FOREGROUND | GDK_GC_FUNCTION | GDK_GC_EXPOSURES); | |
1547 | |
1548 gdk_draw_rectangle (GDK_DRAWABLE (GET_GTK_WIDGET_WINDOW (FRAME_GTK_SHELL_WIDGET (f))), | |
1549 gc, TRUE, w->pixel_left, w->pixel_top, | |
1550 w->pixel_width, w->pixel_height); | |
1551 | |
1552 gdk_flush (); | |
1553 | |
1554 #ifdef HAVE_SELECT | |
1555 { | |
1556 int usecs = 100000; | |
1557 struct timeval tv; | |
1558 tv.tv_sec = usecs / 1000000L; | |
1559 tv.tv_usec = usecs % 1000000L; | |
1560 /* I'm sure someone is going to complain about this... */ | |
1561 select (0, 0, 0, 0, &tv); | |
1562 } | |
1563 #else | |
1564 #ifdef HAVE_POLL | |
1565 poll (0, 0, 100); | |
1566 #else | |
1567 bite me | |
1568 #endif | |
1569 #endif | |
1570 | |
1571 gdk_draw_rectangle (GDK_DRAWABLE (GET_GTK_WIDGET_WINDOW (FRAME_GTK_SHELL_WIDGET (f))), | |
1572 gc, TRUE, w->pixel_left, w->pixel_top, | |
1573 w->pixel_width, w->pixel_height); | |
1574 | |
1575 gdk_flush (); | |
1576 | |
1577 return 1; | |
1578 } | |
1579 | |
1580 static void | 78 static void |
1581 gtk_bevel_area (struct window *w, face_index UNUSED (findex), | 79 gtk_bevel_area (struct window *w, face_index UNUSED (findex), |
1582 int x, int y, int width, int height, | 80 int x, int y, int width, int height, |
1583 int shadow_thickness, int UNUSED (edges), | 81 int shadow_thickness, int UNUSED (edges), |
1584 enum edge_style UNUSED (style)) | 82 enum edge_style UNUSED (style)) |
1601 gdk_beep (); | 99 gdk_beep (); |
1602 } | 100 } |
1603 } | 101 } |
1604 | 102 |
1605 | 103 |
1606 /************************************************************************/ | |
1607 /* initialization */ | |
1608 /************************************************************************/ | |
1609 | |
1610 void | |
1611 console_type_create_redisplay_gtk (void) | |
1612 { | |
1613 /* redisplay methods */ | |
1614 CONSOLE_HAS_METHOD (gtk, text_width); | |
1615 CONSOLE_HAS_METHOD (gtk, output_display_block); | |
1616 CONSOLE_HAS_METHOD (gtk, divider_height); | |
1617 CONSOLE_HAS_METHOD (gtk, eol_cursor_width); | |
1618 CONSOLE_HAS_METHOD (gtk, output_vertical_divider); | |
1619 CONSOLE_HAS_METHOD (gtk, clear_to_window_end); | |
1620 CONSOLE_HAS_METHOD (gtk, clear_region); | |
1621 CONSOLE_HAS_METHOD (gtk, clear_frame); | |
1622 CONSOLE_HAS_METHOD (gtk, flash); | |
1623 CONSOLE_HAS_METHOD (gtk, ring_bell); | |
1624 CONSOLE_HAS_METHOD (gtk, bevel_area); | |
1625 CONSOLE_HAS_METHOD (gtk, output_string); | |
1626 CONSOLE_HAS_METHOD (gtk, output_pixmap); | |
1627 } | |
1628 | |
1629 /* This makes me feel incredibly dirty... but there is no other way to | 104 /* This makes me feel incredibly dirty... but there is no other way to |
1630 get this done right other than calling clear_area before every | 105 get this done right other than calling clear_area before every |
1631 single $#!%@ing piece of text, which I do NOT want to do. */ | 106 single $#!%@ing piece of text, which I do NOT want to do. */ |
1632 #define USE_X_SPECIFIC_DRAW_ROUTINES 1 | 107 #define USE_X_SPECIFIC_DRAW_ROUTINES 1 |
1633 | 108 |