OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [mac/] [tkMacMenu.c] - Blame information for rev 578

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tkMacMenu.c --
3
 *
4
 *      This module implements the Mac-platform specific features of menus.
5
 *
6
 * Copyright (c) 1996-1997 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: tkMacMenu.c,v 1.1.1.1 2002-01-16 10:25:56 markom Exp $
12
 */
13
 
14
#include <Menus.h>
15
#include <OSUtils.h>
16
#include <Palettes.h>
17
#include <Resources.h>
18
#include <string.h>
19
#include <ToolUtils.h>
20
#include <Balloons.h>
21
#include <Appearance.h>
22
#undef Status
23
#include <Devices.h>
24
#include "tkMenu.h"
25
#include "tkMacInt.h"
26
#include "tkMenuButton.h"
27
#include "tkColor.h"
28
 
29
typedef struct MacMenu {
30
    MenuHandle menuHdl;         /* The Menu Manager data structure. */
31
    Rect menuRect;              /* The rectangle as calculated in the
32
                                 * MDEF. This is used to figure ou the
33
                                 * clipping rgn before we push
34
                                 * the <<MenuSelect>> virtual binding
35
                                 * through. */
36
} MacMenu;
37
 
38
typedef struct MenuEntryUserData {
39
    Drawable mdefDrawable;
40
    TkMenuEntry *mePtr;
41
    Tk_Font tkfont;
42
    Tk_FontMetrics *fmPtr;
43
} MenuEntryUserData;
44
/*
45
 * Various geometry definitions:
46
 */
47
 
48
#define CASCADE_ARROW_HEIGHT    10
49
#define CASCADE_ARROW_WIDTH     8
50
#define DECORATION_BORDER_WIDTH 2
51
#define MAC_MARGIN_WIDTH        8
52
 
53
/*
54
 * The following are constants relating to the SICNs used for drawing the MDEF.
55
 */
56
 
57
#define SICN_RESOURCE_NUMBER            128
58
 
59
#define SICN_HEIGHT             16
60
#define SICN_ROWS               2
61
#define CASCADE_ICON_WIDTH      7
62
#define SHIFT_ICON_WIDTH        10
63
#define OPTION_ICON_WIDTH       16
64
#define CONTROL_ICON_WIDTH      12
65
#define COMMAND_ICON_WIDTH      10
66
 
67
#define CASCADE_ARROW           0
68
#define SHIFT_ICON              1
69
#define OPTION_ICON             2
70
#define CONTROL_ICON            3
71
#define COMMAND_ICON            4
72
#define DOWN_ARROW              5
73
#define UP_ARROW                6
74
 
75
/*
76
 * Platform specific flags for menu entries
77
 *
78
 * ENTRY_COMMAND_ACCEL          Indicates the entry has the command key
79
 *                              in its accelerator string.
80
 * ENTRY_OPTION_ACCEL           Indicates the entry has the option key
81
 *                              in its accelerator string.
82
 * ENTRY_SHIFT_ACCEL            Indicates the entry has the shift key
83
 *                              in its accelerator string.
84
 * ENTRY_CONTROL_ACCEL          Indicates the entry has the control key
85
 *                              in its accelerator string.
86
 */
87
 
88
#define ENTRY_COMMAND_ACCEL     ENTRY_PLATFORM_FLAG1
89
#define ENTRY_OPTION_ACCEL      ENTRY_PLATFORM_FLAG2
90
#define ENTRY_SHIFT_ACCEL       ENTRY_PLATFORM_FLAG3
91
#define ENTRY_CONTROL_ACCEL     ENTRY_PLATFORM_FLAG4
92
#define ENTRY_ACCEL_MASK        (ENTRY_COMMAND_ACCEL | ENTRY_OPTION_ACCEL \
93
                                | ENTRY_SHIFT_ACCEL | ENTRY_CONTROL_ACCEL)
94
 
95
/*
96
 * This structure is used to keep track of subfields within Macintosh menu
97
 * items.
98
 */
99
 
100
typedef struct EntryGeometry {
101
    int accelTextStart;         /* Offset into the accel string where
102
                                 * the text starts. Everything before
103
                                 * this is modifier key descriptions.
104
                                 */
105
    int modifierWidth;          /* Width of modifier symbols. */
106
    int accelTextWidth;         /* Width of the text after the modifier
107
                                 * keys. */
108
    int nonAccelMargin;         /* The width of the margin for entries
109
                                 * without accelerators. */
110
} EntryGeometry;
111
 
112
/*
113
 * Structure to keep track of toplevel windows and their menubars.
114
 */
115
 
116
typedef struct TopLevelMenubarList {
117
    struct TopLevelMenubarList *nextPtr;
118
                                /* The next window in the list. */
119
    Tk_Window tkwin;            /* The toplevel window. */
120
    TkMenu *menuPtr;            /* The menu associated with this
121
                                 * toplevel. */
122
} TopLevelMenubarList;
123
 
124
/*
125
 * Platform-specific flags for menus.
126
 *
127
 * MENU_APPLE_MENU              0 indicates a custom Apple menu has
128
 *                              not been installed; 1 a custom Apple
129
 *                              menu has been installed.
130
 * MENU_HELP_MENU               0 indicates a custom Help menu has
131
 *                              not been installed; 1 a custom Help
132
 *                              menu has been installed.
133
 * MENU_RECONFIGURE_PENDING     1 indicates that an idle handler has
134
 *                              been scheduled to reconfigure the
135
 *                              Macintosh MenuHandle.
136
 */
137
 
138
#define MENU_APPLE_MENU                 MENU_PLATFORM_FLAG1
139
#define MENU_HELP_MENU                  MENU_PLATFORM_FLAG2
140
#define MENU_RECONFIGURE_PENDING        MENU_PLATFORM_FLAG3
141
 
142
#define CASCADE_CMD (0x1b)      
143
                                /* The special command char for cascade
144
                                 * menus. */
145
#define SEPARATOR_TEXT "\p(-"
146
                                /* The text for a menu separator. */
147
 
148
#define MENUBAR_REDRAW_PENDING 1
149
 
150
static int gNoTkMenus = 0;      /* This is used by Tk_MacTurnOffMenus as the
151
                                 * flag that Tk is not to draw any menus. */
152
RgnHandle tkMenuCascadeRgn = NULL;
153
                                /* The region to clip drawing to when the
154
                                 * MDEF is up. */
155
int tkUseMenuCascadeRgn = 0;     /* If this is 1, clipping code
156
                                 * should intersect tkMenuCascadeRgn
157
                                 * before drawing occurs.
158
                                 * tkMenuCascadeRgn will only
159
                                 * be valid when the value of this
160
                                 * variable is 1. */
161
 
162
static Tcl_HashTable commandTable;
163
                                /* The list of menuInstancePtrs associated with
164
                                 * menu ids */
165
static short currentAppleMenuID;
166
                                /* The id of the current Apple menu. 0 for
167
                                 * none. */
168
static short currentHelpMenuID; /* The id of the current Help menu. 0 for
169
                                 * none. */
170
static Tcl_Interp *currentMenuBarInterp;
171
                                /* The interpreter of the window that owns
172
                                 * the current menubar. */
173
static char *currentMenuBarName;
174
                                /* Malloced. Name of current menu in menu bar.
175
                                 * NULL if no menu set. TO DO: make this a
176
                                 * DString. */
177
static Tk_Window currentMenuBarOwner;
178
                                /* Which window owns the current menu bar. */
179
static int helpItemCount;       /* The number of items in the help menu.
180
                                 * -1 means that the help menu is
181
                                 * unavailable. This does not include
182
                                 * the automatically generated separator. */
183
static int inPostMenu;          /* We cannot be re-entrant like X
184
                                 * windows. */
185
static short lastMenuID;        /* To pass to NewMenu; need to figure out
186
                                 * a good way to do this. */
187
static unsigned char lastCascadeID;
188
                                /* Cascades have to have ids that are
189
                                 * less than 256. */
190
static MacDrawable macMDEFDrawable;
191
                                /* Drawable for use by MDEF code */
192
static MDEFScrollFlag = 0;       /* Used so that popups don't scroll too soon. */
193
static int menuBarFlags;        /* Used for whether the menu bar needs
194
                                 * redrawing or not. */
195
static TkMenuDefUPP menuDefProc;/* The routine descriptor to the MDEF proc.
196
                                 * The MDEF is needed to draw menus with
197
                                 * non-standard attributes and to support
198
                                 * tearoff menus. */
199
static struct TearoffSelect {
200
    TkMenu *menuPtr;            /* The menu that is torn off */
201
    Point point;                /* The point to place the new menu */
202
    Rect excludeRect;           /* We don't want to drag tearoff highlights
203
                                 * when we are in this menu */
204
} tearoffStruct;
205
 
206
static RgnHandle totalMenuRgn = NULL;
207
                                /* Used to update windows which have been
208
                                 * obscured by menus. */
209
static RgnHandle utilRgn = NULL;/* Used when creating the region that is to
210
                                 * be clipped out while the MDEF is active. */
211
 
212
static TopLevelMenubarList *windowListPtr;
213
                                /* A list of windows that have menubars set. */
214
static MenuItemDrawingUPP tkThemeMenuItemDrawingUPP;
215
                                /* Points to the UPP for theme Item drawing. */
216
 
217
static GC     appearanceGC = NULL; /* The fake appearance GC.  If you
218
                                      pass the foreground of this to TkMacSetColor,
219
                                      it will return false, so you will know
220
                                      not to set the foreground color */
221
 
222
 
223
/*
224
 * Forward declarations for procedures defined later in this file:
225
 */
226
 
227
static void             CompleteIdlers _ANSI_ARGS_((TkMenu *menuPtr));
228
static void             DrawMenuBarWhenIdle _ANSI_ARGS_((
229
                            ClientData clientData));
230
static void             DrawMenuBackground _ANSI_ARGS_((
231
                            Rect *menuRectPtr, Drawable d, ThemeMenuType type));
232
static void             DrawMenuEntryAccelerator _ANSI_ARGS_((
233
                            TkMenu *menuPtr, TkMenuEntry *mePtr,
234
                            Drawable d, GC gc, Tk_Font tkfont,
235
                            CONST Tk_FontMetrics *fmPtr,
236
                            Tk_3DBorder activeBorder, int x, int y,
237
                            int width, int height, int drawArrow));
238
static void             DrawMenuEntryBackground _ANSI_ARGS_((
239
                            TkMenu *menuPtr, TkMenuEntry *mePtr,
240
                            Drawable d, Tk_3DBorder activeBorder,
241
                            Tk_3DBorder bgBorder, int x, int y,
242
                            int width, int heigth));
243
static void             DrawMenuEntryIndicator _ANSI_ARGS_((
244
                            TkMenu *menuPtr, TkMenuEntry *mePtr,
245
                            Drawable d, GC gc, GC indicatorGC,
246
                            Tk_Font tkfont,
247
                            CONST Tk_FontMetrics *fmPtr, int x, int y,
248
                            int width, int height));
249
static void             DrawMenuEntryLabel _ANSI_ARGS_((
250
                            TkMenu * menuPtr, TkMenuEntry *mePtr, Drawable d,
251
                            GC gc, Tk_Font tkfont,
252
                            CONST Tk_FontMetrics *fmPtr, int x, int y,
253
                            int width, int height));
254
static void             DrawMenuSeparator _ANSI_ARGS_((TkMenu *menuPtr,
255
                            TkMenuEntry *mePtr, Drawable d, GC gc,
256
                            Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
257
                            int x, int y, int width, int height));
258
static void             DrawTearoffEntry _ANSI_ARGS_((TkMenu *menuPtr,
259
                            TkMenuEntry *mePtr, Drawable d, GC gc,
260
                            Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
261
                            int x, int y, int width, int height));
262
static Handle           FixMDEF _ANSI_ARGS_((void));
263
static void             GetMenuAccelGeometry _ANSI_ARGS_((TkMenu *menuPtr,
264
                            TkMenuEntry *mePtr, Tk_Font tkfont,
265
                            CONST Tk_FontMetrics *fmPtr, int *modWidthPtr,
266
                            int *textWidthPtr, int *heightPtr));
267
static void             GetMenuLabelGeometry _ANSI_ARGS_((TkMenuEntry *mePtr,
268
                            Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
269
                            int *widthPtr, int *heightPtr));
270
static void             GetMenuIndicatorGeometry _ANSI_ARGS_((
271
                            TkMenu *menuPtr, TkMenuEntry *mePtr,
272
                            Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
273
                            int *widthPtr, int *heightPtr));
274
static void             GetMenuSeparatorGeometry _ANSI_ARGS_((
275
                            TkMenu *menuPtr, TkMenuEntry *mePtr,
276
                            Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
277
                            int *widthPtr, int *heightPtr));
278
static void             GetTearoffEntryGeometry _ANSI_ARGS_((TkMenu *menuPtr,
279
                            TkMenuEntry *mePtr, Tk_Font tkfont,
280
                            CONST Tk_FontMetrics *fmPtr, int *widthPtr,
281
                            int *heightPtr));
282
static int              GetNewID _ANSI_ARGS_((Tcl_Interp *interp,
283
                            TkMenu *menuInstPtr, int cascade,
284
                            short *menuIDPtr));
285
static char             FindMarkCharacter _ANSI_ARGS_((TkMenuEntry *mePtr));
286
static void             FreeID _ANSI_ARGS_((short menuID));
287
static void             InvalidateMDEFRgns _ANSI_ARGS_((void));
288
static void             MenuDefProc _ANSI_ARGS_((short message,
289
                            MenuHandle menu, Rect *menuRectPtr,
290
                            Point hitPt, short *whichItem,
291
                            TkMenuLowMemGlobals *globalsPtr));
292
static void             MenuSelectEvent _ANSI_ARGS_((TkMenu *menuPtr));
293
static void             ReconfigureIndividualMenu _ANSI_ARGS_((
294
                            TkMenu *menuPtr, MenuHandle macMenuHdl,
295
                            int base));
296
static void             ReconfigureMacintoshMenu _ANSI_ARGS_ ((
297
                            ClientData clientData));
298
static void             RecursivelyClearActiveMenu _ANSI_ARGS_((
299
                            TkMenu *menuPtr));
300
static void             RecursivelyDeleteMenu _ANSI_ARGS_((
301
                            TkMenu *menuPtr));
302
static void             RecursivelyInsertMenu _ANSI_ARGS_((
303
                            TkMenu *menuPtr));
304
static void             SetDefaultMenubar _ANSI_ARGS_((void));
305
static int              SetMenuCascade _ANSI_ARGS_((TkMenu *menuPtr));
306
static void             SetMenuIndicator _ANSI_ARGS_((TkMenuEntry *mePtr));
307
static void             AppearanceEntryDrawWrapper _ANSI_ARGS_((TkMenuEntry *mePtr,
308
                            Rect * menuRectPtr, TkMenuLowMemGlobals *globalsPtr,
309
                            Drawable d, Tk_FontMetrics *fmPtr, Tk_Font tkfont,
310
                            int x, int y, int width, int height));
311
pascal void             tkThemeMenuItemDrawingProc _ANSI_ARGS_ ((const Rect *inBounds,
312
                            SInt16 inDepth, Boolean inIsColorDevice,
313
                            SInt32 inUserData));
314
 
315
 
316
/*
317
 *----------------------------------------------------------------------
318
 *
319
 * TkMacUseID --
320
 *
321
 *      Take the ID out of the available list for new menus. Used by the
322
 *      default menu bar's menus so that they do not get created at the tk
323
 *      level. See GetNewID for more information.
324
 *
325
 * Results:
326
 *      Returns TCL_OK if the id was not in use. Returns TCL_ERROR if the
327
 *      id was in use.
328
 *
329
 * Side effects:
330
 *      A hash table entry in the command table is created with a NULL
331
 *      value.
332
 *
333
 *----------------------------------------------------------------------
334
 */
335
 
336
int
337
TkMacUseMenuID(
338
    short macID)                        /* The id to take out of the table */
339
{
340
    Tcl_HashEntry *commandEntryPtr;
341
    int newEntry;
342
 
343
    TkMenuInit();
344
    commandEntryPtr = Tcl_CreateHashEntry(&commandTable, (char *) macID,
345
            &newEntry);
346
    if (newEntry == 1) {
347
        Tcl_SetHashValue(commandEntryPtr, NULL);
348
        return TCL_OK;
349
    } else {
350
        return TCL_ERROR;
351
    }
352
}
353
 
354
/*
355
 *----------------------------------------------------------------------
356
 *
357
 * GetNewID --
358
 *
359
 *      Allocates a new menu id and marks it in use. Each menu on the
360
 *      mac must be designated by a unique id, which is a short. In
361
 *      addition, some ids are reserved by the system. Since Tk uses
362
 *      mostly dynamic menus, we must allocate and free these ids on
363
 *      the fly. We use the id as a key into a hash table; if there
364
 *      is no hash entry, we know that we can use the id.
365
 *
366
 * Results:
367
 *      Returns TCL_OK if succesful; TCL_ERROR if there are no more
368
 *      ids of the appropriate type to allocate. menuIDPtr contains
369
 *      the new id if succesful.
370
 *
371
 * Side effects:
372
 *      An entry is created for the menu in the command hash table,
373
 *      and the hash entry is stored in the appropriate field in the
374
 *      menu data structure.
375
 *
376
 *----------------------------------------------------------------------
377
 */
378
 
379
static int
380
GetNewID(
381
    Tcl_Interp *interp,         /* Used for error reporting */
382
    TkMenu *menuPtr,            /* The menu we are working with */
383
    int cascade,                /* 0 if we are working with a normal menu;
384
                                   1 if we are working with a cascade */
385
    short *menuIDPtr)           /* The resulting id */
386
{
387
    int found = 0;
388
    int newEntry;
389
    Tcl_HashEntry *commandEntryPtr;
390
    short returnID = *menuIDPtr;
391
 
392
    /*
393
     * The following code relies on shorts and unsigned chars wrapping
394
     * when the highest value is incremented. Also, the values between
395
     * 236 and 255 inclusive are reserved for DA's by the Mac OS.
396
     */
397
 
398
    if (!cascade) {
399
        short curID = lastMenuID + 1;
400
        if (curID == 236) {
401
            curID = 256;
402
        }
403
 
404
        while (curID != lastMenuID) {
405
            commandEntryPtr = Tcl_CreateHashEntry(&commandTable,
406
                    (char *) curID, &newEntry);
407
            if (newEntry == 1) {
408
                found = 1;
409
                lastMenuID = returnID = curID;
410
                break;
411
            }
412
            curID++;
413
            if (curID == 236) {
414
                curID = 256;
415
            }
416
        }
417
    } else {
418
 
419
        /*
420
         * Cascade ids must be between 0 and 235 only, so they must be
421
         * dealt with separately.
422
         */
423
 
424
        unsigned char curID = lastCascadeID + 1;
425
        if (curID == 236) {
426
            curID = 0;
427
        }
428
 
429
        while (curID != lastCascadeID) {
430
            commandEntryPtr = Tcl_CreateHashEntry(&commandTable,
431
                    (char *) curID, &newEntry);
432
            if (newEntry == 1) {
433
                found = 1;
434
                lastCascadeID = returnID = curID;
435
                break;
436
            }
437
            curID++;
438
            if (curID == 236) {
439
                curID = 0;
440
            }
441
        }
442
    }
443
 
444
    if (found) {
445
        Tcl_SetHashValue(commandEntryPtr, (char *) menuPtr);
446
        *menuIDPtr = returnID;
447
        return TCL_OK;
448
    } else {
449
        Tcl_AppendResult(interp, "No more menus can be allocated.",
450
                (char *) NULL);
451
        return TCL_ERROR;
452
    }
453
}
454
 
455
/*
456
 *----------------------------------------------------------------------
457
 *
458
 * FreeID --
459
 *
460
 *      Marks the id as free.
461
 *
462
 * Results:
463
 *      None.
464
 *
465
 * Side effects:
466
 *      The hash table entry for the ID is cleared.
467
 *
468
 *----------------------------------------------------------------------
469
 */
470
 
471
static void
472
FreeID(
473
    short menuID)                       /* The id to free */
474
{
475
    Tcl_HashEntry *entryPtr = Tcl_FindHashEntry(&commandTable,
476
            (char *) menuID);
477
 
478
    if (entryPtr != NULL) {
479
         Tcl_DeleteHashEntry(entryPtr);
480
    }
481
    if (menuID == currentAppleMenuID) {
482
        currentAppleMenuID = 0;
483
    }
484
    if (menuID == currentHelpMenuID) {
485
        currentHelpMenuID = 0;
486
    }
487
}
488
 
489
/*
490
 *----------------------------------------------------------------------
491
 *
492
 * TkpNewMenu --
493
 *
494
 *      Gets a new blank menu. Only the platform specific options are filled
495
 *      in.
496
 *
497
 * Results:
498
 *      Returns a standard TCL error.
499
 *
500
 * Side effects:
501
 *      Allocates a Macintosh menu handle and puts in the platformData
502
 *      field of the menuPtr.
503
 *
504
 *----------------------------------------------------------------------
505
 */
506
 
507
int
508
TkpNewMenu(
509
    TkMenu *menuPtr)            /* The common structure we are making the
510
                                 * platform structure for. */
