XEmacs 21.4.4 "Artificial Intelligence".
[chise/xemacs-chise.git.1] / src / redisplay-gtk.c
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 \f
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 }