OSDN Git Service

touched all tk files to ease next import
[pf3gnuchains/pf3gnuchains3x.git] / tk / unix / tkUnixMenu.c
1 /* 
2  * tkUnixMenu.c --
3  *
4  *      This module implements the UNIX platform-specific features of menus.
5  *
6  * Copyright (c) 1996-1998 by Sun Microsystems, Inc.
7  *
8  * See the file "license.terms" for information on usage and redistribution
9  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10  *
11  * RCS: @(#) $Id$
12  */
13
14 #include "tkPort.h"
15 #include "default.h"
16 #include "tkInt.h"
17 #include "tkUnixInt.h"
18 #include "tkMenu.h"
19
20 /*
21  * Constants used for menu drawing.
22  */
23
24 #define MENU_MARGIN_WIDTH       2
25 #define MENU_DIVIDER_HEIGHT     2
26
27 /*
28  * Platform specific flags for Unix.
29  */
30
31 #define ENTRY_HELP_MENU         ENTRY_PLATFORM_FLAG1
32
33 /*
34  * Procedures used internally.
35  */
36
37 static void             SetHelpMenu _ANSI_ARGS_((TkMenu *menuPtr));
38 static void             DrawMenuEntryAccelerator _ANSI_ARGS_((
39                             TkMenu *menuPtr, TkMenuEntry *mePtr, 
40                             Drawable d, GC gc, Tk_Font tkfont,
41                             CONST Tk_FontMetrics *fmPtr,
42                             Tk_3DBorder activeBorder, int x, int y,
43                             int width, int height, int drawArrow));
44 static void             DrawMenuEntryBackground _ANSI_ARGS_((
45                             TkMenu *menuPtr, TkMenuEntry *mePtr,
46                             Drawable d, Tk_3DBorder activeBorder,
47                             Tk_3DBorder bgBorder, int x, int y,
48                             int width, int heigth));
49 static void             DrawMenuEntryIndicator _ANSI_ARGS_((
50                             TkMenu *menuPtr, TkMenuEntry *mePtr,
51                             Drawable d, GC gc, GC indicatorGC, 
52                             Tk_Font tkfont,
53                             CONST Tk_FontMetrics *fmPtr, int x, int y,
54                             int width, int height));
55 static void             DrawMenuEntryLabel _ANSI_ARGS_((
56                             TkMenu * menuPtr, TkMenuEntry *mePtr, Drawable d,
57                             GC gc, Tk_Font tkfont,
58                             CONST Tk_FontMetrics *fmPtr, int x, int y,
59                             int width, int height));
60 static void             DrawMenuSeparator _ANSI_ARGS_((TkMenu *menuPtr,
61                             TkMenuEntry *mePtr, Drawable d, GC gc, 
62                             Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, 
63                             int x, int y, int width, int height));
64 static void             DrawTearoffEntry _ANSI_ARGS_((TkMenu *menuPtr,
65                             TkMenuEntry *mePtr, Drawable d, GC gc, 
66                             Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, 
67                             int x, int y, int width, int height));
68 static void             DrawMenuUnderline _ANSI_ARGS_((TkMenu *menuPtr,
69                             TkMenuEntry *mePtr, Drawable d, GC gc,
70                             Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int x,
71                             int y, int width, int height));
72 static void             GetMenuAccelGeometry _ANSI_ARGS_((TkMenu *menuPtr,
73                             TkMenuEntry *mePtr, Tk_Font tkfont,
74                             CONST Tk_FontMetrics *fmPtr, int *widthPtr,
75                             int *heightPtr));
76 static void             GetMenuLabelGeometry _ANSI_ARGS_((TkMenuEntry *mePtr,
77                             Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
78                             int *widthPtr, int *heightPtr));
79 static void             GetMenuIndicatorGeometry _ANSI_ARGS_((
80                             TkMenu *menuPtr, TkMenuEntry *mePtr, 
81                             Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, 
82                             int *widthPtr, int *heightPtr));
83 static void             GetMenuSeparatorGeometry _ANSI_ARGS_((
84                             TkMenu *menuPtr, TkMenuEntry *mePtr,
85                             Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
86                             int *widthPtr, int *heightPtr));
87 static void             GetTearoffEntryGeometry _ANSI_ARGS_((TkMenu *menuPtr,
88                             TkMenuEntry *mePtr, Tk_Font tkfont,
89                             CONST Tk_FontMetrics *fmPtr, int *widthPtr,
90                             int *heightPtr));
91
92 \f
93 /*
94  *----------------------------------------------------------------------
95  *
96  * TkpNewMenu --
97  *
98  *      Gets the platform-specific piece of the menu. Invoked during idle
99  *      after the generic part of the menu has been created.
100  *
101  * Results:
102  *      Standard TCL error.
103  *
104  * Side effects:
105  *      Allocates any platform specific allocations and places them
106  *      in the platformData field of the menuPtr.
107  *
108  *----------------------------------------------------------------------
109  */
110
111 int
112 TkpNewMenu(menuPtr)
113     TkMenu *menuPtr;
114 {
115     SetHelpMenu(menuPtr);
116     return TCL_OK;
117 }
118 \f
119 /*
120  *----------------------------------------------------------------------
121  *
122  * TkpDestroyMenu --
123  *
124  *      Destroys platform-specific menu structures. Called when the
125  *      generic menu structure is destroyed for the menu.
126  *
127  * Results:
128  *      None.
129  *
130  * Side effects:
131  *      All platform-specific allocations are freed up.
132  *
133  *----------------------------------------------------------------------
134  */
135
136 void
137 TkpDestroyMenu(menuPtr)
138     TkMenu *menuPtr;
139 {
140     /*
141      * Nothing to do.
142      */
143 }
144 \f
145 /*
146  *----------------------------------------------------------------------
147  *
148  * TkpDestroyMenuEntry --
149  *
150  *      Cleans up platform-specific menu entry items. Called when entry
151  *      is destroyed in the generic code.
152  *
153  * Results:
154  *      None.
155  *
156  * Side effects:
157  *      All platform specific allocations are freed up.
158  *
159  *----------------------------------------------------------------------
160  */
161
162 void
163 TkpDestroyMenuEntry(mEntryPtr)
164     TkMenuEntry *mEntryPtr;
165 {
166     /*
167      * Nothing to do.
168      */
169 }
170 \f
171 /*
172  *----------------------------------------------------------------------
173  *
174  * TkpConfigureMenuEntry --
175  *
176  *      Processes configuration options for menu entries. Called when
177  *      the generic options are processed for the menu.
178  *
179  * Results:
180  *      Returns standard TCL result. If TCL_ERROR is returned, then
181  *      the interp's result contains an error message.
182  *
183  * Side effects:
184  *      Configuration information get set for mePtr; old resources
185  *      get freed, if any need it.
186  *
187  *----------------------------------------------------------------------
188  */
189
190 int
191 TkpConfigureMenuEntry(mePtr)
192     register TkMenuEntry *mePtr;        /* Information about menu entry;  may
193                                          * or may not already have values for
194                                          * some fields. */
195 {
196     /*
197      * If this is a cascade menu, and the child menu exists, check to
198      * see if the child menu is a help menu.
199      */
200
201     if ((mePtr->type == CASCADE_ENTRY) && (mePtr->namePtr != NULL)) {
202         TkMenuReferences *menuRefPtr;
203
204         menuRefPtr = TkFindMenuReferencesObj(mePtr->menuPtr->interp,
205                 mePtr->namePtr);
206         if ((menuRefPtr != NULL) && (menuRefPtr->menuPtr != NULL)) {
207             SetHelpMenu(menuRefPtr->menuPtr);
208         }
209     }
210     return TCL_OK;
211 }
212 \f
213 /*
214  *----------------------------------------------------------------------
215  *
216  * TkpMenuNewEntry --
217  *
218  *      Called when a new entry is created in a menu. Fills in platform
219  *      specific data for the entry. The platformEntryData field
220  *      is used to store the indicator diameter for radio button
221  *      and check box entries.
222  *
223  * Results:
224  *      Standard TCL error.
225  *
226  * Side effects:
227  *      None on Unix.
228  *
229  *----------------------------------------------------------------------
230  */
231
232 int
233 TkpMenuNewEntry(mePtr)
234     TkMenuEntry *mePtr;
235 {
236     return TCL_OK;
237 }
238 \f
239 /*
240  *----------------------------------------------------------------------
241  *
242  * TkpSetWindowMenuBar --
243  *
244  *      Sets up the menu as a menubar in the given window.
245  *
246  * Results:
247  *      None.
248  *
249  * Side effects:
250  *      Recomputes geometry of given window.
251  *
252  *----------------------------------------------------------------------
253  */
254
255 void
256 TkpSetWindowMenuBar(tkwin, menuPtr)
257     Tk_Window tkwin;                    /* The window we are setting */
258     TkMenu *menuPtr;                    /* The menu we are setting */
259 {
260     if (menuPtr == NULL) {
261         TkUnixSetMenubar(tkwin, NULL);
262     } else {
263         TkUnixSetMenubar(tkwin, menuPtr->tkwin);
264     }
265 }
266 \f
267 /*
268  *----------------------------------------------------------------------
269  *
270  * TkpSetMainMenuBar --
271  *
272  *      Called when a toplevel widget is brought to front. On the
273  *      Macintosh, sets up the menubar that goes accross the top
274  *      of the main monitor. On other platforms, nothing is necessary.
275  *
276  * Results:
277  *      None.
278  *
279  * Side effects:
280  *      Recompute geometry of given window.
281  *
282  *----------------------------------------------------------------------
283  */
284
285 void
286 TkpSetMainMenubar(interp, tkwin, menuName)
287     Tcl_Interp *interp;
288     Tk_Window tkwin;
289     char *menuName;
290 {
291     /*
292      * Nothing to do.
293      */
294 }
295 \f
296 /*
297  *----------------------------------------------------------------------
298  *
299  * GetMenuIndicatorGeometry --
300  *
301  *      Fills out the geometry of the indicator in a menu item. Note
302  *      that the mePtr->height field must have already been filled in
303  *      by GetMenuLabelGeometry since this height depends on the label
304  *      height.
305  *
306  * Results:
307  *      widthPtr and heightPtr point to the new geometry values.
308  *
309  * Side effects:
310  *      None.
311  *
312  *----------------------------------------------------------------------
313  */
314
315 static void
316 GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr, heightPtr)
317     TkMenu *menuPtr;                    /* The menu we are drawing. */
318     TkMenuEntry *mePtr;                 /* The entry we are interested in. */
319     Tk_Font tkfont;                     /* The precalculated font */
320     CONST Tk_FontMetrics *fmPtr;        /* The precalculated metrics */
321     int *widthPtr;                      /* The resulting width */
322     int *heightPtr;                     /* The resulting height */
323 {
324     if ((mePtr->type == CHECK_BUTTON_ENTRY)
325             || (mePtr->type == RADIO_BUTTON_ENTRY)) {
326         if (!mePtr->hideMargin && mePtr->indicatorOn) {
327             if ((mePtr->image != NULL) || (mePtr->bitmapPtr != NULL)) {
328                 *widthPtr = (14 * mePtr->height) / 10;
329                 *heightPtr = mePtr->height;
330                 if (mePtr->type == CHECK_BUTTON_ENTRY) {
331                     mePtr->platformEntryData = 
332                             (TkMenuPlatformEntryData) ((65 * mePtr->height)
333                             / 100);
334                 } else {
335                     mePtr->platformEntryData = 
336                             (TkMenuPlatformEntryData) ((75 * mePtr->height)
337                             / 100);
338                 }                   
339             } else {
340                 *widthPtr = *heightPtr = mePtr->height;
341                 if (mePtr->type == CHECK_BUTTON_ENTRY) {
342                     mePtr->platformEntryData = (TkMenuPlatformEntryData)
343                         ((80 * mePtr->height) / 100);
344                 } else {
345                     mePtr->platformEntryData = (TkMenuPlatformEntryData)
346                         mePtr->height;
347                 }
348             }
349         } else {
350             int borderWidth;
351
352             Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
353                     menuPtr->borderWidthPtr, &borderWidth);
354             *heightPtr = 0;
355             *widthPtr = borderWidth;
356         }
357     } else {
358         int borderWidth;
359
360         Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
361                 &borderWidth);
362         *heightPtr = 0;
363         *widthPtr = borderWidth;
364     }
365 }
366
367 \f
368 /*
369  *----------------------------------------------------------------------
370  *
371  * GetMenuAccelGeometry --
372  *
373  *      Get the geometry of the accelerator area of a menu item.
374  *
375  * Results:
376  *      heightPtr and widthPtr are set.
377  *
378  * Side effects:
379  *      None.
380  *
381  *----------------------------------------------------------------------
382  */
383
384 static void
385 GetMenuAccelGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr, heightPtr)
386     TkMenu *menuPtr;            /* The menu was are drawing */
387     TkMenuEntry *mePtr;         /* The entry we are getting the geometry for */
388     Tk_Font tkfont;             /* The precalculated font */
389     CONST Tk_FontMetrics *fmPtr;/* The precalculated font metrics */
390     int *widthPtr;              /* The width of the acclerator area */
391     int *heightPtr;             /* The height of the accelerator area */
392 {
393     *heightPtr = fmPtr->linespace;
394     if (mePtr->type == CASCADE_ENTRY) {
395         *widthPtr = 2 * CASCADE_ARROW_WIDTH;
396     } else if ((menuPtr->menuType != MENUBAR)
397             && (mePtr->accelPtr != NULL)) {
398         char *accel = Tcl_GetStringFromObj(mePtr->accelPtr, NULL);
399         
400         *widthPtr = Tk_TextWidth(tkfont, accel, mePtr->accelLength);
401     } else {
402         *widthPtr = 0;
403     }
404 }
405 \f
406 /*
407  *----------------------------------------------------------------------
408  *
409  * DrawMenuEntryBackground --
410  *
411  *      This procedure draws the background part of a menu.
412  *
413  * Results:
414  *      None.
415  *
416  * Side effects:
417  *      Commands are output to X to display the menu in its
418  *      current mode.
419  *
420  *----------------------------------------------------------------------
421  */
422
423 static void
424 DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder, bgBorder, x, y,
425         width, height)
426     TkMenu *menuPtr;            /* The menu we are drawing */
427     TkMenuEntry *mePtr;         /* The entry we are drawing. */
428     Drawable d;                 /* The drawable we are drawing into */
429     Tk_3DBorder activeBorder;   /* The border for an active item */
430     Tk_3DBorder bgBorder;       /* The background border */
431     int x;                      /* Left coordinate of entry rect */
432     int y;                      /* Right coordinate of entry rect */
433     int width;                  /* Width of entry rect */
434     int height;                 /* Height of entry rect */
435 {
436     if (mePtr->state == ENTRY_ACTIVE) {
437         int relief;
438         int activeBorderWidth;
439
440         bgBorder = activeBorder;
441
442         if ((menuPtr->menuType == MENUBAR)
443                 && ((menuPtr->postedCascade == NULL)
444                 || (menuPtr->postedCascade != mePtr))) {
445             relief = TK_RELIEF_FLAT;
446         } else {
447             relief = TK_RELIEF_RAISED;
448         }
449
450         Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
451                 menuPtr->activeBorderWidthPtr, &activeBorderWidth);
452         Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, x, y, width, height,
453                 activeBorderWidth, relief);
454     } else {
455         Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, x, y, width, height,
456                 0, TK_RELIEF_FLAT);
457     }
458 }
459 \f
460 /*
461  *----------------------------------------------------------------------
462  *
463  * DrawMenuEntryAccelerator --
464  *
465  *      This procedure draws the background part of a menu.
466  *
467  * Results:
468  *      None.
469  *
470  * Side effects:
471  *      Commands are output to X to display the menu in its
472  *      current mode.
473  *
474  *----------------------------------------------------------------------
475  */
476
477 static void
478 DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr, activeBorder,
479         x, y, width, height, drawArrow)
480     TkMenu *menuPtr;                    /* The menu we are drawing */
481     TkMenuEntry *mePtr;                 /* The entry we are drawing */
482     Drawable d;                         /* The drawable we are drawing into */
483     GC gc;                              /* The precalculated gc to draw with */
484     Tk_Font tkfont;                     /* The precalculated font */
485     CONST Tk_FontMetrics *fmPtr;        /* The precalculated metrics */
486     Tk_3DBorder activeBorder;           /* The border for an active item */
487     int x;                              /* Left coordinate of entry rect */
488     int y;                              /* Top coordinate of entry rect */
489     int width;                          /* Width of entry */
490     int height;                         /* Height of entry */
491     int drawArrow;                      /* Whether or not to draw arrow. */
492 {
493     XPoint points[3];
494     int borderWidth, activeBorderWidth;
495     
496     /*
497      * Draw accelerator or cascade arrow.
498      */
499
500     if (menuPtr->menuType == MENUBAR) {
501         return;
502     }
503
504     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
505             &borderWidth);
506     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr,
507             &activeBorderWidth);
508     if ((mePtr->type == CASCADE_ENTRY) && drawArrow) {
509         points[0].x = x + width - borderWidth - activeBorderWidth
510                 - CASCADE_ARROW_WIDTH;
511         points[0].y = y + (height - CASCADE_ARROW_HEIGHT)/2;
512         points[1].x = points[0].x;
513         points[1].y = points[0].y + CASCADE_ARROW_HEIGHT;
514         points[2].x = points[0].x + CASCADE_ARROW_WIDTH;
515         points[2].y = points[0].y + CASCADE_ARROW_HEIGHT/2;
516         Tk_Fill3DPolygon(menuPtr->tkwin, d, activeBorder, points, 3,
517                 DECORATION_BORDER_WIDTH,
518                 (menuPtr->postedCascade == mePtr)
519                 ? TK_RELIEF_SUNKEN : TK_RELIEF_RAISED);
520     } else if (mePtr->accelPtr != NULL) {
521         char *accel = Tcl_GetStringFromObj(mePtr->accelPtr, NULL);
522         int left = x + mePtr->labelWidth + activeBorderWidth
523                 + mePtr->indicatorSpace;
524         
525         if (menuPtr->menuType == MENUBAR) {
526             left += 5;
527         }
528         Tk_DrawChars(menuPtr->display, d, gc, tkfont, accel,
529                 mePtr->accelLength, left,
530                 (y + (height + fmPtr->ascent - fmPtr->descent) / 2));
531     }
532 }
533 \f
534 /*
535  *----------------------------------------------------------------------
536  *
537  * DrawMenuEntryIndicator --
538  *
539  *      This procedure draws the background part of a menu.
540  *
541  * Results:
542  *      None.
543  *
544  * Side effects:
545  *      Commands are output to X to display the menu in its
546  *      current mode.
547  *
548  *----------------------------------------------------------------------
549  */
550
551 static void
552 DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont, fmPtr,
553         x, y, width, height)
554     TkMenu *menuPtr;                    /* The menu we are drawing */
555     TkMenuEntry *mePtr;                 /* The entry we are drawing */
556     Drawable d;                         /* The drawable to draw into */
557     GC gc;                              /* The gc to draw with */
558     GC indicatorGC;                     /* The gc that indicators draw with */
559     Tk_Font tkfont;                     /* The font to draw with */
560     CONST Tk_FontMetrics *fmPtr;        /* The font metrics of the font */
561     int x;                              /* The left of the entry rect */
562     int y;                              /* The top of the entry rect */
563     int width;                          /* Width of menu entry */
564     int height;                         /* Height of menu entry */
565 {
566     /*
567      * Draw check-button indicator.
568      */
569
570     if ((mePtr->type == CHECK_BUTTON_ENTRY) && mePtr->indicatorOn) {
571         int dim, top, left;
572         int activeBorderWidth;
573         Tk_3DBorder border;
574         
575         dim = (int) mePtr->platformEntryData;
576         Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
577                 menuPtr->activeBorderWidthPtr, &activeBorderWidth);
578         left = x + activeBorderWidth + (mePtr->indicatorSpace - dim)/2;
579         if (menuPtr->menuType == MENUBAR) {
580             left += 5;
581         }
582         top = y + (height - dim)/2;
583         border = Tk_Get3DBorderFromObj(menuPtr->tkwin,
584                 menuPtr->borderPtr);
585         Tk_Fill3DRectangle(menuPtr->tkwin, d, border, left, top, dim,
586                 dim, DECORATION_BORDER_WIDTH, TK_RELIEF_SUNKEN);
587         left += DECORATION_BORDER_WIDTH;
588         top += DECORATION_BORDER_WIDTH;
589         dim -= 2*DECORATION_BORDER_WIDTH;
590         if ((dim > 0) && (mePtr->entryFlags
591                 & ENTRY_SELECTED)) {
592             XFillRectangle(menuPtr->display, d, indicatorGC, left, top,
593                     (unsigned int) dim, (unsigned int) dim);
594         }
595     }
596
597     /*
598      * Draw radio-button indicator.
599      */
600
601     if ((mePtr->type == RADIO_BUTTON_ENTRY) && mePtr->indicatorOn) {
602         XPoint points[4];
603         int radius;
604         Tk_3DBorder border;
605
606         border = Tk_Get3DBorderFromObj(menuPtr->tkwin, 
607                 menuPtr->borderPtr);
608         radius = ((int) mePtr->platformEntryData)/2;
609         points[0].x = x + (mePtr->indicatorSpace
610                 - (int) mePtr->platformEntryData)/2;
611         points[0].y = y + (height)/2;
612         points[1].x = points[0].x + radius;
613         points[1].y = points[0].y + radius;
614         points[2].x = points[1].x + radius;
615         points[2].y = points[0].y;
616         points[3].x = points[1].x;
617         points[3].y = points[0].y - radius;
618         if (mePtr->entryFlags & ENTRY_SELECTED) {
619             XFillPolygon(menuPtr->display, d, indicatorGC, points, 4,
620                     Convex, CoordModeOrigin);
621         } else {
622             Tk_Fill3DPolygon(menuPtr->tkwin, d, border, points, 4,
623                     DECORATION_BORDER_WIDTH, TK_RELIEF_FLAT);
624         }
625         Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 4,
626                 DECORATION_BORDER_WIDTH, TK_RELIEF_SUNKEN);
627     }
628 }
629 \f
630 /*
631  *----------------------------------------------------------------------
632  *
633  * DrawMenuSeparator --
634  *
635  *      This procedure draws a separator menu item.
636  *
637  * Results:
638  *      None.
639  *
640  * Side effects:
641  *      Commands are output to X to display the menu in its
642  *      current mode.
643  *
644  *----------------------------------------------------------------------
645  */
646
647 static void
648 DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height)
649     TkMenu *menuPtr;                    /* The menu we are drawing */
650     TkMenuEntry *mePtr;                 /* The entry we are drawing */
651     Drawable d;                         /* The drawable we are using */
652     GC gc;                              /* The gc to draw into */
653     Tk_Font tkfont;                     /* The font to draw with */
654     CONST Tk_FontMetrics *fmPtr;        /* The font metrics from the font */
655     int x;
656     int y;
657     int width;
658     int height;
659 {
660     XPoint points[2];
661     Tk_3DBorder border;
662
663     if (menuPtr->menuType == MENUBAR) {
664         return;
665     }
666     
667     points[0].x = x;
668     points[0].y = y + height/2;
669     points[1].x = width - 1;
670     points[1].y = points[0].y;
671     border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr);
672     Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 2, 1,
673             TK_RELIEF_RAISED);
674 }
675 \f
676 /*
677  *----------------------------------------------------------------------
678  *
679  * DrawMenuEntryLabel --
680  *
681  *      This procedure draws the label part of a menu.
682  *
683  * Results:
684  *      None.
685  *
686  * Side effects:
687  *      Commands are output to X to display the menu in its
688  *      current mode.
689  *
690  *----------------------------------------------------------------------
691  */
692
693 static void
694 DrawMenuEntryLabel(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height)
695     TkMenu *menuPtr;            /* The menu we are drawing. */
696     TkMenuEntry *mePtr;         /* The entry we are drawing. */
697     Drawable d;                 /* What we are drawing into. */
698     GC gc;                      /* The gc we are drawing into.*/
699     Tk_Font tkfont;             /* The precalculated font. */
700     CONST Tk_FontMetrics *fmPtr;/* The precalculated font metrics. */
701     int x;                      /* Left edge. */
702     int y;                      /* Top edge. */
703     int width;                  /* width of entry. */
704     int height;                 /* height of entry. */
705 {
706     int baseline;
707     int indicatorSpace =  mePtr->indicatorSpace;
708     int activeBorderWidth;
709     int leftEdge;
710     int imageHeight, imageWidth;
711
712     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr,
713             &activeBorderWidth);
714     leftEdge = x + indicatorSpace + activeBorderWidth;
715     if (menuPtr->menuType == MENUBAR) {
716         leftEdge += 5;
717     }
718     
719     /*
720      * Draw label or bitmap or image for entry.
721      */
722
723     baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2;
724     if (mePtr->image != NULL) {
725         Tk_SizeOfImage(mePtr->image, &imageWidth, &imageHeight);
726         if ((mePtr->selectImage != NULL)
727                 && (mePtr->entryFlags & ENTRY_SELECTED)) {
728             Tk_RedrawImage(mePtr->selectImage, 0, 0,
729                     imageWidth, imageHeight, d, leftEdge,
730                     (int) (y + (mePtr->height - imageHeight)/2));
731         } else {
732             Tk_RedrawImage(mePtr->image, 0, 0, imageWidth,
733                     imageHeight, d, leftEdge,
734                     (int) (y + (mePtr->height - imageHeight)/2));
735         }
736     } else if (mePtr->bitmapPtr != None) {
737         int width, height;
738         Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr);
739         Tk_SizeOfBitmap(menuPtr->display,bitmap, &width, &height);
740         XCopyPlane(menuPtr->display, bitmap, d, gc, 0, 0, (unsigned) width,
741                 (unsigned) height, leftEdge,
742                 (int) (y + (mePtr->height - height)/2), 1);
743     } else {
744         if (mePtr->labelLength > 0) {
745             char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL);
746             Tk_DrawChars(menuPtr->display, d, gc, tkfont, label,
747                     mePtr->labelLength, leftEdge, baseline);
748             DrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y,
749                     width, height);
750         }
751     }
752
753     if (mePtr->state == ENTRY_DISABLED) {
754         if (menuPtr->disabledFgPtr == NULL) {
755             XFillRectangle(menuPtr->display, d, menuPtr->disabledGC, x, y,
756                     (unsigned) width, (unsigned) height);
757         } else if ((mePtr->image != NULL) 
758                 && (menuPtr->disabledImageGC != None)) {
759             XFillRectangle(menuPtr->display, d, menuPtr->disabledImageGC,
760                     leftEdge,
761                     (int) (y + (mePtr->height - imageHeight)/2),
762                     (unsigned) imageWidth, (unsigned) imageHeight);
763         }
764     }
765 }
766 \f
767 /*
768  *----------------------------------------------------------------------
769  *
770  * DrawMenuUnderline --
771  *
772  *      On appropriate platforms, draw the underline character for the
773  *      menu.
774  *
775  * Results:
776  *      None.
777  *
778  * Side effects:
779  *      Commands are output to X to display the menu in its
780  *      current mode.
781  *
782  *----------------------------------------------------------------------
783  */
784
785 static void
786 DrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height)
787     TkMenu *menuPtr;                    /* The menu to draw into */
788     TkMenuEntry *mePtr;                 /* The entry we are drawing */
789     Drawable d;                         /* What we are drawing into */
790     GC gc;                              /* The gc to draw into */
791     Tk_Font tkfont;                     /* The precalculated font */
792     CONST Tk_FontMetrics *fmPtr;        /* The precalculated font metrics */
793     int x;
794     int y;
795     int width;
796     int height;
797 {
798     int indicatorSpace = mePtr->indicatorSpace;
799
800     if (mePtr->underline >= 0) {
801         int activeBorderWidth;
802         int leftEdge;
803         char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL);
804         char *start = Tcl_UtfAtIndex(label, mePtr->underline);
805         char *end = Tcl_UtfNext(start);
806
807         Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
808                 menuPtr->activeBorderWidthPtr, &activeBorderWidth);
809         leftEdge = x + indicatorSpace + activeBorderWidth;
810         if (menuPtr->menuType == MENUBAR) {
811             leftEdge += 5;
812         }
813
814         Tk_UnderlineChars(menuPtr->display, d, gc, tkfont, label,
815                 leftEdge, y + (height + fmPtr->ascent - fmPtr->descent) / 2,
816                 start - label, end - label);
817     }           
818 }
819 \f
820 /*
821  *----------------------------------------------------------------------
822  *
823  * TkpPostMenu --
824  *
825  *      Posts a menu on the screen
826  *
827  * Results:
828  *      None.
829  *
830  * Side effects:
831  *      The menu is posted and handled.
832  *
833  *----------------------------------------------------------------------
834  */
835
836 int
837 TkpPostMenu(interp, menuPtr, x, y)
838     Tcl_Interp *interp;
839     TkMenu *menuPtr;
840     int x;
841     int y;
842 {
843     return TkPostTearoffMenu(interp, menuPtr, x, y);
844 }
845 \f
846 /*
847  *----------------------------------------------------------------------
848  *
849  * GetMenuSeparatorGeometry --
850  *
851  *      Gets the width and height of the indicator area of a menu.
852  *
853  * Results:
854  *      widthPtr and heightPtr are set.
855  *
856  * Side effects:
857  *      None.
858  *
859  *----------------------------------------------------------------------
860  */
861
862 static void
863 GetMenuSeparatorGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr,
864         heightPtr) 
865     TkMenu *menuPtr;                    /* The menu we are measuring */
866     TkMenuEntry *mePtr;                 /* The entry we are measuring */
867     Tk_Font tkfont;                     /* The precalculated font */
868     CONST Tk_FontMetrics *fmPtr;        /* The precalcualted font metrics */
869     int *widthPtr;                      /* The resulting width */
870     int *heightPtr;                     /* The resulting height */
871 {
872     *widthPtr = 0;
873     *heightPtr = fmPtr->linespace;
874 }
875 \f
876 /*
877  *----------------------------------------------------------------------
878  *
879  * GetTearoffEntryGeometry --
880  *
881  *      Gets the width and height of the indicator area of a menu.
882  *
883  * Results:
884  *      widthPtr and heightPtr are set.
885  *
886  * Side effects:
887  *      None.
888  *
889  *----------------------------------------------------------------------
890  */
891
892 static void
893 GetTearoffEntryGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr, heightPtr)
894     TkMenu *menuPtr;                    /* The menu we are drawing */
895     TkMenuEntry *mePtr;                 /* The entry we are measuring */
896     Tk_Font tkfont;                     /* The precalculated font */
897     CONST Tk_FontMetrics *fmPtr;        /* The precalculated font metrics */
898     int *widthPtr;                      /* The resulting width */
899     int *heightPtr;                     /* The resulting height */
900 {
901     if (menuPtr->menuType != MASTER_MENU) {
902         *heightPtr = 0;
903         *widthPtr = 0;
904     } else {
905         *heightPtr = fmPtr->linespace;
906         *widthPtr = Tk_TextWidth(tkfont, "W", 1);
907     }
908 }
909 \f
910 /*
911  *--------------------------------------------------------------
912  *
913  * TkpComputeMenubarGeometry --
914  *
915  *      This procedure is invoked to recompute the size and
916  *      layout of a menu that is a menubar clone.
917  *
918  * Results:
919  *      None.
920  *
921  * Side effects:
922  *      Fields of menu entries are changed to reflect their
923  *      current positions, and the size of the menu window
924  *      itself may be changed.
925  *
926  *--------------------------------------------------------------
927  */
928
929 void
930 TkpComputeMenubarGeometry(menuPtr)
931     TkMenu *menuPtr;            /* Structure describing menu. */
932 {
933     Tk_Font tkfont;
934     Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr;
935     int width, height;
936     int i, j;
937     int x, y, currentRowHeight, maxWidth;
938     int maxWindowWidth;
939     int lastRowBreak;
940     int helpMenuIndex = -1;
941     TkMenuEntry *mePtr;
942     int lastEntry;
943     Tk_Font menuFont;
944     int borderWidth;
945     int activeBorderWidth;
946     
947     if (menuPtr->tkwin == NULL) {
948         return;
949     }
950
951     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
952             &borderWidth);
953     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr,
954             &activeBorderWidth);
955     maxWidth = 0;
956     if (menuPtr->numEntries == 0) {
957         height = 0;
958     } else {
959         int borderWidth;
960         
961         maxWindowWidth = Tk_Width(menuPtr->tkwin);
962         if (maxWindowWidth == 1) {
963             maxWindowWidth = 0x7ffffff;
964         }
965         currentRowHeight = 0;
966         Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
967                 &borderWidth);
968         x = y = borderWidth;
969         lastRowBreak = 0;
970         
971         /*
972          * On the Mac especially, getting font metrics can be quite slow,
973          * so we want to do it intelligently. We are going to precalculate
974          * them and pass them down to all of the measureing and drawing
975          * routines. We will measure the font metrics of the menu once,
976          * and if an entry has a font set, we will measure it as we come
977          * to it, and then we decide which set to give the geometry routines.
978          */
979
980         menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr);
981         Tk_GetFontMetrics(menuFont, &menuMetrics);
982         
983         for (i = 0; i < menuPtr->numEntries; i++) {
984             mePtr = menuPtr->entries[i];
985             mePtr->entryFlags &= ~ENTRY_LAST_COLUMN;
986             if (mePtr->fontPtr != NULL) {
987                 tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr);
988                 Tk_GetFontMetrics(tkfont, &entryMetrics);
989                 fmPtr = &entryMetrics;
990             } else {
991                 tkfont = menuFont;
992                 fmPtr = &menuMetrics;
993             }
994
995             /*
996              * For every entry, we need to check to see whether or not we
997              * wrap. If we do wrap, then we have to adjust all of the previous
998              * entries' height and y position, because when we see them
999              * the first time, we don't know how big its neighbor might
1000              * be.
1001              */
1002             
1003             if ((mePtr->type == SEPARATOR_ENTRY)
1004                     || (mePtr->type == TEAROFF_ENTRY)) {
1005                 mePtr->height = mePtr->width = 0;
1006             } else {
1007                 GetMenuLabelGeometry(mePtr, tkfont, fmPtr, &width, &height);
1008                 mePtr->height = height + 2 * activeBorderWidth + 10;
1009                 mePtr->width = width;
1010
1011                 GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont, fmPtr,
1012                         &width, &height);
1013                 mePtr->indicatorSpace = width;
1014                 if (width > 0) {
1015                     mePtr->width += width;
1016                 }
1017                 mePtr->width += 2 * activeBorderWidth + 10;
1018             }
1019             if (mePtr->entryFlags & ENTRY_HELP_MENU) {
1020                 helpMenuIndex = i;
1021             } else if (x + mePtr->width + borderWidth > maxWindowWidth) {
1022
1023                 if (i == lastRowBreak) {
1024                     mePtr->y = y;
1025                     mePtr->x = x;
1026                     lastRowBreak++;
1027                     y += mePtr->height;
1028                     currentRowHeight = 0;
1029                 } else {
1030                     x = borderWidth;
1031                     for (j = lastRowBreak; j < i; j++) {
1032                         menuPtr->entries[j]->y = y + currentRowHeight
1033                                 - menuPtr->entries[j]->height;
1034                         menuPtr->entries[j]->x = x;
1035                         x += menuPtr->entries[j]->width;
1036                     }
1037                     lastRowBreak = i;
1038                     y += currentRowHeight;
1039                     currentRowHeight = mePtr->height;
1040                 }
1041                 if (x > maxWidth) {
1042                     maxWidth = x;
1043                 }
1044                 x = borderWidth;
1045             } else {
1046                 x += mePtr->width;
1047                 if (mePtr->height > currentRowHeight) {
1048                     currentRowHeight = mePtr->height;
1049                 }
1050             } 
1051         }
1052
1053         lastEntry = menuPtr->numEntries - 1;
1054         if (helpMenuIndex == lastEntry) {
1055             lastEntry--;
1056         }
1057         if ((lastEntry >= 0) && (x + menuPtr->entries[lastEntry]->width
1058                 + borderWidth > maxWidth)) {
1059             maxWidth = x + menuPtr->entries[lastEntry]->width + borderWidth;
1060         }
1061         x = borderWidth;
1062         for (j = lastRowBreak; j < menuPtr->numEntries; j++) {
1063             if (j == helpMenuIndex) {
1064                 continue;
1065             }
1066             menuPtr->entries[j]->y = y + currentRowHeight
1067                     - menuPtr->entries[j]->height;
1068             menuPtr->entries[j]->x = x;
1069             x += menuPtr->entries[j]->width;
1070         }
1071         
1072
1073         if (helpMenuIndex != -1) {
1074             mePtr = menuPtr->entries[helpMenuIndex];
1075             if (x + mePtr->width + borderWidth > maxWindowWidth) {
1076                 y += currentRowHeight;
1077                 currentRowHeight = mePtr->height;
1078                 x = borderWidth;
1079             } else if (mePtr->height > currentRowHeight) {
1080                 currentRowHeight = mePtr->height;
1081             }
1082             mePtr->x = maxWindowWidth - borderWidth - mePtr->width;
1083             mePtr->y = y + currentRowHeight - mePtr->height;
1084         }
1085         height = y + currentRowHeight + borderWidth;
1086     }
1087     width = Tk_Width(menuPtr->tkwin);    
1088
1089     /*
1090      * The X server doesn't like zero dimensions, so round up to at least
1091      * 1 (a zero-sized menu should never really occur, anyway).
1092      */
1093
1094     if (width <= 0) {
1095         width = 1;
1096     }
1097     if (height <= 0) {
1098         height = 1;
1099     }
1100     menuPtr->totalWidth = maxWidth;
1101     menuPtr->totalHeight = height;
1102 }
1103 \f
1104 /*
1105  *----------------------------------------------------------------------
1106  *
1107  * DrawTearoffEntry --
1108  *
1109  *      This procedure draws the background part of a menu.
1110  *
1111  * Results:
1112  *      None.
1113  *
1114  * Side effects:
1115  *      Commands are output to X to display the menu in its
1116  *      current mode.
1117  *
1118  *----------------------------------------------------------------------
1119  */
1120
1121 static void
1122 DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height)
1123     TkMenu *menuPtr;                    /* The menu we are drawing */
1124     TkMenuEntry *mePtr;                 /* The entry we are drawing */
1125     Drawable d;                         /* The drawable we are drawing into */
1126     GC gc;                              /* The gc we are drawing with */
1127     Tk_Font tkfont;                     /* The font we are drawing with */
1128     CONST Tk_FontMetrics *fmPtr;        /* The metrics we are drawing with */
1129     int x;
1130     int y;
1131     int width;
1132     int height;
1133 {
1134     XPoint points[2];
1135     int segmentWidth, maxX;
1136     Tk_3DBorder border;
1137
1138     if (menuPtr->menuType != MASTER_MENU) {
1139         return;
1140     }
1141     
1142     points[0].x = x;
1143     points[0].y = y + height/2;
1144     points[1].y = points[0].y;
1145     segmentWidth = 6;
1146     maxX  = width - 1;
1147     border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr);
1148
1149     while (points[0].x < maxX) {
1150         points[1].x = points[0].x + segmentWidth;
1151         if (points[1].x > maxX) {
1152             points[1].x = maxX;
1153         }
1154         Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 2, 1,
1155                 TK_RELIEF_RAISED);
1156         points[0].x += 2 * segmentWidth;
1157     }
1158 }
1159 \f
1160 /*
1161  *--------------------------------------------------------------
1162  *
1163  * TkpInitializeMenuBindings --
1164  *
1165  *      For every interp, initializes the bindings for Windows
1166  *      menus. Does nothing on Mac or XWindows.
1167  *
1168  * Results:
1169  *      None.
1170  *
1171  * Side effects:
1172  *      C-level bindings are setup for the interp which will
1173  *      handle Alt-key sequences for menus without beeping
1174  *      or interfering with user-defined Alt-key bindings.
1175  *
1176  *--------------------------------------------------------------
1177  */
1178
1179 void
1180 TkpInitializeMenuBindings(interp, bindingTable)
1181     Tcl_Interp *interp;             /* The interpreter to set. */
1182     Tk_BindingTable bindingTable;   /* The table to add to. */
1183 {
1184     /*
1185      * Nothing to do.
1186      */
1187 }
1188 \f
1189 /*
1190  *----------------------------------------------------------------------
1191  *
1192  * SetHelpMenu --
1193  *
1194  *      Given a menu, check to see whether or not it is a help menu
1195  *      cascade in a menubar. If it is, the entry that points to
1196  *      this menu will be marked.
1197  *
1198  * RESULTS:
1199  *      None.
1200  *
1201  * Side effects:
1202  *      Will set the ENTRY_HELP_MENU flag appropriately.
1203  *
1204  *----------------------------------------------------------------------
1205  */
1206
1207 static void
1208 SetHelpMenu(menuPtr)
1209      TkMenu *menuPtr;           /* The menu we are checking */
1210 {
1211     TkMenuEntry *cascadeEntryPtr;
1212
1213     for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr;
1214             cascadeEntryPtr != NULL;
1215             cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) {
1216         if ((cascadeEntryPtr->menuPtr->menuType == MENUBAR)
1217                 && (cascadeEntryPtr->menuPtr->masterMenuPtr->tkwin != NULL)
1218                 && (menuPtr->masterMenuPtr->tkwin != NULL)) {
1219             TkMenu *masterMenuPtr = cascadeEntryPtr->menuPtr->masterMenuPtr;
1220             char *helpMenuName = ckalloc(strlen(Tk_PathName(
1221                     masterMenuPtr->tkwin)) + strlen(".help") + 1);
1222
1223             strcpy(helpMenuName, Tk_PathName(masterMenuPtr->tkwin));
1224             strcat(helpMenuName, ".help");
1225             if (strcmp(helpMenuName,
1226                     Tk_PathName(menuPtr->masterMenuPtr->tkwin)) == 0) {
1227                 cascadeEntryPtr->entryFlags |= ENTRY_HELP_MENU;
1228             } else {
1229                 cascadeEntryPtr->entryFlags &= ~ENTRY_HELP_MENU;
1230             }
1231             ckfree(helpMenuName);
1232         }
1233     }
1234 }
1235 \f
1236 /*
1237  *----------------------------------------------------------------------
1238  *
1239  * TkpDrawMenuEntry --
1240  *
1241  *      Draws the given menu entry at the given coordinates with the
1242  *      given attributes.
1243  *
1244  * Results:
1245  *      None.
1246  *
1247  * Side effects:
1248  *      X Server commands are executed to display the menu entry.
1249  *
1250  *----------------------------------------------------------------------
1251  */
1252
1253 void
1254 TkpDrawMenuEntry(mePtr, d, tkfont, menuMetricsPtr, x, y, width, height, 
1255         strictMotif, drawArrow)
1256     TkMenuEntry *mePtr;             /* The entry to draw */
1257     Drawable d;                     /* What to draw into */
1258     Tk_Font tkfont;                 /* Precalculated font for menu */
1259     CONST Tk_FontMetrics *menuMetricsPtr;
1260                                     /* Precalculated metrics for menu */
1261     int x;                          /* X-coordinate of topleft of entry */
1262     int y;                          /* Y-coordinate of topleft of entry */
1263     int width;                      /* Width of the entry rectangle */
1264     int height;                     /* Height of the current rectangle */
1265     int strictMotif;                /* Boolean flag */
1266     int drawArrow;                  /* Whether or not to draw the cascade
1267                                      * arrow for cascade items. Only applies
1268                                      * to Windows. */
1269 {
1270     GC gc, indicatorGC;
1271     TkMenu *menuPtr = mePtr->menuPtr;
1272     Tk_3DBorder bgBorder, activeBorder;
1273     CONST Tk_FontMetrics *fmPtr;
1274     Tk_FontMetrics entryMetrics;
1275     int padY = (menuPtr->menuType == MENUBAR) ? 3 : 0;
1276     int adjustedY = y + padY;
1277     int adjustedHeight = height - 2 * padY;
1278
1279     /*
1280      * Choose the gc for drawing the foreground part of the entry.
1281      */
1282
1283     if ((mePtr->state == ENTRY_ACTIVE) && !strictMotif) {
1284         gc = mePtr->activeGC;
1285         if (gc == NULL) {
1286             gc = menuPtr->activeGC;
1287         }
1288     } else {
1289         TkMenuEntry *cascadeEntryPtr;
1290         int parentDisabled = 0;
1291         
1292         for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr;
1293                 cascadeEntryPtr != NULL;
1294                 cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) {
1295             if (cascadeEntryPtr->namePtr != NULL) {
1296                 char *name = Tcl_GetStringFromObj(cascadeEntryPtr->namePtr,
1297                         NULL);
1298
1299                 if (strcmp(name, Tk_PathName(menuPtr->tkwin)) == 0) {
1300                     if (cascadeEntryPtr->state == ENTRY_DISABLED) {
1301                         parentDisabled = 1;
1302                     }
1303                     break;
1304                 }
1305             }
1306         }
1307
1308         if (((parentDisabled || (mePtr->state == ENTRY_DISABLED)))
1309                 && (menuPtr->disabledFgPtr != NULL)) {
1310             gc = mePtr->disabledGC;
1311             if (gc == NULL) {
1312                 gc = menuPtr->disabledGC;
1313             }
1314         } else {
1315             gc = mePtr->textGC;
1316             if (gc == NULL) {
1317                 gc = menuPtr->textGC;
1318             }
1319         }
1320     }
1321     indicatorGC = mePtr->indicatorGC;
1322     if (indicatorGC == NULL) {
1323         indicatorGC = menuPtr->indicatorGC;
1324     }
1325
1326     bgBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin,
1327             (mePtr->borderPtr == NULL)
1328             ? menuPtr->borderPtr : mePtr->borderPtr);
1329     if (strictMotif) {
1330         activeBorder = bgBorder;
1331     } else {
1332         activeBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin,
1333             (mePtr->activeBorderPtr == NULL)
1334             ? menuPtr->activeBorderPtr : mePtr->activeBorderPtr);
1335     }
1336
1337     if (mePtr->fontPtr == NULL) {
1338         fmPtr = menuMetricsPtr;
1339     } else {
1340         tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr);
1341         Tk_GetFontMetrics(tkfont, &entryMetrics);
1342         fmPtr = &entryMetrics;
1343     }
1344
1345     /*
1346      * Need to draw the entire background, including padding. On Unix,
1347      * for menubars, we have to draw the rest of the entry taking
1348      * into account the padding.
1349      */
1350     
1351     DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder, 
1352             bgBorder, x, y, width, height);
1353     
1354     if (mePtr->type == SEPARATOR_ENTRY) {
1355         DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, 
1356                 fmPtr, x, adjustedY, width, adjustedHeight);
1357     } else if (mePtr->type == TEAROFF_ENTRY) {
1358         DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY,
1359                 width, adjustedHeight);
1360     } else {
1361         DrawMenuEntryLabel(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY,
1362                 width, adjustedHeight);
1363         DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr,
1364                 activeBorder, x, adjustedY, width, adjustedHeight, drawArrow);
1365         if (!mePtr->hideMargin) {
1366             DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont,
1367                     fmPtr, x, adjustedY, width, adjustedHeight);
1368         }
1369     }
1370 }
1371 \f
1372 /*
1373  *----------------------------------------------------------------------
1374  *
1375  * GetMenuLabelGeometry --
1376  *
1377  *      Figures out the size of the label portion of a menu item.
1378  *
1379  * Results:
1380  *      widthPtr and heightPtr are filled in with the correct geometry
1381  *      information.
1382  *
1383  * Side effects:
1384  *      None.
1385  *
1386  *----------------------------------------------------------------------
1387  */
1388
1389 static void
1390 GetMenuLabelGeometry(mePtr, tkfont, fmPtr, widthPtr, heightPtr)
1391     TkMenuEntry *mePtr;                 /* The entry we are computing */
1392     Tk_Font tkfont;                     /* The precalculated font */
1393     CONST Tk_FontMetrics *fmPtr;        /* The precalculated metrics */
1394     int *widthPtr;                      /* The resulting width of the label
1395                                          * portion */
1396     int *heightPtr;                     /* The resulting height of the label
1397                                          * portion */
1398 {
1399     TkMenu *menuPtr = mePtr->menuPtr;
1400  
1401     if (mePtr->image != NULL) {
1402         Tk_SizeOfImage(mePtr->image, widthPtr, heightPtr);
1403     } else if (mePtr->bitmapPtr !=  NULL) {
1404         Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr);
1405         Tk_SizeOfBitmap(menuPtr->display, bitmap, widthPtr, heightPtr);
1406     } else {
1407         *heightPtr = fmPtr->linespace;
1408         
1409         if (mePtr->labelPtr != NULL) {
1410             char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL);
1411             
1412             *widthPtr = Tk_TextWidth(tkfont, label, mePtr->labelLength);
1413         } else {
1414             *widthPtr = 0;
1415         }
1416     }
1417     *heightPtr += 1;
1418 }
1419 \f
1420 /*
1421  *--------------------------------------------------------------
1422  *
1423  * TkpComputeStandardMenuGeometry --
1424  *
1425  *      This procedure is invoked to recompute the size and
1426  *      layout of a menu that is not a menubar clone.
1427  *
1428  * Results:
1429  *      None.
1430  *
1431  * Side effects:
1432  *      Fields of menu entries are changed to reflect their
1433  *      current positions, and the size of the menu window
1434  *      itself may be changed.
1435  *
1436  *--------------------------------------------------------------
1437  */
1438
1439 void
1440 TkpComputeStandardMenuGeometry(
1441     menuPtr)            /* Structure describing menu. */
1442     TkMenu *menuPtr;
1443 {
1444     Tk_Font tkfont, menuFont;
1445     Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr;
1446     int x, y, height, width, indicatorSpace, labelWidth, accelWidth;
1447     int windowWidth, windowHeight, accelSpace;
1448     int i, j, lastColumnBreak = 0;
1449     TkMenuEntry *mePtr;
1450     int borderWidth, activeBorderWidth;
1451     
1452     if (menuPtr->tkwin == NULL) {
1453         return;
1454     }
1455
1456     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
1457             &borderWidth);
1458     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr,
1459             &activeBorderWidth);
1460     x = y = borderWidth;
1461     indicatorSpace = labelWidth = accelWidth = 0;
1462     windowHeight = windowWidth = 0;
1463
1464     /*
1465      * On the Mac especially, getting font metrics can be quite slow,
1466      * so we want to do it intelligently. We are going to precalculate
1467      * them and pass them down to all of the measuring and drawing
1468      * routines. We will measure the font metrics of the menu once.
1469      * If an entry does not have its own font set, then we give
1470      * the geometry/drawing routines the menu's font and metrics.
1471      * If an entry has its own font, we will measure that font and
1472      * give all of the geometry/drawing the entry's font and metrics.
1473      */
1474
1475     menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr);
1476     Tk_GetFontMetrics(menuFont, &menuMetrics);
1477     accelSpace = Tk_TextWidth(menuFont, "M", 1);
1478
1479     for (i = 0; i < menuPtr->numEntries; i++) {
1480         mePtr = menuPtr->entries[i];
1481         if (mePtr->fontPtr == NULL) {
1482             tkfont = menuFont;
1483             fmPtr = &menuMetrics;
1484         } else {
1485             tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr);
1486             Tk_GetFontMetrics(tkfont, &entryMetrics);
1487             fmPtr = &entryMetrics;
1488         }
1489
1490         if ((i > 0) && mePtr->columnBreak) {
1491             if (accelWidth != 0) {
1492                 labelWidth += accelSpace;
1493             }
1494             for (j = lastColumnBreak; j < i; j++) {
1495                 menuPtr->entries[j]->indicatorSpace = indicatorSpace;
1496                 menuPtr->entries[j]->labelWidth = labelWidth;
1497                 menuPtr->entries[j]->width = indicatorSpace + labelWidth
1498                         + accelWidth + 2 * activeBorderWidth;
1499                 menuPtr->entries[j]->x = x;
1500                 menuPtr->entries[j]->entryFlags &= ~ENTRY_LAST_COLUMN;
1501             }
1502             x += indicatorSpace + labelWidth + accelWidth
1503                     + 2 * activeBorderWidth;
1504             windowWidth = x;
1505             indicatorSpace = labelWidth = accelWidth = 0;
1506             lastColumnBreak = i;
1507             y = borderWidth;
1508         }
1509
1510         if (mePtr->type == SEPARATOR_ENTRY) {
1511             GetMenuSeparatorGeometry(menuPtr, mePtr, tkfont,
1512                     fmPtr, &width, &height);
1513             mePtr->height = height;
1514         } else if (mePtr->type == TEAROFF_ENTRY) {
1515             GetTearoffEntryGeometry(menuPtr, mePtr, tkfont, 
1516                     fmPtr, &width, &height);
1517             mePtr->height = height;
1518             labelWidth = width;
1519         } else {
1520             
1521             /*
1522              * For each entry, compute the height required by that
1523              * particular entry, plus three widths:  the width of the
1524              * label, the width to allow for an indicator to be displayed
1525              * to the left of the label (if any), and the width of the
1526              * accelerator to be displayed to the right of the label
1527              * (if any).  These sizes depend, of course, on the type
1528              * of the entry.
1529              */
1530             
1531             GetMenuLabelGeometry(mePtr, tkfont, fmPtr, &width,
1532                     &height);
1533             mePtr->height = height;
1534             if (!mePtr->hideMargin) {
1535                 width += MENU_MARGIN_WIDTH;
1536             }
1537             if (width > labelWidth) {
1538                 labelWidth = width;
1539             }
1540         
1541             GetMenuAccelGeometry(menuPtr, mePtr, tkfont,
1542                     fmPtr, &width, &height);
1543             if (height > mePtr->height) {
1544                 mePtr->height = height;
1545             }
1546             if (!mePtr->hideMargin) {
1547                 width += MENU_MARGIN_WIDTH;
1548             }
1549             if (width > accelWidth) {
1550                 accelWidth = width;
1551             }
1552
1553             GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont, 
1554                     fmPtr, &width, &height);
1555             if (height > mePtr->height) {
1556                 mePtr->height = height;
1557             }
1558             if (!mePtr->hideMargin) {
1559                 width += MENU_MARGIN_WIDTH;
1560             }
1561             if (width > indicatorSpace) {
1562                 indicatorSpace = width;
1563             }
1564
1565             mePtr->height += 2 * activeBorderWidth + MENU_DIVIDER_HEIGHT;
1566         }
1567         mePtr->y = y;
1568         y += mePtr->height;
1569         if (y > windowHeight) {
1570             windowHeight = y;
1571         }
1572     }
1573
1574     if (accelWidth != 0) {
1575         labelWidth += accelSpace;
1576     }
1577     for (j = lastColumnBreak; j < menuPtr->numEntries; j++) {
1578         menuPtr->entries[j]->indicatorSpace = indicatorSpace;
1579         menuPtr->entries[j]->labelWidth = labelWidth;
1580         menuPtr->entries[j]->width = indicatorSpace + labelWidth
1581                 + accelWidth + 2 * activeBorderWidth;
1582         menuPtr->entries[j]->x = x;
1583         menuPtr->entries[j]->entryFlags |= ENTRY_LAST_COLUMN;
1584     }
1585     windowWidth = x + indicatorSpace + labelWidth + accelWidth
1586             + 2 * activeBorderWidth + 2 * borderWidth;
1587
1588
1589     windowHeight += borderWidth;
1590     
1591     /*
1592      * The X server doesn't like zero dimensions, so round up to at least
1593      * 1 (a zero-sized menu should never really occur, anyway).
1594      */
1595
1596     if (windowWidth <= 0) {
1597         windowWidth = 1;
1598     }
1599     if (windowHeight <= 0) {
1600         windowHeight = 1;
1601     }
1602     menuPtr->totalWidth = windowWidth;
1603     menuPtr->totalHeight = windowHeight;
1604 }
1605 \f
1606 /*
1607  *----------------------------------------------------------------------
1608  *
1609  * TkpMenuNotifyToplevelCreate --
1610  *
1611  *      This routine reconfigures the menu and the clones indicated by
1612  *      menuName becuase a toplevel has been created and any system
1613  *      menus need to be created. Not applicable to UNIX.
1614  *
1615  * Results:
1616  *      None.
1617  *
1618  * Side effects:
1619  *      An idle handler is set up to do the reconfiguration.
1620  *
1621  *----------------------------------------------------------------------
1622  */
1623
1624 void
1625 TkpMenuNotifyToplevelCreate(interp, menuName)
1626     Tcl_Interp *interp;                 /* The interp the menu lives in. */
1627     char *menuName;                     /* The name of the menu to 
1628                                          * reconfigure. */
1629 {
1630     /*
1631      * Nothing to do.
1632      */
1633 }
1634 \f
1635 /*
1636  *----------------------------------------------------------------------
1637  *
1638  * TkpMenuInit --
1639  *
1640  *      Does platform-specific initialization of menus.
1641  *
1642  * Results:
1643  *      None.
1644  *
1645  * Side effects:
1646  *      None.
1647  *
1648  *----------------------------------------------------------------------
1649  */
1650
1651 void
1652 TkpMenuInit()
1653 {
1654     /*
1655      * Nothing to do.
1656      */
1657 }
1658
1659 \f
1660 /*
1661  *----------------------------------------------------------------------
1662  *
1663  * TkpMenuThreadInit --
1664  *
1665  *      Does platform-specific initialization of thread-specific
1666  *      menu state.
1667  *
1668  * Results:
1669  *      None.
1670  *
1671  * Side effects:
1672  *      None.
1673  *
1674  *----------------------------------------------------------------------
1675  */
1676
1677 void
1678 TkpMenuThreadInit()
1679 {
1680     /*
1681      * Nothing to do.
1682      */
1683 }
1684
1685