511
{
512
    short menuID;
513
    Str255 itemText;
514
    int length;
515
    MenuHandle macMenuHdl;
516
    int error = TCL_OK;
517
 
518
    error = GetNewID(menuPtr->interp, menuPtr, 0, &menuID);
519
    if (error != TCL_OK) {
520
        return error;
521
    }
522
    length = strlen(Tk_PathName(menuPtr->tkwin));
523
    memmove(&itemText[1], Tk_PathName(menuPtr->tkwin),
524
            (length > 230) ? 230 : length);
525
    itemText[0] = (length > 230) ? 230 : length;
526
    macMenuHdl = NewMenu(menuID, itemText);
527
#ifdef GENERATINGCFM
528
    {
529
        Handle mdefProc = FixMDEF();
530
        if ((mdefProc != NULL)) {
531
            (*macMenuHdl)->menuProc = mdefProc;
532
        }
533
    }
534
#endif
535
    menuPtr->platformData = (TkMenuPlatformData) ckalloc(sizeof(MacMenu));
536
    ((MacMenu *) menuPtr->platformData)->menuHdl = macMenuHdl;
537
    SetRect(&((MacMenu *) menuPtr->platformData)->menuRect, 0, 0, 0, 0);
538
 
539
    if ((currentMenuBarInterp == menuPtr->interp)
540
            && (currentMenuBarName != NULL)) {
541
        Tk_Window parentWin = Tk_Parent(menuPtr->tkwin);
542
 
543
        if (strcmp(currentMenuBarName, Tk_PathName(parentWin)) == 0) {
544
            if ((strcmp(Tk_PathName(menuPtr->tkwin)
545
                    + strlen(Tk_PathName(parentWin)), ".apple") == 0)
546
                    || (strcmp(Tk_PathName(menuPtr->tkwin)
547
                    + strlen(Tk_PathName(parentWin)), ".help") == 0)) {
548
                if (!(menuBarFlags & MENUBAR_REDRAW_PENDING)) {
549
                    Tcl_DoWhenIdle(DrawMenuBarWhenIdle, (ClientData *) NULL);
550
                    menuBarFlags |= MENUBAR_REDRAW_PENDING;
551
                }
552
            }
553
        }
554
    }
555
 
556
    menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
557
    Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr);
558
    return TCL_OK;
559
}
560
 
561
/*
562
 *----------------------------------------------------------------------
563
 *
564
 * TkpDestroyMenu --
565
 *
566
 *      Destroys platform-specific menu structures.
567
 *
568
 * Results:
569
 *      None.
570
 *
571
 * Side effects:
572
 *      All platform-specific allocations are freed up.
573
 *
574
 *----------------------------------------------------------------------
575
 */
576
 
577
void
578
TkpDestroyMenu(
579
    TkMenu *menuPtr)            /* The common menu structure */
580
{
581
    MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl;
582
 
583
    if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) {
584
        Tcl_CancelIdleCall(ReconfigureMacintoshMenu, (ClientData) menuPtr);
585
        menuPtr->menuFlags &= ~MENU_RECONFIGURE_PENDING;
586
    }
587
 
588
    if ((*macMenuHdl)->menuID == currentHelpMenuID) {
589
        MenuHandle helpMenuHdl;
590
 
591
        if ((HMGetHelpMenuHandle(&helpMenuHdl) == noErr)
592
                && (helpMenuHdl != NULL)) {
593
            int i, count = CountMItems(helpMenuHdl);
594
 
595
            for (i = helpItemCount; i <= count; i++) {
596
                DeleteMenuItem(helpMenuHdl, helpItemCount);
597
            }
598
        }
599
        currentHelpMenuID = 0;
600
    }
601
 
602
    if (menuPtr->platformData != NULL) {
603
        DeleteMenu((*macMenuHdl)->menuID);
604
        FreeID((*macMenuHdl)->menuID);
605
        DisposeMenu(macMenuHdl);
606
        ckfree((char *) menuPtr->platformData);
607
        menuPtr->platformData = NULL;
608
    }
609
}
610
 
611
/*
612
 *----------------------------------------------------------------------
613
 *
614
 * SetMenuCascade --
615
 *
616
 *      Does any cleanup to change a menu from a normal to a cascade.
617
 *
618
 * Results:
619
 *      Standard Tcl error.
620
 *
621
 * Side effects:
622
 *      The mac menu id is reset.
623
 *
624
 *----------------------------------------------------------------------
625
 */
626
 
627
static int
628
SetMenuCascade(
629
    TkMenu* menuPtr)            /* The menu we are setting up to be a
630
                                 * cascade. */
631
{
632
    MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl;
633
    short newMenuID, menuID = (*macMenuHdl)->menuID;
634
    int error = TCL_OK;
635
 
636
    if (menuID >= 256) {
637
        error = GetNewID(menuPtr->interp, menuPtr, 1, &newMenuID);
638
        if (error == TCL_OK) {
639
            FreeID(menuID);
640
            (*macMenuHdl)->menuID = newMenuID;
641
        }
642
    }
643
    return error;
644
}
645
 
646
/*
647
 *----------------------------------------------------------------------
648
 *
649
 * TkpDestroyMenuEntry --
650
 *
651
 *      Cleans up platform-specific menu entry items.
652
 *
653
 * Results:
654
 *      None
655
 *
656
 * Side effects:
657
 *      All platform-specific allocations are freed up.
658
 *
659
 *----------------------------------------------------------------------
660
 */
661
 
662
void
663
TkpDestroyMenuEntry(
664
    TkMenuEntry *mePtr)         /* The common structure for the menu
665
                                 * entry. */
666
{
667
    TkMenu *menuPtr = mePtr->menuPtr;
668
 
669
    ckfree((char *) mePtr->platformEntryData);
670
    if ((menuPtr->platformData != NULL)
671
            && !(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) {
672
        menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
673
        Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr);
674
    }
675
}
676
 
677
/*
678
 *----------------------------------------------------------------------
679
 *
680
 * GetEntryText --
681
 *
682
 *      Given a menu entry, gives back the text that should go in it.
683
 *      Separators should be done by the caller, as they have to be
684
 *      handled specially.
685
 *
686
 * Results:
687
 *      itemText points to the new text for the item.
688
 *
689
 * Side effects:
690
 *      None.
691
 *
692
 *----------------------------------------------------------------------
693
 */
694
 
695
static void
696
GetEntryText(
697
    TkMenuEntry *mePtr,         /* A pointer to the menu entry. */
698
    Str255 itemText)            /* The pascal string containing the text */
699
{
700
    if (mePtr->type == TEAROFF_ENTRY) {
701
        strcpy((char *)itemText, (const char *)"\p(Tear-off)");
702
    } else if (mePtr->imageString != NULL) {
703
        strcpy((char *)itemText, (const char *)"\p(Image)");
704
    } else if (mePtr->bitmap != None) {
705
        strcpy((char *)itemText, (const char *)"\p(Pixmap)");
706
    } else if (mePtr->label == NULL || mePtr->labelLength == 0) {
707
 
708
        /*
709
         * The Mac menu manager does not like null strings.
710
         */
711
 
712
        strcpy((char *)itemText, (const char *)"\p ");
713
    } else {
714
        char *text = mePtr->label;
715
        int i;
716
 
717
        itemText[0] = 0;
718
        for (i = 1; (*text != '\0') && (i <= 230); i++, text++) {
719
            if ((*text == '.')
720
                    && (*(text + 1) != '\0') && (*(text + 1) == '.')
721
                    && (*(text + 2) != '\0') && (*(text + 2) == '.')) {
722
                itemText[i] = 'É';
723
                text += 2;
724
            } else {
725
                itemText[i] = *text;
726
            }
727
            itemText[0] += 1;
728
        }
729
    }
730
}
731
 
732
/*
733
 *----------------------------------------------------------------------
734
 *
735
 * FindMarkCharacter --
736
 *
737
 *      Finds the Macintosh mark character based on the font of the
738
 *      item. We calculate a good mark character based on the font
739
 *      that this item is rendered in.
740
 *
741
 *      We try the following special mac characters. If none of them
742
 *      are present, just use the check mark.
743
 *      '' - Check mark character
744
 *      '¥' - Bullet character
745
 *      '' - Filled diamond
746
 *      '×' - Hollow diamond
747
 *      'Ñ' = Long dash ("em dash")
748
 *      '-' = short dash (minus, "en dash");
749
 *
750
 * Results:
751
 *      None.
752
 *
753
 * Side effects:
754
 *      New item is added to platform menu
755
 *
756
 *----------------------------------------------------------------------
757
 */
758
 
759
static char
760
FindMarkCharacter(
761
    TkMenuEntry *mePtr)         /* The entry we are finding the character
762
                                 * for. */
763
{
764
    char markChar;
765
    Tk_Font tkfont = (mePtr->tkfont == NULL) ? mePtr->menuPtr->tkfont
766
            : mePtr->tkfont;
767
 
768
    if (!TkMacIsCharacterMissing(tkfont, '')) {
769
        markChar = '';
770
    } else if (!TkMacIsCharacterMissing(tkfont, '¥')) {
771
        markChar = '¥';
772
    } else if (!TkMacIsCharacterMissing(tkfont, '')) {
773
        markChar = '';
774
    } else if (!TkMacIsCharacterMissing(tkfont, '×')) {
775
        markChar = '×';
776
    } else if (!TkMacIsCharacterMissing(tkfont, 'Ñ')) {
777
        markChar = 'Ñ';
778
    } else if (!TkMacIsCharacterMissing(tkfont, '-')) {
779
        markChar = '-';
780
    } else {
781
        markChar = '';
782
    }
783
    return markChar;
784
}
785
 
786
/*
787
 *----------------------------------------------------------------------
788
 *
789
 * SetMenuIndicator --
790
 *
791
 *      Sets the Macintosh mark character based on the font of the
792
 *      item.
793
 *
794
 * Results:
795
 *      None.
796
 *
797
 * Side effects:
798
 *      New item is added to platform menu
799
 *
800
 *----------------------------------------------------------------------
801
 */
802
 
803
static void
804
SetMenuIndicator(
805
    TkMenuEntry *mePtr)         /* The entry we are setting */
806
{
807
    TkMenu *menuPtr = mePtr->menuPtr;
808
    MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl;
809
    char markChar;
810
 
811
    /*
812
     * There can be no indicators on menus that are not checkbuttons
813
     * or radiobuttons. However, we should go ahead and set them
814
     * so that menus look right when they are displayed. We should
815
     * not set cascade entries, however, as the mark character
816
     * means something different for cascade items on the Mac.
817
     * Also, we do reflect the tearOff menu items in the Mac menu
818
     * handle, so we ignore them.
819
     */
820
 
821
    if (mePtr->type == CASCADE_ENTRY) {
822
        return;
823
    }
824
 
825
    if (((mePtr->type == RADIO_BUTTON_ENTRY)
826
            || (mePtr->type == CHECK_BUTTON_ENTRY))
827
            && (mePtr->indicatorOn)
828
            && (mePtr->entryFlags & ENTRY_SELECTED)) {
829
        markChar = FindMarkCharacter(mePtr);
830
    } else {
831
        markChar = 0;
832
    }
833
    SetItemMark(macMenuHdl, mePtr->index + 1, markChar);
834
}
835
 
836
/*
837
 *----------------------------------------------------------------------
838
 *
839
 * SetMenuTitle --
840
 *
841
 *      Sets title of menu so that the text displays correctly in menubar.
842
 *      This code directly manipulates menu handle data. This code
843
 *      was originally part of an ancient Apple Developer Response mail.
844
 *
845
 * Results:
846
 *      None.
847
 *
848
 * Side effects:
849
 *      The menu handle will change size depending on the length of the
850
 *      title
851
 *
852
 *----------------------------------------------------------------------
853
 */
854
 
855
static void
856
SetMenuTitle(
857
    MenuHandle menuHdl,         /* The menu we are setting the title of. */
858
    char *title)                /* The C string to set the title to. */
859
{
860
    int oldLength, newLength, oldHandleSize, dataLength;
861
    Ptr menuDataPtr;
862
 
863
    menuDataPtr = (Ptr) (*menuHdl)->menuData;
864
 
865
    if (strncmp(title, menuDataPtr + 1, menuDataPtr[0]) != 0) {
866
        newLength = strlen(title) + 1;
867
        oldLength = menuDataPtr[0] + 1;
868
        oldHandleSize = GetHandleSize((Handle) menuHdl);
869
        dataLength = oldHandleSize - (sizeof(MenuInfo) - sizeof(Str255))
870
                - oldLength;
871
        if (newLength > oldLength) {
872
            SetHandleSize((Handle) menuHdl, oldHandleSize + (newLength
873
                    - oldLength));
874
            menuDataPtr = (Ptr) (*menuHdl)->menuData;
875
        }
876
 
877
        BlockMove(menuDataPtr + oldLength, menuDataPtr + newLength,
878
                dataLength);
879
        BlockMove(title, menuDataPtr + 1, newLength - 1);
880
        menuDataPtr[0] = newLength - 1;
881
 
882
        if (newLength < oldLength) {
883
            SetHandleSize((Handle) menuHdl, oldHandleSize + (newLength
884
                    - oldLength));
885
        }
886
    }
887
}
888
 
889
/*
890
 *----------------------------------------------------------------------
891
 *
892
 * TkpConfigureMenuEntry --
893
 *
894
 *      Processes configurations for menu entries.
895
 *
896
 * Results:
897
 *      Returns standard TCL result. If TCL_ERROR is returned, then
898
 *      interp->result contains an error message.
899
 *
900
 * Side effects:
901
 *      Configuration information get set for mePtr; old resources
902
 *      get freed, if any need it.
903
 *
904
 *----------------------------------------------------------------------
905
 */
906
 
907
int
908
TkpConfigureMenuEntry(
909
    register TkMenuEntry *mePtr)        /* Information about menu entry;  may
910
                                         * or may not already have values for
911
                                         * some fields. */
912
{
913
    TkMenu *menuPtr = mePtr->menuPtr;
914
    int index = mePtr->index;
915
    MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl;
916
    MenuHandle helpMenuHdl = NULL;
917
 
918
    /*
919
     * Cascade menus have to have menu IDs of less than 256. So
920
     * we need to change the child menu if this has been configured
921
     * for a cascade item.
922
     */
923
 
924
    if (mePtr->type == CASCADE_ENTRY) {
925
        if ((mePtr->childMenuRefPtr != NULL)
926
                && (mePtr->childMenuRefPtr->menuPtr != NULL)) {
927
            MenuHandle childMenuHdl = ((MacMenu *) mePtr
928
                    ->childMenuRefPtr->menuPtr->platformData)->menuHdl;
929
 
930
            if (childMenuHdl != NULL) {
931
                int error = SetMenuCascade(mePtr->childMenuRefPtr->menuPtr);
932
 
933
                if (error != TCL_OK) {
934
                    return error;
935
                }
936
 
937
                if (menuPtr->menuType == MENUBAR) {
938
                    SetMenuTitle(childMenuHdl, mePtr->label);
939
                }
940
            }
941
        }
942
    }
943
 
944
    /*
945
     * We need to parse the accelerator string. If it has the strings
946
     * for Command, Control, Shift or Option, we need to flag it
947
     * so we can draw the symbols for it. We also need to precalcuate
948
     * the position of the first real character we are drawing.
949
     */
950
 
951
    if (0 == mePtr->accelLength) {
952
        ((EntryGeometry *)mePtr->platformEntryData)->accelTextStart = -1;
953
    } else {
954
        char *accelString = mePtr->accel;
955
        mePtr->entryFlags |= ~ENTRY_ACCEL_MASK;
956
 
957
        while (1) {
958
            if ((0 == strncasecmp("Control", accelString, 6))
959
                    && (('-' == accelString[6]) || ('+' == accelString[6]))) {
960
                mePtr->entryFlags |= ENTRY_CONTROL_ACCEL;
961
                accelString += 7;
962
            } else if ((0 == strncasecmp("Ctrl", accelString, 4))
963
                    && (('-' == accelString[4]) || ('+' == accelString[4]))) {
964
                mePtr->entryFlags |= ENTRY_CONTROL_ACCEL;
965
                accelString += 5;
966
            } else if ((0 == strncasecmp("Shift", accelString, 5))
967
                    && (('-' == accelString[5]) || ('+' == accelString[5]))) {
968
                mePtr->entryFlags |= ENTRY_SHIFT_ACCEL;
969
                accelString += 6;
970
            } else if ((0 == strncasecmp("Option", accelString, 6))
971
                    && (('-' == accelString[6]) || ('+' == accelString[6]))) {
972
                mePtr->entryFlags |= ENTRY_OPTION_ACCEL;
973
                accelString += 7;
974
            } else if ((0 == strncasecmp("Opt", accelString, 3))
975
                    && (('-' == accelString[3]) || ('+' == accelString[3]))) {
976
                mePtr->entryFlags |= ENTRY_OPTION_ACCEL;
977
                accelString += 4;
978
            } else if ((0 == strncasecmp("Command", accelString, 7))
979
                    && (('-' == accelString[7]) || ('+' == accelString[7]))) {
980
                mePtr->entryFlags |= ENTRY_COMMAND_ACCEL;
981
                accelString += 8;
982
            } else if ((0 == strncasecmp("Cmd", accelString, 3))
983
                    && (('-' == accelString[3]) || ('+' == accelString[3]))) {
984
                mePtr->entryFlags |= ENTRY_COMMAND_ACCEL;
985
                accelString += 4;
986
            } else if ((0 == strncasecmp("Alt", accelString, 3))
987
                    && (('-' == accelString[3]) || ('+' == accelString[3]))) {
988
                mePtr->entryFlags |= ENTRY_OPTION_ACCEL;
989
                accelString += 4;
990
            } else if ((0 == strncasecmp("Meta", accelString, 4))
991
                    && (('-' == accelString[4]) || ('+' == accelString[4]))) {
992
                mePtr->entryFlags |= ENTRY_COMMAND_ACCEL;
993
                accelString += 5;
994
            } else {
995
                break;
996
            }
997
        }
998
 
999
        ((EntryGeometry *)mePtr->platformEntryData)->accelTextStart
1000
                = ((long) accelString - (long) mePtr->accel);
1001
    }
1002
 
1003
    if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) {
1004
        menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
1005
        Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr);
1006
    }
1007
 
1008
    return TCL_OK;
1009
}
1010
 
1011
/*
1012
 *----------------------------------------------------------------------
1013
 *
1014
 * ReconfigureIndividualMenu --
1015
 *
1016
 *      This routine redoes the guts of the menu. It works from
1017
 *      a base item and offset, so that a regular menu will
1018
 *      just have all of its items added, but the help menu will
1019
 *      have all of its items appended after the apple-defined
1020
 *      items.
1021
 *
1022
 * Results:
1023
 *      None.
1024
 *
1025
 * Side effects:
1026
 *      The Macintosh menu handle is updated
1027
 *
1028
 *----------------------------------------------------------------------
1029
 */
1030
 
1031
static void
1032
ReconfigureIndividualMenu(
1033
    TkMenu *menuPtr,            /* The menu we are affecting. */
1034
    MenuHandle macMenuHdl,      /* The macintosh menu we are affecting.
1035
                                 * Will not necessarily be
1036
                                 * menuPtr->platformData because this could
1037
                                 * be the help menu. */
1038
    int base)                   /* The last index that we do not want
1039
                                 * touched. 0 for normal menus;
1040
                                 * helpMenuItemCount for help menus. */
1041
{
1042
    int count;
1043
    int index;
1044
    TkMenuEntry *mePtr;
1045
    Str255 itemText;
1046
    int parentDisabled = 0;
1047
 
1048
    for (mePtr = menuPtr->menuRefPtr->parentEntryPtr; mePtr != NULL;
1049
            mePtr = mePtr->nextCascadePtr) {
1050
        if (strcmp(Tk_PathName(menuPtr->tkwin), mePtr->name) == 0) {
1051
            if (mePtr->state == tkDisabledUid) {
1052
                parentDisabled = 1;
1053
            }
1054
            break;
1055
        }
1056
    }
1057
 
1058
    /*
1059
     * First, we get rid of all of the old items.
1060
     */
1061
 
1062
    count = CountMItems(macMenuHdl);
1063
    for (index = base; index < count; index++) {
1064
        DeleteMenuItem(macMenuHdl, base + 1);
1065
    }
1066
 
1067
    count = menuPtr->numEntries;
1068
 
1069
    for (index = 1; index <= count; index++) {
1070
        mePtr = menuPtr->entries[index - 1];
1071
 
1072
        /*
1073
         * We have to do separators separately because SetMenuItemText
1074
         * does not parse meta-characters.
1075
         */
1076
 
1077
        if (mePtr->type == SEPARATOR_ENTRY) {
1078
            AppendMenu(macMenuHdl, SEPARATOR_TEXT);
1079
        } else {
1080
            GetEntryText(mePtr, itemText);
1081
            AppendMenu(macMenuHdl, "\px");
1082
            SetMenuItemText(macMenuHdl, base + index, itemText);
1083
 
1084
            /*
1085
             * Set enabling and disabling correctly.
1086
             */
1087
 
1088
            if (parentDisabled || (mePtr->state == tkDisabledUid)) {
1089
                DisableItem(macMenuHdl, base + index);
1090
            } else {
1091
                EnableItem(macMenuHdl, base + index);
1092
            }
1093
 
1094
            /*
1095
             * Set the check mark for check entries and radio entries.
1096
             */
1097
 
1098
            SetItemMark(macMenuHdl, base + index, 0);
1099
            if ((mePtr->type == CHECK_BUTTON_ENTRY)
1100
                    || (mePtr->type == RADIO_BUTTON_ENTRY)) {
1101
                CheckItem(macMenuHdl, base + index, (mePtr->entryFlags
1102
                        & ENTRY_SELECTED) && (mePtr->indicatorOn));
1103
                if ((mePtr->indicatorOn)
1104
                        && (mePtr->entryFlags & ENTRY_SELECTED)) {
1105
                    SetItemMark(macMenuHdl, base + index,
1106
                            FindMarkCharacter(mePtr));
1107
                }
1108
            }
1109
 
1110
            if (mePtr->type == CASCADE_ENTRY) {
1111
                if ((mePtr->childMenuRefPtr != NULL)
1112
                        && (mePtr->childMenuRefPtr->menuPtr != NULL)) {
1113
                    MenuHandle childMenuHdl =
1114
                            ((MacMenu *) mePtr->childMenuRefPtr
1115
                            ->menuPtr->platformData)->menuHdl;
1116
 
1117
                    if (childMenuHdl == NULL) {
1118
                        childMenuHdl = ((MacMenu *) mePtr->childMenuRefPtr
1119
                                ->menuPtr->platformData)->menuHdl;
1120
                    }
1121
                    if (childMenuHdl != NULL) {
1122
                        if (TkMacHaveAppearance() > 1) {
1123
                            SetMenuItemHierarchicalID(macMenuHdl, base + index,
1124
                                    (*childMenuHdl)->menuID);
1125
                        } else {
1126
                        SetItemMark(macMenuHdl, base + index,
1127
                                (*childMenuHdl)->menuID);
1128
                        SetItemCmd(macMenuHdl, base + index, CASCADE_CMD);
1129
                    }
1130
                    }
1131
                    /*
1132
                     * If we changed the highligthing of this menu, its
1133
                     * children all have to be reconfigured so that
1134
                     * their state will be reflected in the menubar.
1135
                     */
1136
 
1137
                    if (!(mePtr->childMenuRefPtr->menuPtr->menuFlags
1138
                                & MENU_RECONFIGURE_PENDING)) {
1139
                        mePtr->childMenuRefPtr->menuPtr->menuFlags
1140
                                |= MENU_RECONFIGURE_PENDING;
1141
                        Tcl_DoWhenIdle(ReconfigureMacintoshMenu,
1142
                                (ClientData) mePtr->childMenuRefPtr->menuPtr);
1143
                    }
1144
                }
1145
            }
1146
 
1147
            if ((mePtr->type != CASCADE_ENTRY)
1148
                    && (ENTRY_COMMAND_ACCEL
1149
                    == (mePtr->entryFlags & ENTRY_ACCEL_MASK))) {
1150
                SetItemCmd(macMenuHdl, index, mePtr
1151
                        ->accel[((EntryGeometry *)mePtr->platformEntryData)
1152
                        ->accelTextStart]);
1153
            }
1154
        }
1155
    }
1156
}
1157
 
