XEmacs 21.2.36 "Notos"
[chise/xemacs-chise.git.1] / src / toolbar-x.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 /* This file Mule-ized (more like Mule-verified) by Ben Wing, 7-8-00. */
27
28 #include <config.h>
29 #include "lisp.h"
30
31 #include "console-x.h"
32 #include "glyphs-x.h"
33 #include "objects-x.h"
34 #include "EmacsFrame.h"
35 #include "EmacsFrameP.h"
36
37 #include "faces.h"
38 #include "frame.h"
39 #include "toolbar.h"
40 #include "window.h"
41
42 static void
43 x_draw_blank_toolbar_button (struct frame *f, int x, int y, int width,
44                              int height, int threed, int border_width,
45                              int vertical)
46 {
47   struct device *d = XDEVICE (f->device);
48   EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
49   int shadow_thickness = ef->emacs_frame.toolbar_shadow_thickness;
50   int sx = x, sy = y, swidth = width, sheight = height;
51
52   Display *dpy = DEVICE_X_DISPLAY (d);
53   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
54   GC top_shadow_gc, bottom_shadow_gc, background_gc;
55
56   background_gc = FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f);
57
58   if (threed)
59     {
60       top_shadow_gc = FRAME_X_TOOLBAR_TOP_SHADOW_GC (f);
61       bottom_shadow_gc = FRAME_X_TOOLBAR_BOTTOM_SHADOW_GC (f);
62     }
63   else
64     {
65       top_shadow_gc = background_gc;
66       bottom_shadow_gc = background_gc;
67     }
68
69   if (vertical)
70     {
71       sx += border_width;
72       swidth -= 2 * border_width;
73     }
74   else
75     {
76       sy += border_width;
77       sheight -= 2 * border_width;
78     }
79
80   /* Draw the outline. */
81   x_output_shadows (f, sx, sy, swidth, sheight, top_shadow_gc,
82                     bottom_shadow_gc, background_gc, shadow_thickness,
83                     EDGE_ALL);
84
85   /* Blank the middle. */
86   XFillRectangle (dpy, x_win, background_gc, sx + shadow_thickness,
87                   sy + shadow_thickness, swidth - shadow_thickness * 2,
88                   sheight - shadow_thickness * 2);
89
90   /* Do the border */
91   XFillRectangle (dpy, x_win, background_gc, x, y,
92                   (vertical ? border_width : width),
93                   (vertical ? height : border_width));
94   XFillRectangle (dpy, x_win, background_gc,
95                   (vertical ? sx + swidth : x),
96                   (vertical ? y : sy + sheight),
97                   (vertical ? border_width : width),
98                   (vertical ? height : border_width));
99 }
100
101 static void
102 x_output_toolbar_button (struct frame *f, Lisp_Object button)
103 {
104   struct device *d = XDEVICE (f->device);
105   EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
106   int shadow_thickness = ef->emacs_frame.toolbar_shadow_thickness;
107   int x_adj, y_adj, width_adj, height_adj;
108
109   Display *dpy = DEVICE_X_DISPLAY (d);
110   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
111   GC top_shadow_gc, bottom_shadow_gc, background_gc;
112   Lisp_Object instance, frame, window, glyph;
113   struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
114   Lisp_Image_Instance *p;
115   struct window *w;
116   int vertical = tb->vertical;
117   int border_width = tb->border_width;
118
119   if (vertical)
120     {
121       x_adj = border_width;
122       width_adj = - 2 * border_width;
123       y_adj = 0;
124       height_adj = 0;
125     }
126   else
127     {
128       x_adj = 0;
129       width_adj = 0;
130       y_adj = border_width;
131       height_adj = - 2 * border_width;
132     }
133
134   XSETFRAME (frame, f);
135   window = FRAME_LAST_NONMINIBUF_WINDOW (f);
136   w = XWINDOW (window);
137
138   glyph = get_toolbar_button_glyph (w, tb);
139
140   if (tb->enabled)
141     {
142       if (tb->down)
143         {
144           top_shadow_gc = FRAME_X_TOOLBAR_BOTTOM_SHADOW_GC (f);
145           bottom_shadow_gc = FRAME_X_TOOLBAR_TOP_SHADOW_GC (f);
146         }
147       else
148         {
149           top_shadow_gc = FRAME_X_TOOLBAR_TOP_SHADOW_GC (f);
150           bottom_shadow_gc = FRAME_X_TOOLBAR_BOTTOM_SHADOW_GC (f);
151         }
152     }
153   else
154     {
155       top_shadow_gc = FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f);
156       bottom_shadow_gc = FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f);
157     }
158   background_gc = FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f);
159
160   /* Draw the outline. */
161   x_output_shadows (f, tb->x + x_adj, tb->y + y_adj,
162                     tb->width + width_adj, tb->height + height_adj,
163                     top_shadow_gc,
164                     bottom_shadow_gc, background_gc, shadow_thickness,
165                     EDGE_ALL);
166
167   /* Clear the pixmap area. */
168   XFillRectangle (dpy, x_win, background_gc, tb->x + x_adj + shadow_thickness,
169                   tb->y + y_adj + shadow_thickness,
170                   tb->width + width_adj - shadow_thickness * 2,
171                   tb->height + height_adj - shadow_thickness * 2);
172
173   /* Do the border. */
174   XFillRectangle (dpy, x_win, background_gc, tb->x, tb->y,
175                   (vertical ? border_width : tb->width),
176                   (vertical ? tb->height : border_width));
177
178   XFillRectangle (dpy, x_win, background_gc,
179                   (vertical ? tb->x + tb->width - border_width : tb->x),
180                   (vertical ? tb->y : tb->y + tb->height - border_width),
181                   (vertical ? border_width : tb->width),
182                   (vertical ? tb->height : border_width));
183
184   background_gc = FRAME_X_TOOLBAR_PIXMAP_BACKGROUND_GC (f);
185
186   /* #### It is currently possible for users to trash us by directly
187      changing the toolbar glyphs.  Avoid crashing in that case. */
188   if (GLYPHP (glyph))
189     instance = glyph_image_instance (glyph, window, ERROR_ME_NOT, 1);
190   else
191     instance = Qnil;
192
193   if (IMAGE_INSTANCEP (instance))
194     {
195       int width = tb->width + width_adj - shadow_thickness * 2;
196       int height = tb->height + height_adj - shadow_thickness * 2;
197       int x_offset = x_adj + shadow_thickness;
198       int y_offset = y_adj + shadow_thickness;
199
200       p = XIMAGE_INSTANCE (instance);
201
202       if (IMAGE_INSTANCE_PIXMAP_TYPE_P (p))
203         {
204           if (width > (int) IMAGE_INSTANCE_PIXMAP_WIDTH (p))
205             {
206               x_offset += ((int) (width - IMAGE_INSTANCE_PIXMAP_WIDTH (p))
207                            / 2);
208               width = IMAGE_INSTANCE_PIXMAP_WIDTH (p);
209             }
210           if (height > (int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p))
211             {
212               y_offset += ((int) (height - IMAGE_INSTANCE_PIXMAP_HEIGHT (p))
213                            / 2);
214               height = IMAGE_INSTANCE_PIXMAP_HEIGHT (p);
215             }
216
217           x_output_x_pixmap (f, XIMAGE_INSTANCE (instance), tb->x + x_offset,
218                              tb->y + y_offset, 0, 0, width, height,
219                              0, 0, background_gc);
220         }
221       else if (IMAGE_INSTANCE_TYPE (p) == IMAGE_TEXT)
222         {
223           /* #### We need to make the face used configurable. */
224           struct face_cachel *cachel =
225             WINDOW_FACE_CACHEL (w, DEFAULT_INDEX);
226           struct display_line dl;
227           Lisp_Object string = IMAGE_INSTANCE_TEXT_STRING (p);
228           unsigned char charsets[NUM_LEADING_BYTES];
229           Emchar_dynarr *buf;
230           struct font_metric_info fm;
231
232           /* This could be true if we were called via the Expose event
233              handler.  Mark the button as dirty and return
234              immediately. */
235           if (f->window_face_cache_reset)
236             {
237               tb->dirty = 1;
238               MARK_TOOLBAR_CHANGED;
239               return;
240             }
241           buf = Dynarr_new (Emchar);
242           convert_bufbyte_string_into_emchar_dynarr
243             (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
244           find_charsets_in_emchar_string (charsets, Dynarr_atp (buf, 0),
245                                           Dynarr_length (buf));
246           ensure_face_cachel_complete (cachel, window, charsets);
247           face_cachel_charset_font_metric_info (cachel, charsets, &fm);
248
249           dl.ascent = fm.ascent;
250           dl.descent = fm.descent;
251           dl.ypos = tb->y + y_offset + fm.ascent;
252
253           if (fm.ascent + fm.descent <= height)
254             {
255               dl.ypos += (height - fm.ascent - fm.descent) / 2;
256               dl.clip = 0;
257             }
258           else
259             {
260               dl.clip = fm.ascent + fm.descent - height;
261             }
262
263           x_output_string (w, &dl, buf, tb->x + x_offset, 0, 0, width,
264                            DEFAULT_INDEX, 0, 0, 0, 0);
265           Dynarr_free (buf);
266         }
267
268       /* We silently ignore the image if it isn't a pixmap or text. */
269     }
270
271   tb->dirty = 0;
272 }
273
274 static int
275 x_get_button_size (struct frame *f, Lisp_Object window,
276                    struct toolbar_button *tb, int vert, int pos)
277 {
278   EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
279   int shadow_thickness = ef->emacs_frame.toolbar_shadow_thickness;
280   int size;
281
282   if (tb->blank)
283     {
284       if (!NILP (tb->down_glyph))
285         size = XINT (tb->down_glyph);
286       else
287         size = DEFAULT_TOOLBAR_BLANK_SIZE;
288     }
289   else
290     {
291       struct window *w = XWINDOW (window);
292       Lisp_Object glyph = get_toolbar_button_glyph (w, tb);
293
294       /* Unless, of course, the user has done something stupid like
295          change the glyph out from under us.  Use a blank placeholder
296          in that case. */
297       if (NILP (glyph))
298         return XINT (f->toolbar_size[pos]);
299
300       if (vert)
301         size = glyph_height (glyph, window);
302       else
303         size = glyph_width (glyph, window);
304     }
305
306   if (!size)
307     {
308       /* If the glyph doesn't have a size we'll insert a blank
309          placeholder instead. */
310       return XINT (f->toolbar_size[pos]);
311     }
312
313   size += shadow_thickness * 2;
314
315   return (size);
316 }
317
318 #define X_OUTPUT_BUTTONS_LOOP(left)                                     \
319   do {                                                                  \
320     while (!NILP (button))                                              \
321       {                                                                 \
322         struct toolbar_button *tb = XTOOLBAR_BUTTON (button);           \
323         int size, height, width;                                        \
324                                                                         \
325         if (left && tb->pushright)                                      \
326           break;                                                        \
327                                                                         \
328         size = x_get_button_size (f, window, tb, vert, pos);            \
329                                                                         \
330         if (vert)                                                       \
331           {                                                             \
332             width = bar_width;                                          \
333             if (y + size > max_pixpos)                                  \
334               height = max_pixpos - y;                                  \
335             else                                                        \
336               height = size;                                            \
337           }                                                             \
338         else                                                            \
339           {                                                             \
340             if (x + size > max_pixpos)                                  \
341               width = max_pixpos - x;                                   \
342             else                                                        \
343               width = size;                                             \
344             height = bar_height;                                        \
345           }                                                             \
346                                                                         \
347         if (tb->x != x                                                  \
348             || tb->y != y                                               \
349             || tb->width != width                                       \
350             || tb->height != height                                     \
351             || tb->dirty)                                               \
352           {                                                             \
353             if (width && height)                                        \
354               {                                                         \
355                 tb->x = x;                                              \
356                 tb->y = y;                                              \
357                 tb->width = width;                                      \
358                 tb->height = height;                                    \
359                 tb->border_width = border_width;                        \
360                 tb->vertical = vert;                                    \
361                                                                         \
362                 if (tb->blank || NILP (tb->up_glyph))                   \
363                   {                                                     \
364                     int threed = (EQ (Qt, tb->up_glyph) ? 1 : 0);       \
365                     x_draw_blank_toolbar_button (f, x, y, width,        \
366                                                  height, threed,        \
367                                                  border_width, vert);   \
368                   }                                                     \
369                 else                                                    \
370                   x_output_toolbar_button (f, button);                  \
371               }                                                         \
372           }                                                             \
373                                                                         \
374         if (vert)                                                       \
375           y += height;                                                  \
376         else                                                            \
377           x += width;                                                   \
378                                                                         \
379         if ((vert && y == max_pixpos) || (!vert && x == max_pixpos))    \
380           button = Qnil;                                                \
381         else                                                            \
382           button = tb->next;                                            \
383       }                                                                 \
384   } while (0)
385
386 #define SET_TOOLBAR_WAS_VISIBLE_FLAG(frame, pos, flag)                  \
387   do {                                                                  \
388     switch (pos)                                                        \
389       {                                                                 \
390       case TOP_TOOLBAR:                                                 \
391         (frame)->top_toolbar_was_visible = flag;                        \
392         break;                                                          \
393       case BOTTOM_TOOLBAR:                                              \
394         (frame)->bottom_toolbar_was_visible = flag;                     \
395         break;                                                          \
396       case LEFT_TOOLBAR:                                                \
397         (frame)->left_toolbar_was_visible = flag;                       \
398         break;                                                          \
399       case RIGHT_TOOLBAR:                                               \
400         (frame)->right_toolbar_was_visible = flag;                      \
401         break;                                                          \
402       default:                                                          \
403         abort ();                                                       \
404       }                                                                 \
405   } while (0)
406
407 static void
408 x_output_toolbar (struct frame *f, enum toolbar_pos pos)
409 {
410   struct device *d = XDEVICE (f->device);
411   int x, y, bar_width, bar_height, vert;
412   int max_pixpos, right_size, right_start, blank_size;
413   int border_width = FRAME_REAL_TOOLBAR_BORDER_WIDTH (f, pos);
414   Lisp_Object button, window;
415   Display *dpy = DEVICE_X_DISPLAY (d);
416   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
417   GC background_gc = FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f);
418
419   get_toolbar_coords (f, pos, &x, &y, &bar_width, &bar_height, &vert, 1);
420   window = FRAME_LAST_NONMINIBUF_WINDOW (f);
421
422   /* Do the border */
423   XFillRectangle (dpy, x_win, background_gc, x, y,
424                   (vert ? bar_width : border_width),
425                   (vert ? border_width : bar_height));
426   XFillRectangle (dpy, x_win, background_gc,
427                   (vert ? x : x + bar_width - border_width),
428                   (vert ? y + bar_height - border_width : y),
429                   (vert ? bar_width : border_width),
430                   (vert ? border_width : bar_height));
431
432   if (vert)
433     {
434       max_pixpos = y + bar_height - border_width;
435       y += border_width;
436     }
437   else
438     {
439       max_pixpos = x + bar_width - border_width;
440       x += border_width;
441     }
442
443   button = FRAME_TOOLBAR_BUTTONS (f, pos);
444   right_size = 0;
445
446   /* First loop over all of the buttons to determine how much room we
447      need for left hand and right hand buttons.  This loop will also
448      make sure that all instances are instantiated so when we actually
449      output them they will come up immediately. */
450   while (!NILP (button))
451     {
452       struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
453       int size = x_get_button_size (f, window, tb, vert, pos);
454
455       if (tb->pushright)
456         right_size += size;
457
458       button = tb->next;
459     }
460
461   button = FRAME_TOOLBAR_BUTTONS (f, pos);
462
463   /* Loop over the left buttons, updating and outputting them. */
464   X_OUTPUT_BUTTONS_LOOP (1);
465
466   /* Now determine where the right buttons start. */
467   right_start = max_pixpos - right_size;
468   if (right_start < (vert ? y : x))
469     right_start = (vert ? y : x);
470
471   /* Output the blank which goes from the end of the left buttons to
472      the start of the right. */
473   blank_size = right_start - (vert ? y : x);
474   if (blank_size)
475     {
476       int height, width;
477
478       if (vert)
479         {
480           width = bar_width;
481           height = blank_size;
482         }
483       else
484         {
485           width = blank_size;
486           height = bar_height;
487         }
488
489       /*
490        * Use a 3D pushright separator only if there isn't a toolbar
491        * border.  A flat separator meshes with the border and looks
492        * better.
493        */
494       x_draw_blank_toolbar_button (f, x, y, width, height, !border_width,
495                                    border_width, vert);
496
497       if (vert)
498         y += height;
499       else
500         x += width;
501     }
502
503   /* Loop over the right buttons, updating and outputting them. */
504   X_OUTPUT_BUTTONS_LOOP (0);
505
506   if (!vert)
507     {
508       Lisp_Object frame;
509
510       XSETFRAME (frame, f);
511       redisplay_clear_region (frame,
512                               DEFAULT_INDEX, FRAME_PIXWIDTH (f) - 1, y, 1,
513                               bar_height);
514     }
515
516   SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 1);
517
518   XFlush (DEVICE_X_DISPLAY (d));
519 }
520
521 static void
522 x_clear_toolbar (struct frame *f, enum toolbar_pos pos, int thickness_change)
523 {
524   Lisp_Object frame;
525   struct device *d = XDEVICE (f->device);
526   int x, y, width, height, vert;
527
528   get_toolbar_coords (f, pos, &x, &y, &width, &height, &vert, 1);
529   XSETFRAME (frame, f);
530
531   /* The thickness_change parameter is used by the toolbar resize routines
532      to clear any excess toolbar if the size shrinks. */
533   if (thickness_change < 0)
534     {
535       if (pos == LEFT_TOOLBAR || pos == RIGHT_TOOLBAR)
536         {
537           x = x + width + thickness_change;
538           width = -thickness_change;
539         }
540       else
541         {
542           y = y + height + thickness_change;
543           height = -thickness_change;
544         }
545     }
546
547   SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 0);
548
549   redisplay_clear_region (frame, DEFAULT_INDEX, x, y, width, height);
550   XFlush (DEVICE_X_DISPLAY (d));
551 }
552
553 static void
554 x_output_frame_toolbars (struct frame *f)
555 {
556   assert (FRAME_X_P (f));
557
558   if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
559     x_output_toolbar (f, TOP_TOOLBAR);
560   else if (f->top_toolbar_was_visible)
561     x_clear_toolbar (f, TOP_TOOLBAR, 0);
562
563   if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
564     x_output_toolbar (f, BOTTOM_TOOLBAR);
565   else if (f->bottom_toolbar_was_visible)
566     x_clear_toolbar (f, BOTTOM_TOOLBAR, 0);
567
568   if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
569     x_output_toolbar (f, LEFT_TOOLBAR);
570   else if (f->left_toolbar_was_visible)
571     x_clear_toolbar (f, LEFT_TOOLBAR, 0);
572
573   if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
574     x_output_toolbar (f, RIGHT_TOOLBAR);
575   else if (f->right_toolbar_was_visible)
576     x_clear_toolbar (f, RIGHT_TOOLBAR, 0);
577 }
578
579 static void
580 x_redraw_exposed_toolbar (struct frame *f, enum toolbar_pos pos, int x, int y,
581                           int width, int height)
582 {
583   int bar_x, bar_y, bar_width, bar_height, vert;
584   Lisp_Object button = FRAME_TOOLBAR_BUTTONS (f, pos);
585
586   get_toolbar_coords (f, pos, &bar_x, &bar_y, &bar_width, &bar_height,
587                       &vert, 1);
588
589   if (((y + height) < bar_y) || (y > (bar_y + bar_height)))
590     return;
591   if (((x + width) < bar_x) || (x > (bar_x + bar_width)))
592     return;
593
594   while (!NILP (button))
595     {
596       struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
597
598       if (vert)
599         {
600           if (((tb->y + tb->height) > y) && (tb->y < (y + height)))
601             tb->dirty = 1;
602
603           /* If this is true we have gone past the exposed region. */
604           if (tb->y > (y + height))
605             break;
606         }
607       else
608         {
609           if (((tb->x + tb->width) > x) && (tb->x < (x + width)))
610             tb->dirty = 1;
611
612           /* If this is true we have gone past the exposed region. */
613           if (tb->x > (x + width))
614             break;
615         }
616
617       button = tb->next;
618     }
619
620   /* Even if none of the buttons is in the area, the blank region at
621      the very least must be because the first thing we did is verify
622      that some portion of the toolbar is in the exposed region. */
623   x_output_toolbar (f, pos);
624 }
625
626 static void
627 x_redraw_exposed_toolbars (struct frame *f, int x, int y, int width,
628                            int height)
629 {
630   assert (FRAME_X_P (f));
631
632   if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
633     x_redraw_exposed_toolbar (f, TOP_TOOLBAR, x, y, width, height);
634
635   if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
636     x_redraw_exposed_toolbar (f, BOTTOM_TOOLBAR, x, y, width, height);
637
638   if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
639     x_redraw_exposed_toolbar (f, LEFT_TOOLBAR, x, y, width, height);
640
641   if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
642     x_redraw_exposed_toolbar (f, RIGHT_TOOLBAR, x, y, width, height);
643 }
644
645 static void
646 x_redraw_frame_toolbars (struct frame *f)
647 {
648   /* There are certain startup paths that lead to update_EmacsFrame in
649      faces.c being called before a new frame is fully initialized.  In
650      particular before we have actually mapped it.  That routine can
651      call this one.  So, we need to make sure that the frame is
652      actually ready before we try and draw all over it. */
653
654   if (XtIsRealized (FRAME_X_SHELL_WIDGET (f)))
655     x_redraw_exposed_toolbars (f, 0, 0, FRAME_PIXWIDTH (f),
656                                FRAME_PIXHEIGHT (f));
657 }
658
659 \f
660 static void
661 x_initialize_frame_toolbar_gcs (struct frame *f)
662 {
663   EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
664   EmacsFramePart *efp = &(ef->emacs_frame);
665   XGCValues gcv;
666   unsigned long flags = (GCForeground | GCBackground | GCGraphicsExposures);
667
668   /*
669    * If backgroundToolBarColor is specified, use it.
670    * Otherwise use the background resource.
671    */
672   if (efp->background_toolbar_pixel == (Pixel) (-1))
673     efp->background_toolbar_pixel = efp->background_pixel;
674
675   /*
676    * ####
677    * If foregroundToolBarColor is specified, use it.
678    * Otherwise use the foreground resource.
679    *
680    * The foreground pixel is currently unused, but will likely be
681    * used when toolbar captions are generated by the toolbar code
682    * instead being incorporated into the icon image.
683    */
684   if (efp->foreground_toolbar_pixel == (Pixel) (-1))
685     efp->foreground_toolbar_pixel = efp->foreground_pixel;
686
687   gcv.foreground = efp->background_toolbar_pixel;
688   gcv.background = ef->core.background_pixel;
689   gcv.graphics_exposures = False;
690   FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f) =
691     XtGetGC ((Widget) ef, flags, &gcv);
692
693   if (efp->top_toolbar_shadow_pixel == efp->bottom_toolbar_shadow_pixel)
694     {
695       efp->top_toolbar_shadow_pixel    = efp->background_toolbar_pixel;
696       efp->bottom_toolbar_shadow_pixel = efp->background_toolbar_pixel;
697     }
698
699   x_generate_shadow_pixels (f, &efp->top_toolbar_shadow_pixel,
700                             &efp->bottom_toolbar_shadow_pixel,
701                             efp->background_toolbar_pixel,
702                             ef->core.background_pixel);
703
704   gcv.foreground = efp->top_toolbar_shadow_pixel;
705   gcv.background = ef->core.background_pixel;
706   gcv.graphics_exposures = False;
707   flags = GCForeground | GCBackground | GCGraphicsExposures;
708   if (efp->top_toolbar_shadow_pixmap)
709     {
710       gcv.fill_style = FillOpaqueStippled;
711       gcv.stipple = efp->top_toolbar_shadow_pixmap;
712       flags |= GCStipple | GCFillStyle;
713     }
714   FRAME_X_TOOLBAR_TOP_SHADOW_GC (f) = XtGetGC ((Widget) ef, flags, &gcv);
715
716   gcv.foreground = efp->bottom_toolbar_shadow_pixel;
717   gcv.background = ef->core.background_pixel;
718   gcv.graphics_exposures = False;
719   flags = GCForeground | GCBackground | GCGraphicsExposures;
720   if (efp->bottom_toolbar_shadow_pixmap)
721     {
722       gcv.fill_style = FillOpaqueStippled;
723       gcv.stipple = efp->bottom_toolbar_shadow_pixmap;
724       flags |= GCStipple | GCFillStyle;
725     }
726   FRAME_X_TOOLBAR_BOTTOM_SHADOW_GC (f) = XtGetGC ((Widget) ef, flags, &gcv);
727
728 #ifdef HAVE_XPM
729   FRAME_X_TOOLBAR_PIXMAP_BACKGROUND_GC (f) =
730     FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f);
731 #else
732   {
733     struct device *d = XDEVICE (f->device);
734     Display *dpy = DEVICE_X_DISPLAY (d);
735
736     gcv.background = WhitePixelOfScreen (DefaultScreenOfDisplay (dpy));
737     gcv.foreground = BlackPixelOfScreen (DefaultScreenOfDisplay (dpy));
738     gcv.graphics_exposures = False;
739     flags = GCForeground | GCBackground | GCGraphicsExposures;
740     FRAME_X_TOOLBAR_PIXMAP_BACKGROUND_GC (f) =
741       XtGetGC ((Widget) ef, flags, &gcv);
742   }
743 #endif
744 }
745
746 static void
747 x_release_frame_toolbar_gcs (struct frame *f)
748 {
749   Widget ew = (Widget) FRAME_X_TEXT_WIDGET (f);
750   XtReleaseGC (ew, FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f));
751   /* If compiled with XPM support, this is a pointer to the same GC as
752      FRAME_X_BLANK_BACKGROUND_GC so we need to make sure we don't
753      release it twice. */
754 #ifndef HAVE_XPM
755   XtReleaseGC (ew, FRAME_X_TOOLBAR_PIXMAP_BACKGROUND_GC (f));
756 #endif
757   XtReleaseGC (ew, FRAME_X_TOOLBAR_TOP_SHADOW_GC (f));
758   XtReleaseGC (ew, FRAME_X_TOOLBAR_BOTTOM_SHADOW_GC (f));
759
760   /* Seg fault if we try and use these again. */
761   FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC  (f) = (GC) - 1;
762   FRAME_X_TOOLBAR_PIXMAP_BACKGROUND_GC (f) = (GC) - 1;
763   FRAME_X_TOOLBAR_TOP_SHADOW_GC        (f) = (GC) - 1;
764   FRAME_X_TOOLBAR_BOTTOM_SHADOW_GC     (f) = (GC) - 1;
765 }
766
767 static void
768 x_initialize_frame_toolbars (struct frame *f)
769 {
770   EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
771
772   if (ef->emacs_frame.toolbar_shadow_thickness < MINIMUM_SHADOW_THICKNESS)
773     Xt_SET_VALUE (FRAME_X_TEXT_WIDGET (f),
774                   XtNtoolBarShadowThickness, MINIMUM_SHADOW_THICKNESS);
775
776   x_initialize_frame_toolbar_gcs (f);
777 }
778
779 /* This only calls one function but we go ahead and create this in
780    case we ever do decide that we need to do more work. */
781 static void
782 x_free_frame_toolbars (struct frame *f)
783 {
784   x_release_frame_toolbar_gcs (f);
785 }
786
787 \f
788 /************************************************************************/
789 /*                            initialization                            */
790 /************************************************************************/
791
792 void
793 console_type_create_toolbar_x (void)
794 {
795   CONSOLE_HAS_METHOD (x, output_frame_toolbars);
796   CONSOLE_HAS_METHOD (x, initialize_frame_toolbars);
797   CONSOLE_HAS_METHOD (x, free_frame_toolbars);
798   CONSOLE_HAS_METHOD (x, output_toolbar_button);
799   CONSOLE_HAS_METHOD (x, redraw_exposed_toolbars);
800   CONSOLE_HAS_METHOD (x, redraw_frame_toolbars);
801 }