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