(g2-UU+5B73): Add `=decomposition@hanyo-denshi'.
[chise/xemacs-chise.git.1] / src / toolbar-gtk.c
1 /* toolbar implementation -- X interface.
2    Copyright (C) 1995 Board of Trustees, University of Illinois.
3    Copyright (C) 1995 Sun Microsystems, Inc.
4    Copyright (C) 1995, 1996 Ben Wing.
5    Copyright (C) 1996 Chuck Thompson.
6
7 This file is part of XEmacs.
8
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
12 later version.
13
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING.  If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24 /* Synched up with: Not in FSF. */
25
26 #include <config.h>
27 #include "lisp.h"
28
29 #include "console-gtk.h"
30 #include "glyphs-gtk.h"
31 #include "objects-gtk.h"
32 #include "gtk-xemacs.h"
33 #include "gccache-gtk.h"
34
35 #include "faces.h"
36 #include "frame.h"
37 #include "toolbar.h"
38 #include "window.h"
39
40 extern GdkGC *gtk_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
41                           Lisp_Object bg_pmap, Lisp_Object lwidth);
42
43 static GdkGC *get_toolbar_gc (struct frame *f)
44 {
45   Lisp_Object fg, bg;
46   Lisp_Object frame;
47
48   XSETFRAME (frame, f);
49
50   fg = Fspecifier_instance (Fget (Vtoolbar_face, Qforeground, Qnil), frame, Qnil, Qnil);
51   bg = Fspecifier_instance (Fget (Vtoolbar_face, Qbackground, Qnil), frame, Qnil, Qnil);
52                                    
53   /* Need to swap the foreground/background here or most themes look bug ugly */
54   return (gtk_get_gc (XDEVICE (FRAME_DEVICE (f)), Qnil, bg, fg, Qnil, Qnil));
55 }
56
57 static void
58 gtk_draw_blank_toolbar_button (struct frame *f, int x, int y, int width,
59                                int height, int threed, int border_width,
60                                int vertical)
61 {
62   GtkXEmacs *ef = GTK_XEMACS (FRAME_GTK_TEXT_WIDGET (f));
63   int sx = x, sy = y, swidth = width, sheight = height;
64   GdkWindow *x_win = GTK_WIDGET (ef)->window;
65   GdkGC *background_gc = get_toolbar_gc (f);
66
67   if (vertical)
68     {
69       sx += border_width;
70       swidth -= 2 * border_width;
71     }
72   else
73     {
74       sy += border_width;
75       sheight -= 2 * border_width;
76     }
77
78   /* Blank the entire area. */
79   gdk_draw_rectangle (x_win, background_gc, TRUE, sx, sy, swidth, sheight);
80
81   /* Draw the outline. */
82   if (threed)
83     gtk_output_shadows (f, sx, sy, swidth, sheight, 2);
84
85   /* Do the border */
86   gdk_draw_rectangle (x_win, background_gc, TRUE, x, y,
87                       (vertical ? border_width : width),
88                       (vertical ? height : border_width));
89   gdk_draw_rectangle (x_win, background_gc, TRUE,
90                       (vertical ? sx + swidth : x),
91                       (vertical ? y : sy + sheight),
92                       (vertical ? border_width : width),
93                       (vertical ? height : border_width));
94 }
95
96 static void
97 gtk_output_toolbar_button (struct frame *f, Lisp_Object button)
98 {
99   int shadow_thickness = 2;
100   int x_adj, y_adj, width_adj, height_adj;
101   GdkWindow *x_win = FRAME_GTK_TEXT_WIDGET (f)->window;
102   GdkGC *background_gc = get_toolbar_gc (f);
103   Lisp_Object instance, frame, window, glyph;
104   struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
105   struct Lisp_Image_Instance *p;
106   struct window *w;
107   int vertical = tb->vertical;
108   int border_width = tb->border_width;
109
110   if (vertical)
111     {
112       x_adj = border_width;
113       width_adj = - 2 * border_width;
114       y_adj = 0;
115       height_adj = 0;
116     }
117   else
118     {
119       x_adj = 0;
120       width_adj = 0;
121       y_adj = border_width;
122       height_adj = - 2 * border_width;
123     }
124
125   XSETFRAME (frame, f);
126   window = FRAME_LAST_NONMINIBUF_WINDOW (f);
127   w = XWINDOW (window);
128
129   glyph = get_toolbar_button_glyph (w, tb);
130
131   if (tb->enabled)
132     {
133       if (tb->down)
134         {
135           shadow_thickness = -2;
136         }
137       else
138         {
139           shadow_thickness = 2;
140         }
141     }
142   else
143     {
144       shadow_thickness = 0;
145     }
146
147   background_gc = get_toolbar_gc (f);
148
149   /* Clear the entire area. */
150   gdk_draw_rectangle (x_win, background_gc, TRUE,
151                       tb->x + x_adj,
152                       tb->y + y_adj,
153                       tb->width + width_adj,
154                       tb->height + height_adj);
155
156   /* Draw the outline. */
157   if (shadow_thickness)
158     gtk_output_shadows (f, tb->x + x_adj, tb->y + y_adj,
159                         tb->width + width_adj, tb->height + height_adj,
160                         shadow_thickness);
161
162   /* Do the border. */
163   gdk_draw_rectangle (x_win, background_gc, TRUE, tb->x, tb->y,
164                       (vertical ? border_width : tb->width),
165                       (vertical ? tb->height : border_width));
166
167   gdk_draw_rectangle (x_win, background_gc, TRUE,
168                       (vertical ? tb->x + tb->width - border_width : tb->x),
169                       (vertical ? tb->y : tb->y + tb->height - border_width),
170                       (vertical ? border_width : tb->width),
171                       (vertical ? tb->height : border_width));
172
173   background_gc = get_toolbar_gc (f);
174
175   /* #### It is currently possible for users to trash us by directly
176      changing the toolbar glyphs.  Avoid crashing in that case. */
177   if (GLYPHP (glyph))
178     instance = glyph_image_instance (glyph, window, ERROR_ME_NOT, 1);
179   else
180     instance = Qnil;
181
182   if (IMAGE_INSTANCEP (instance))
183     {
184       int width = tb->width + width_adj - shadow_thickness * 2;
185       int height = tb->height + height_adj - shadow_thickness * 2;
186       int x_offset = x_adj + shadow_thickness;
187       int y_offset = y_adj + shadow_thickness;
188
189       p = XIMAGE_INSTANCE (instance);
190
191       if (IMAGE_INSTANCE_PIXMAP_TYPE_P (p))
192         {
193           if (width > (int) IMAGE_INSTANCE_PIXMAP_WIDTH (p))
194             {
195               x_offset += ((int) (width - IMAGE_INSTANCE_PIXMAP_WIDTH (p))
196                            / 2);
197               width = IMAGE_INSTANCE_PIXMAP_WIDTH (p);
198             }
199           if (height > (int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p))
200             {
201               y_offset += ((int) (height - IMAGE_INSTANCE_PIXMAP_HEIGHT (p))
202                            / 2);
203               height = IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
204             }
205
206           gtk_output_gdk_pixmap (f, XIMAGE_INSTANCE (instance), tb->x + x_offset,
207                                  tb->y + y_offset, 0, 0, 0, 0, width, height,
208                                  0, 0, 0, background_gc);
209         }
210       else if (IMAGE_INSTANCE_TYPE (p) == IMAGE_TEXT)
211         {
212           /* #### We need to make the face used configurable. */
213           struct face_cachel *cachel =
214             WINDOW_FACE_CACHEL (w, DEFAULT_INDEX);
215           struct display_line dl;
216           Lisp_Object string = IMAGE_INSTANCE_TEXT_STRING (p);
217           unsigned char charsets[NUM_LEADING_BYTES];
218           Emchar_dynarr *buf;
219           struct font_metric_info fm;
220
221           /* This could be true if we were called via the Expose event
222              handler.  Mark the button as dirty and return
223              immediately. */
224           if (f->window_face_cache_reset)
225             {
226               tb->dirty = 1;
227               MARK_TOOLBAR_CHANGED;
228               return;
229             }
230           buf = Dynarr_new (Emchar);
231           convert_bufbyte_string_into_emchar_dynarr
232             (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
233           find_charsets_in_emchar_string (charsets, Dynarr_atp (buf, 0),
234                                           Dynarr_length (buf));
235           ensure_face_cachel_complete (cachel, window, charsets);
236           face_cachel_charset_font_metric_info (cachel, charsets, &fm);
237
238           dl.ascent = fm.ascent;
239           dl.descent = fm.descent;
240           dl.ypos = tb->y + y_offset + fm.ascent;
241
242           if (fm.ascent + fm.descent <= height)
243             {
244               dl.ypos += (height - fm.ascent - fm.descent) / 2;
245               dl.clip = 0;
246             }
247           else
248             {
249               dl.clip = fm.ascent + fm.descent - height;
250             }
251
252           gtk_output_string (w, &dl, buf, tb->x + x_offset, 0, 0, width,
253                              DEFAULT_INDEX, 0, 0, 0, 0);
254           Dynarr_free (buf);
255         }
256
257       /* We silently ignore the image if it isn't a pixmap or text. */
258     }
259
260   tb->dirty = 0;
261 }
262
263 static int
264 gtk_get_button_size (struct frame *f, Lisp_Object window,
265                      struct toolbar_button *tb, int vert, int pos)
266 {
267   int shadow_thickness = 2;
268   int size;
269
270   if (tb->blank)
271     {
272       if (!NILP (tb->down_glyph))
273         size = XINT (tb->down_glyph);
274       else
275         size = DEFAULT_TOOLBAR_BLANK_SIZE;
276     }
277   else
278     {
279       struct window *w = XWINDOW (window);
280       Lisp_Object glyph = get_toolbar_button_glyph (w, tb);
281
282       /* Unless, of course, the user has done something stupid like
283          change the glyph out from under us.  Use a blank placeholder
284          in that case. */
285       if (NILP (glyph))
286         return XINT (f->toolbar_size[pos]);
287
288       if (vert)
289         size = glyph_height (glyph, window);
290       else
291         size = glyph_width (glyph, window);
292     }
293
294   if (!size)
295     {
296       /* If the glyph doesn't have a size we'll insert a blank
297          placeholder instead. */
298       return XINT (f->toolbar_size[pos]);
299     }
300
301   size += shadow_thickness * 2;
302
303   return (size);
304 }
305
306 #define GTK_OUTPUT_BUTTONS_LOOP(left)                                   \
307   do {                                                                  \
308     while (!NILP (button))                                              \
309       {                                                                 \
310         struct toolbar_button *tb = XTOOLBAR_BUTTON (button);           \
311         int size, height, width;                                        \
312                                                                         \
313         if (left && tb->pushright)                                      \
314           break;                                                        \
315                                                                         \
316         size = gtk_get_button_size (f, window, tb, vert, pos);          \
317                                                                         \
318         if (vert)                                                       \
319           {                                                             \
320             width = bar_width;                                          \
321             if (y + size > max_pixpos)                                  \
322               height = max_pixpos - y;                                  \
323             else                                                        \
324               height = size;                                            \
325           }                                                             \
326         else                                                            \
327           {                                                             \
328             if (x + size > max_pixpos)                                  \
329               width = max_pixpos - x;                                   \
330             else                                                        \
331               width = size;                                             \
332             height = bar_height;                                        \
333           }                                                             \
334                                                                         \
335         if (tb->x != x                                                  \
336             || tb->y != y                                               \
337             || tb->width != width                                       \
338             || tb->height != height                                     \
339             || tb->dirty                                                \
340             || f->clear) /* This is clearly necessary. */               \
341           {                                                             \
342             if (width && height)                                        \
343               {                                                         \
344                 tb->x = x;                                              \
345                 tb->y = y;                                              \
346                 tb->width = width;                                      \
347                 tb->height = height;                                    \
348                 tb->border_width = border_width;                        \
349                 tb->vertical = vert;                                    \
350                                                                         \
351                 if (tb->blank || NILP (tb->up_glyph))                   \
352                   {                                                     \
353                     int threed = (EQ (Qt, tb->up_glyph) ? 1 : 0);       \
354                     gtk_draw_blank_toolbar_button (f, x, y, width,      \
355                                                  height, threed,        \
356                                                  border_width, vert);   \
357                   }                                                     \
358                 else                                                    \
359                   gtk_output_toolbar_button (f, button);                \
360               }                                                         \
361           }                                                             \
362                                                                         \
363         if (vert)                                                       \
364           y += height;                                                  \
365         else                                                            \
366           x += width;                                                   \
367                                                                         \
368         if ((vert && y == max_pixpos) || (!vert && x == max_pixpos))    \
369           button = Qnil;                                                \
370         else                                                            \
371           button = tb->next;                                            \
372       }                                                                 \
373   } while (0)
374
375 #define SET_TOOLBAR_WAS_VISIBLE_FLAG(frame, pos, flag)                  \
376   do {                                                                  \
377     switch (pos)                                                        \
378       {                                                                 \
379       case TOP_TOOLBAR:                                                 \
380         (frame)->top_toolbar_was_visible = flag;                        \
381         break;                                                          \
382       case BOTTOM_TOOLBAR:                                              \
383         (frame)->bottom_toolbar_was_visible = flag;                     \
384         break;                                                          \
385       case LEFT_TOOLBAR:                                                \
386         (frame)->left_toolbar_was_visible = flag;                       \
387         break;                                                          \
388       case RIGHT_TOOLBAR:                                               \
389         (frame)->right_toolbar_was_visible = flag;                      \
390         break;                                                          \
391       default:                                                          \
392         ABORT ();                                                       \
393       }                                                                 \
394   } while (0)
395
396 static void
397 gtk_output_toolbar (struct frame *f, enum toolbar_pos pos)
398 {
399   int x, y, bar_width, bar_height, vert;
400   int max_pixpos, right_size, right_start, blank_size;
401   int border_width = FRAME_REAL_TOOLBAR_BORDER_WIDTH (f, pos);
402   Lisp_Object button, window;
403   GdkWindow *x_win = FRAME_GTK_TEXT_WIDGET (f)->window;
404   GdkGC *background_gc = get_toolbar_gc (f);
405
406   get_toolbar_coords (f, pos, &x, &y, &bar_width, &bar_height, &vert, 1);
407   window = FRAME_LAST_NONMINIBUF_WINDOW (f);
408
409   /* Do the border */
410   gdk_draw_rectangle (x_win, background_gc, TRUE, x, y,
411                       (vert ? bar_width : border_width),
412                       (vert ? border_width : bar_height));
413   gdk_draw_rectangle (x_win, background_gc, TRUE,
414                       (vert ? x : x + bar_width - border_width),
415                       (vert ? y + bar_height - border_width : y),
416                       (vert ? bar_width : border_width),
417                       (vert ? border_width : bar_height));
418
419   if (vert)
420     {
421       max_pixpos = y + bar_height - border_width;
422       y += border_width;
423     }
424   else
425     {
426       max_pixpos = x + bar_width - border_width;
427       x += border_width;
428     }
429
430   button = FRAME_TOOLBAR_BUTTONS (f, pos);
431   right_size = 0;
432
433   /* First loop over all of the buttons to determine how much room we
434      need for left hand and right hand buttons.  This loop will also
435      make sure that all instances are instantiated so when we actually
436      output them they will come up immediately. */
437   while (!NILP (button))
438     {
439       struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
440       int size = gtk_get_button_size (f, window, tb, vert, pos);
441
442       if (tb->pushright)
443         right_size += size;
444
445       button = tb->next;
446     }
447
448   button = FRAME_TOOLBAR_BUTTONS (f, pos);
449
450   /* Loop over the left buttons, updating and outputting them. */
451   GTK_OUTPUT_BUTTONS_LOOP (1);
452
453   /* Now determine where the right buttons start. */
454   right_start = max_pixpos - right_size;
455   if (right_start < (vert ? y : x))
456     right_start = (vert ? y : x);
457
458   /* Output the blank which goes from the end of the left buttons to
459      the start of the right. */
460   blank_size = right_start - (vert ? y : x);
461   if (blank_size)
462     {
463       int height, width;
464
465       if (vert)
466         {
467           width = bar_width;
468           height = blank_size;
469         }
470       else
471         {
472           width = blank_size;
473           height = bar_height;
474         }
475
476       /*
477        * Use a 3D pushright separator only if there isn't a toolbar
478        * border.  A flat separator meshes with the border and looks
479        * better.
480        */
481       gtk_draw_blank_toolbar_button (f, x, y, width, height, !border_width,
482                                      border_width, vert);
483
484       if (vert)
485         y += height;
486       else
487         x += width;
488     }
489
490   /* Loop over the right buttons, updating and outputting them. */
491   GTK_OUTPUT_BUTTONS_LOOP (0);
492
493   if (!vert)
494     {
495       Lisp_Object frame;
496
497       XSETFRAME (frame, f);
498       redisplay_clear_region (frame,
499                               DEFAULT_INDEX, FRAME_PIXWIDTH (f) - 1, y, 1,
500                               bar_height);
501     }
502
503   SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 1);
504
505   gdk_flush ();
506 }
507
508 static void
509 gtk_clear_toolbar (struct frame *f, enum toolbar_pos pos, int thickness_change)
510 {
511   Lisp_Object frame;
512   int x, y, width, height, vert;
513
514   get_toolbar_coords (f, pos, &x, &y, &width, &height, &vert, 1);
515   XSETFRAME (frame, f);
516
517   /* The thickness_change parameter is used by the toolbar resize routines
518      to clear any excess toolbar if the size shrinks. */
519   if (thickness_change < 0)
520     {
521       if (pos == LEFT_TOOLBAR || pos == RIGHT_TOOLBAR)
522         {
523           x = x + width + thickness_change;
524           width = -thickness_change;
525         }
526       else
527         {
528           y = y + height + thickness_change;
529           height = -thickness_change;
530         }
531     }
532
533   SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 0);
534
535   redisplay_clear_region (frame, DEFAULT_INDEX, x, y, width, height);
536   gdk_flush ();
537 }
538
539 static void
540 gtk_output_frame_toolbars (struct frame *f)
541 {
542   assert (FRAME_GTK_P (f));
543
544   if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
545     gtk_output_toolbar (f, TOP_TOOLBAR);
546   if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
547     gtk_output_toolbar (f, BOTTOM_TOOLBAR);
548   if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
549     gtk_output_toolbar (f, LEFT_TOOLBAR);
550   if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
551     gtk_output_toolbar (f, RIGHT_TOOLBAR);
552 }
553
554 static void
555 gtk_clear_frame_toolbars (struct frame *f)
556 {
557   assert (FRAME_GTK_P (f));
558
559   if (f->top_toolbar_was_visible
560       && !FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
561     gtk_clear_toolbar (f, TOP_TOOLBAR, 0);
562   if (f->bottom_toolbar_was_visible
563       && !FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
564     gtk_clear_toolbar (f, BOTTOM_TOOLBAR, 0);
565   if (f->left_toolbar_was_visible 
566       && !FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
567     gtk_clear_toolbar (f, LEFT_TOOLBAR, 0);
568   if (f->right_toolbar_was_visible 
569       && !FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
570     gtk_clear_toolbar (f, RIGHT_TOOLBAR, 0);
571 }
572
573 static void
574 gtk_redraw_exposed_toolbar (struct frame *f, enum toolbar_pos pos, int x, int y,
575                             int width, int height)
576 {
577   int bar_x, bar_y, bar_width, bar_height, vert;
578   Lisp_Object button = FRAME_TOOLBAR_BUTTONS (f, pos);
579
580   get_toolbar_coords (f, pos, &bar_x, &bar_y, &bar_width, &bar_height,
581                       &vert, 1);
582
583   if (((y + height) < bar_y) || (y > (bar_y + bar_height)))
584     return;
585   if (((x + width) < bar_x) || (x > (bar_x + bar_width)))
586     return;
587
588   while (!NILP (button))
589     {
590       struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
591
592       if (vert)
593         {
594           if (((tb->y + tb->height) > y) && (tb->y < (y + height)))
595             tb->dirty = 1;
596
597           /* If this is true we have gone past the exposed region. */
598           if (tb->y > (y + height))
599             break;
600         }
601       else
602         {
603           if (((tb->x + tb->width) > x) && (tb->x < (x + width)))
604             tb->dirty = 1;
605
606           /* If this is true we have gone past the exposed region. */
607           if (tb->x > (x + width))
608             break;
609         }
610
611       button = tb->next;
612     }
613
614   /* Even if none of the buttons is in the area, the blank region at
615      the very least must be because the first thing we did is verify
616      that some portion of the toolbar is in the exposed region. */
617   gtk_output_toolbar (f, pos);
618 }
619
620 static void
621 gtk_redraw_exposed_toolbars (struct frame *f, int x, int y, int width,
622                              int height)
623 {
624   assert (FRAME_GTK_P (f));
625
626   if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
627     gtk_redraw_exposed_toolbar (f, TOP_TOOLBAR, x, y, width, height);
628
629   if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
630     gtk_redraw_exposed_toolbar (f, BOTTOM_TOOLBAR, x, y, width, height);
631
632   if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
633     gtk_redraw_exposed_toolbar (f, LEFT_TOOLBAR, x, y, width, height);
634
635   if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
636     gtk_redraw_exposed_toolbar (f, RIGHT_TOOLBAR, x, y, width, height);
637 }
638
639 static void
640 gtk_redraw_frame_toolbars (struct frame *f)
641 {
642   /* There are certain startup paths that lead to update_EmacsFrame in
643      faces.c being called before a new frame is fully initialized.  In
644      particular before we have actually mapped it.  That routine can
645      call this one.  So, we need to make sure that the frame is
646      actually ready before we try and draw all over it. */
647
648   if (GTK_WIDGET_REALIZED (FRAME_GTK_TEXT_WIDGET (f)))
649     gtk_redraw_exposed_toolbars (f, 0, 0, FRAME_PIXWIDTH (f),
650                                  FRAME_PIXHEIGHT (f));
651 }
652
653 \f
654 static void
655 gtk_initialize_frame_toolbars (struct frame *f)
656 {
657 }
658
659 /* This only calls one function but we go ahead and create this in
660    case we ever do decide that we need to do more work. */
661 static void
662 gtk_free_frame_toolbars (struct frame *f)
663 {
664 }
665
666 \f
667 /************************************************************************/
668 /*                            initialization                            */
669 /************************************************************************/
670
671 void
672 console_type_create_toolbar_gtk (void)
673 {
674   CONSOLE_HAS_METHOD (gtk, output_frame_toolbars);
675   CONSOLE_HAS_METHOD (gtk, clear_frame_toolbars);
676   CONSOLE_HAS_METHOD (gtk, initialize_frame_toolbars);
677   CONSOLE_HAS_METHOD (gtk, free_frame_toolbars);
678   CONSOLE_HAS_METHOD (gtk, output_toolbar_button);
679   CONSOLE_HAS_METHOD (gtk, redraw_exposed_toolbars);
680   CONSOLE_HAS_METHOD (gtk, redraw_frame_toolbars);
681 }