comparison src/redisplay-gtk.c @ 462:0784d089fdc9 r21-2-46

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