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