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