1158
/*
1159
 *----------------------------------------------------------------------
1160
 *
1161
 * ReconfigureMacintoshMenu --
1162
 *
1163
 *      Rebuilds the Macintosh MenuHandle items from the menu. Called
1164
 *      usually as an idle handler, but can be called synchronously
1165
 *      if the menu is about to be posted.
1166
 *
1167
 * Results:
1168
 *      None.
1169
 *
1170
 * Side effects:
1171
 *      Configuration information get set for mePtr; old resources
1172
 *      get freed, if any need it.
1173
 *
1174
 *----------------------------------------------------------------------
1175
 */
1176
 
1177
static void
1178
ReconfigureMacintoshMenu(
1179
    ClientData clientData)              /* Information about menu entry;  may
1180
                                         * or may not already have values for
1181
                                         * some fields. */
1182
{
1183
    TkMenu *menuPtr = (TkMenu *) clientData;
1184
    MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl;
1185
    MenuHandle helpMenuHdl = NULL;
1186
 
1187
    menuPtr->menuFlags &= ~MENU_RECONFIGURE_PENDING;
1188
 
1189
    if (NULL == macMenuHdl) {
1190
        return;
1191
    }
1192
 
1193
    ReconfigureIndividualMenu(menuPtr, macMenuHdl, 0);
1194
 
1195
    if (menuPtr->menuFlags & MENU_APPLE_MENU) {
1196
        AddResMenu(macMenuHdl, 'DRVR');
1197
    }
1198
 
1199
    if ((*macMenuHdl)->menuID == currentHelpMenuID) {
1200
        HMGetHelpMenuHandle(&helpMenuHdl);
1201
        if (helpMenuHdl != NULL) {
1202
            ReconfigureIndividualMenu(menuPtr, helpMenuHdl, helpItemCount);
1203
        }
1204
    }
1205
 
1206
    if (menuPtr->menuType == MENUBAR) {
1207
        if (!(menuBarFlags & MENUBAR_REDRAW_PENDING)) {
1208
            Tcl_DoWhenIdle(DrawMenuBarWhenIdle, (ClientData *) NULL);
1209
            menuBarFlags |= MENUBAR_REDRAW_PENDING;
1210
        }
1211
    }
1212
}
1213
 
1214
/*
1215
 *----------------------------------------------------------------------
1216
 *
1217
 * CompleteIdlers --
1218
 *
1219
 *      Completes all idle handling so that the menus are in sync when
1220
 *      the user invokes them with the mouse.
1221
 *
1222
 * Results:
1223
 *      None.
1224
 *
1225
 * Side effects:
1226
 *      The Macintosh menu handles are flushed out.
1227
 *
1228
 *----------------------------------------------------------------------
1229
 */
1230
 
1231
static void
1232
CompleteIdlers(
1233
    TkMenu *menuPtr)                    /* The menu we are completing. */
1234
{
1235
    int i;
1236
 
1237
    if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) {
1238
        Tcl_CancelIdleCall(ReconfigureMacintoshMenu, (ClientData) menuPtr);
1239
        ReconfigureMacintoshMenu((ClientData) menuPtr);
1240
    }
1241
 
1242
    for (i = 0; i < menuPtr->numEntries; i++) {
1243
        if (menuPtr->entries[i]->type == CASCADE_ENTRY) {
1244
            if ((menuPtr->entries[i]->childMenuRefPtr != NULL)
1245
                    && (menuPtr->entries[i]->childMenuRefPtr->menuPtr
1246
                    != NULL)) {
1247
                CompleteIdlers(menuPtr->entries[i]->childMenuRefPtr
1248
                        ->menuPtr);
1249
            }
1250
        }
1251
    }
1252
}
1253
 
1254
/*
1255
 *----------------------------------------------------------------------
1256
 *
1257
 * TkpPostMenu --
1258
 *
1259
 *      Posts a menu on the screen
1260
 *
1261
 * Results:
1262
 *      None.
1263
 *
1264
 * Side effects:
1265
 *      The menu is posted and handled.
1266
 *
1267
 *----------------------------------------------------------------------
1268
 */
1269
 
1270
int
1271
TkpPostMenu(
1272
    Tcl_Interp *interp,         /* The interpreter this menu lives in */
1273
    TkMenu *menuPtr,            /* The menu we are posting */
1274
    int x,                      /* The global x-coordinate of the top, left-
1275
                                 * hand corner of where the menu is supposed
1276
                                 * to be posted. */
1277
    int y)                      /* The global y-coordinate */
1278
{
1279
    MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl;
1280
    long popUpResult;
1281
    int result;
1282
    int oldMode;
1283
 
1284
    if (inPostMenu) {
1285
        Tcl_AppendResult(interp,
1286
                "Cannot call post menu while already posting menu",
1287
                (char *) NULL);
1288
        result = TCL_ERROR;
1289
    } else {
1290
        Window dummyWin;
1291
        unsigned int state;
1292
        int dummy, mouseX, mouseY;
1293
        short menuID;
1294
        Window window;
1295
        int oldWidth = menuPtr->totalWidth;
1296
        Tk_Window parentWindow = Tk_Parent(menuPtr->tkwin);
1297
 
1298
        inPostMenu++;
1299
 
1300
        result = TkPreprocessMenu(menuPtr);
1301
        if (result != TCL_OK) {
1302
            inPostMenu--;
1303
            return result;
1304
        }
1305
 
1306
        /*
1307
         * The post commands could have deleted the menu, which means
1308
         * we are dead and should go away.
1309
         */
1310
 
1311
        if (menuPtr->tkwin == NULL) {
1312
            inPostMenu--;
1313
            return TCL_OK;
1314
        }
1315
 
1316
        CompleteIdlers(menuPtr);
1317
        if (menuBarFlags & MENUBAR_REDRAW_PENDING) {
1318
            Tcl_CancelIdleCall(DrawMenuBarWhenIdle, (ClientData *) NULL);
1319
            DrawMenuBarWhenIdle((ClientData *) NULL);
1320
        }
1321
 
1322
        if (NULL == parentWindow) {
1323
            tearoffStruct.excludeRect.top = tearoffStruct.excludeRect.left
1324
                    = tearoffStruct.excludeRect.bottom
1325
                    = tearoffStruct.excludeRect.right = SHRT_MAX;
1326
        } else {
1327
            int left, top;
1328
 
1329
            Tk_GetRootCoords(parentWindow, &left, &top);
1330
            tearoffStruct.excludeRect.left = left;
1331
            tearoffStruct.excludeRect.top = top;
1332
            tearoffStruct.excludeRect.right = left + Tk_Width(parentWindow);
1333
            tearoffStruct.excludeRect.bottom = top + Tk_Height(parentWindow);
1334
            if (Tk_Class(parentWindow) == Tk_GetUid("Menubutton")) {
1335
                TkWindow *parentWinPtr = (TkWindow *) parentWindow;
1336
                TkMenuButton *mbPtr =
1337
                        (TkMenuButton *) parentWinPtr->instanceData;
1338
                int menuButtonWidth = Tk_Width(parentWindow)
1339
                        - 2 * (mbPtr->highlightWidth + mbPtr->borderWidth + 1);
1340
                menuPtr->totalWidth = menuButtonWidth > menuPtr->totalWidth
1341
                        ? menuButtonWidth : menuPtr->totalWidth;
1342
            }
1343
        }
1344
 
1345
        InsertMenu(macMenuHdl, -1);
1346
        RecursivelyInsertMenu(menuPtr);
1347
        CountMItems(macMenuHdl);
1348
 
1349
        FixMDEF();
1350
        oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
1351
        popUpResult = PopUpMenuSelect(macMenuHdl, y, x, menuPtr->active);
1352
        Tcl_SetServiceMode(oldMode);
1353
 
1354
        menuPtr->totalWidth = oldWidth;
1355
        RecursivelyDeleteMenu(menuPtr);
1356
        DeleteMenu((*macMenuHdl)->menuID);
1357
 
1358
        /*
1359
         * Simulate the mouse up.
1360
         */
1361
 
1362
        XQueryPointer(NULL, None, &dummyWin, &dummyWin, &mouseX,
1363
            &mouseY, &dummy, &dummy, &state);
1364
        window = Tk_WindowId(menuPtr->tkwin);
1365
        TkGenerateButtonEvent(mouseX, mouseY, window, state);
1366
 
1367
        /*
1368
         * Dispatch the command.
1369
         */
1370
 
1371
        menuID = HiWord(popUpResult);
1372
        if (menuID != 0) {
1373
            result = TkMacDispatchMenuEvent(menuID, LoWord(popUpResult));
1374
        } else {
1375
            TkMacHandleTearoffMenu();
1376
            result = TCL_OK;
1377
        }
1378
        InvalidateMDEFRgns();
1379
        RecursivelyClearActiveMenu(menuPtr);
1380
 
1381
        inPostMenu--;
1382
    }
1383
    return result;
1384
}
1385
 
1386
/*
1387
 *----------------------------------------------------------------------
1388
 *
1389
 * TkpMenuNewEntry --
1390
 *
1391
 *      Adds a pointer to a new menu entry structure with the platform-
1392
 *      specific fields filled in. The Macintosh uses the
1393
 *      platformEntryData field of the TkMenuEntry record to store
1394
 *      geometry information.
1395
 *
1396
 * Results:
1397
 *      Standard TCL error.
1398
 *
1399
 * Side effects:
1400
 *      Storage gets allocated. New menu entry data is put into the
1401
 *      platformEntryData field of the mePtr.
1402
 *
1403
 *----------------------------------------------------------------------
1404
 */
1405
 
1406
int
1407
TkpMenuNewEntry(
1408
    TkMenuEntry *mePtr)         /* The menu we are adding an entry to */
1409
{
1410
    EntryGeometry *geometryPtr =
1411
            (EntryGeometry *) ckalloc(sizeof(EntryGeometry));
1412
    TkMenu *menuPtr = mePtr->menuPtr;
1413
 
1414
    geometryPtr->accelTextStart = 0;
1415
    geometryPtr->accelTextWidth = 0;
1416
    geometryPtr->nonAccelMargin = 0;
1417
    geometryPtr->modifierWidth = 0;
1418
    mePtr->platformEntryData = (TkMenuPlatformEntryData) geometryPtr;
1419
    if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) {
1420
        menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
1421
        Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr);
1422
    }
1423
    return TCL_OK;
1424
}
1425
 
1426
/*
1427
 *----------------------------------------------------------------------
1428
 *
1429
 *
1430
 * Tk_MacTurnOffMenus --
1431
 *
1432
 *      Turns off all the menu drawing code.  This is more than just disabling
1433
 *      the "menu" command, this means that Tk will NEVER touch the menubar.
1434
 *      It is needed in the Plugin, where Tk does not own the menubar.
1435
 *
1436
 * Results:
1437
 *      None.
1438
 *
1439
 * Side effects:
1440
 *      A flag is set which will disable all menu drawing.
1441
 *
1442
 *----------------------------------------------------------------------
1443
 */
1444
 
1445
EXTERN void
1446
Tk_MacTurnOffMenus()
1447
{
1448
    gNoTkMenus = 1;
1449
}
1450
 
1451
/*
1452
 *----------------------------------------------------------------------
1453
 *
1454
 *
1455
 * DrawMenuBarWhenIdle --
1456
 *
1457
 *      Update the menu bar next time there is an idle event.
1458
 *
1459
 * Results:
1460
 *      None.
1461
 *
1462
 * Side effects:
1463
 *      Menu bar is redrawn.
1464
 *
1465
 *----------------------------------------------------------------------
1466
 */
1467
 
1468
static void
1469
DrawMenuBarWhenIdle(
1470
    ClientData clientData)      /* ignored here */
1471
{
1472
    TkMenuReferences *menuRefPtr;
1473
    TkMenu *appleMenuPtr, *helpMenuPtr;
1474
    MenuHandle macMenuHdl;
1475
    Tcl_HashEntry *hashEntryPtr;
1476
 
1477
    /*
1478
     * If we have been turned off, exit.
1479
     */
1480
 
1481
    if (gNoTkMenus) {
1482
        return;
1483
    }
1484
 
1485
    /*
1486
     * We need to clear the apple and help menus of any extra items.
1487
     */
1488
 
1489
    if (currentAppleMenuID != 0) {
1490
        hashEntryPtr = Tcl_FindHashEntry(&commandTable,
1491
                (char *) currentAppleMenuID);
1492
        appleMenuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr);
1493
        TkpDestroyMenu(appleMenuPtr);
1494
        TkpNewMenu(appleMenuPtr);
1495
        appleMenuPtr->menuFlags &= ~MENU_APPLE_MENU;
1496
        appleMenuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
1497
        Tcl_DoWhenIdle(ReconfigureMacintoshMenu,
1498
                (ClientData) appleMenuPtr);
1499
    }
1500
 
1501
    if (currentHelpMenuID != 0) {
1502
        hashEntryPtr = Tcl_FindHashEntry(&commandTable,
1503
                (char *) currentHelpMenuID);
1504
        helpMenuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr);
1505
        TkpDestroyMenu(helpMenuPtr);
1506
        TkpNewMenu(helpMenuPtr);
1507
        helpMenuPtr->menuFlags &= ~MENU_HELP_MENU;
1508
        helpMenuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
1509
        Tcl_DoWhenIdle(ReconfigureMacintoshMenu,
1510
                (ClientData) helpMenuPtr);
1511
    }
1512
 
1513
    /*
1514
     * We need to find the clone of this menu that is the menubar.
1515
     * Once we do that, for every cascade in the menu, we need to
1516
     * insert the Mac menu in the Mac menubar. Finally, we need
1517
     * to redraw the menubar.
1518
     */
1519
 
1520
    menuRefPtr = NULL;
1521
    if (currentMenuBarName != NULL) {
1522
        menuRefPtr = TkFindMenuReferences(currentMenuBarInterp,
1523
                currentMenuBarName);
1524
    }
1525
    if (menuRefPtr != NULL) {
1526
        TkMenu *menuPtr, *menuBarPtr;
1527
        TkMenu *cascadeMenuPtr;
1528
        char *appleMenuName, *helpMenuName;
1529
        int appleIndex = -1, helpIndex = -1;
1530
        int i;
1531
 
1532
        menuPtr = menuRefPtr->menuPtr;
1533
        if (menuPtr != NULL) {
1534
            TkMenuReferences *specialMenuRefPtr;
1535
            TkMenuEntry *specialEntryPtr;
1536
 
1537
            appleMenuName = ckalloc(strlen(currentMenuBarName)
1538
                    + 1 + strlen(".apple") + 1);
1539
            sprintf(appleMenuName, "%s.apple",
1540
                    Tk_PathName(menuPtr->tkwin));
1541
            specialMenuRefPtr = TkFindMenuReferences(currentMenuBarInterp,
1542
                    appleMenuName);
1543
            if ((specialMenuRefPtr != NULL)
1544
                    && (specialMenuRefPtr->menuPtr != NULL)) {
1545
                for (specialEntryPtr
1546
                        = specialMenuRefPtr->parentEntryPtr;
1547
                        specialEntryPtr != NULL;
1548
                        specialEntryPtr
1549
                        = specialEntryPtr->nextCascadePtr) {
1550
                    if (specialEntryPtr->menuPtr == menuPtr) {
1551
                        appleIndex = specialEntryPtr->index;
1552
                        break;
1553
                    }
1554
                }
1555
            }
1556
            ckfree(appleMenuName);
1557
 
1558
            helpMenuName = ckalloc(strlen(currentMenuBarName)
1559
                    + 1 + strlen(".help") + 1);
1560
            sprintf(helpMenuName, "%s.help",
1561
                    Tk_PathName(menuPtr->tkwin));
1562
            specialMenuRefPtr = TkFindMenuReferences(currentMenuBarInterp,
1563
                    helpMenuName);
1564
            if ((specialMenuRefPtr != NULL)
1565
                    && (specialMenuRefPtr->menuPtr != NULL)) {
1566
                for (specialEntryPtr
1567
                        = specialMenuRefPtr->parentEntryPtr;
1568
                        specialEntryPtr != NULL;
1569
                        specialEntryPtr
1570
                        = specialEntryPtr->nextCascadePtr) {
1571
                    if (specialEntryPtr->menuPtr == menuPtr) {
1572
                        helpIndex = specialEntryPtr->index;
1573
                        break;
1574
                    }
1575
                }
1576
            }
1577
            ckfree(helpMenuName);
1578
 
1579
        }
1580
 
1581
        for (menuBarPtr = menuPtr;
1582
                (menuBarPtr != NULL)
1583
                && (menuBarPtr->menuType != MENUBAR);
1584
                menuBarPtr = menuBarPtr->nextInstancePtr) {
1585
 
1586
            /*
1587
             * Null loop body.
1588
             */
1589
 
1590
        }
1591
 
1592
        if (menuBarPtr == NULL) {
1593
            SetDefaultMenubar();
1594
        } else {
1595
            if (menuBarPtr->tearOff != menuPtr->tearOff) {
1596
                if (menuBarPtr->tearOff) {
1597
                    appleIndex = (-1 == appleIndex) ? appleIndex
1598
                            : appleIndex + 1;
1599
                    helpIndex = (-1 == helpIndex) ? helpIndex
1600
                            : helpIndex + 1;
1601
                } else {
1602
                    appleIndex = (-1 == appleIndex) ? appleIndex
1603
                            : appleIndex - 1;
1604
                    helpIndex = (-1 == helpIndex) ? helpIndex
1605
                            : helpIndex - 1;
1606
                }
1607
            }
1608
            ClearMenuBar();
1609
 
1610
            if (appleIndex == -1) {
1611
                InsertMenu(tkAppleMenu, 0);
1612
                currentAppleMenuID = 0;
1613
            } else {
1614
                short appleID;
1615
                appleMenuPtr = menuBarPtr->entries[appleIndex]
1616
                        ->childMenuRefPtr->menuPtr;
1617
                TkpDestroyMenu(appleMenuPtr);
1618
                GetNewID(appleMenuPtr->interp, appleMenuPtr, 0,
1619
                        &appleID);
1620
                macMenuHdl = NewMenu(appleID, "\p\024");
1621
                appleMenuPtr->platformData =
1622
                        (TkMenuPlatformData) ckalloc(sizeof(MacMenu));
1623
                ((MacMenu *)appleMenuPtr->platformData)->menuHdl
1624
                        = macMenuHdl;
1625
                SetRect(&((MacMenu *) appleMenuPtr->platformData)->menuRect,
1626
                        0, 0, 0, 0);
1627
                appleMenuPtr->menuFlags |= MENU_APPLE_MENU;
1628
                if (!(appleMenuPtr->menuFlags
1629
                        & MENU_RECONFIGURE_PENDING)) {
1630
                    appleMenuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
1631
                    Tcl_DoWhenIdle(ReconfigureMacintoshMenu,
1632
                            (ClientData) appleMenuPtr);
1633
                }
1634
                InsertMenu(macMenuHdl, 0);
1635
                RecursivelyInsertMenu(appleMenuPtr);
1636
                currentAppleMenuID = appleID;
1637
            }
1638
            if (helpIndex == -1) {
1639
                currentHelpMenuID = 0;
1640
            }
1641
 
1642
            for (i = 0; i < menuBarPtr->numEntries; i++) {
1643
                if (i == appleIndex) {
1644
                    if (menuBarPtr->entries[i]->state == tkDisabledUid) {
1645
                        DisableItem(((MacMenu *) menuBarPtr->entries[i]
1646
                                ->childMenuRefPtr->menuPtr
1647
                                ->platformData)->menuHdl,
1648
                                0);
1649
                    } else {
1650
                        EnableItem(((MacMenu *) menuBarPtr->entries[i]
1651
                                ->childMenuRefPtr->menuPtr
1652
                                ->platformData)->menuHdl,
1653
                                0);
1654
                    }
1655
                    continue;
1656
                } else if (i == helpIndex) {
1657
                    TkMenu *helpMenuPtr = menuBarPtr->entries[i]
1658
                            ->childMenuRefPtr->menuPtr;
1659
                    MenuHandle helpMenuHdl = NULL;
1660
 
1661
                    if (helpMenuPtr == NULL) {
1662
                        continue;
1663
                    }
1664
                    helpMenuPtr->menuFlags |= MENU_HELP_MENU;
1665
                    if (!(helpMenuPtr->menuFlags
1666
                            & MENU_RECONFIGURE_PENDING)) {
1667
                        helpMenuPtr->menuFlags
1668
                                |= MENU_RECONFIGURE_PENDING;
1669
                        Tcl_DoWhenIdle(ReconfigureMacintoshMenu,
1670
                                (ClientData) helpMenuPtr);
1671
                    }
1672
                    macMenuHdl =
1673
                            ((MacMenu *) helpMenuPtr->platformData)->menuHdl;
1674
                    currentHelpMenuID = (*macMenuHdl)->menuID;
1675
                } else if (menuBarPtr->entries[i]->type
1676
                        == CASCADE_ENTRY) {
1677
                    if ((menuBarPtr->entries[i]->childMenuRefPtr != NULL)
1678
                            && menuBarPtr->entries[i]->childMenuRefPtr
1679
                            ->menuPtr != NULL) {
1680
                        cascadeMenuPtr = menuBarPtr->entries[i]
1681
                                ->childMenuRefPtr->menuPtr;
1682
                        macMenuHdl = ((MacMenu *) cascadeMenuPtr
1683
                                ->platformData)->menuHdl;
1684
                        DeleteMenu((*macMenuHdl)->menuID);
1685
                        InsertMenu(macMenuHdl, 0);
1686
                        RecursivelyInsertMenu(cascadeMenuPtr);
1687
                        if (menuBarPtr->entries[i]->state == tkDisabledUid) {
1688
                            DisableItem(((MacMenu *) menuBarPtr->entries[i]
1689
                                    ->childMenuRefPtr->menuPtr
1690
                                    ->platformData)->menuHdl,
1691
                                    0);
1692
                        } else {
1693
                            EnableItem(((MacMenu *) menuBarPtr->entries[i]
1694
                                    ->childMenuRefPtr->menuPtr
1695
                                    ->platformData)->menuHdl,
1696
                                    0);
1697
                         }
1698
                    }
1699
                }
1700
            }
1701
        }
1702
    } else {
1703
        SetDefaultMenubar();
1704
    }
