Mercurial > hg > xemacs-beta
annotate src/redisplay-gtk.c @ 4881:a4322ac49e37
break out common separate-into-runs routines into redisplay-xlike-inc.c
-------------------- ChangeLog entries follow: --------------------
src/ChangeLog addition:
2010-01-18 Ben Wing <ben@xemacs.org>
* redisplay-xlike-inc.c:
* redisplay-xlike-inc.c (separate_textual_runs_nomule):
* redisplay-xlike-inc.c (separate_textual_runs_xft_nomule):
* redisplay-xlike-inc.c (separate_textual_runs_xft_mule):
* redisplay-xlike-inc.c (separate_textual_runs_mule):
Break separate_textual_runs_* functions from redisplay-x.c.
(Code in redisplay-gtk.c should have been identical but was
bit-rotted.)
* redisplay-gtk.c:
* redisplay-x.c:
Delete code, replace with include statement.
* depend: Regenerate.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Mon, 18 Jan 2010 06:21:05 -0600 |
parents | 2b84dd8eb906 |
children | eab9498ecc0e |
rev | line source |
---|---|
714 | 1 /* GTK output and frame manipulation routines. |
462 | 2 Copyright (C) 1994, 1995 Board of Trustees, University of Illinois. |
3 Copyright (C) 1994 Lucid, Inc. | |
4 Copyright (C) 1995 Sun Microsystems, Inc. | |
1318 | 5 Copyright (C) 2002, 2003 Ben Wing. |
462 | 6 |
7 This file is part of XEmacs. | |
8 | |
9 XEmacs is free software; you can redistribute it and/or modify it | |
10 under the terms of the GNU General Public License as published by the | |
11 Free Software Foundation; either version 2, or (at your option) any | |
12 later version. | |
13 | |
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 for more details. | |
18 | |
19 You should have received a copy of the GNU General Public License | |
20 along with XEmacs; see the file COPYING. If not, write to | |
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
22 Boston, MA 02111-1307, USA. */ | |
23 | |
24 /* Synched up with: Not in FSF. */ | |
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" | |
872 | 36 #include "device-impl.h" |
462 | 37 #include "faces.h" |
872 | 38 #include "file-coding.h" |
39 #include "frame-impl.h" | |
462 | 40 #include "gutter.h" |
41 #include "redisplay.h" | |
42 #include "sysdep.h" | |
43 #include "window.h" | |
872 | 44 |
45 #include "console-gtk-impl.h" | |
46 #include "gccache-gtk.h" | |
47 #include "glyphs-gtk.h" | |
48 #include "objects-gtk-impl.h" | |
462 | 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 | |
714 | 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); | |
462 | 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); | |
714 | 73 static void gtk_output_horizontal_line (struct window *w, |
74 struct display_line *dl, | |
75 struct rune *rb); | |
462 | 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 | |
4881
a4322ac49e37
break out common separate-into-runs routines into redisplay-xlike-inc.c
Ben Wing <ben@xemacs.org>
parents:
3479
diff
changeset
|
90 #include "redisplay-xlike-inc.c" |
462 | 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 | |
2286 | 132 gtk_text_width (struct frame *UNUSED (f), struct face_cachel *cachel, |
133 CONST Ichar *str, Charcount len) | |
462 | 134 { |
2367 | 135 /* !!#### */ |
462 | 136 int width_so_far = 0; |
851 | 137 unsigned char *text_storage = (unsigned char *) ALLOCA (2 * len); |
462 | 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); | |
3479 | 189 Ichar_dynarr *buf; |
462 | 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 | |
793 | 202 window = wrap_window (w); |
462 | 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) | |
867 | 216 charset = ichar_charset (rb->object.chr.ch); |
462 | 217 } |
218 | |
219 if (end < 0) | |
220 end = Dynarr_length (rba); | |
3479 | 221 buf = Dynarr_new (Ichar); |
462 | 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 | |
867 | 229 && EQ (charset, ichar_charset (rb->object.chr.ch))) |
462 | 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; | |
867 | 252 charset = ichar_charset (rb->object.chr.ch); |
462 | 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; | |
714 | 298 gtk_output_horizontal_line (w, dl, rb); |
462 | 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, | |
819 | 316 rb->object.dglyph.yoffset ,start_pixpos, |
317 rb->width, &dbox, &dga); | |
462 | 318 |
793 | 319 window = wrap_window (w); |
462 | 320 instance = glyph_image_instance (rb->object.dglyph.glyph, |
793 | 321 window, ERROR_ME_DEBUG_WARN, 1); |
462 | 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); | |
867 | 333 convert_ibyte_string_into_ichar_dynarr |
462 | 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: | |
714 | 348 redisplay_output_pixmap (w, instance, &dbox, &dga, |
349 findex,cursor_start, | |
350 cursor_width, cursor_height, 0); | |
462 | 351 break; |
352 | |
353 case IMAGE_POINTER: | |
2500 | 354 ABORT (); |
462 | 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: | |
2500 | 378 ABORT (); |
462 | 379 } |
380 | |
381 xpos += rb->width; | |
382 elt++; | |
383 } | |
384 else | |
2500 | 385 ABORT (); |
462 | 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 | |
405 /***************************************************************************** | |
406 gtk_bevel_modeline | |
407 | |
408 Draw a 3d border around the modeline on window W. | |
409 ****************************************************************************/ | |
410 static void | |
411 gtk_bevel_modeline (struct window *w, struct display_line *dl) | |
412 { | |
413 struct frame *f = XFRAME (w->frame); | |
414 int shadow_thickness = MODELINE_SHADOW_THICKNESS (w); | |
415 int x,y, width, height; | |
416 | |
417 x = WINDOW_MODELINE_LEFT (w); | |
418 width = WINDOW_MODELINE_RIGHT (w) - x; | |
419 y = dl->ypos - dl->ascent - shadow_thickness; | |
420 height = dl->ascent + dl->descent + 2 * shadow_thickness; | |
421 | |
422 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 | |
2054 | 505 return gc_cache_lookup (DEVICE_GTK_GC_CACHE (d), &gcv, (GdkGCValuesMask) mask); |
462 | 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. | |
867 | 521 BUF Dynamic array of Ichars specifying what is actually to be |
462 | 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 ****************************************************************************/ | |
714 | 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); | |
462 | 549 |
550 void | |
551 gtk_output_string (struct window *w, struct display_line *dl, | |
867 | 552 Ichar_dynarr *buf, int xpos, int xoffset, int clip_start, |
462 | 553 int width, face_index findex, int cursor, |
554 int cursor_start, int cursor_width, int cursor_height) | |
555 { | |
2367 | 556 /* !!#### Needs review */ |
462 | 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); | |
851 | 578 unsigned char *text_storage = (unsigned char *) ALLOCA (2 * len); |
462 | 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 | |
793 | 584 device = wrap_device (d); |
585 window = wrap_window (w); | |
462 | 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 { | |
2054 | 746 int upos, uthick; |
462 | 747 |
748 /* Cannot get at font properties in Gtk, so we resort to | |
749 guessing */ | |
750 upos = dl->descent / 2; | |
751 uthick = 1; | |
752 | |
778 | 753 if ((dl->ypos + upos) < (dl->ypos + dl->descent - dl->clip)) |
462 | 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) { | |
2054 | 772 gint ascent,descent,upos, uthick; |
462 | 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 | |
714 | 944 static void |
462 | 945 gtk_output_gdk_pixmap (struct frame *f, struct Lisp_Image_Instance *p, int x, |
714 | 946 int y, int xoffset, int yoffset, |
947 int width, int height, | |
462 | 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); | |
714 | 969 gcv.clip_x_origin = x - xoffset; |
970 gcv.clip_y_origin = y - yoffset; | |
462 | 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? | |
714 | 978 - dkindred@cs.cmu.edu |
979 Yes. We don't clip at all now - andy@xemacs.org | |
980 */ | |
462 | 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), | |
714 | 997 xoffset, yoffset, x, y, width, height); |
462 | 998 } |
999 else | |
1000 { | |
1001 our_draw_bitmap (GDK_DRAWABLE (x_win), gc, | |
1002 IMAGE_INSTANCE_GTK_PIXMAP (p), | |
714 | 1003 xoffset, yoffset, x, y, width, height); |
462 | 1004 } |
1005 } | |
1006 | |
1007 static void | |
714 | 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, | |
2286 | 1016 int UNUSED (bg_pixmap)) |
462 | 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 | |
793 | 1025 window = wrap_window (w); |
462 | 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 | |
714 | 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); | |
462 | 1041 } |
1042 | |
1043 /* Draw a cursor over top of the pixmap. */ | |
714 | 1044 if (cursor_width && cursor_height && (cursor_start >= db->xpos) |
462 | 1045 && !NILP (w->text_cursor_visible_p) |
714 | 1046 && (cursor_start < (db->xpos + dga->width))) |
462 | 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 | |
714 | 1057 if (cursor_width > db->xpos + dga->width - cursor_start) |
1058 cursor_width = db->xpos + dga->width - cursor_start; | |
462 | 1059 |
1060 gdk_draw_rectangle (GDK_DRAWABLE (x_win), gc, focus ? TRUE : FALSE, | |
714 | 1061 cursor_start, db->ypos, cursor_width, |
462 | 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 | |
3087 | 1072 gtk_output_vertical_divider (struct window *w, int UNUSED(clear)) |
462 | 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 /***************************************************************************** | |
714 | 1229 gtk_output_horizontal_line |
462 | 1230 |
1231 Output a horizontal line in the foreground of its face. | |
1232 ****************************************************************************/ | |
1233 static void | |
714 | 1234 gtk_output_horizontal_line (struct window *w, |
1235 struct display_line *dl, | |
1236 struct rune *rb) | |
462 | 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 } | |
1284 | |
1285 /***************************************************************************** | |
1286 gtk_output_shadows | |
1287 | |
1288 Draw a shadow around the given area using the standard theme engine routines. | |
1289 ****************************************************************************/ | |
1290 void | |
1291 gtk_output_shadows (struct frame *f, int x, int y, int width, int height, | |
1292 int shadow_thickness) | |
1293 { | |
1294 GdkWindow *x_win = GET_GTK_WIDGET_WINDOW (FRAME_GTK_TEXT_WIDGET (f)); | |
1295 GtkStyle *style = FRAME_GTK_TEXT_WIDGET (f)->style; | |
1296 GtkShadowType stype = GTK_SHADOW_OUT; | |
1297 | |
1298 if (shadow_thickness < 0) | |
1299 { | |
1300 stype = GTK_SHADOW_IN; | |
1301 } | |
1302 else if (shadow_thickness == 0) | |
1303 { | |
1304 stype = GTK_SHADOW_NONE; | |
1305 } | |
1306 | |
1307 /* Do we want to have some magic constants to set | |
1308 GTK_SHADOW_ETCHED_IN or GTK_SHADOW_ETCHED_OUT? */ | |
1309 | |
1310 gtk_paint_shadow (style, x_win, GTK_STATE_NORMAL, stype, NULL, | |
1311 FRAME_GTK_TEXT_WIDGET (f), "modeline", | |
1312 x, y, width, height); | |
1313 } | |
1314 | |
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); | |
793 | 1335 window = wrap_window (w); |
462 | 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 | |
2286 | 1370 gtk_clear_region (Lisp_Object UNUSED (locale), struct device* d, |
1371 struct frame* f, face_index UNUSED (findex), int x, int y, | |
462 | 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 | |
793 | 1426 window = wrap_window (w); |
462 | 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 | |
793 | 1514 frame = wrap_frame (f); |
462 | 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 | |
793 | 1534 frame = wrap_frame (f); |
462 | 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 | |
778 | 1564 #ifdef HAVE_POLL |
1565 poll (0, 0, 100); | |
1566 #else | |
462 | 1567 bite me |
778 | 1568 #endif |
1569 #endif | |
462 | 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 | |
2286 | 1581 gtk_bevel_area (struct window *w, face_index UNUSED (findex), |
462 | 1582 int x, int y, int width, int height, |
2286 | 1583 int shadow_thickness, int UNUSED (edges), |
1584 enum edge_style UNUSED (style)) | |
462 | 1585 { |
1586 struct frame *f = XFRAME (w->frame); | |
1587 | |
1588 gtk_output_shadows (f, x, y, width, height, shadow_thickness); | |
1589 } | |
1590 | |
1591 | |
1592 | |
1593 /* Make audible bell. */ | |
1594 static void | |
2286 | 1595 gtk_ring_bell (struct device *UNUSED (d), int volume, int UNUSED (pitch), |
1596 int UNUSED (duration)) | |
462 | 1597 { |
714 | 1598 /* Gdk does not allow us to control the duration / pitch / volume */ |
1599 if (volume > 0) | |
1600 { | |
1601 gdk_beep (); | |
1602 } | |
462 | 1603 } |
1604 | |
1605 | |
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); | |
714 | 1626 CONSOLE_HAS_METHOD (gtk, output_pixmap); |
462 | 1627 } |
1628 | |
1629 /* 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 | |
1631 single $#!%@ing piece of text, which I do NOT want to do. */ | |
1632 #define USE_X_SPECIFIC_DRAW_ROUTINES 1 | |
1633 | |
1634 #include <gdk/gdkx.h> | |
1635 | |
714 | 1636 static |
1637 void gdk_draw_text_image (GdkDrawable *drawable, | |
1638 GdkFont *font, | |
1639 GdkGC *gc, | |
1640 gint x, | |
1641 gint y, | |
1642 const gchar *text, | |
1643 gint text_length) | |
462 | 1644 { |
1645 #if !USE_X_SPECIFIC_DRAW_ROUTINES | |
1646 int width = gdk_text_measure (font, text, text_length); | |
1647 int height = gdk_text_height (font, text, text_length); | |
1648 | |
1649 gdk_draw_rectangle (drawable, gc, TRUE, x, y, width, height); | |
1650 gdk_draw_text (drawable, font, gc, x, y, text, text_length); | |
1651 #else | |
1652 GdkWindowPrivate *drawable_private; | |
1653 GdkFontPrivate *font_private; | |
1654 GdkGCPrivate *gc_private; | |
1655 | |
1656 g_return_if_fail (drawable != NULL); | |
1657 g_return_if_fail (font != NULL); | |
1658 g_return_if_fail (gc != NULL); | |
1659 g_return_if_fail (text != NULL); | |
1660 | |
1661 drawable_private = (GdkWindowPrivate*) drawable; | |
1662 if (drawable_private->destroyed) | |
1663 return; | |
1664 gc_private = (GdkGCPrivate*) gc; | |
1665 font_private = (GdkFontPrivate*) font; | |
1666 | |
1667 if (font->type == GDK_FONT_FONT) | |
1668 { | |
1669 XFontStruct *xfont = (XFontStruct *) font_private->xfont; | |
1670 XSetFont(drawable_private->xdisplay, gc_private->xgc, xfont->fid); | |
1671 if ((xfont->min_byte1 == 0) && (xfont->max_byte1 == 0)) | |
1672 { | |
1673 XDrawImageString (drawable_private->xdisplay, drawable_private->xwindow, | |
1674 gc_private->xgc, x, y, text, text_length); | |
1675 } | |
1676 else | |
1677 { | |
1678 XDrawImageString16 (drawable_private->xdisplay, drawable_private->xwindow, | |
1679 gc_private->xgc, x, y, (XChar2b *) text, text_length / 2); | |
1680 } | |
1681 } | |
1682 else if (font->type == GDK_FONT_FONTSET) | |
1683 { | |
1684 XFontSet fontset = (XFontSet) font_private->xfont; | |
1685 XmbDrawImageString (drawable_private->xdisplay, drawable_private->xwindow, | |
1686 fontset, gc_private->xgc, x, y, text, text_length); | |
1687 } | |
1688 else | |
1689 g_error("undefined font type\n"); | |
1690 #endif | |
1691 } | |
1692 | |
1693 static void | |
1694 our_draw_bitmap (GdkDrawable *drawable, | |
1695 GdkGC *gc, | |
1696 GdkPixmap *src, | |
1697 gint xsrc, | |
1698 gint ysrc, | |
1699 gint xdest, | |
1700 gint ydest, | |
1701 gint width, | |
1702 gint height) | |
1703 { | |
1704 GdkWindowPrivate *drawable_private; | |
1705 GdkWindowPrivate *src_private; | |
1706 GdkGCPrivate *gc_private; | |
1707 | |
1708 g_return_if_fail (drawable != NULL); | |
1709 g_return_if_fail (src != NULL); | |
1710 g_return_if_fail (gc != NULL); | |
1711 | |
1712 drawable_private = (GdkWindowPrivate*) drawable; | |
1713 src_private = (GdkWindowPrivate*) src; | |
1714 if (drawable_private->destroyed || src_private->destroyed) | |
1715 return; | |
1716 gc_private = (GdkGCPrivate*) gc; | |
1717 | |
1718 if (width == -1) | |
1719 width = src_private->width; | |
1720 if (height == -1) | |
1721 height = src_private->height; | |
1722 | |
1723 XCopyPlane (drawable_private->xdisplay, | |
1724 src_private->xwindow, | |
1725 drawable_private->xwindow, | |
1726 gc_private->xgc, | |
1727 xsrc, ysrc, | |
1728 width, height, | |
1729 xdest, ydest, 1L); | |
1730 } |