(JSP-5368): Separate JX1-7A24.
[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           Charset_ID charsets[NUM_LEADING_BYTES];
229           Charc_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 (Charc);
242           convert_bufbyte_string_into_charc_dynarr
243             (XSTRING_DATA (string), XSTRING_LENGTH (string), buf);
244           find_charsets_in_charc_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             || f->clear) /* This is clearly necessary. */               \
353           {                                                             \
354             if (width && height)                                        \
355               {                                                         \
356                 tb->x = x;                                              \
357                 tb->y = y;                                              \
358                 tb->width = width;                                      \
359                 tb->height = height;                                    \
360                 tb->border_width = border_width;                        \
361                 tb->vertical = vert;                                    \
362                                                                         \
363                 if (tb->blank || NILP (tb->up_glyph))                   \
364                   {                                                     \
365                     int threed = (EQ (Qt, tb->up_glyph) ? 1 : 0);       \
366                     x_draw_blank_toolbar_button (f, x, y, width,        \
367                                                  height, threed,        \
368                                                  border_width, vert);   \
369                   }                                                     \
370                 else                                                    \
371                   x_output_toolbar_button (f, button);                  \
372               }                                                         \
373           }                                                             \
374                                                                         \
375         if (vert)                                                       \
376           y += height;                                                  \
377         else                                                            \
378           x += width;                                                   \
379                                                                         \
380         if ((vert && y == max_pixpos) || (!vert && x == max_pixpos))    \
381           button = Qnil;                                                \
382         else                                                            \
383           button = tb->next;                                            \
384       }                                                                 \
385   } while (0)
386
387 #define SET_TOOLBAR_WAS_VISIBLE_FLAG(frame, pos, flag)                  \
388   do {                                                                  \
389     switch (pos)                                                        \
390       {                                                                 \
391       case TOP_TOOLBAR:                                                 \
392         (frame)->top_toolbar_was_visible = flag;                        \
393         break;                                                          \
394       case BOTTOM_TOOLBAR:                                              \
395         (frame)->bottom_toolbar_was_visible = flag;                     \
396         break;                                                          \
397       case LEFT_TOOLBAR:                                                \
398         (frame)->left_toolbar_was_visible = flag;                       \
399         break;                                                          \
400       case RIGHT_TOOLBAR:                                               \
401         (frame)->right_toolbar_was_visible = flag;                      \
402         break;                                                          \
403       default:                                                          \
404         ABORT ();                                                       \
405       }                                                                 \
406   } while (0)
407
408 static void
409 x_output_toolbar (struct frame *f, enum toolbar_pos pos)
410 {
411   struct device *d = XDEVICE (f->device);
412   int x, y, bar_width, bar_height, vert;
413   int max_pixpos, right_size, right_start, blank_size;
414   int border_width = FRAME_REAL_TOOLBAR_BORDER_WIDTH (f, pos);
415   Lisp_Object button, window;
416   Display *dpy = DEVICE_X_DISPLAY (d);
417   Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
418   GC background_gc = FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f);
419
420   get_toolbar_coords (f, pos, &x, &y, &bar_width, &bar_height, &vert, 1);
421   window = FRAME_LAST_NONMINIBUF_WINDOW (f);
422
423   /* Do the border */
424   XFillRectangle (dpy, x_win, background_gc, x, y,
425                   (vert ? bar_width : border_width),
426                   (vert ? border_width : bar_height));
427   XFillRectangle (dpy, x_win, background_gc,
428                   (vert ? x : x + bar_width - border_width),
429                   (vert ? y + bar_height - border_width : y),
430                   (vert ? bar_width : border_width),
431                   (vert ? border_width : bar_height));
432
433   if (vert)
434     {
435       max_pixpos = y + bar_height - border_width;
436       y += border_width;
437     }
438   else
439     {
440       max_pixpos = x + bar_width - border_width;
441       x += border_width;
442     }
443
444   button = FRAME_TOOLBAR_BUTTONS (f, pos);
445   right_size = 0;
446
447   /* First loop over all of the buttons to determine how much room we
448      need for left hand and right hand buttons.  This loop will also
449      make sure that all instances are instantiated so when we actually
450      output them they will come up immediately. */
451   while (!NILP (button))
452     {
453       struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
454       int size = x_get_button_size (f, window, tb, vert, pos);
455
456       if (tb->pushright)
457         right_size += size;
458
459       button = tb->next;
460     }
461
462   button = FRAME_TOOLBAR_BUTTONS (f, pos);
463
464   /* Loop over the left buttons, updating and outputting them. */
465   X_OUTPUT_BUTTONS_LOOP (1);
466
467   /* Now determine where the right buttons start. */
468   right_start = max_pixpos - right_size;
469   if (right_start < (vert ? y : x))
470     right_start = (vert ? y : x);
471
472   /* Output the blank which goes from the end of the left buttons to
473      the start of the right. */
474   blank_size = right_start - (vert ? y : x);
475   if (blank_size)
476     {
477       int height, width;
478
479       if (vert)
480         {
481           width = bar_width;
482           height = blank_size;
483         }
484       else
485         {
486           width = blank_size;
487           height = bar_height;
488         }
489
490       /*
491        * Use a 3D pushright separator only if there isn't a toolbar
492        * border.  A flat separator meshes with the border and looks
493        * better.
494        */
495       x_draw_blank_toolbar_button (f, x, y, width, height, !border_width,
496                                    border_width, vert);
497
498       if (vert)
499         y += height;
500       else
501         x += width;
502     }
503
504   /* Loop over the right buttons, updating and outputting them. */
505   X_OUTPUT_BUTTONS_LOOP (0);
506
507   if (!vert)
508     {
509       Lisp_Object frame;
510
511       XSETFRAME (frame, f);
512       redisplay_clear_region (frame,
513                               DEFAULT_INDEX, FRAME_PIXWIDTH (f) - 1, y, 1,
514                               bar_height);
515     }
516
517   SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 1);
518
519   XFlush (DEVICE_X_DISPLAY (d));
520 }
521
522 static void
523 x_clear_toolbar (struct frame *f, enum toolbar_pos pos, int thickness_change)
524 {
525   Lisp_Object frame;
526   struct device *d = XDEVICE (f->device);
527   int x, y, width, height, vert;
528
529   get_toolbar_coords (f, pos, &x, &y, &width, &height, &vert, 1);
530   XSETFRAME (frame, f);
531
532   /* The thickness_change parameter is used by the toolbar resize routines
533      to clear any excess toolbar if the size shrinks. */
534   if (thickness_change < 0)
535     {
536       if (pos == LEFT_TOOLBAR || pos == RIGHT_TOOLBAR)
537         {
538           x = x + width + thickness_change;
539           width = -thickness_change;
540         }
541       else
542         {
543           y = y + height + thickness_change;
544           height = -thickness_change;
545         }
546     }
547
548   SET_TOOLBAR_WAS_VISIBLE_FLAG (f, pos, 0);
549
550   redisplay_clear_region (frame, DEFAULT_INDEX, x, y, width, height);
551   XFlush (DEVICE_X_DISPLAY (d));
552 }
553
554 static void
555 x_output_frame_toolbars (struct frame *f)
556 {
557   assert (FRAME_X_P (f));
558
559   if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
560     x_output_toolbar (f, TOP_TOOLBAR);
561   if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
562     x_output_toolbar (f, BOTTOM_TOOLBAR);
563   if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
564     x_output_toolbar (f, LEFT_TOOLBAR);
565   if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
566     x_output_toolbar (f, RIGHT_TOOLBAR);
567 }
568
569 static void
570 x_clear_frame_toolbars (struct frame *f)
571 {
572   assert (FRAME_X_P (f));
573
574   if (f->top_toolbar_was_visible
575       && !FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
576     x_clear_toolbar (f, TOP_TOOLBAR, 0);
577   if (f->bottom_toolbar_was_visible
578       && !FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
579     x_clear_toolbar (f, BOTTOM_TOOLBAR, 0);
580   if (f->left_toolbar_was_visible 
581       && !FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
582     x_clear_toolbar (f, LEFT_TOOLBAR, 0);
583   if (f->right_toolbar_was_visible 
584       && !FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
585     x_clear_toolbar (f, RIGHT_TOOLBAR, 0);
586 }
587
588 static void
589 x_redraw_exposed_toolbar (struct frame *f, enum toolbar_pos pos, int x, int y,
590                           int width, int height)
591 {
592   int bar_x, bar_y, bar_width, bar_height, vert;
593   Lisp_Object button = FRAME_TOOLBAR_BUTTONS (f, pos);
594
595   get_toolbar_coords (f, pos, &bar_x, &bar_y, &bar_width, &bar_height,
596                       &vert, 1);
597
598   if (((y + height) < bar_y) || (y > (bar_y + bar_height)))
599     return;
600   if (((x + width) < bar_x) || (x > (bar_x + bar_width)))
601     return;
602
603   while (!NILP (button))
604     {
605       struct toolbar_button *tb = XTOOLBAR_BUTTON (button);
606
607       if (vert)
608         {
609           if (((tb->y + tb->height) > y) && (tb->y < (y + height)))
610             tb->dirty = 1;
611
612           /* If this is true we have gone past the exposed region. */
613           if (tb->y > (y + height))
614             break;
615         }
616       else
617         {
618           if (((tb->x + tb->width) > x) && (tb->x < (x + width)))
619             tb->dirty = 1;
620
621           /* If this is true we have gone past the exposed region. */
622           if (tb->x > (x + width))
623             break;
624         }
625
626       button = tb->next;
627     }
628
629   /* Even if none of the buttons is in the area, the blank region at
630      the very least must be because the first thing we did is verify
631      that some portion of the toolbar is in the exposed region. */
632   x_output_toolbar (f, pos);
633 }
634
635 static void
636 x_redraw_exposed_toolbars (struct frame *f, int x, int y, int width,
637                            int height)
638 {
639   assert (FRAME_X_P (f));
640
641   if (FRAME_REAL_TOP_TOOLBAR_VISIBLE (f))
642     x_redraw_exposed_toolbar (f, TOP_TOOLBAR, x, y, width, height);
643
644   if (FRAME_REAL_BOTTOM_TOOLBAR_VISIBLE (f))
645     x_redraw_exposed_toolbar (f, BOTTOM_TOOLBAR, x, y, width, height);
646
647   if (FRAME_REAL_LEFT_TOOLBAR_VISIBLE (f))
648     x_redraw_exposed_toolbar (f, LEFT_TOOLBAR, x, y, width, height);
649
650   if (FRAME_REAL_RIGHT_TOOLBAR_VISIBLE (f))
651     x_redraw_exposed_toolbar (f, RIGHT_TOOLBAR, x, y, width, height);
652 }
653
654 static void
655 x_redraw_frame_toolbars (struct frame *f)
656 {
657   /* There are certain startup paths that lead to update_EmacsFrame in
658      faces.c being called before a new frame is fully initialized.  In
659      particular before we have actually mapped it.  That routine can
660      call this one.  So, we need to make sure that the frame is
661      actually ready before we try and draw all over it. */
662
663   if (XtIsRealized (FRAME_X_SHELL_WIDGET (f)))
664     x_redraw_exposed_toolbars (f, 0, 0, FRAME_PIXWIDTH (f),
665                                FRAME_PIXHEIGHT (f));
666 }
667
668 \f
669 static void
670 x_initialize_frame_toolbar_gcs (struct frame *f)
671 {
672   EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
673   EmacsFramePart *efp = &(ef->emacs_frame);
674   XGCValues gcv;
675   unsigned long flags = (GCForeground | GCBackground | GCGraphicsExposures);
676
677   /*
678    * If backgroundToolBarColor is specified, use it.
679    * Otherwise use the background resource.
680    */
681   if (efp->background_toolbar_pixel == (Pixel) (-1))
682     efp->background_toolbar_pixel = efp->background_pixel;
683
684   /*
685    * ####
686    * If foregroundToolBarColor is specified, use it.
687    * Otherwise use the foreground resource.
688    *
689    * The foreground pixel is currently unused, but will likely be
690    * used when toolbar captions are generated by the toolbar code
691    * instead being incorporated into the icon image.
692    */
693   if (efp->foreground_toolbar_pixel == (Pixel) (-1))
694     efp->foreground_toolbar_pixel = efp->foreground_pixel;
695
696   gcv.foreground = efp->background_toolbar_pixel;
697   gcv.background = ef->core.background_pixel;
698   gcv.graphics_exposures = False;
699   FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f) =
700     XtGetGC ((Widget) ef, flags, &gcv);
701
702   if (efp->top_toolbar_shadow_pixel == efp->bottom_toolbar_shadow_pixel)
703     {
704       efp->top_toolbar_shadow_pixel    = efp->background_toolbar_pixel;
705       efp->bottom_toolbar_shadow_pixel = efp->background_toolbar_pixel;
706     }
707
708   x_generate_shadow_pixels (f, &efp->top_toolbar_shadow_pixel,
709                             &efp->bottom_toolbar_shadow_pixel,
710                             efp->background_toolbar_pixel,
711                             ef->core.background_pixel);
712
713   gcv.foreground = efp->top_toolbar_shadow_pixel;
714   gcv.background = ef->core.background_pixel;
715   gcv.graphics_exposures = False;
716   flags = GCForeground | GCBackground | GCGraphicsExposures;
717   if (efp->top_toolbar_shadow_pixmap)
718     {
719       gcv.fill_style = FillOpaqueStippled;
720       gcv.stipple = efp->top_toolbar_shadow_pixmap;
721       flags |= GCStipple | GCFillStyle;
722     }
723   FRAME_X_TOOLBAR_TOP_SHADOW_GC (f) = XtGetGC ((Widget) ef, flags, &gcv);
724
725   gcv.foreground = efp->bottom_toolbar_shadow_pixel;
726   gcv.background = ef->core.background_pixel;
727   gcv.graphics_exposures = False;
728   flags = GCForeground | GCBackground | GCGraphicsExposures;
729   if (efp->bottom_toolbar_shadow_pixmap)
730     {
731       gcv.fill_style = FillOpaqueStippled;
732       gcv.stipple = efp->bottom_toolbar_shadow_pixmap;
733       flags |= GCStipple | GCFillStyle;
734     }
735   FRAME_X_TOOLBAR_BOTTOM_SHADOW_GC (f) = XtGetGC ((Widget) ef, flags, &gcv);
736
737 #ifdef HAVE_XPM
738   FRAME_X_TOOLBAR_PIXMAP_BACKGROUND_GC (f) =
739     FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f);
740 #else
741   {
742     struct device *d = XDEVICE (f->device);
743     Display *dpy = DEVICE_X_DISPLAY (d);
744
745     gcv.background = WhitePixelOfScreen (DefaultScreenOfDisplay (dpy));
746     gcv.foreground = BlackPixelOfScreen (DefaultScreenOfDisplay (dpy));
747     gcv.graphics_exposures = False;
748     flags = GCForeground | GCBackground | GCGraphicsExposures;
749     FRAME_X_TOOLBAR_PIXMAP_BACKGROUND_GC (f) =
750       XtGetGC ((Widget) ef, flags, &gcv);
751   }
752 #endif
753 }
754
755 static void
756 x_release_frame_toolbar_gcs (struct frame *f)
757 {
758   Widget ew = (Widget) FRAME_X_TEXT_WIDGET (f);
759   XtReleaseGC (ew, FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC (f));
760   /* If compiled with XPM support, this is a pointer to the same GC as
761      FRAME_X_BLANK_BACKGROUND_GC so we need to make sure we don't
762      release it twice. */
763 #ifndef HAVE_XPM
764   XtReleaseGC (ew, FRAME_X_TOOLBAR_PIXMAP_BACKGROUND_GC (f));
765 #endif
766   XtReleaseGC (ew, FRAME_X_TOOLBAR_TOP_SHADOW_GC (f));
767   XtReleaseGC (ew, FRAME_X_TOOLBAR_BOTTOM_SHADOW_GC (f));
768
769   /* Seg fault if we try and use these again. */
770   FRAME_X_TOOLBAR_BLANK_BACKGROUND_GC  (f) = (GC) - 1;
771   FRAME_X_TOOLBAR_PIXMAP_BACKGROUND_GC (f) = (GC) - 1;
772   FRAME_X_TOOLBAR_TOP_SHADOW_GC        (f) = (GC) - 1;
773   FRAME_X_TOOLBAR_BOTTOM_SHADOW_GC     (f) = (GC) - 1;
774 }
775
776 static void
777 x_initialize_frame_toolbars (struct frame *f)
778 {
779   EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
780
781   if (ef->emacs_frame.toolbar_shadow_thickness < MINIMUM_SHADOW_THICKNESS)
782     Xt_SET_VALUE (FRAME_X_TEXT_WIDGET (f),
783                   XtNtoolBarShadowThickness, MINIMUM_SHADOW_THICKNESS);
784
785   x_initialize_frame_toolbar_gcs (f);
786 }
787
788 /* This only calls one function but we go ahead and create this in
789    case we ever do decide that we need to do more work. */
790 static void
791 x_free_frame_toolbars (struct frame *f)
792 {
793   x_release_frame_toolbar_gcs (f);
794 }
795
796 \f
797 /************************************************************************/
798 /*                            initialization                            */
799 /************************************************************************/
800
801 void
802 console_type_create_toolbar_x (void)
803 {
804   CONSOLE_HAS_METHOD (x, output_frame_toolbars);
805   CONSOLE_HAS_METHOD (x, clear_frame_toolbars);
806   CONSOLE_HAS_METHOD (x, initialize_frame_toolbars);
807   CONSOLE_HAS_METHOD (x, free_frame_toolbars);
808   CONSOLE_HAS_METHOD (x, output_toolbar_button);
809   CONSOLE_HAS_METHOD (x, redraw_exposed_toolbars);
810   CONSOLE_HAS_METHOD (x, redraw_frame_toolbars);
811 }