1705
    DrawMenuBar();
1706
    menuBarFlags &= ~MENUBAR_REDRAW_PENDING;
1707
}
1708
 
1709
 
1710
/*
1711
 *----------------------------------------------------------------------
1712
 *
1713
 * RecursivelyInsertMenu --
1714
 *
1715
 *      Puts all of the cascades of this menu in the Mac hierarchical list.
1716
 *
1717
 *
1718
 * Results:
1719
 *      None.
1720
 *
1721
 * Side effects:
1722
 *      The menubar is changed.
1723
 *
1724
 *----------------------------------------------------------------------
1725
 */
1726
 
1727
static void
1728
RecursivelyInsertMenu(
1729
    TkMenu *menuPtr)            /* All of the cascade items in this menu
1730
                                 * will be inserted into the mac menubar. */
1731
{
1732
    int i;
1733
    TkMenu *cascadeMenuPtr;
1734
    MenuHandle macMenuHdl;
1735
 
1736
    for (i = 0; i < menuPtr->numEntries; i++) {
1737
        if (menuPtr->entries[i]->type == CASCADE_ENTRY) {
1738
            if ((menuPtr->entries[i]->childMenuRefPtr != NULL)
1739
                    && (menuPtr->entries[i]->childMenuRefPtr->menuPtr
1740
                    != NULL)) {
1741
                cascadeMenuPtr = menuPtr->entries[i]->childMenuRefPtr->menuPtr;
1742
                macMenuHdl = ((MacMenu *) cascadeMenuPtr->platformData)->menuHdl;
1743
                InsertMenu(macMenuHdl, -1);
1744
                RecursivelyInsertMenu(cascadeMenuPtr);
1745
            }
1746
        }
1747
    }
1748
}
1749
 
1750
/*
1751
 *----------------------------------------------------------------------
1752
 *
1753
 * RecursivelyDeleteMenu --
1754
 *
1755
 *      Takes all of the cascades of this menu out of the Mac hierarchical
1756
 *      list.
1757
 *
1758
 *
1759
 * Results:
1760
 *      None.
1761
 *
1762
 * Side effects:
1763
 *      The menubar is changed.
1764
 *
1765
 *----------------------------------------------------------------------
1766
 */
1767
 
1768
static void
1769
RecursivelyDeleteMenu(
1770
    TkMenu *menuPtr)            /* All of the cascade items in this menu
1771
                                 * will be inserted into the mac menubar. */
1772
{
1773
    int i;
1774
    TkMenu *cascadeMenuPtr;
1775
    MenuHandle macMenuHdl;
1776
 
1777
    for (i = 0; i < menuPtr->numEntries; i++) {
1778
        if (menuPtr->entries[i]->type == CASCADE_ENTRY) {
1779
            if ((menuPtr->entries[i]->childMenuRefPtr != NULL)
1780
                    && (menuPtr->entries[i]->childMenuRefPtr->menuPtr
1781
                    != NULL)) {
1782
                cascadeMenuPtr = menuPtr->entries[i]->childMenuRefPtr->menuPtr;
1783
                macMenuHdl = ((MacMenu *) cascadeMenuPtr->platformData)->menuHdl;
1784
                DeleteMenu((*macMenuHdl)->menuID);
1785
                RecursivelyInsertMenu(cascadeMenuPtr);
1786
            }
1787
        }
1788
    }
1789
}
1790
 
1791
/*
1792
 *----------------------------------------------------------------------
1793
 *
1794
 * SetDefaultMenubar --
1795
 *
1796
 *      Puts the Apple, File and Edit menus into the Macintosh menubar.
1797
 *
1798
 * Results:
1799
 *      None.
1800
 *
1801
 * Side effects:
1802
 *      The menubar is changed.
1803
 *
1804
 *----------------------------------------------------------------------
1805
 */
1806
 
1807
static void
1808
SetDefaultMenubar()
1809
{
1810
    if (currentMenuBarName != NULL) {
1811
        ckfree(currentMenuBarName);
1812
        currentMenuBarName = NULL;
1813
    }
1814
    currentMenuBarOwner = NULL;
1815
    ClearMenuBar();
1816
    InsertMenu(tkAppleMenu, 0);
1817
    InsertMenu(tkFileMenu, 0);
1818
    InsertMenu(tkEditMenu, 0);
1819
    if (!(menuBarFlags & MENUBAR_REDRAW_PENDING)) {
1820
        Tcl_DoWhenIdle(DrawMenuBarWhenIdle, (ClientData *) NULL);
1821
        menuBarFlags |= MENUBAR_REDRAW_PENDING;
1822
    }
1823
}
1824
 
1825
/*
1826
 *----------------------------------------------------------------------
1827
 *
1828
 * TkpSetMainMenubar --
1829
 *
1830
 *      Puts the menu associated with a window into the menubar. Should
1831
 *      only be called when the window is in front.
1832
 *
1833
 * Results:
1834
 *      None.
1835
 *
1836
 * Side effects:
1837
 *      The menubar is changed.
1838
 *
1839
 *----------------------------------------------------------------------
1840
 */
1841
 
1842
void
1843
TkpSetMainMenubar(
1844
    Tcl_Interp *interp,         /* The interpreter of the application */
1845
    Tk_Window tkwin,            /* The frame we are setting up */
1846
    char *menuName)             /* The name of the menu to put in front.
1847
                                 * If NULL, use the default menu bar.
1848
                                 */
1849
{
1850
    TkWindow *winPtr = (TkWindow *) tkwin;
1851
    WindowRef macWindowPtr = (WindowRef) TkMacGetDrawablePort(winPtr->window);
1852
 
1853
    if ((macWindowPtr == NULL) || (macWindowPtr != FrontWindow())) {
1854
        return;
1855
    }
1856
 
1857
    if ((currentMenuBarInterp != interp)
1858
            || (currentMenuBarOwner != tkwin)
1859
            || (currentMenuBarName == NULL)
1860
            || (menuName == NULL)
1861
            || (strcmp(menuName, currentMenuBarName) != 0)) {
1862
        Tk_Window searchWindow;
1863
        TopLevelMenubarList *listPtr;
1864
 
1865
        if (currentMenuBarName != NULL) {
1866
            ckfree(currentMenuBarName);
1867
        }
1868
 
1869
        if (menuName == NULL) {
1870
            searchWindow = tkwin;
1871
            if (strcmp(Tk_Class(searchWindow), "Menu") == 0) {
1872
                TkMenuReferences *menuRefPtr;
1873
 
1874
                menuRefPtr = TkFindMenuReferences(interp, Tk_PathName(tkwin));
1875
                if (menuRefPtr != NULL) {
1876
                    TkMenu *menuPtr = menuRefPtr->menuPtr;
1877
                    if (menuPtr != NULL) {
1878
                        menuPtr = menuPtr->masterMenuPtr;
1879
                        searchWindow = menuPtr->tkwin;
1880
                    }
1881
                }
1882
            }
1883
            for (; searchWindow != NULL;
1884
                    searchWindow = Tk_Parent(searchWindow)) {
1885
 
1886
                for (listPtr = windowListPtr; listPtr != NULL;
1887
                        listPtr = listPtr->nextPtr) {
1888
                    if (listPtr->tkwin == searchWindow) {
1889
                        break;
1890
                    }
1891
                }
1892
                if (listPtr != NULL) {
1893
                    menuName = Tk_PathName(listPtr->menuPtr->masterMenuPtr->tkwin);
1894
                    break;
1895
                }
1896
            }
1897
        }
1898
 
1899
        if (menuName == NULL) {
1900
            currentMenuBarName = NULL;
1901
        } else {
1902
            currentMenuBarName = ckalloc(strlen(menuName) + 1);
1903
            strcpy(currentMenuBarName, menuName);
1904
        }
1905
        currentMenuBarOwner = tkwin;
1906
        currentMenuBarInterp = interp;
1907
    }
1908
    if (!(menuBarFlags & MENUBAR_REDRAW_PENDING)) {
1909
        Tcl_DoWhenIdle(DrawMenuBarWhenIdle, (ClientData *) NULL);
1910
        menuBarFlags |= MENUBAR_REDRAW_PENDING;
1911
    }
1912
}
1913
 
1914
/*
1915
 *----------------------------------------------------------------------
1916
 *
1917
 * TkpSetWindowMenuBar --
1918
 *
1919
 *      Associates a given menu with a window.
1920
 *
1921
 * Results:
1922
 *      None.
1923
 *
1924
 * Side effects:
1925
 *      On Windows and UNIX, associates the platform menu with the
1926
 *      platform window.
1927
 *
1928
 *----------------------------------------------------------------------
1929
 */
1930
 
1931
void
1932
TkpSetWindowMenuBar(
1933
    Tk_Window tkwin,            /* The window we are setting the menu in */
1934
    TkMenu *menuPtr)            /* The menu we are setting */
1935
{
1936
    TopLevelMenubarList *listPtr, *prevPtr;
1937
 
1938
    /*
1939
     * Remove any existing reference to this window.
1940
     */
1941
 
1942
    for (prevPtr = NULL, listPtr = windowListPtr;
1943
            listPtr != NULL;
1944
            prevPtr = listPtr, listPtr = listPtr->nextPtr) {
1945
        if (listPtr->tkwin == tkwin) {
1946
            break;
1947
        }
1948
    }
1949
 
1950
    if (listPtr != NULL) {
1951
        if (prevPtr != NULL) {
1952
            prevPtr->nextPtr = listPtr->nextPtr;
1953
        } else {
1954
            windowListPtr = listPtr->nextPtr;
1955
        }
1956
        ckfree((char *) listPtr);
1957
    }
1958
 
1959
    if (menuPtr != NULL) {
1960
        listPtr = (TopLevelMenubarList *) ckalloc(sizeof(TopLevelMenubarList));
1961
        listPtr->nextPtr = windowListPtr;
1962
        windowListPtr = listPtr;
1963
        listPtr->tkwin = tkwin;
1964
        listPtr->menuPtr = menuPtr;
1965
    }
1966
}
1967
 
1968
/*
1969
 *----------------------------------------------------------------------
1970
 *
1971
 * TkMacDispatchMenuEvent --
1972
 *
1973
 *      Given a menu id and an item, dispatches the command associated
1974
 *      with it.
1975
 *
1976
 * Results:
1977
 *      None.
1978
 *
1979
 * Side effects:
1980
 *      Commands get executed.
1981
 *
1982
 *----------------------------------------------------------------------
1983
 */
1984
 
1985
int
1986
TkMacDispatchMenuEvent(
1987
    int menuID,         /* The menu id of the menu we are invoking */
1988
    int index)          /* The one-based index of the item that was
1989
                         * selected. */
1990
{
1991
    int result = TCL_OK;
1992
    if (menuID != 0) {
1993
        if (menuID == kHMHelpMenuID) {
1994
            if (currentMenuBarOwner != NULL) {
1995
                TkMenuReferences *helpMenuRef;
1996
                char *helpMenuName = ckalloc(strlen(currentMenuBarName)
1997
                        + strlen(".help") + 1);
1998
                sprintf(helpMenuName, "%s.help", currentMenuBarName);
1999
                helpMenuRef = TkFindMenuReferences(currentMenuBarInterp,
2000
                        helpMenuName);
2001
                ckfree(helpMenuName);
2002
                if ((helpMenuRef != NULL) && (helpMenuRef->menuPtr != NULL)) {
2003
                    int newIndex = index - helpItemCount - 1;
2004
                    result = TkInvokeMenu(currentMenuBarInterp,
2005
                            helpMenuRef->menuPtr, newIndex);
2006
                }
2007
            }
2008
        } else {
2009
            Tcl_HashEntry *commandEntryPtr =
2010
                    Tcl_FindHashEntry(&commandTable, (char *) menuID);
2011
            TkMenu *menuPtr = (TkMenu *) Tcl_GetHashValue(commandEntryPtr);
2012
            if ((currentAppleMenuID == menuID)
2013
                    && (index > menuPtr->numEntries + 1)) {
2014
                Str255 itemText;
2015
 
2016
                GetMenuItemText(GetMenuHandle(menuID), index, itemText);
2017
                OpenDeskAcc(itemText);
2018
                result = TCL_OK;
2019
            } else {
2020
                result = TkInvokeMenu(menuPtr->interp, menuPtr, index - 1);
2021
            }
2022
        }
2023
    }
2024
    return result;
2025
}
2026
 
2027
/*
2028
 *----------------------------------------------------------------------
2029
 *
2030
 * GetMenuIndicatorGeometry --
2031
 *
2032
 *      Gets the width and height of the indicator area of a menu.
2033
 *
2034
 * Results:
2035
 *      widthPtr and heightPtr are set.
2036
 *
2037
 * Side effects:
2038
 *      None.
2039
 *
2040
 *----------------------------------------------------------------------
2041
 */
2042
 
2043
static void
2044
GetMenuIndicatorGeometry (
2045
    TkMenu *menuPtr,                    /* The menu we are drawing */
2046
    TkMenuEntry *mePtr,                 /* The entry we are measuring */
2047
    Tk_Font tkfont,                     /* Precalculated font */
2048
    CONST Tk_FontMetrics *fmPtr,        /* Precalculated font metrics */
2049
    int *widthPtr,                      /* The resulting width */
2050
    int *heightPtr)                     /* The resulting height */
2051
{
2052
    char markChar;
2053
 
2054
    *heightPtr = fmPtr->linespace;
2055
 
2056
    markChar = (char) FindMarkCharacter(mePtr);
2057
    *widthPtr = Tk_TextWidth(tkfont, &markChar, 1) + 4;
2058
}
2059
 
2060
/*
2061
 *----------------------------------------------------------------------
2062
 *
2063
 * GetMenuAccelGeometry --
2064
 *
2065
 *      Gets the width and height of the accelerator area of a menu.
2066
 *
2067
 * Results:
2068
 *      widthPtr and heightPtr are set.
2069
 *
2070
 * Side effects:
2071
 *      None.
2072
 *
2073
 *----------------------------------------------------------------------
2074
 */
2075
 
2076
static void
2077
GetMenuAccelGeometry (
2078
    TkMenu *menuPtr,                    /* The menu we are measuring */
2079
    TkMenuEntry *mePtr,                 /* The entry we are measuring */
2080
    Tk_Font tkfont,                     /* The precalculated font */
2081
    CONST Tk_FontMetrics *fmPtr,        /* The precalculated font metrics */
2082
    int *modWidthPtr,                   /* The width of all of the key
2083
                                         * modifier symbols. */
2084
    int *textWidthPtr,                  /* The resulting width */
2085
    int *heightPtr)                     /* The resulting height */
2086
{
2087
    *heightPtr = fmPtr->linespace;
2088
    *modWidthPtr = 0;
2089
    if (mePtr->type == CASCADE_ENTRY) {
2090
        *textWidthPtr = SICN_HEIGHT;
2091
        *modWidthPtr = Tk_TextWidth(tkfont, "W", 1);
2092
    } else if (0 == mePtr->accelLength) {
2093
        *textWidthPtr = 0;
2094
    } else {
2095
 
2096
        if (NULL == GetResource('SICN', SICN_RESOURCE_NUMBER)) {
2097
            *textWidthPtr = Tk_TextWidth(tkfont, mePtr->accel,
2098
                    mePtr->accelLength);
2099
        } else {
2100
            int emWidth = Tk_TextWidth(tkfont, "W", 1) + 1;
2101
            if ((mePtr->entryFlags & ENTRY_ACCEL_MASK) == 0) {
2102
                int width = Tk_TextWidth(tkfont, mePtr->accel,
2103
                        mePtr->accelLength);
2104
                *textWidthPtr = emWidth;
2105
                if (width < emWidth) {
2106
                    *modWidthPtr = 0;
2107
                } else {
2108
                    *modWidthPtr = width - emWidth;
2109
                }
2110
            } else {
2111
                int length = ((EntryGeometry *)mePtr->platformEntryData)
2112
                        ->accelTextStart;
2113
                if (mePtr->entryFlags & ENTRY_CONTROL_ACCEL) {
2114
                    *modWidthPtr += CONTROL_ICON_WIDTH;
2115
                }
2116
                if (mePtr->entryFlags & ENTRY_SHIFT_ACCEL) {
2117
                    *modWidthPtr += SHIFT_ICON_WIDTH;
2118
                }
2119
                if (mePtr->entryFlags & ENTRY_OPTION_ACCEL) {
2120
                    *modWidthPtr += OPTION_ICON_WIDTH;
2121
                }
2122
                if (mePtr->entryFlags & ENTRY_COMMAND_ACCEL) {
2123
                    *modWidthPtr += COMMAND_ICON_WIDTH;
2124
                }
2125
                if (1 == (mePtr->accelLength - length)) {
2126
                    *textWidthPtr = emWidth;
2127
                } else {
2128
                    *textWidthPtr += Tk_TextWidth(tkfont, mePtr->accel
2129
                            + length, mePtr->accelLength - length);
2130
                }
2131
            }
2132
        }
2133
    }
2134
}
2135
 
2136
/*
2137
 *----------------------------------------------------------------------
2138
 *
2139
 * GetTearoffEntryGeometry --
2140
 *
2141
 *      Gets the width and height of of a tearoff entry.
2142
 *
2143
 * Results:
2144
 *      widthPtr and heightPtr are set.
2145
 *
2146
 * Side effects:
2147
 *      None.
2148
 *
2149
 *----------------------------------------------------------------------
2150
 */
2151
 
2152
static void
2153
GetTearoffEntryGeometry (
2154
    TkMenu *menuPtr,                    /* The menu we are drawing */
2155
    TkMenuEntry *mePtr,                 /* The entry we are measuring */
2156
    Tk_Font tkfont,                     /* The precalculated font */
2157
    CONST Tk_FontMetrics *fmPtr,        /* The precalculated font metrics */
2158
    int *widthPtr,                      /* The resulting width */
2159
    int *heightPtr)                     /* The resulting height */
2160
{
2161
    if ((GetResource('MDEF', 591) == NULL) &&
2162
            (menuPtr->menuType == MASTER_MENU)) {
2163
        *heightPtr = fmPtr->linespace;
2164
        *widthPtr = 0;
2165
    } else {
2166
        *widthPtr = *heightPtr = 0;
2167
    }
2168
}
2169
 
2170
/*
2171
 *----------------------------------------------------------------------
2172
 *
2173
 * GetMenuSeparatorGeometry --
2174
 *
2175
 *      Gets the width and height of menu separator.
2176
 *
2177
 * Results:
2178
 *      widthPtr and heightPtr are set.
2179
 *
2180
 * Side effects:
2181
 *      None.
2182
 *
2183
 *----------------------------------------------------------------------
2184
 */
2185
 
2186
static void
2187
GetMenuSeparatorGeometry(
2188
    TkMenu *menuPtr,                    /* The menu we are drawing */
2189
    TkMenuEntry *mePtr,                 /* The entry we are measuring */
2190
    Tk_Font tkfont,                     /* The precalculated font */
2191
    CONST Tk_FontMetrics *fmPtr,        /* The precalcualted font metrics */
2192
    int *widthPtr,                      /* The resulting width */
2193
    int *heightPtr)                     /* The resulting height */
2194
{
2195
    if (TkMacHaveAppearance() > 1) {
2196
        SInt16 outHeight;
2197
 
2198
        GetThemeMenuSeparatorHeight(&outHeight);
2199
        *widthPtr = 0;
2200
        *heightPtr = outHeight;
2201
    } else {
2202
        *widthPtr = 0;
2203
        *heightPtr = fmPtr->linespace;
2204
    }
2205
}
2206
 
2207
/*
2208
 *----------------------------------------------------------------------
2209
 *
2210
 * DrawMenuEntryIndicator --
2211
 *
2212
 *      This procedure draws the indicator part of a menu.
2213
 *
2214
 * Results:
2215
 *      None.
2216
 *
2217
 * Side effects:
2218
 *      Commands are output to X to display the menu in its
2219
 *      current mode.
2220
 *
2221
 *----------------------------------------------------------------------
2222
 */
2223
 
