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