2224
static void
2225
DrawMenuEntryIndicator(
2226
    TkMenu *menuPtr,                    /* The menu we are drawing */
2227
    TkMenuEntry *mePtr,                 /* The entry we are drawing */
2228
    Drawable d,                         /* The drawable we are drawing */
2229
    GC gc,                              /* The GC we are drawing with */
2230
    GC indicatorGC,                     /* The GC to use for the indicator */
2231
    Tk_Font tkfont,                     /* The precalculated font */
2232
    CONST Tk_FontMetrics *fmPtr,        /* The precalculated font metrics */
2233
    int x,                              /* topleft hand corner of entry */
2234
    int y,                              /* topleft hand corner of entry */
2235
    int width,                          /* width of entry */
2236
    int height)                         /* height of entry */
2237
{
2238
    if (((mePtr->type == CHECK_BUTTON_ENTRY) ||
2239
            (mePtr->type == RADIO_BUTTON_ENTRY))
2240
            && (mePtr->indicatorOn)
2241
            && (mePtr->entryFlags & ENTRY_SELECTED)) {
2242
        int baseline;
2243
        short markShort;
2244
        char markChar;
2245
 
2246
        baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2;
2247
        GetItemMark(((MacMenu *) menuPtr->platformData)->menuHdl,
2248
                mePtr->index + 1, &markShort);
2249
        if (markShort != 0) {
2250
            markChar = (char) markShort;
2251
            Tk_DrawChars(menuPtr->display, d, gc, tkfont, &markChar, 1,
2252
                    x + 2, baseline);
2253
        }
2254
    }
2255
}
2256
 
2257
/*
2258
 *----------------------------------------------------------------------
2259
 *
2260
 * DrawMenuBackground --
2261
 *
2262
 *      If Appearance is present, draws the Appearance background
2263
 *
2264
 * Results:
2265
 *      Nothing
2266
 *
2267
 * Side effects:
2268
 *      Commands are output to X to display the menu in its
2269
 *      current mode.
2270
 *
2271
 *----------------------------------------------------------------------
2272
 */
2273
static void
2274
DrawMenuBackground(
2275
    Rect     *menuRectPtr,      /* The menu rect */
2276
    Drawable d,                 /* What we are drawing into */
2277
    ThemeMenuType type                  /* Type of menu */
2278
    )
2279
{
2280
    if (!TkMacHaveAppearance()) {
2281
        return;
2282
    } else {
2283
        CGrafPtr saveWorld;
2284
        GDHandle saveDevice;
2285
        GWorldPtr destPort;
2286
 
2287
        destPort = TkMacGetDrawablePort(d);
2288
        GetGWorld(&saveWorld, &saveDevice);
2289
        SetGWorld(destPort, NULL);
2290
        TkMacSetUpClippingRgn(d);
2291
        DrawThemeMenuBackground (menuRectPtr, type);
2292
        SetGWorld(saveWorld, saveDevice);
2293
        return;
2294
    }
2295
}
2296
 
2297
/*
2298
 *----------------------------------------------------------------------
2299
 *
2300
 * DrawSICN --
2301
 *
2302
 *      Given a resource id and an index, loads the appropriate SICN
2303
 *      and draws it into a given drawable using the given gc.
2304
 *
2305
 * Results:
2306
 *      Returns 1 if the SICN was found, 0 if not found.
2307
 *
2308
 * Side effects:
2309
 *      Commands are output to X to display the menu in its
2310
 *      current mode.
2311
 *
2312
 *----------------------------------------------------------------------
2313
 */
2314
static int
2315
DrawSICN(
2316
    int resourceID,                 /* The resource # of the SICN table */
2317
    int index,                      /* The index into the SICN table of the
2318
                                     * icon we want. */
2319
    Drawable d,                     /* What we are drawing into */
2320
    GC gc,                          /* The GC to draw with */
2321
    int x,                          /* The left hand coord of the SICN */
2322
    int y)                          /* The top coord of the SICN */
2323
{
2324
    Handle sicnHandle = (Handle) GetResource('SICN', SICN_RESOURCE_NUMBER);
2325
 
2326
    if (NULL == sicnHandle) {
2327
        return 0;
2328
    } else {
2329
        BitMap sicnBitmap;
2330
        Rect destRect;
2331
        CGrafPtr saveWorld;
2332
        GDHandle saveDevice;
2333
        GWorldPtr destPort;
2334
        BitMapPtr destBitMap;
2335
        RGBColor origForeColor, origBackColor, foreColor, backColor;
2336
 
2337
        HLock(sicnHandle);
2338
        destPort = TkMacGetDrawablePort(d);
2339
        GetGWorld(&saveWorld, &saveDevice);
2340
        SetGWorld(destPort, NULL);
2341
        TkMacSetUpClippingRgn(d);
2342
        TkMacSetUpGraphicsPort(gc);
2343
        GetForeColor(&origForeColor);
2344
        GetBackColor(&origBackColor);
2345
 
2346
        if (TkSetMacColor(gc->foreground, &foreColor) == true) {
2347
            RGBForeColor(&foreColor);
2348
        }
2349
 
2350
        if (TkSetMacColor(gc->background, &backColor) == true) {
2351
            RGBBackColor(&backColor);
2352
        }
2353
 
2354
        SetRect(&destRect, x, y, x + SICN_HEIGHT, y + SICN_HEIGHT);
2355
        sicnBitmap.baseAddr = (Ptr) (*sicnHandle) + index * SICN_HEIGHT
2356
            * SICN_ROWS;
2357
        sicnBitmap.rowBytes = SICN_ROWS;
2358
        SetRect(&sicnBitmap.bounds, 0, 0, 16, 16);
2359
        destBitMap = &((GrafPtr) destPort)->portBits;
2360
        CopyBits(&sicnBitmap, destBitMap, &sicnBitmap.bounds, &destRect,
2361
            destPort->txMode, NULL);
2362
        HUnlock(sicnHandle);
2363
        RGBForeColor(&origForeColor);
2364
        RGBBackColor(&origBackColor);
2365
        SetGWorld(saveWorld, saveDevice);
2366
        return 1;
2367
    }
2368
}
2369
 
2370
/*
2371
 *----------------------------------------------------------------------
2372
 *
2373
 * DrawMenuEntryAccelerator --
2374
 *
2375
 *      This procedure draws the accelerator part of a menu. We
2376
 *      need to decide what to draw here. Should we replace strings
2377
 *      like "Control", "Command", etc?
2378
 *
2379
 * Results:
2380
 *      None.
2381
 *
2382
 * Side effects:
2383
 *      Commands are output to X to display the menu in its
2384
 *      current mode.
2385
 *
2386
 *----------------------------------------------------------------------
2387
 */
2388
 
2389
static void
2390
DrawMenuEntryAccelerator(
2391
    TkMenu *menuPtr,                /* The menu we are drawing */
2392
    TkMenuEntry *mePtr,             /* The entry we are drawing */
2393
    Drawable d,                     /* The drawable we are drawing in */
2394
    GC gc,                          /* The gc to draw into */
2395
    Tk_Font tkfont,                 /* The precalculated font */
2396
    CONST Tk_FontMetrics *fmPtr,    /* The precalculated font metrics */
2397
    Tk_3DBorder activeBorder,       /* border for menu background */
2398
    int x,                          /* The left side of the entry */
2399
    int y,                          /* The top of the entry */
2400
    int width,                      /* The width of the entry */
2401
    int height,                     /* The height of the entry */
2402
    int drawArrow)                  /* Whether or not to draw cascade arrow */
2403
{
2404
    if (mePtr->type == CASCADE_ENTRY) {
2405
        /*
2406
         * Under Appearance, we let the Appearance Manager draw the icon
2407
         */
2408
 
2409
        if (!TkMacHaveAppearance()) {
2410
        if (0 == DrawSICN(SICN_RESOURCE_NUMBER, CASCADE_ARROW, d, gc,
2411
                x + width - SICN_HEIGHT, (y + (height / 2))
2412
                - (SICN_HEIGHT / 2))) {
2413
            XPoint points[3];
2414
            Tk_Window tkwin = menuPtr->tkwin;
2415
 
2416
            if (mePtr->type == CASCADE_ENTRY) {
2417
                points[0].x = width - menuPtr->activeBorderWidth
2418
                        - MAC_MARGIN_WIDTH - CASCADE_ARROW_WIDTH;
2419
                points[0].y = y + (height - CASCADE_ARROW_HEIGHT)/2;
2420
                points[1].x = points[0].x;
2421
                points[1].y = points[0].y + CASCADE_ARROW_HEIGHT;
2422
                points[2].x = points[0].x + CASCADE_ARROW_WIDTH;
2423
                points[2].y = points[0].y + CASCADE_ARROW_HEIGHT/2;
2424
                Tk_Fill3DPolygon(menuPtr->tkwin, d, activeBorder, points,
2425
                        3, DECORATION_BORDER_WIDTH, TK_RELIEF_FLAT);
2426
            }
2427
        }
2428
        }
2429
    } else if (mePtr->accelLength != 0) {
2430
        int leftEdge = x + width;
2431
        int baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2;
2432
 
2433
        if (NULL == GetResource('SICN', SICN_RESOURCE_NUMBER)) {
2434
            leftEdge -= ((EntryGeometry *) mePtr->platformEntryData)
2435
                    ->accelTextWidth;
2436
            Tk_DrawChars(menuPtr->display, d, gc, tkfont, mePtr->accel,
2437
                    mePtr->accelLength, leftEdge, baseline);
2438
        } else {
2439
            EntryGeometry *geometryPtr =
2440
                    (EntryGeometry *) mePtr->platformEntryData;
2441
            int length = mePtr->accelLength - geometryPtr->accelTextStart;
2442
 
2443
            leftEdge -= geometryPtr->accelTextWidth;
2444
            if ((mePtr->entryFlags & ENTRY_ACCEL_MASK) == 0) {
2445
                leftEdge -= geometryPtr->modifierWidth;
2446
            }
2447
 
2448
            Tk_DrawChars(menuPtr->display, d, gc, tkfont, mePtr->accel
2449
                    + geometryPtr->accelTextStart, length, leftEdge, baseline);
2450
 
2451
            if (mePtr->entryFlags & ENTRY_COMMAND_ACCEL) {
2452
                leftEdge -= COMMAND_ICON_WIDTH;
2453
                DrawSICN(SICN_RESOURCE_NUMBER, COMMAND_ICON, d, gc,
2454
                        leftEdge, (y + (height / 2)) - (SICN_HEIGHT / 2) - 1);
2455
            }
2456
 
2457
            if (mePtr->entryFlags & ENTRY_OPTION_ACCEL) {
2458
                leftEdge -= OPTION_ICON_WIDTH;
2459
                DrawSICN(SICN_RESOURCE_NUMBER, OPTION_ICON, d, gc,
2460
                        leftEdge, (y + (height / 2)) - (SICN_HEIGHT / 2) - 1);
2461
            }
2462
 
2463
            if (mePtr->entryFlags & ENTRY_SHIFT_ACCEL) {
2464
                leftEdge -= SHIFT_ICON_WIDTH;
2465
                DrawSICN(SICN_RESOURCE_NUMBER, SHIFT_ICON, d, gc,
2466
                        leftEdge, (y + (height / 2)) - (SICN_HEIGHT / 2) - 1);
2467
            }
2468
 
2469
            if (mePtr->entryFlags & ENTRY_CONTROL_ACCEL) {
2470
                leftEdge -= CONTROL_ICON_WIDTH;
2471
                DrawSICN(SICN_RESOURCE_NUMBER, CONTROL_ICON, d, gc,
2472
                        leftEdge, (y + (height / 2)) - (SICN_HEIGHT / 2) - 1);
2473
            }
2474
        }
2475
    }
2476
}
2477
 
2478
/*
2479
 *----------------------------------------------------------------------
2480
 *
2481
 * DrawMenuSeparator --
2482
 *
2483
 *      The menu separator is drawn.
2484
 *
2485
 * Results:
2486
 *      None.
2487
 *
2488
 * Side effects:
2489
 *      Commands are output to X to display the menu in its
2490
 *      current mode.
2491
 *
2492
 *----------------------------------------------------------------------
2493
 */
2494
 
2495
static void
2496
DrawMenuSeparator(
2497
    TkMenu *menuPtr,                    /* The menu we are drawing */
2498
    TkMenuEntry *mePtr,                 /* The entry we are drawing */
2499
    Drawable d,                         /* The drawable we are drawing into */
2500
    GC gc,                              /* The gc we are drawing with */
2501
    Tk_Font tkfont,                     /* The precalculated font */
2502
    CONST Tk_FontMetrics *fmPtr,        /* The precalculated font metrics */
2503
    int x,                              /* left coordinate of entry */
2504
    int y,                              /* top coordinate of entry */
2505
    int width,                          /* width of entry */
2506
    int height)                         /* height of entry */
2507
{
2508
    CGrafPtr saveWorld;
2509
    GDHandle saveDevice;
2510
    GWorldPtr destPort;
2511
 
2512
    destPort = TkMacGetDrawablePort(d);
2513
    GetGWorld(&saveWorld, &saveDevice);
2514
    SetGWorld(destPort, NULL);
2515
    TkMacSetUpClippingRgn(d);
2516
    if (TkMacHaveAppearance() > 1) {
2517
        Rect r;
2518
        r.top = y;
2519
        r.left = x;
2520
        r.bottom = y + height;
2521
        r.right = x + width;
2522
 
2523
        DrawThemeMenuSeparator(&r);
2524
    } else {
2525
    /*
2526
     * We don't want to use the text GC for drawing the separator. It
2527
     * needs to be the same color as disabled items.
2528
     */
2529
 
2530
    TkMacSetUpGraphicsPort(mePtr->disabledGC != None ? mePtr->disabledGC
2531
            : menuPtr->disabledGC);
2532
 
2533
    MoveTo(x, y + (height / 2));
2534
    Line(width, 0);
2535
 
2536
    SetGWorld(saveWorld, saveDevice);
2537
}
2538
}
2539
 
2540
/*
2541
 *----------------------------------------------------------------------
2542
 *
2543
 * MenuDefProc --
2544
 *
2545
 *      This routine is the MDEF handler for Tk. It receives all messages
2546
 *      for the menu and dispatches them.
2547
 *
2548
 * Results:
2549
 *      None.
2550
 *
2551
 * Side effects:
2552
 *      This routine causes menus to be drawn and will certainly allocate
2553
 *      memory as a result. Also, the menu can scroll up and down, and
2554
 *      various other interface actions can take place.
2555
 *
2556
 *----------------------------------------------------------------------
2557
 */
2558
 
2559
static void
2560
MenuDefProc(
2561
    short message,                      /* What action are we taking? */
2562
    MenuHandle menu,                    /* The menu we are working with */
2563
    Rect *menuRectPtr,                  /* A pointer to the rect for the
2564
                                         * whole menu. */
2565
    Point hitPt,                        /* Where the mouse was clicked for
2566
                                         * the appropriate messages. */
2567
    short *whichItem,                   /* Output result. Which item was
2568
                                         * hit by the user? */
2569
    TkMenuLowMemGlobals *globalsPtr)    /* The low mem globals we have
2570
                                         * to change */
2571
{
2572
#define SCREEN_MARGIN 5
2573
    TkMenu *menuPtr;
2574
    TkMenuEntry *parentEntryPtr;
2575
    Tcl_HashEntry *commandEntryPtr;
2576
    GrafPtr windowMgrPort;
2577
    Tk_Font tkfont;
2578
    Tk_FontMetrics fontMetrics, entryMetrics;
2579
    Tk_FontMetrics *fmPtr;
2580
    TkMenuEntry *mePtr;
2581
    int i;
2582
    int maxMenuHeight;
2583
    int oldItem;
2584
    int newItem = -1;
2585
    GDHandle device;
2586
    Rect itemRect;
2587
    short windowPart;
2588
    WindowRef whichWindow;
2589
    RGBColor bgColor;
2590
    RGBColor fgColor;
2591
    RGBColor origFgColor;
2592
    PenState origPenState;
2593
    Rect dragRect;
2594
    Rect scratchRect = {-32768, -32768, 32767, 32767};
2595
    RgnHandle oldClipRgn;
2596
    TkMenuReferences *menuRefPtr;
2597
    TkMenu *searchMenuPtr;
2598
    Rect menuClipRect;
2599
 
2600
    HLock((Handle) menu);
2601
    commandEntryPtr = Tcl_FindHashEntry(&commandTable,
2602
            (char *) (*menu)->menuID);
2603
    HUnlock((Handle) menu);
2604
    menuPtr = (TkMenu *) Tcl_GetHashValue(commandEntryPtr);
2605
 
2606
    switch (message) {
2607
        case mSizeMsg:
2608
            GetWMgrPort(&windowMgrPort);
2609
            maxMenuHeight = windowMgrPort->portRect.bottom
2610
                    - windowMgrPort->portRect.top
2611
                    - GetMBarHeight() - SCREEN_MARGIN;
2612
            (*menu)->menuWidth = menuPtr->totalWidth;
2613
            (*menu)->menuHeight = maxMenuHeight < menuPtr->totalHeight ?
2614
                    maxMenuHeight : menuPtr->totalHeight;
2615
            break;
2616
 
2617
        case mDrawMsg:
2618
 
2619
            /*
2620
             * Store away the menu rectangle so we can keep track of the
2621
             * different regions that the menu obscures.
2622
             */
2623
 
2624
            ((MacMenu *) menuPtr->platformData)->menuRect = *menuRectPtr;
2625
            if (tkMenuCascadeRgn == NULL) {
2626
                tkMenuCascadeRgn = NewRgn();
2627
            }
2628
            if (utilRgn == NULL) {
2629
                utilRgn = NewRgn();
2630
            }
2631
            if (totalMenuRgn == NULL) {
2632
                totalMenuRgn = NewRgn();
2633
            }
2634
            SetEmptyRgn(tkMenuCascadeRgn);
2635
            for (searchMenuPtr = menuPtr; searchMenuPtr != NULL; ) {
2636
                RectRgn(utilRgn,
2637
                        &((MacMenu *) searchMenuPtr->platformData)->menuRect);
2638
                InsetRgn(utilRgn, -1, -1);
2639
                UnionRgn(tkMenuCascadeRgn, utilRgn, tkMenuCascadeRgn);
2640
                OffsetRgn(utilRgn, 1, 1);
2641
                UnionRgn(tkMenuCascadeRgn, utilRgn, tkMenuCascadeRgn);
2642
 
2643
                if (searchMenuPtr->menuRefPtr->parentEntryPtr != NULL) {
2644
                    searchMenuPtr = searchMenuPtr->menuRefPtr
2645
                            ->parentEntryPtr->menuPtr;
2646
                } else {
2647
                    break;
2648
                }
2649
                if (searchMenuPtr->menuType == MENUBAR) {
2650
                    break;
2651
                }
2652
            }
2653
            UnionRgn(totalMenuRgn, tkMenuCascadeRgn, totalMenuRgn);
2654
            SetEmptyRgn(utilRgn);
2655
 
2656
            /*
2657
             * Now draw the background if Appearance is present...
2658
             */
2659
 
2660
            GetGWorld(&macMDEFDrawable.portPtr, &device);
2661
            if (TkMacHaveAppearance() > 1) {
2662
                ThemeMenuType menuType;
2663
 
2664
                if (menuPtr->menuRefPtr->topLevelListPtr != NULL) {
2665
                    menuType = kThemeMenuTypePullDown;
2666
                } else if (menuPtr->menuRefPtr->parentEntryPtr != NULL) {
2667
                    menuType = kThemeMenuTypeHierarchical;
2668
                } else {
2669
                    menuType = kThemeMenuTypePopUp;
2670
                }
2671
 
2672
                DrawMenuBackground(menuRectPtr, (Drawable) &macMDEFDrawable,
2673
                        menuType);
2674
            }
2675
 
2676
            /*
2677
             * Next, figure out scrolling information.
2678
             */
2679
 
2680
            menuClipRect = *menuRectPtr;
2681
            if ((menuClipRect.bottom - menuClipRect.top)
2682
                    < menuPtr->totalHeight) {
2683
                if (globalsPtr->menuTop < menuRectPtr->top) {
2684
                    DrawSICN(SICN_RESOURCE_NUMBER, UP_ARROW,
2685
                            (Drawable) &macMDEFDrawable,
2686
                            menuPtr->textGC,
2687
                            menuRectPtr->left
2688
                            + menuPtr->entries[1]->indicatorSpace,
2689
                            menuRectPtr->top);
2690
                    menuClipRect.top += SICN_HEIGHT;
2691
                }
2692
                if ((globalsPtr->menuTop + menuPtr->totalHeight)
2693
                        > menuRectPtr->bottom) {
2694
                    DrawSICN(SICN_RESOURCE_NUMBER, DOWN_ARROW,
2695
                            (Drawable) &macMDEFDrawable,
2696
                            menuPtr->textGC,
2697
                            menuRectPtr->left
2698
                            + menuPtr->entries[1]->indicatorSpace,
2699
                            menuRectPtr->bottom - SICN_HEIGHT);
2700
                    menuClipRect.bottom -= SICN_HEIGHT;
2701
                }
2702
                GetClip(utilRgn);
2703
            }
2704
 
2705
            /*
2706
             * Now, actually draw the menu. Don't draw entries that
2707
             * are higher than the top arrow, and don't draw entries
2708
             * that are lower than the bottom.
2709
             */
2710
 
2711
            Tk_GetFontMetrics(menuPtr->tkfont, &fontMetrics);
2712
            for (i = 0; i < menuPtr->numEntries; i++) {
2713
                mePtr = menuPtr->entries[i];
2714
                if (globalsPtr->menuTop + mePtr->y + mePtr->height
2715
                        < menuClipRect.top) {
2716
                    continue;
2717
                } else if (globalsPtr->menuTop + mePtr->y
2718
                        > menuClipRect.bottom) {
2719
                    continue;
2720
                }
2721
                /* ClipRect(&menuClipRect); */
2722
                if (mePtr->tkfont == NULL) {
2723
                    fmPtr = &fontMetrics;
2724
                    tkfont = menuPtr->tkfont;
2725
                } else {
2726
                    tkfont = mePtr->tkfont;
2727
                    Tk_GetFontMetrics(tkfont, &entryMetrics);
2728
                    fmPtr = &entryMetrics;
2729
                }
2730
                AppearanceEntryDrawWrapper(mePtr, menuRectPtr, globalsPtr,
2731
                        (Drawable) &macMDEFDrawable, fmPtr, tkfont,
2732
                        menuRectPtr->left + mePtr->x,
2733
                        globalsPtr->menuTop + mePtr->y,
2734
                        (mePtr->entryFlags & ENTRY_LAST_COLUMN) ?
2735
                            menuPtr->totalWidth - mePtr->x : mePtr->width,
2736
                        menuPtr->entries[i]->height);
2737
            }
2738
            globalsPtr->menuBottom = globalsPtr->menuTop
2739
                    + menuPtr->totalHeight;
2740
            if (!EmptyRgn(utilRgn)) {
2741
                SetClip(utilRgn);
2742
                SetEmptyRgn(utilRgn);
2743
            }
2744
            MDEFScrollFlag = 1;
2745
            break;
2746
 
2747
        case mChooseMsg: {
2748
            int hasTopScroll, hasBottomScroll;
2749
            enum {
2750
                DONT_SCROLL, DOWN_SCROLL, UP_SCROLL
2751
            } scrollDirection;
2752
            Rect updateRect;
2753
            short scrollAmt;
2754
            RGBColor origForeColor, origBackColor, foreColor, backColor;
2755
 
2756
            GetGWorld(&macMDEFDrawable.portPtr, &device);
2757
            GetForeColor(&origForeColor);
2758
            GetBackColor(&origBackColor);
2759
 
2760
            if (TkSetMacColor(menuPtr->textGC->foreground,
2761
                    &foreColor) == true) {
2762
                if (!TkMacHaveAppearance()) {
2763
                    RGBForeColor(&foreColor);
2764
                }
2765
            }
2766
            if (TkSetMacColor(menuPtr->textGC->background,
2767
                    &backColor) == true) {
2768
                if (!TkMacHaveAppearance()) {
2769
                    RGBBackColor(&backColor);
2770
                }
2771
            }
2772
 
2773
            /*
2774
             * Find out which item was hit. If it is the same as the old item,
2775
             * we don't need to do anything.
2776
             */
2777
 
2778
            oldItem = *whichItem - 1;
2779
 
2780
            if (PtInRect(hitPt, menuRectPtr)) {
2781
                for (i = 0; i < menuPtr->numEntries; i++) {
2782
                    mePtr = menuPtr->entries[i];
2783
                    itemRect.left = menuRectPtr->left + mePtr->x;
2784
                    itemRect.top = globalsPtr->menuTop + mePtr->y;
2785
                    if (mePtr->entryFlags & ENTRY_LAST_COLUMN) {
2786
                        itemRect.right = itemRect.left + menuPtr->totalWidth
2787
                                - mePtr->x;
2788
                    } else {
2789
                        itemRect.right = itemRect.left + mePtr->width;
2790
                    }
2791
                    itemRect.bottom = itemRect.top
2792
                            + menuPtr->entries[i]->height;
2793
                    if (PtInRect(hitPt, &itemRect)) {
2794
                        if ((mePtr->type == SEPARATOR_ENTRY)
2795
                                || (mePtr->state == tkDisabledUid)) {
2796
                            newItem = -1;
2797
                        } else {
2798
                            TkMenuEntry *cascadeEntryPtr;
2799
                            int parentDisabled = 0;
2800
 
2801
                            for (cascadeEntryPtr
2802
                                    = menuPtr->menuRefPtr->parentEntryPtr;
2803
                                    cascadeEntryPtr != NULL;
2804
                                    cascadeEntryPtr
2805
                                    = cascadeEntryPtr->nextCascadePtr) {
2806
                                if (strcmp(cascadeEntryPtr->name,
2807
                                        Tk_PathName(menuPtr->tkwin)) == 0) {
2808
                                    if (cascadeEntryPtr->state
2809
                                            == tkDisabledUid) {
2810
                                        parentDisabled = 1;
2811
                                    }
2812
                                    break;
2813
                                }
2814
                            }
2815
                            if (parentDisabled) {
2816
                                newItem = -1;
2817
                            } else {
2818
                                newItem = i;
2819
                                if ((mePtr->type == CASCADE_ENTRY)
2820
                                        && (oldItem != newItem)) {
2821
                                    globalsPtr->itemRect = itemRect;
2822
                                }
2823
                            }
2824
                        }
2825
                        break;
2826
                    }
2827
                }
2828
            }
2829
 
2830
            /*
2831
             * Now we need to take care of scrolling the menu.
2832
             */
2833
 
2834
            hasTopScroll = globalsPtr->menuTop < menuRectPtr->top;
2835
            hasBottomScroll = globalsPtr->menuBottom > menuRectPtr->bottom;
2836
            scrollDirection = DONT_SCROLL;
2837
            if (hasTopScroll
2838
                    && (hitPt.v < menuRectPtr->top + SICN_HEIGHT)) {
2839
                newItem = -1;
2840
                scrollDirection = DOWN_SCROLL;
2841
            } else if (hasBottomScroll
2842
                    && (hitPt.v > menuRectPtr->bottom - SICN_HEIGHT)) {
2843
                newItem = -1;
2844
                scrollDirection = UP_SCROLL;
2845
            }
2846
            menuClipRect = *menuRectPtr;
2847
            if (hasTopScroll) {
2848
                menuClipRect.top += SICN_HEIGHT;
2849
            }
2850
            if (hasBottomScroll) {
2851
                menuClipRect.bottom -= SICN_HEIGHT;
2852
            }
2853
            if (MDEFScrollFlag) {
2854
                scrollDirection = DONT_SCROLL;
2855
                MDEFScrollFlag = 0;
2856
            }
2857
            GetClip(utilRgn);
2858
            ClipRect(&menuClipRect);
2859
 
2860
            if (oldItem != newItem) {
2861
                if (oldItem >= 0) {
2862
                    mePtr = menuPtr->entries[oldItem];
2863
                    tkfont = mePtr->tkfont ? mePtr->tkfont : menuPtr->tkfont;
2864
                    Tk_GetFontMetrics(tkfont, &fontMetrics);
2865
                    AppearanceEntryDrawWrapper(mePtr, menuRectPtr, globalsPtr,
2866
                        (Drawable) &macMDEFDrawable, &fontMetrics, tkfont,
2867
                        menuRectPtr->left + mePtr->x,
2868
                        globalsPtr->menuTop + mePtr->y,
2869
                        (mePtr->entryFlags & ENTRY_LAST_COLUMN) ?
2870
                            menuPtr->totalWidth - mePtr->x : mePtr->width,
2871
                        mePtr->height);
2872
                }
2873
                if (newItem != -1) {
2874
                    int oldActiveItem = menuPtr->active;
2875
 
2876
                    mePtr = menuPtr->entries[newItem];
2877
                    if (mePtr->state != tkDisabledUid) {
2878
                        TkActivateMenuEntry(menuPtr, newItem);
2879
                    }
2880
                    tkfont = mePtr->tkfont ? mePtr->tkfont : menuPtr->tkfont;
2881
                    Tk_GetFontMetrics(tkfont, &fontMetrics);
2882
                    AppearanceEntryDrawWrapper(mePtr, menuRectPtr, globalsPtr,
2883
                        (Drawable) &macMDEFDrawable, &fontMetrics, tkfont,
2884
                        menuRectPtr->left + mePtr->x,
2885
                        globalsPtr->menuTop + mePtr->y,
2886
                        (mePtr->entryFlags & ENTRY_LAST_COLUMN) ?
2887
                            menuPtr->totalWidth - mePtr->x : mePtr->width,
2888
                        mePtr->height);
2889
                }
2890
 
2891
                tkUseMenuCascadeRgn = 1;
2892
                MenuSelectEvent(menuPtr);
2893
                Tcl_ServiceAll();
2894
                tkUseMenuCascadeRgn = 0;
2895
                if (mePtr->state != tkDisabledUid) {
2896
                    TkActivateMenuEntry(menuPtr, -1);
2897
                }
2898
                *whichItem = newItem + 1;
2899
            }
2900
            globalsPtr->menuDisable = ((*menu)->menuID << 16) | (newItem + 1);
2901
 
2902
            if (scrollDirection == UP_SCROLL) {
2903
                scrollAmt = menuClipRect.bottom - hitPt.v;
2904
                if (scrollAmt < menuRectPtr->bottom
2905
                        - globalsPtr->menuBottom) {
2906
                    scrollAmt = menuRectPtr->bottom - globalsPtr->menuBottom;
2907
                }
2908
                if (!hasTopScroll && ((globalsPtr->menuTop + scrollAmt) < menuRectPtr->top)) {
2909
                    SetRect(&updateRect, menuRectPtr->left,
2910
                            globalsPtr->menuTop, menuRectPtr->right,
2911
                            globalsPtr->menuTop + SICN_HEIGHT);
2912
                    EraseRect(&updateRect);
2913
                    DrawSICN(SICN_RESOURCE_NUMBER, UP_ARROW,
2914
                            (Drawable) &macMDEFDrawable,
2915
                            menuPtr->textGC, menuRectPtr->left
2916
                            + menuPtr->entries[1]->indicatorSpace,
2917
                            menuRectPtr->top);
2918
                    menuClipRect.top += SICN_HEIGHT;
2919
                }
2920
            } else if (scrollDirection == DOWN_SCROLL) {
2921
                scrollAmt = menuClipRect.top - hitPt.v;
2922
                if (scrollAmt > menuRectPtr->top - globalsPtr->menuTop) {
2923
                    scrollAmt = menuRectPtr->top - globalsPtr->menuTop;
2924
                }
2925
                if (!hasBottomScroll && ((globalsPtr->menuBottom + scrollAmt)
2926
                        > menuRectPtr->bottom)) {
2927
                    SetRect(&updateRect, menuRectPtr->left,
2928
                            globalsPtr->menuBottom - SICN_HEIGHT,
2929
                            menuRectPtr->right, globalsPtr->menuBottom);
2930
                    EraseRect(&updateRect);
2931
                    DrawSICN(SICN_RESOURCE_NUMBER, DOWN_ARROW,
2932
                            (Drawable) &macMDEFDrawable,
2933
                            menuPtr->textGC, menuRectPtr->left
2934
                            + menuPtr->entries[1]->indicatorSpace,
2935
                            menuRectPtr->bottom - SICN_HEIGHT);
2936
                    menuClipRect.bottom -= SICN_HEIGHT;
2937
                }
2938
            }
2939
            if (scrollDirection != DONT_SCROLL) {
2940
                RgnHandle updateRgn = NewRgn();
2941
                ScrollRect(&menuClipRect, 0, scrollAmt, updateRgn);
2942
                updateRect = (*updateRgn)->rgnBBox;
2943
                DisposeRgn(updateRgn);
2944
                globalsPtr->menuTop += scrollAmt;
2945
                globalsPtr->menuBottom += scrollAmt;
2946
                if (globalsPtr->menuTop == menuRectPtr->top) {
2947
                    updateRect.top -= SICN_HEIGHT;
2948
                }
2949
                if (globalsPtr->menuBottom == menuRectPtr->bottom) {
2950
                    updateRect.bottom += SICN_HEIGHT;
2951
                }
2952
                ClipRect(&updateRect);
2953
                EraseRect(&updateRect);
2954
                Tk_GetFontMetrics(menuPtr->tkfont, &fontMetrics);
2955
                for (i = 0; i < menuPtr->numEntries; i++) {
2956
                    mePtr = menuPtr->entries[i];
2957
                    if (globalsPtr->menuTop + mePtr->y + mePtr->height
2958
                            < updateRect.top) {
2959
                        continue;
2960
                    } else if (globalsPtr->menuTop + mePtr->y
2961
                            > updateRect.bottom) {
2962
                        continue;
2963
                    }
2964
                    if (mePtr->tkfont == NULL) {
2965
                        fmPtr = &fontMetrics;
2966
                        tkfont = menuPtr->tkfont;
2967
                    } else {
2968
                        tkfont = mePtr->tkfont;
2969
                        Tk_GetFontMetrics(tkfont, &entryMetrics);
2970
                        fmPtr = &entryMetrics;
2971
                    }
2972
                    AppearanceEntryDrawWrapper(mePtr, menuRectPtr, globalsPtr,
2973
                        (Drawable) &macMDEFDrawable, fmPtr, tkfont,
2974
                        menuRectPtr->left + mePtr->x,
2975
                        globalsPtr->menuTop + mePtr->y,
2976
                        (mePtr->entryFlags & ENTRY_LAST_COLUMN) ?
2977
                            menuPtr->totalWidth - mePtr->x : mePtr->width,
2978
                        menuPtr->entries[i]->height);
2979
                }
2980
            }
2981
 
2982
            SetClip(utilRgn);
2983
            SetEmptyRgn(utilRgn);
2984
            RGBForeColor(&origForeColor);
2985
            RGBBackColor(&origBackColor);
2986
 
2987
            /*
2988
             * If the menu is a tearoff, and the mouse is outside the menu,
2989
             * we need to draw the drag rectangle.
2990
             *
2991
             * In order for tearoffs to work properly, we need to set
2992
             * the active member of the containing menubar.
2993
             */
2994
 
2995
            menuRefPtr = TkFindMenuReferences(menuPtr->interp,
2996
                    Tk_PathName(menuPtr->tkwin));
2997
            if ((menuRefPtr != NULL) && (menuRefPtr->parentEntryPtr != NULL)) {
2998
                for (parentEntryPtr = menuRefPtr->parentEntryPtr;
2999
                        strcmp(parentEntryPtr->name,
3000
                        Tk_PathName(menuPtr->tkwin)) == 0;
3001
                        parentEntryPtr = parentEntryPtr->nextCascadePtr) {
3002
                }
3003
                if (parentEntryPtr != NULL) {
3004
                    TkActivateMenuEntry(parentEntryPtr->menuPtr,
3005
                            parentEntryPtr->index);
3006
                }
3007
            }
3008
 
3009
            if (menuPtr->tearOff) {
3010
                scratchRect = *menuRectPtr;
3011
                if (tearoffStruct.menuPtr == NULL) {
3012
                    scratchRect.top -= 10;
3013
                    scratchRect.bottom += 10;
3014
                    scratchRect.left -= 10;
3015
                    scratchRect.right += 10;
3016
                }
3017
 
3018
                windowPart = FindWindow(hitPt, &whichWindow);
3019
                if ((windowPart != inMenuBar) && (newItem == -1)
3020
                        && (hitPt.v != 0) && (hitPt.h != 0)
3021
                        && (!PtInRect(hitPt, &scratchRect))
3022
                        && (!PtInRect(hitPt, &tearoffStruct.excludeRect))) {
3023
/*
3024
 * This is the second argument to the Toolbox Delay function.  It changed
3025
 * from long to unsigned long between Universal Headers 2.0 & 3.0
3026
 */
3027
#if !defined(UNIVERSAL_INTERFACES_VERSION) || (UNIVERSAL_INTERFACES_VERSION < 0x0300)
3028
                    long dummy;
3029
#else
3030
                    unsigned long dummy;
3031
#endif              
3032
                    oldClipRgn = NewRgn();
3033
                    GetClip(oldClipRgn);
3034
                    GetForeColor(&origFgColor);
3035
                    GetPenState(&origPenState);
3036
                    GetForeColor(&fgColor);
3037
                    GetBackColor(&bgColor);
3038
                    GetGray(device, &bgColor, &fgColor);
3039
                    RGBForeColor(&fgColor);
3040
                    SetRect(&scratchRect, -32768, -32768, 32767, 32767);
3041
                    ClipRect(&scratchRect);
3042
 
3043
                    dragRect = *menuRectPtr;
3044
                    tearoffStruct.menuPtr = menuPtr;
3045
 
3046
                    PenMode(srcXor);
3047
                    dragRect = *menuRectPtr;
3048
                    OffsetRect(&dragRect, -dragRect.left, -dragRect.top);
3049
                    OffsetRect(&dragRect, tearoffStruct.point.h,
3050
                            tearoffStruct.point.v);
3051
                    if ((dragRect.top != 0) && (dragRect.left != 0)) {
3052
                        FrameRect(&dragRect);
3053
                        Delay(1, &dummy);
3054
                        FrameRect(&dragRect);
3055
                    }
3056
                    tearoffStruct.point = hitPt;
3057
 
3058
                    SetClip(oldClipRgn);
3059
                    DisposeRgn(oldClipRgn);
3060
                    RGBForeColor(&origFgColor);
3061
                    SetPenState(&origPenState);
3062
                } else {
3063
                    tearoffStruct.menuPtr = NULL;
3064
                    tearoffStruct.point.h = tearoffStruct.point.v = 0;
3065
                }
3066
            } else {
3067
                tearoffStruct.menuPtr = NULL;
3068
                tearoffStruct.point.h = tearoffStruct.point.v = 0;
3069
            }
3070
 
3071
            break;
3072
        }
3073
 
3074
        case mPopUpMsg:
3075
 
3076
            /*
3077
             * Note that for some oddball reason, h and v are reversed in the
3078
             * point given to us by the MDEF.
3079
             */
3080
 
3081
            oldItem = *whichItem;
3082
            if (oldItem >= menuPtr->numEntries) {
3083
                oldItem = -1;
3084
            }
3085
            GetWMgrPort(&windowMgrPort);
3086
            maxMenuHeight = windowMgrPort->portRect.bottom
3087
                    - windowMgrPort->portRect.top
3088
                    - GetMBarHeight() - SCREEN_MARGIN;
3089
            if (menuPtr->totalHeight > maxMenuHeight) {
3090
                menuRectPtr->top = GetMBarHeight();
3091
            } else {
3092
                menuRectPtr->top = hitPt.h;
3093
                if (oldItem >= 0) {
3094
                    menuRectPtr->top -= menuPtr->entries[oldItem]->y;
3095
                }
3096
                if (menuRectPtr->top + menuPtr->totalHeight > maxMenuHeight) {
3097
                    menuRectPtr->top -= maxMenuHeight - menuPtr->totalHeight;
3098
                }
3099
            }
3100
            menuRectPtr->left = hitPt.v;
3101
            menuRectPtr->right = menuRectPtr->left + menuPtr->totalWidth;
3102
            menuRectPtr->bottom = menuRectPtr->top +
3103
                    ((maxMenuHeight < menuPtr->totalHeight)
3104
                    ? maxMenuHeight : menuPtr->totalHeight);
3105
            if (menuRectPtr->top == GetMBarHeight()) {
3106
                *whichItem = hitPt.h;
3107
            } else {
3108
                *whichItem = menuRectPtr->top;
3109
            }
3110
            break;
3111
    }
3112
}
3113
 
3114
/*
3115
 *----------------------------------------------------------------------
3116
 *
3117
 *   AppearanceEntryDrawWrapper --
3118
 *
3119
 *      This routine wraps the TkpDrawMenuEntry function.  Under Appearance,
3120
 *      it routes to the Appearance Managers DrawThemeEntry, otherwise it
3121
 *      just goes straight to TkpDrawMenuEntry.
3122
 *
3123
 * Results:
3124
 *      A menu entry is drawn
3125
 *
3126
 * Side effects:
3127
 *      None
3128
 *
3129
 *----------------------------------------------------------------------
3130
 */
3131
static void
3132
AppearanceEntryDrawWrapper(
3133
    TkMenuEntry *mePtr,
3134
    Rect *menuRectPtr,
3135
    TkMenuLowMemGlobals *globalsPtr,
3136
    Drawable d,
3137
    Tk_FontMetrics *fmPtr,
3138
    Tk_Font tkfont,
3139
    int x,
3140
    int y,
3141
    int width,
3142
    int height)
3143
{
3144
    if (TkMacHaveAppearance() > 1) {
3145
        MenuEntryUserData meData;
3146
        Rect itemRect;
3147
        ThemeMenuState theState;
3148
        ThemeMenuItemType theType;
3149
 
3150
        meData.mePtr = mePtr;
3151
        meData.mdefDrawable = d;
3152
        meData.fmPtr = fmPtr;
3153
        meData.tkfont = tkfont;
3154
 
3155
        itemRect.top = y;
3156
        itemRect.left = x;
3157
        itemRect.bottom = itemRect.top + height;
3158
        itemRect.right = itemRect.left + width;
3159
 
3160
        if (mePtr->state == tkActiveUid) {
3161
            theState = kThemeMenuSelected;
3162
        } else if (mePtr->state == tkDisabledUid) {
3163
            theState = kThemeMenuDisabled;
3164
        } else {
3165
            theState = kThemeMenuActive;
3166
        }
3167
 
3168
        if (mePtr->type == CASCADE_ENTRY) {
3169
            theType = kThemeMenuItemHierarchical;
3170
        } else {
3171
            theType = kThemeMenuItemPlain;
3172
        }
3173
 
3174
        DrawThemeMenuItem (menuRectPtr, &itemRect,
3175
                globalsPtr->menuTop, globalsPtr->menuBottom, theState,
3176
                theType, tkThemeMenuItemDrawingUPP,
3177
                (unsigned long) &meData);
3178
 
3179
    } else {
3180
        TkpDrawMenuEntry(mePtr, d, tkfont, fmPtr,
3181
                x, y, width, height, 0, 1);
3182
    }
3183
}
3184
 
3185
/*
3186
 *----------------------------------------------------------------------
3187
 *
3188
 *  tkThemeMenuItemDrawingProc --
3189
 *
3190
 *      This routine is called from the Appearance DrawThemeMenuEntry
3191
 *
3192
 * Results:
3193
 *      A menu entry is drawn
3194
 *
3195
 * Side effects:
3196
 *      None
3197
 *
3198
 *----------------------------------------------------------------------
3199
 */
3200
pascal void
3201
tkThemeMenuItemDrawingProc (
3202
        const Rect *inBounds,
3203
        SInt16 inDepth,
3204
        Boolean inIsColorDevice,
3205
        SInt32 inUserData)
3206
{
3207
    MenuEntryUserData *meData = (MenuEntryUserData *) inUserData;
3208
 
3209
    TkpDrawMenuEntry(meData->mePtr, meData->mdefDrawable,
3210
         meData->tkfont, meData->fmPtr, inBounds->left,
3211
         inBounds->top, inBounds->right - inBounds->left,
3212
         inBounds->bottom - inBounds->top, 0, 1);
3213
 
3214
}
3215
 
3216
/*
3217
 *----------------------------------------------------------------------
3218
 *
3219
 * TkMacHandleTearoffMenu() --
3220
 *
3221
 *      This routine sees if the MDEF has set a menu and a mouse position
3222
 *      for tearing off and makes a tearoff menu if it has.
3223
 *
3224
 * Results:
3225
 *      menuPtr->interp will have the result of the tearoff command.
3226
 *
3227
 * Side effects:
3228
 *      A new tearoff menu is created if it is supposed to be.
3229
 *
3230
 *----------------------------------------------------------------------
3231
 */
3232
 
3233
void
3234
TkMacHandleTearoffMenu(void)
3235
{
3236
    if (tearoffStruct.menuPtr != NULL) {
3237
        Tcl_DString tearoffCmdStr;
3238
        char intString[20];
3239
        short windowPart;
3240
        WindowRef whichWindow;
3241
 
3242
        windowPart = FindWindow(tearoffStruct.point, &whichWindow);
3243
 
3244
        if (windowPart != inMenuBar) {
3245
            Tcl_DStringInit(&tearoffCmdStr);
3246
            Tcl_DStringAppendElement(&tearoffCmdStr, "tkTearOffMenu");
3247
            Tcl_DStringAppendElement(&tearoffCmdStr,
3248
                    Tk_PathName(tearoffStruct.menuPtr->tkwin));
3249
            sprintf(intString, "%d", tearoffStruct.point.h);
3250
            Tcl_DStringAppendElement(&tearoffCmdStr, intString);
3251
            sprintf(intString, "%d", tearoffStruct.point.v);
3252
            Tcl_DStringAppendElement(&tearoffCmdStr, intString);
3253
            Tcl_Eval(tearoffStruct.menuPtr->interp,
3254
                    Tcl_DStringValue(&tearoffCmdStr));
3255
            Tcl_DStringFree(&tearoffCmdStr);
3256
            tearoffStruct.menuPtr = NULL;
3257
        }
3258
    }
3259
}
3260
 
3261
/*
3262
 *--------------------------------------------------------------
3263
 *
3264
 * TkpInitializeMenuBindings --
3265
 *
3266
 *      For every interp, initializes the bindings for Windows
3267
 *      menus. Does nothing on Mac or XWindows.
3268
 *
3269
 * Results:
3270
 *      None.
3271
 *
3272
 * Side effects:
3273
 *      C-level bindings are setup for the interp which will
3274
 *      handle Alt-key sequences for menus without beeping
3275
 *      or interfering with user-defined Alt-key bindings.
3276
 *
3277
 *--------------------------------------------------------------
3278
 */
3279
 
3280
void
3281
TkpInitializeMenuBindings(interp, bindingTable)
3282
    Tcl_Interp *interp;             /* The interpreter to set. */
3283
    Tk_BindingTable bindingTable;   /* The table to add to. */
3284
{
3285
    /*
3286
     * Nothing to do.
3287
     */
3288
}
3289
 
3290
/*
3291
 *--------------------------------------------------------------
3292
 *
3293
 * TkpComputeMenubarGeometry --
3294
 *
3295
 *      This procedure is invoked to recompute the size and
3296
 *      layout of a menu that is a menubar clone.
3297
 *
3298
 * Results:
3299
 *      None.
3300
 *
3301
 * Side effects:
3302
 *      Fields of menu entries are changed to reflect their
3303
 *      current positions, and the size of the menu window
3304
 *      itself may be changed.
3305
 *
3306
 *--------------------------------------------------------------
3307
 */
3308
 
3309
void
3310
TkpComputeMenubarGeometry(menuPtr)
3311
    TkMenu *menuPtr;            /* Structure describing menu. */
3312
{
3313
    TkpComputeStandardMenuGeometry(menuPtr);
3314
}
3315
 
3316
/*
3317
 *----------------------------------------------------------------------
3318
 *
3319
 * DrawTearoffEntry --
3320
 *
3321
 *      This procedure draws the background part of a menu.
3322
 *
3323
 * Results:
3324
 *      None.
3325
 *
3326
 * Side effects:
3327
 *      Commands are output to X to display the menu in its
3328
 *      current mode.
3329
 *
3330
 *----------------------------------------------------------------------
3331
 */
3332
 
3333
void
3334
DrawTearoffEntry(
3335
    TkMenu *menuPtr,                    /* The menu we are drawing */
3336
    TkMenuEntry *mePtr,                 /* The entry we are drawing */
3337
    Drawable d,                         /* The drawable we are drawing into */
3338
    GC gc,                              /* The gc we are drawing with */
3339
    Tk_Font tkfont,                     /* The font we are drawing with */
3340
    CONST Tk_FontMetrics *fmPtr,        /* The metrics we are drawing with */
3341
    int x,                              /* Left edge of entry. */
3342
    int y,                              /* Top edge of entry. */
3343
    int width,                          /* Width of entry. */
3344
    int height)                         /* Height of entry. */
3345
{
3346
    XPoint points[2];
3347
    int margin, segmentWidth, maxX;
3348
 
3349
    if ((menuPtr->menuType != MASTER_MENU) || (FixMDEF() != NULL)) {
3350
        return;
3351
    }
3352
 
3353
    margin = (fmPtr->ascent + fmPtr->descent)/2;
3354
    points[0].x = x;
3355
    points[0].y = y + height/2;
3356
    points[1].y = points[0].y;
3357
    segmentWidth = 6;
3358
    maxX  = width - 1;
3359
 
3360
    while (points[0].x < maxX) {
3361
        points[1].x = points[0].x + segmentWidth;
3362
        if (points[1].x > maxX) {
3363
            points[1].x = maxX;
3364
        }
3365
        Tk_Draw3DPolygon(menuPtr->tkwin, d, menuPtr->border, points, 2, 1,
3366
                TK_RELIEF_RAISED);
3367
        points[0].x += 2*segmentWidth;
3368
    }
3369
}
3370
 
3371
/*
3372
 *----------------------------------------------------------------------
3373
 *
3374
 * TkMacSetHelpMenuItemCount --
3375
 *
3376
 *      Has to be called after the first call to InsertMenu. Sets
3377
 *      up the global variable for the number of items in the
3378
 *      unmodified help menu.
3379
 *
3380
 * Results:
3381
 *      None.
3382
 *
3383
 * Side effects:
3384
 *      Sets the global helpItemCount.
3385
 *
3386
 *----------------------------------------------------------------------
3387
 */
3388
 
3389
void
3390
TkMacSetHelpMenuItemCount()
3391
{
3392
    MenuHandle helpMenuHandle;
3393
 
3394
    if ((HMGetHelpMenuHandle(&helpMenuHandle) != noErr)
3395
            || (helpMenuHandle == NULL)) {
3396
        helpItemCount = -1;
3397
    } else {
3398
        helpItemCount = CountMItems(helpMenuHandle);
3399
        DeleteMenuItem(helpMenuHandle, helpItemCount);
3400
    }
3401
}
3402
 
3403
/*
3404
 *----------------------------------------------------------------------
3405
 *
3406
 * TkMacMenuClick --
3407
 *
3408
 *      Prepares a menubar for MenuSelect or MenuKey.
3409
 *
3410
 * Results:
3411
 *      None.
3412
 *
3413
 * Side effects:
3414
 *      Any pending configurations of the menubar are completed.
3415
 *
3416
 *----------------------------------------------------------------------
3417
 */
3418
 
3419
void
3420
TkMacMenuClick()
3421
{
3422
    TkMenu *menuPtr;
3423
    TkMenuReferences *menuRefPtr;
3424
 
3425
    if ((currentMenuBarInterp != NULL) && (currentMenuBarName != NULL)) {
3426
        menuRefPtr = TkFindMenuReferences(currentMenuBarInterp,
3427
                currentMenuBarName);
3428
        for (menuPtr = menuRefPtr->menuPtr->masterMenuPtr;
3429
                menuPtr != NULL; menuPtr = menuPtr->nextInstancePtr) {
3430
            if (menuPtr->menuType == MENUBAR) {
3431
                CompleteIdlers(menuPtr);
3432
                break;
3433
            }
3434
        }
3435
    }
3436
 
3437
    if (menuBarFlags & MENUBAR_REDRAW_PENDING) {
3438
        Tcl_CancelIdleCall(DrawMenuBarWhenIdle, (ClientData *) NULL);
3439
        DrawMenuBarWhenIdle((ClientData *) NULL);
3440
    }
3441
}
3442
 
3443
/*
3444
 *----------------------------------------------------------------------
3445
 *
3446
 * TkpDrawMenuEntry --
3447
 *
3448
 *      Draws the given menu entry at the given coordinates with the
3449
 *      given attributes.
3450
 *
3451
 * Results:
3452
 *      None.
3453
 *
3454
 * Side effects:
3455
 *      X Server commands are executed to display the menu entry.
3456
 *
3457
 *----------------------------------------------------------------------
3458
 */
3459
 
3460
void
3461
TkpDrawMenuEntry(
3462
    TkMenuEntry *mePtr,             /* The entry to draw */
3463
    Drawable d,                     /* What to draw into */
3464
    Tk_Font tkfont,                 /* Precalculated font for menu */
3465
    CONST Tk_FontMetrics *menuMetricsPtr,
3466
                                    /* Precalculated metrics for menu */
3467
    int x,                          /* X-coordinate of topleft of entry */
3468
    int y,                          /* Y-coordinate of topleft of entry */
3469
    int width,                      /* Width of the entry rectangle */
3470
    int height,                     /* Height of the current rectangle */
3471
    int strictMotif,                /* Boolean flag */
3472
    int drawArrow)                  /* Whether or not to draw the cascade
3473
                                     * arrow for cascade items. Only applies
3474
                                     * to Windows. */
3475
{
3476
    GC gc, indicatorGC;
3477
    TkMenu *menuPtr = mePtr->menuPtr;
3478
    Tk_3DBorder bgBorder, activeBorder;
3479
    CONST Tk_FontMetrics *fmPtr;
3480
    Tk_FontMetrics entryMetrics;
3481
    int padY = (menuPtr->menuType == MENUBAR) ? 3 : 0;
3482
    int adjustedY = y + padY;
3483
    int adjustedHeight = height - 2 * padY;
3484
 
3485
    /*
3486
     * Choose the gc for drawing the foreground part of the entry.
3487
     * Under Appearance, we pass a null (appearanceGC) to tell
3488
     * ourselves not to change whatever color the appearance manager has set.
3489
     */
3490
 
3491
    if ((mePtr->state == tkActiveUid)
3492
            && !strictMotif) {
3493
        gc = mePtr->activeGC;
3494
        if (gc == NULL) {
3495
            if ((TkMacHaveAppearance() > 1) && (menuPtr->menuType != TEAROFF_MENU)) {
3496
                SetThemeTextColor(kThemeSelectedMenuItemTextColor,32,true);
3497
                gc = appearanceGC;
3498
            } else {
3499
                gc = menuPtr->activeGC;
3500
            }
3501
        }
3502
    } else {
3503
        TkMenuEntry *cascadeEntryPtr;
3504
        int parentDisabled = 0;
3505
 
3506
        for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr;
3507
                cascadeEntryPtr != NULL;
3508
                cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) {
3509
            if (strcmp(cascadeEntryPtr->name,
3510
                    Tk_PathName(menuPtr->tkwin)) == 0) {
3511
                if (cascadeEntryPtr->state == tkDisabledUid) {
3512
                    parentDisabled = 1;
3513
                }
3514
                break;
3515
            }
3516
        }
3517
 
3518
        if (((parentDisabled || (mePtr->state == tkDisabledUid)))
3519
                && (menuPtr->disabledFg != NULL)) {
3520
            gc = mePtr->disabledGC;
3521
            if (gc == NULL) {
3522
                if ((TkMacHaveAppearance() > 1) && (mePtr->bitmap == NULL)) {
3523
                    SetThemeTextColor(kThemeDisabledMenuItemTextColor,32,true);
3524
                    gc = appearanceGC;
3525
                } else {
3526
                gc = menuPtr->disabledGC;
3527
            }
3528
            }
3529
        } else {
3530
            gc = mePtr->textGC;
3531
            if (gc == NULL) {
3532
                if ((TkMacHaveAppearance() > 1) && (mePtr->bitmap == NULL)) {
3533
                    SetThemeTextColor(kThemeActiveMenuItemTextColor,32,true);
3534
                    gc = appearanceGC;
3535
                } else {
3536
                    gc = menuPtr->textGC;
3537
                }
3538
            }
3539
        }
3540
    }
3541
 
3542
    indicatorGC = mePtr->indicatorGC;
3543
    if (indicatorGC == NULL) {
3544
        indicatorGC = menuPtr->indicatorGC;
3545
    }
3546
 
3547
    bgBorder = mePtr->border;
3548
    if (bgBorder == NULL) {
3549
        bgBorder = menuPtr->border;
3550
    }
3551
    if (strictMotif) {
3552
        activeBorder = bgBorder;
3553
    } else {
3554
        activeBorder = mePtr->activeBorder;
3555
        if (activeBorder == NULL) {
3556
            activeBorder = menuPtr->activeBorder;
3557
        }
3558
    }
3559
 
3560
    if (mePtr->tkfont == NULL) {
3561
        fmPtr = menuMetricsPtr;
3562
    } else {
3563
        tkfont = mePtr->tkfont;
3564
        Tk_GetFontMetrics(tkfont, &entryMetrics);
3565
        fmPtr = &entryMetrics;
3566
    }
3567
 
3568
    /*
3569
     * Need to draw the entire background, including padding. On Unix,
3570
     * for menubars, we have to draw the rest of the entry taking
3571
     * into account the padding.
3572
     */
3573
 
3574
    DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder,
3575
            bgBorder, x, y, width, height);
3576
 
3577
    if (mePtr->type == SEPARATOR_ENTRY) {
3578
        DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont,
3579
                fmPtr, x, adjustedY, width, adjustedHeight);
3580
    } else if (mePtr->type == TEAROFF_ENTRY) {
3581
        DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY,
3582
                width, adjustedHeight);
3583
    } else {
3584
        DrawMenuEntryLabel(menuPtr, mePtr, d, gc, tkfont, fmPtr, x,
3585
                adjustedY, width, adjustedHeight);
3586
        DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr,
3587
                activeBorder, x, adjustedY, width, adjustedHeight, drawArrow);
3588
        if (!mePtr->hideMargin) {
3589
            DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont,
3590
                    fmPtr, x, adjustedY, width, adjustedHeight);
3591
        }
3592
 
3593
    }
3594
}
3595
 
3596
/*
3597
 *--------------------------------------------------------------
3598
 *
3599
 * TkpComputeStandardMenuGeometry --
3600
 *
3601
 *      This procedure is invoked to recompute the size and
3602
 *      layout of a menu that is not a menubar clone.
3603
 *
3604
 * Results:
3605
 *      None.
3606
 *
3607
 * Side effects:
3608
 *      Fields of menu entries are changed to reflect their
3609
 *      current positions, and the size of the menu window
3610
 *      itself may be changed.
3611
 *
3612
 *--------------------------------------------------------------
3613
 */
3614
 
3615
void
3616
TkpComputeStandardMenuGeometry(
3617
    TkMenu *menuPtr)            /* Structure describing menu. */
3618
{
3619
    Tk_Font tkfont;
3620
    Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr;
3621
    int x, y, height, modifierWidth, labelWidth, indicatorSpace;
3622
    int windowWidth, windowHeight, accelWidth, maxAccelTextWidth;
3623
    int i, j, lastColumnBreak, maxModifierWidth, maxWidth, nonAccelMargin;
3624
    int maxNonAccelMargin, maxEntryWithAccelWidth, maxEntryWithoutAccelWidth;
3625
    int entryWidth, maxIndicatorSpace;
3626
    TkMenuEntry *mePtr, *columnEntryPtr;
3627
    EntryGeometry *geometryPtr;
3628
 
3629
    if (menuPtr->tkwin == NULL) {
3630
        return;
3631
    }
3632
 
3633
    x = y = menuPtr->borderWidth;
3634
    indicatorSpace = labelWidth = accelWidth = maxAccelTextWidth = 0;
3635
    windowHeight = windowWidth = maxWidth = lastColumnBreak = 0;
3636
    maxModifierWidth = nonAccelMargin = maxNonAccelMargin = 0;
3637
    maxEntryWithAccelWidth = maxEntryWithoutAccelWidth = 0;
3638
    maxIndicatorSpace = 0;
3639
 
3640
    /*
3641
     * On the Mac especially, getting font metrics can be quite slow,
3642
     * so we want to do it intelligently. We are going to precalculate
3643
     * them and pass them down to all of the measuring and drawing
3644
     * routines. We will measure the font metrics of the menu once.
3645
     * If an entry does not have its own font set, then we give
3646
     * the geometry/drawing routines the menu's font and metrics.
3647
     * If an entry has its own font, we will measure that font and
3648
     * give all of the geometry/drawing the entry's font and metrics.
3649
     */
3650
 
3651
    Tk_GetFontMetrics(menuPtr->tkfont, &menuMetrics);
3652
 
3653
    for (i = 0; i < menuPtr->numEntries; i++) {
3654
        mePtr = menuPtr->entries[i];
3655
        tkfont = mePtr->tkfont;
3656
        if (tkfont == NULL) {
3657
            tkfont = menuPtr->tkfont;
3658
            fmPtr = &menuMetrics;
3659
        } else {
3660
            Tk_GetFontMetrics(tkfont, &entryMetrics);
3661
            fmPtr = &entryMetrics;
3662
        }
3663
 
3664
        if ((i > 0) && mePtr->columnBreak) {
3665
            if (maxIndicatorSpace != 0) {
3666
                maxIndicatorSpace += 2;
3667
            }
3668
            for (j = lastColumnBreak; j < i; j++) {
3669
                columnEntryPtr = menuPtr->entries[j];
3670
                geometryPtr =
3671
                        (EntryGeometry *) columnEntryPtr->platformEntryData;
3672
 
3673
                columnEntryPtr->indicatorSpace = maxIndicatorSpace;
3674
                columnEntryPtr->width = maxIndicatorSpace + maxWidth
3675
                        + 2 * menuPtr->activeBorderWidth;
3676
                geometryPtr->accelTextWidth = maxAccelTextWidth;
3677
                geometryPtr->modifierWidth = maxModifierWidth;
3678
                columnEntryPtr->x = x;
3679
                columnEntryPtr->entryFlags &= ~ENTRY_LAST_COLUMN;
3680
                if (maxEntryWithoutAccelWidth > maxEntryWithAccelWidth) {
3681
                    geometryPtr->nonAccelMargin = maxEntryWithoutAccelWidth
3682
                            - maxEntryWithAccelWidth;
3683
                    if (geometryPtr->nonAccelMargin > maxNonAccelMargin) {
3684
                        geometryPtr->nonAccelMargin = maxNonAccelMargin;
3685
                    }
3686
                } else {
3687
                    geometryPtr->nonAccelMargin = 0;
3688
                }
3689
            }
3690
            x += maxIndicatorSpace + maxWidth + 2 * menuPtr->borderWidth;
3691
            windowWidth = x;
3692
            maxWidth = maxIndicatorSpace = maxAccelTextWidth = 0;
3693
            maxModifierWidth = maxNonAccelMargin = maxEntryWithAccelWidth = 0;
3694
            maxEntryWithoutAccelWidth = 0;
3695
            lastColumnBreak = i;
3696
            y = menuPtr->borderWidth;
3697
        }
3698
 
3699
        if (mePtr->type == SEPARATOR_ENTRY) {
3700
            GetMenuSeparatorGeometry(menuPtr, mePtr, tkfont,
3701
                    fmPtr, &entryWidth, &height);
3702
            mePtr->height = height;
3703
        } else if (mePtr->type == TEAROFF_ENTRY) {
3704
            GetTearoffEntryGeometry(menuPtr, mePtr, tkfont,
3705
                    fmPtr, &entryWidth, &height);
3706
            mePtr->height = height;
3707
        } else {
3708
 
3709
            /*
3710
             * For each entry, compute the height required by that
3711
             * particular entry, plus three widths:  the width of the
3712
             * label, the width to allow for an indicator to be displayed
3713
             * to the left of the label (if any), and the width of the
3714
             * accelerator to be displayed to the right of the label
3715
             * (if any).  These sizes depend, of course, on the type
3716
             * of the entry.
3717
             */
3718
 
3719
            GetMenuLabelGeometry(mePtr, tkfont, fmPtr, &labelWidth,
3720
                    &height);
3721
            mePtr->height = height;
3722
 
3723
            if (mePtr->type == CASCADE_ENTRY) {
3724
                GetMenuAccelGeometry(menuPtr, mePtr, tkfont, fmPtr,
3725
                        &modifierWidth, &accelWidth, &height);
3726
                nonAccelMargin = 0;
3727
            } else if (mePtr->accelLength == 0) {
3728
                nonAccelMargin = mePtr->hideMargin ? 0
3729
                        : Tk_TextWidth(tkfont, "m", 1);
3730
                accelWidth = modifierWidth = 0;
3731
            } else {
3732
                labelWidth += Tk_TextWidth(tkfont, "m", 1);
3733
                GetMenuAccelGeometry(menuPtr, mePtr, tkfont,
3734
                        fmPtr, &modifierWidth, &accelWidth, &height);
3735
                if (height > mePtr->height) {
3736
                    mePtr->height = height;
3737
                }
3738
                nonAccelMargin = 0;
3739
            }
3740
 
3741
            if (!(mePtr->hideMargin)) {
3742
                GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont,
3743
                        fmPtr, &indicatorSpace, &height);
3744
                if (height > mePtr->height) {
3745
                    mePtr->height = height;
3746
                }
3747
            } else {
3748
                indicatorSpace = 0;
3749
            }
3750
 
3751
            if (nonAccelMargin > maxNonAccelMargin) {
3752
                maxNonAccelMargin = nonAccelMargin;
3753
            }
3754
            if (accelWidth > maxAccelTextWidth) {
3755
                maxAccelTextWidth = accelWidth;
3756
            }
3757
            if (modifierWidth > maxModifierWidth) {
3758
                maxModifierWidth = modifierWidth;
3759
            }
3760
            if (indicatorSpace > maxIndicatorSpace) {
3761
                maxIndicatorSpace = indicatorSpace;
3762
            }
3763
 
3764
            entryWidth = labelWidth + modifierWidth + accelWidth
3765
                    + nonAccelMargin;
3766
 
3767
            if (entryWidth > maxWidth) {
3768
                maxWidth = entryWidth;
3769
            }
3770
 
3771
            if (mePtr->accelLength > 0) {
3772
                if (entryWidth > maxEntryWithAccelWidth) {
3773
                    maxEntryWithAccelWidth = entryWidth;
3774
                }
3775
            } else {
3776
                if (entryWidth > maxEntryWithoutAccelWidth) {
3777
                    maxEntryWithoutAccelWidth = entryWidth;
3778
                }
3779
            }
3780
 
3781
            mePtr->height += 2 * menuPtr->activeBorderWidth;
3782
        }
3783
        mePtr->y = y;
3784
        y += menuPtr->entries[i]->height + menuPtr->borderWidth;
3785
        if (y > windowHeight) {
3786
            windowHeight = y;
3787
        }
3788
    }
3789
 
3790
    for (j = lastColumnBreak; j < menuPtr->numEntries; j++) {
3791
        columnEntryPtr = menuPtr->entries[j];
3792
        geometryPtr = (EntryGeometry *) columnEntryPtr->platformEntryData;
3793
 
3794
        columnEntryPtr->indicatorSpace = maxIndicatorSpace;
3795
        columnEntryPtr->width = maxIndicatorSpace + maxWidth
3796
                + 2 * menuPtr->activeBorderWidth;
3797
        geometryPtr->accelTextWidth = maxAccelTextWidth;
3798
        geometryPtr->modifierWidth = maxModifierWidth;
3799
        columnEntryPtr->x = x;
3800
        columnEntryPtr->entryFlags |= ENTRY_LAST_COLUMN;
3801
        if (maxEntryWithoutAccelWidth > maxEntryWithAccelWidth) {
3802
            geometryPtr->nonAccelMargin = maxEntryWithoutAccelWidth
3803
                    - maxEntryWithAccelWidth;
3804
            if (geometryPtr->nonAccelMargin > maxNonAccelMargin) {
3805
                geometryPtr->nonAccelMargin = maxNonAccelMargin;
3806
            }
3807
        } else {
3808
            geometryPtr->nonAccelMargin = 0;
3809
        }
3810
    }
3811
    windowWidth = x + maxIndicatorSpace + maxWidth
3812
            + 2 * menuPtr->activeBorderWidth + menuPtr->borderWidth;
3813
    windowHeight += menuPtr->borderWidth;
3814
 
3815
    /*
3816
     * The X server doesn't like zero dimensions, so round up to at least
3817
     * 1 (a zero-sized menu should never really occur, anyway).
3818
     */
3819
 
3820
    if (windowWidth <= 0) {
3821
        windowWidth = 1;
3822
    }
3823
    if (windowHeight <= 0) {
3824
        windowHeight = 1;
3825
    }
3826
    menuPtr->totalWidth = windowWidth;
3827
    menuPtr->totalHeight = windowHeight;
3828
}
3829
 
3830
/*
3831
 *----------------------------------------------------------------------
3832
 *
3833
 * DrawMenuEntryLabel --
3834
 *
3835
 *      This procedure draws the label part of a menu.
3836
 *
3837
 * Results:
3838
 *      None.
3839
 *
3840
 * Side effects:
3841
 *      Commands are output to X to display the menu in its
3842
 *      current mode.
3843
 *
3844
 *----------------------------------------------------------------------
3845
 */
3846
 
3847
static void
3848
DrawMenuEntryLabel(
3849
    TkMenu *menuPtr,                    /* The menu we are drawing */
3850
    TkMenuEntry *mePtr,                 /* The entry we are drawing */
3851
    Drawable d,                         /* What we are drawing into */
3852
    GC gc,                              /* The gc we are drawing into */
3853
    Tk_Font tkfont,                     /* The precalculated font */
3854
    CONST Tk_FontMetrics *fmPtr,        /* The precalculated font metrics */
3855
    int x,                              /* left edge */
3856
    int y,                              /* right edge */
3857
    int width,                          /* width of entry */
3858
    int height)                         /* height of entry */
3859
{
3860
    int baseline;
3861
    int indicatorSpace =  mePtr->indicatorSpace;
3862
    int leftEdge = x + indicatorSpace;
3863
    int imageHeight, imageWidth;
3864
 
3865
    /*
3866
     * Draw label or bitmap or image for entry.
3867
     */
3868
 
3869
    baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2;
3870
    if (mePtr->image != NULL) {
3871
        Tk_SizeOfImage(mePtr->image, &imageWidth, &imageHeight);
3872
        if ((mePtr->selectImage != NULL)
3873
                && (mePtr->entryFlags & ENTRY_SELECTED)) {
3874
            Tk_RedrawImage(mePtr->selectImage, 0, 0,
3875
                    imageWidth, imageHeight, d, leftEdge,
3876
                    (int) (y + (mePtr->height - imageHeight)/2));
3877
        } else {
3878
            Tk_RedrawImage(mePtr->image, 0, 0, imageWidth,
3879
                    imageHeight, d, leftEdge,
3880
                    (int) (y + (mePtr->height - imageHeight)/2));
3881
        }
3882
    } else if (mePtr->bitmap != None) {
3883
        int width, height;
3884
 
3885
        Tk_SizeOfBitmap(menuPtr->display,
3886
                mePtr->bitmap, &width, &height);
3887
        XCopyPlane(menuPtr->display,
3888
                mePtr->bitmap, d,
3889
                gc, 0, 0, (unsigned) width, (unsigned) height, leftEdge,
3890
                (int) (y + (mePtr->height - height)/2), 1);
3891
    } else {
3892
        if (mePtr->labelLength > 0) {
3893
            Str255 itemText;
3894
 
3895
            GetEntryText(mePtr, itemText);
3896
            Tk_DrawChars(menuPtr->display, d, gc,
3897
                    tkfont, (char *) itemText + 1, itemText[0],
3898
                    leftEdge, baseline);
3899
/*          TkpDrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y,
3900
                    width, height);*/
3901
        }
3902
    }
3903
 
3904
    if (mePtr->state == tkDisabledUid) {
3905
        if (menuPtr->disabledFg == NULL) {
3906
            if (!TkMacHaveAppearance()) {
3907
                XFillRectangle(menuPtr->display, d, menuPtr->disabledGC, x, y,
3908
                        (unsigned) width, (unsigned) height);
3909
            }
3910
        } else if ((mePtr->image != NULL)
3911
                && (menuPtr->disabledImageGC != None)) {
3912
            XFillRectangle(menuPtr->display, d, menuPtr->disabledImageGC,
3913
                    leftEdge,
3914
                    (int) (y + (mePtr->height - imageHeight)/2),
3915
                    (unsigned) imageWidth, (unsigned) imageHeight);
3916
        }
3917
    }
3918
}
3919
 
3920
/*
3921
 *----------------------------------------------------------------------
3922
 *
3923
 * DrawMenuEntryBackground --
3924
 *
3925
 *      This procedure draws the background part of a menu entry.
3926
 *      Under Appearance, we only draw the background if the entry's
3927
 *      border is set, we DO NOT inherit it from the menu...
3928
 *
3929
 * Results:
3930
 *      None.
3931
 *
3932
 * Side effects:
3933
 *      Commands are output to X to display the menu in its
3934
 *      current mode.
3935
 *
3936
 *----------------------------------------------------------------------
3937
 */
3938
 
3939
static void
3940
DrawMenuEntryBackground(
3941
    TkMenu *menuPtr,                    /* The menu we are drawing. */
3942
    TkMenuEntry *mePtr,                 /* The entry we are drawing. */
3943
    Drawable d,                         /* What we are drawing into */
3944
    Tk_3DBorder activeBorder,           /* Border for active items */
3945
    Tk_3DBorder bgBorder,               /* Border for the background */
3946
    int x,                              /* left edge */
3947
    int y,                              /* top edge */
3948
    int width,                          /* width of rectangle to draw */
3949
    int height)                         /* height of rectangle to draw */
3950
{
3951
    if (!TkMacHaveAppearance()
3952
            || (menuPtr->menuType == TEAROFF_MENU)
3953
            || ((mePtr->state == tkActiveUid) && (mePtr->activeBorder != NULL))
3954
            || ((mePtr->state != tkActiveUid) && (mePtr->border != NULL))) {
3955
        if (mePtr->state == tkActiveUid) {
3956
            bgBorder = activeBorder;
3957
        }
3958
        Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder,
3959
                x, y, width, height, 0, TK_RELIEF_FLAT);
3960
    }
3961
}
3962
 
3963
/*
3964
 *----------------------------------------------------------------------
3965
 *
3966
 * GetMenuLabelGeometry --
3967
 *
3968
 *      Figures out the size of the label portion of a menu item.
3969
 *
3970
 * Results:
3971
 *      widthPtr and heightPtr are filled in with the correct geometry
3972
 *      information.
3973
 *
3974
 * Side effects:
3975
 *      None.
3976
 *
3977
 *----------------------------------------------------------------------
3978
 */
3979
 
3980
static void
3981
GetMenuLabelGeometry(
3982
    TkMenuEntry *mePtr,                 /* The entry we are computing */
3983
    Tk_Font tkfont,                     /* The precalculated font */
3984
    CONST Tk_FontMetrics *fmPtr,        /* The precalculated metrics */
3985
    int *widthPtr,                      /* The resulting width of the label
3986
                                         * portion */
3987
    int *heightPtr)                     /* The resulting height of the label
3988
                                         * portion */
3989
{
3990
    TkMenu *menuPtr = mePtr->menuPtr;
3991
 
3992
    if (mePtr->image != NULL) {
3993
        Tk_SizeOfImage(mePtr->image, widthPtr, heightPtr);
3994
    } else if (mePtr->bitmap != (Pixmap) NULL) {
3995
        Tk_SizeOfBitmap(menuPtr->display, mePtr->bitmap, widthPtr, heightPtr);
3996
    } else {
3997
        *heightPtr = fmPtr->linespace;
3998
 
3999
        if (mePtr->label != NULL) {
4000
            Str255 itemText;
4001
 
4002
            GetEntryText(mePtr, itemText);
4003
            *widthPtr = Tk_TextWidth(tkfont, (char *) itemText + 1,
4004
                    itemText[0]);
4005
        } else {
4006
            *widthPtr = 0;
4007
        }
4008
    }
4009
    *heightPtr += 1;
4010
}
4011
 
4012
/*
4013
 *----------------------------------------------------------------------
4014
 *
4015
 * MenuSelectEvent --
4016
 *
4017
 *      Generates a "MenuSelect" virtual event. This can be used to
4018
 *      do context-sensitive menu help.
4019
 *
4020
 * Results:
4021
 *      None.
4022
 *
4023
 * Side effects:
4024
 *      Places a virtual event on the event queue.
4025
 *
4026
 *----------------------------------------------------------------------
4027
 */
4028
 
4029
static void
4030
MenuSelectEvent(
4031
    TkMenu *menuPtr)            /* the menu we have selected. */
4032
{
4033
    XVirtualEvent event;
4034
    Point where;
4035
 
4036
    event.type = VirtualEvent;
4037
    event.serial = menuPtr->display->request;
4038
    event.send_event = false;
4039
    event.display = menuPtr->display;
4040
    Tk_MakeWindowExist(menuPtr->tkwin);
4041
    event.event = Tk_WindowId(menuPtr->tkwin);
4042
    event.root = XRootWindow(menuPtr->display, 0);
4043
    event.subwindow = None;
4044
    event.time = TkpGetMS();
4045
 
4046
    GetMouse(&where);
4047
    event.x_root = where.h;
4048
    event.y_root = where.v;
4049
    event.state = TkMacButtonKeyState();
4050
    event.same_screen = true;
4051
    event.name = Tk_GetUid("MenuSelect");
4052
    Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL);
4053
}
4054
 
4055
/*
4056
 *----------------------------------------------------------------------
4057
 *
4058
 * RecursivelyClearActiveMenu --
4059
 *
4060
 *      Recursively clears the active entry in the menu's cascade hierarchy.
4061
 *
4062
 * Results:
4063
 *      None.
4064
 *
4065
 * Side effects:
4066
 *      Generates <<MenuSelect>> virtual events.
4067
 *
4068
 *----------------------------------------------------------------------
4069
 */
4070
 
4071
void
4072
RecursivelyClearActiveMenu(
4073
    TkMenu *menuPtr)            /* The menu to reset. */
4074
{
4075
    int i;
4076
    TkMenuEntry *mePtr;
4077
 
4078
    TkActivateMenuEntry(menuPtr, -1);
4079
    MenuSelectEvent(menuPtr);
4080
    for (i = 0; i < menuPtr->numEntries; i++) {
4081
        mePtr = menuPtr->entries[i];
4082
        if (mePtr->type == CASCADE_ENTRY) {
4083
            if ((mePtr->childMenuRefPtr != NULL)
4084
                    && (mePtr->childMenuRefPtr->menuPtr != NULL)) {
4085
                RecursivelyClearActiveMenu(mePtr->childMenuRefPtr->menuPtr);
4086
            }
4087
        }
4088
    }
4089
}
4090
 
4091
/*
4092
 *----------------------------------------------------------------------
4093
 *
4094
 * InvalidateMDEFRgns --
4095
 *
4096
 *      Invalidates the regions covered by menus that did redrawing and
4097
 *      might be damaged.
4098
 *
4099
 * Results:
4100
 *      None.
4101
 *
4102
 * Side effects:
4103
 *      Generates Mac update events for affected windows.
4104
 *
4105
 *----------------------------------------------------------------------
4106
 */
4107
 
4108
void
4109
InvalidateMDEFRgns(void) {
4110
    GDHandle saveDevice;
4111
    GWorldPtr saveWorld, destPort;
4112
    Point scratch;
4113
    MacDrawable *macDraw;
4114
    TkMacWindowList *listPtr;
4115
 
4116
    if (totalMenuRgn == NULL) {
4117
        return;
4118
    }
4119
 
4120
    GetGWorld(&saveWorld, &saveDevice);
4121
    for (listPtr = tkMacWindowListPtr ; listPtr != NULL;
4122
            listPtr = listPtr->nextPtr) {
4123
        macDraw = (MacDrawable *) Tk_WindowId(listPtr->winPtr);
4124
        if (macDraw->flags & TK_DRAWN_UNDER_MENU) {
4125
            destPort = TkMacGetDrawablePort(Tk_WindowId(listPtr->winPtr));
4126
            SetGWorld(destPort, NULL);
4127
            scratch.h = scratch.v = 0;
4128
            GlobalToLocal(&scratch);
4129
            OffsetRgn(totalMenuRgn, scratch.v, scratch.h);
4130
            InvalRgn(totalMenuRgn);
4131
            OffsetRgn(totalMenuRgn, -scratch.v, -scratch.h);
4132
            macDraw->flags &= ~TK_DRAWN_UNDER_MENU;
4133
        }
4134
    }
4135
 
4136
    SetGWorld(saveWorld, saveDevice);
4137
    SetEmptyRgn(totalMenuRgn);
4138
}
4139
 
4140
/*
4141
 *----------------------------------------------------------------------
4142
 *
4143
 * TkMacClearMenubarActive --
4144
 *
4145
 *      Recursively clears the active entry in the current menubar hierarchy.
4146
 *
4147
 * Results:
4148
 *      None.
4149
 *
4150
 * Side effects:
4151
 *      Generates <<MenuSelect>> virtual events.
4152
 *
4153
 *----------------------------------------------------------------------
4154
 */
4155
 
4156
void
4157
TkMacClearMenubarActive(void) {
4158
    TkMenuReferences *menuBarRefPtr;
4159
 
4160
    if (currentMenuBarName != NULL) {
4161
        menuBarRefPtr = TkFindMenuReferences(currentMenuBarInterp,
4162
                currentMenuBarName);
4163
        if ((menuBarRefPtr != NULL) && (menuBarRefPtr->menuPtr != NULL)) {
4164
            TkMenu *menuPtr;
4165
 
4166
            for (menuPtr = menuBarRefPtr->menuPtr->masterMenuPtr; menuPtr != NULL;
4167
                    menuPtr = menuPtr->nextInstancePtr) {
4168
                if (menuPtr->menuType == MENUBAR) {
4169
                    RecursivelyClearActiveMenu(menuPtr);
4170
                }
4171
            }
4172
        }
4173
    }
4174
    InvalidateMDEFRgns();
4175
    FixMDEF();
4176
}
4177
 
4178
/*
4179
 *----------------------------------------------------------------------
4180
 *
4181
 * TkpMenuNotifyToplevelCreate --
4182
 *
4183
 *      This routine reconfigures the menu and the clones indicated by
4184
 *      menuName becuase a toplevel has been created and any system
4185
 *      menus need to be created. Only applicable to Windows.
4186
 *
4187
 * Results:
4188
 *      None.
4189
 *
4190
 * Side effects:
4191
 *      An idle handler is set up to do the reconfiguration.
4192
 *
4193
 *----------------------------------------------------------------------
4194
 */
4195
 
4196
void
4197
TkpMenuNotifyToplevelCreate(
4198
    Tcl_Interp *interp,                 /* The interp the menu lives in. */
4199
    char *menuName)                     /* The name of the menu to
4200
                                         * reconfigure. */
4201
{
4202
    /*
4203
     * Nothing to do.
4204
     */
4205
}
4206
 
4207
/*
4208
 *----------------------------------------------------------------------
4209
 *
4210
 * FixMDEF --
4211
 *
4212
 *      Loads the MDEF and blasts our routine descriptor into it.
4213
 *      We have to set up the MDEF. This is pretty slimy. The real MDEF
4214
 *      resource is 68K code. All this code does is call another procedure.
4215
 *      When the application in launched, a dummy value for the procedure
4216
 *      is compiled into the MDEF. We are going to replace that dummy
4217
 *      value with a routine descriptor. When the routine descriptor
4218
 *      is invoked, the globals and everything will be setup, and we
4219
 *      can do what we need. This will not work from 68K or CFM 68k
4220
 *      currently, so we will conditional compile this until we
4221
 *      figure it out.
4222
 *
4223
 * Results:
4224
 *      Returns the MDEF handle.
4225
 *
4226
 * Side effects:
4227
 *      The MDEF is read in and massaged.
4228
 *
4229
 *----------------------------------------------------------------------
4230
 */
4231
 
4232
static Handle
4233
FixMDEF(void)
4234
{
4235
#ifdef GENERATINGCFM
4236
    Handle MDEFHandle = GetResource('MDEF', 591);
4237
    Handle SICNHandle = GetResource('SICN', SICN_RESOURCE_NUMBER);
4238
    if ((MDEFHandle != NULL) && (SICNHandle != NULL)) {
4239
        HLock(MDEFHandle);
4240
        HLock(SICNHandle);
4241
        if (menuDefProc == NULL) {
4242
            menuDefProc = TkNewMenuDefProc(MenuDefProc);
4243
        }
4244
        memmove((void *) (((long) (*MDEFHandle)) + 0x24), &menuDefProc, 4);
4245
        return MDEFHandle;
4246
    } else {
4247
        return NULL;
4248
    }
4249
#else
4250
    return NULL;
4251
#endif
4252
}
4253
 
4254
/*
4255
 *----------------------------------------------------------------------
4256
 *
4257
 * TkpMenuInit --
4258
 *
4259
 *      Initializes Mac-specific menu data.
4260
 *
4261
 * Results:
4262
 *      None.
4263
 *
4264
 * Side effects:
4265
 *      Allcates a hash table.
4266
 *
4267
 *----------------------------------------------------------------------
4268
 */
4269
 
4270
void
4271
TkpMenuInit(void)
4272
{
4273
    lastMenuID = 256;
4274
    Tcl_InitHashTable(&commandTable, TCL_ONE_WORD_KEYS);
4275
    currentMenuBarOwner = NULL;
4276
    tearoffStruct.menuPtr = NULL;
4277
    currentAppleMenuID = 0;
4278
    currentHelpMenuID = 0;
4279
    currentMenuBarInterp = NULL;
4280
    currentMenuBarName = NULL;
4281
    windowListPtr = NULL;
4282
 
4283
    /*
4284
     * Get the GC that we will use as the sign to the font
4285
     * routines that they should not muck with the foreground color...
4286
     */
4287
 
4288
    if (TkMacHaveAppearance() > 1) {
4289
        XGCValues tmpValues;
4290
        TkColor *tmpColorPtr;
4291
 
4292
        tmpColorPtr = TkpGetColor(NULL, "systemAppearanceColor");
4293
        tmpValues.foreground = tmpColorPtr->color.pixel;
4294
        tmpValues.background = tmpColorPtr->color.pixel;
4295
        appearanceGC = XCreateGC(NULL, NULL, GCForeground | GCBackground, &tmpValues);
4296
        ckfree((char *) tmpColorPtr);
4297
 
4298
        tkThemeMenuItemDrawingUPP = NewMenuItemDrawingProc(tkThemeMenuItemDrawingProc);
4299
    }
4300
    FixMDEF();
4301
 
4302
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.