1 |
/* $Header$ */ |
2 |
|
3 |
/* |
4 |
* tkWinMenu.c -- |
5 |
* |
6 |
* This module implements the Windows platform-specific features of menus. |
7 |
* |
8 |
* Copyright (c) 1996-1998 by Sun Microsystems, Inc. |
9 |
* Copyright (c) 1998-1999 by Scriptics Corporation. |
10 |
* |
11 |
* See the file "license.terms" for information on usage and redistribution |
12 |
* of this file, and for a DISCLAIMER OF ALL WARRANTIES. |
13 |
* |
14 |
* RCS: @(#) $Id: tkwinmenu.c,v 1.1.1.1 2001/06/13 05:14:08 dtashley Exp $ |
15 |
*/ |
16 |
|
17 |
#define OEMRESOURCE |
18 |
#include "tkWinInt.h" |
19 |
#include "tkMenu.h" |
20 |
|
21 |
#include <string.h> |
22 |
|
23 |
/* |
24 |
* The class of the window for popup menus. |
25 |
*/ |
26 |
|
27 |
#define MENU_CLASS_NAME "MenuWindowClass" |
28 |
|
29 |
/* |
30 |
* Used to align a windows bitmap inside a rectangle |
31 |
*/ |
32 |
|
33 |
#define ALIGN_BITMAP_LEFT 0x00000001 |
34 |
#define ALIGN_BITMAP_RIGHT 0x00000002 |
35 |
#define ALIGN_BITMAP_TOP 0x00000004 |
36 |
#define ALIGN_BITMAP_BOTTOM 0x00000008 |
37 |
|
38 |
/* |
39 |
* Platform-specific menu flags: |
40 |
* |
41 |
* MENU_SYSTEM_MENU Non-zero means that the Windows menu handle |
42 |
* was retrieved with GetSystemMenu and needs |
43 |
* to be disposed of specially. |
44 |
* MENU_RECONFIGURE_PENDING |
45 |
* Non-zero means that an idle handler has |
46 |
* been set up to reconfigure the Windows menu |
47 |
* handle for this menu. |
48 |
*/ |
49 |
|
50 |
#define MENU_SYSTEM_MENU MENU_PLATFORM_FLAG1 |
51 |
#define MENU_RECONFIGURE_PENDING MENU_PLATFORM_FLAG2 |
52 |
|
53 |
static int indicatorDimensions[2]; |
54 |
/* The dimensions of the indicator space |
55 |
* in a menu entry. Calculated at init |
56 |
* time to save time. */ |
57 |
|
58 |
typedef struct ThreadSpecificData { |
59 |
Tcl_HashTable commandTable; |
60 |
/* A map of command ids to menu entries */ |
61 |
int inPostMenu; /* We cannot be re-entrant like X Windows. */ |
62 |
WORD lastCommandID; /* The last command ID we allocated. */ |
63 |
HWND menuHWND; /* A window to service popup-menu messages |
64 |
* in. */ |
65 |
int oldServiceMode; /* Used while processing a menu; we need |
66 |
* to set the event mode specially when we |
67 |
* enter the menu processing modal loop |
68 |
* and reset it when menus go away. */ |
69 |
TkMenu *modalMenuPtr; /* The menu we are processing inside the modal |
70 |
* loop. We need this to reset all of the |
71 |
* active items when menus go away since |
72 |
* Windows does not see fit to give this |
73 |
* to us when it sends its WM_MENUSELECT. */ |
74 |
Tcl_HashTable winMenuTable; |
75 |
/* Need this to map HMENUs back to menuPtrs */ |
76 |
} ThreadSpecificData; |
77 |
static Tcl_ThreadDataKey dataKey; |
78 |
|
79 |
/* |
80 |
* The following are default menu value strings. |
81 |
*/ |
82 |
|
83 |
static int defaultBorderWidth; /* The windows default border width. */ |
84 |
static Tcl_DString menuFontDString; |
85 |
/* A buffer to store the default menu font |
86 |
* string. */ |
87 |
TCL_DECLARE_MUTEX(winMenuMutex) |
88 |
|
89 |
/* |
90 |
* Forward declarations for procedures defined later in this file: |
91 |
*/ |
92 |
|
93 |
static void DrawMenuEntryAccelerator _ANSI_ARGS_(( |
94 |
TkMenu *menuPtr, TkMenuEntry *mePtr, |
95 |
Drawable d, GC gc, Tk_Font tkfont, |
96 |
CONST Tk_FontMetrics *fmPtr, |
97 |
Tk_3DBorder activeBorder, int x, int y, |
98 |
int width, int height, int drawArrow)); |
99 |
static void DrawMenuEntryBackground _ANSI_ARGS_(( |
100 |
TkMenu *menuPtr, TkMenuEntry *mePtr, |
101 |
Drawable d, Tk_3DBorder activeBorder, |
102 |
Tk_3DBorder bgBorder, int x, int y, |
103 |
int width, int heigth)); |
104 |
static void DrawMenuEntryIndicator _ANSI_ARGS_(( |
105 |
TkMenu *menuPtr, TkMenuEntry *mePtr, |
106 |
Drawable d, GC gc, GC indicatorGC, |
107 |
Tk_Font tkfont, |
108 |
CONST Tk_FontMetrics *fmPtr, int x, int y, |
109 |
int width, int height)); |
110 |
static void DrawMenuEntryLabel _ANSI_ARGS_(( |
111 |
TkMenu * menuPtr, TkMenuEntry *mePtr, Drawable d, |
112 |
GC gc, Tk_Font tkfont, |
113 |
CONST Tk_FontMetrics *fmPtr, int x, int y, |
114 |
int width, int height)); |
115 |
static void DrawMenuSeparator _ANSI_ARGS_((TkMenu *menuPtr, |
116 |
TkMenuEntry *mePtr, Drawable d, GC gc, |
117 |
Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, |
118 |
int x, int y, int width, int height)); |
119 |
static void DrawTearoffEntry _ANSI_ARGS_((TkMenu *menuPtr, |
120 |
TkMenuEntry *mePtr, Drawable d, GC gc, |
121 |
Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, |
122 |
int x, int y, int width, int height)); |
123 |
static void DrawMenuUnderline _ANSI_ARGS_((TkMenu *menuPtr, |
124 |
TkMenuEntry *mePtr, Drawable d, GC gc, |
125 |
Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int x, |
126 |
int y, int width, int height)); |
127 |
static void DrawWindowsSystemBitmap _ANSI_ARGS_(( |
128 |
Display *display, Drawable drawable, |
129 |
GC gc, CONST RECT *rectPtr, int bitmapID, |
130 |
int alignFlags)); |
131 |
static void FreeID _ANSI_ARGS_((int commandID)); |
132 |
static TCHAR * GetEntryText _ANSI_ARGS_((TkMenuEntry *mePtr)); |
133 |
static void GetMenuAccelGeometry _ANSI_ARGS_((TkMenu *menuPtr, |
134 |
TkMenuEntry *mePtr, Tk_Font tkfont, |
135 |
CONST Tk_FontMetrics *fmPtr, int *widthPtr, |
136 |
int *heightPtr)); |
137 |
static void GetMenuLabelGeometry _ANSI_ARGS_((TkMenuEntry *mePtr, |
138 |
Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, |
139 |
int *widthPtr, int *heightPtr)); |
140 |
static void GetMenuIndicatorGeometry _ANSI_ARGS_(( |
141 |
TkMenu *menuPtr, TkMenuEntry *mePtr, |
142 |
Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, |
143 |
int *widthPtr, int *heightPtr)); |
144 |
static void GetMenuSeparatorGeometry _ANSI_ARGS_(( |
145 |
TkMenu *menuPtr, TkMenuEntry *mePtr, |
146 |
Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, |
147 |
int *widthPtr, int *heightPtr)); |
148 |
static void GetTearoffEntryGeometry _ANSI_ARGS_((TkMenu *menuPtr, |
149 |
TkMenuEntry *mePtr, Tk_Font tkfont, |
150 |
CONST Tk_FontMetrics *fmPtr, int *widthPtr, |
151 |
int *heightPtr)); |
152 |
static int GetNewID _ANSI_ARGS_((TkMenuEntry *mePtr, |
153 |
int *menuIDPtr)); |
154 |
static void MenuExitProc _ANSI_ARGS_((ClientData clientData)); |
155 |
static int MenuKeyBindProc _ANSI_ARGS_(( |
156 |
ClientData clientData, |
157 |
Tcl_Interp *interp, XEvent *eventPtr, |
158 |
Tk_Window tkwin, KeySym keySym)); |
159 |
static void MenuSelectEvent _ANSI_ARGS_((TkMenu *menuPtr)); |
160 |
static void ReconfigureWindowsMenu _ANSI_ARGS_(( |
161 |
ClientData clientData)); |
162 |
static void RecursivelyClearActiveMenu _ANSI_ARGS_(( |
163 |
TkMenu *menuPtr)); |
164 |
static void SetDefaults _ANSI_ARGS_((int firstTime)); |
165 |
static LRESULT CALLBACK TkWinMenuProc _ANSI_ARGS_((HWND hwnd, |
166 |
UINT message, WPARAM wParam, |
167 |
LPARAM lParam)); |
168 |
|
169 |
|
170 |
|
171 |
/* |
172 |
*---------------------------------------------------------------------- |
173 |
* |
174 |
* GetNewID -- |
175 |
* |
176 |
* Allocates a new menu id and marks it in use. |
177 |
* |
178 |
* Results: |
179 |
* Returns TCL_OK if succesful; TCL_ERROR if there are no more |
180 |
* ids of the appropriate type to allocate. menuIDPtr contains |
181 |
* the new id if succesful. |
182 |
* |
183 |
* Side effects: |
184 |
* An entry is created for the menu in the command hash table, |
185 |
* and the hash entry is stored in the appropriate field in the |
186 |
* menu data structure. |
187 |
* |
188 |
*---------------------------------------------------------------------- |
189 |
*/ |
190 |
|
191 |
static int |
192 |
GetNewID(mePtr, menuIDPtr) |
193 |
TkMenuEntry *mePtr; /* The menu we are working with */ |
194 |
int *menuIDPtr; /* The resulting id */ |
195 |
{ |
196 |
int found = 0; |
197 |
int newEntry; |
198 |
Tcl_HashEntry *commandEntryPtr; |
199 |
WORD returnID; |
200 |
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) |
201 |
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); |
202 |
|
203 |
WORD curID = tsdPtr->lastCommandID + 1; |
204 |
|
205 |
/* |
206 |
* The following code relies on WORD wrapping when the highest value is |
207 |
* incremented. |
208 |
*/ |
209 |
|
210 |
while (curID != tsdPtr->lastCommandID) { |
211 |
commandEntryPtr = Tcl_CreateHashEntry(&tsdPtr->commandTable, |
212 |
(char *) curID, &newEntry); |
213 |
if (newEntry == 1) { |
214 |
found = 1; |
215 |
returnID = curID; |
216 |
break; |
217 |
} |
218 |
curID++; |
219 |
} |
220 |
|
221 |
if (found) { |
222 |
Tcl_SetHashValue(commandEntryPtr, (char *) mePtr); |
223 |
*menuIDPtr = (int) returnID; |
224 |
tsdPtr->lastCommandID = returnID; |
225 |
return TCL_OK; |
226 |
} else { |
227 |
return TCL_ERROR; |
228 |
} |
229 |
} |
230 |
|
231 |
/* |
232 |
*---------------------------------------------------------------------- |
233 |
* |
234 |
* FreeID -- |
235 |
* |
236 |
* Marks the itemID as free. |
237 |
* |
238 |
* Results: |
239 |
* None. |
240 |
* |
241 |
* Side effects: |
242 |
* The hash table entry for the ID is cleared. |
243 |
* |
244 |
*---------------------------------------------------------------------- |
245 |
*/ |
246 |
|
247 |
static void |
248 |
FreeID(commandID) |
249 |
int commandID; |
250 |
{ |
251 |
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) |
252 |
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); |
253 |
|
254 |
Tcl_HashEntry *entryPtr = Tcl_FindHashEntry(&tsdPtr->commandTable, |
255 |
(char *) commandID); |
256 |
|
257 |
if (entryPtr != NULL) { |
258 |
Tcl_DeleteHashEntry(entryPtr); |
259 |
} |
260 |
} |
261 |
|
262 |
/* |
263 |
*---------------------------------------------------------------------- |
264 |
* |
265 |
* TkpNewMenu -- |
266 |
* |
267 |
* Gets a new blank menu. Only the platform specific options are filled |
268 |
* in. |
269 |
* |
270 |
* Results: |
271 |
* Standard TCL error. |
272 |
* |
273 |
* Side effects: |
274 |
* Allocates a Windows menu handle and places it in the platformData |
275 |
* field of the menuPtr. |
276 |
* |
277 |
*---------------------------------------------------------------------- |
278 |
*/ |
279 |
|
280 |
int |
281 |
TkpNewMenu(menuPtr) |
282 |
TkMenu *menuPtr; /* The common structure we are making the |
283 |
* platform structure for. */ |
284 |
{ |
285 |
HMENU winMenuHdl; |
286 |
Tcl_HashEntry *hashEntryPtr; |
287 |
int newEntry; |
288 |
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) |
289 |
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); |
290 |
|
291 |
winMenuHdl = CreatePopupMenu(); |
292 |
|
293 |
if (winMenuHdl == NULL) { |
294 |
Tcl_AppendResult(menuPtr->interp, "No more menus can be allocated.", |
295 |
(char *) NULL); |
296 |
return TCL_ERROR; |
297 |
} |
298 |
|
299 |
/* |
300 |
* We hash all of the HMENU's so that we can get their menu ptrs |
301 |
* back when dispatch messages. |
302 |
*/ |
303 |
|
304 |
hashEntryPtr = Tcl_CreateHashEntry(&tsdPtr->winMenuTable, (char *) winMenuHdl, |
305 |
&newEntry); |
306 |
Tcl_SetHashValue(hashEntryPtr, (char *) menuPtr); |
307 |
|
308 |
menuPtr->platformData = (TkMenuPlatformData) winMenuHdl; |
309 |
return TCL_OK; |
310 |
} |
311 |
|
312 |
/* |
313 |
*---------------------------------------------------------------------- |
314 |
* |
315 |
* TkpDestroyMenu -- |
316 |
* |
317 |
* Destroys platform-specific menu structures. |
318 |
* |
319 |
* Results: |
320 |
* None. |
321 |
* |
322 |
* Side effects: |
323 |
* All platform-specific allocations are freed up. |
324 |
* |
325 |
*---------------------------------------------------------------------- |
326 |
*/ |
327 |
|
328 |
void |
329 |
TkpDestroyMenu(menuPtr) |
330 |
TkMenu *menuPtr; /* The common menu structure */ |
331 |
{ |
332 |
HMENU winMenuHdl = (HMENU) menuPtr->platformData; |
333 |
char *searchName; |
334 |
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) |
335 |
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); |
336 |
|
337 |
if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) { |
338 |
Tcl_CancelIdleCall(ReconfigureWindowsMenu, (ClientData) menuPtr); |
339 |
} |
340 |
|
341 |
if (winMenuHdl == NULL) { |
342 |
return; |
343 |
} |
344 |
|
345 |
if (menuPtr->menuFlags & MENU_SYSTEM_MENU) { |
346 |
TkMenuEntry *searchEntryPtr; |
347 |
Tcl_HashTable *tablePtr = TkGetMenuHashTable(menuPtr->interp); |
348 |
char *menuName = Tcl_GetHashKey(tablePtr, |
349 |
menuPtr->menuRefPtr->hashEntryPtr); |
350 |
|
351 |
/* |
352 |
* Search for the menu in the menubar, if it is present, get the |
353 |
* wrapper window associated with the toplevel and reset its |
354 |
* system menu to the default menu. |
355 |
*/ |
356 |
|
357 |
for (searchEntryPtr = menuPtr->menuRefPtr->parentEntryPtr; |
358 |
searchEntryPtr != NULL; |
359 |
searchEntryPtr = searchEntryPtr->nextCascadePtr) { |
360 |
searchName = Tcl_GetStringFromObj(searchEntryPtr->namePtr, NULL); |
361 |
if (strcmp(searchName, menuName) == 0) { |
362 |
Tk_Window parentTopLevelPtr = searchEntryPtr |
363 |
->menuPtr->parentTopLevelPtr; |
364 |
|
365 |
if (parentTopLevelPtr != NULL) { |
366 |
GetSystemMenu(TkWinGetWrapperWindow(parentTopLevelPtr), |
367 |
TRUE); |
368 |
} |
369 |
break; |
370 |
} |
371 |
} |
372 |
} else { |
373 |
Tcl_HashEntry *hashEntryPtr; |
374 |
|
375 |
/* |
376 |
* Remove the menu from the menu hash table, then destroy the handle. |
377 |
*/ |
378 |
|
379 |
hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->winMenuTable, |
380 |
(char *) winMenuHdl); |
381 |
if (hashEntryPtr != NULL) { |
382 |
Tcl_DeleteHashEntry(hashEntryPtr); |
383 |
} |
384 |
DestroyMenu(winMenuHdl); |
385 |
} |
386 |
menuPtr->platformData = NULL; |
387 |
|
388 |
if (menuPtr == tsdPtr->modalMenuPtr) { |
389 |
tsdPtr->modalMenuPtr = NULL; |
390 |
} |
391 |
} |
392 |
|
393 |
/* |
394 |
*---------------------------------------------------------------------- |
395 |
* |
396 |
* TkpDestroyMenuEntry -- |
397 |
* |
398 |
* Cleans up platform-specific menu entry items. |
399 |
* |
400 |
* Results: |
401 |
* None |
402 |
* |
403 |
* Side effects: |
404 |
* All platform-specific allocations are freed up. |
405 |
* |
406 |
*---------------------------------------------------------------------- |
407 |
*/ |
408 |
|
409 |
void |
410 |
TkpDestroyMenuEntry(mePtr) |
411 |
TkMenuEntry *mePtr; /* The entry to destroy */ |
412 |
{ |
413 |
TkMenu *menuPtr = mePtr->menuPtr; |
414 |
HMENU winMenuHdl = (HMENU) menuPtr->platformData; |
415 |
|
416 |
if (NULL != winMenuHdl) { |
417 |
if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) { |
418 |
menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; |
419 |
Tcl_DoWhenIdle(ReconfigureWindowsMenu, (ClientData) menuPtr); |
420 |
} |
421 |
} |
422 |
FreeID((int) mePtr->platformEntryData); |
423 |
mePtr->platformEntryData = NULL; |
424 |
} |
425 |
|
426 |
/* |
427 |
*---------------------------------------------------------------------- |
428 |
* |
429 |
* GetEntryText -- |
430 |
* |
431 |
* Given a menu entry, gives back the text that should go in it. |
432 |
* Separators should be done by the caller, as they have to be |
433 |
* handled specially. Allocates the memory with alloc. The caller |
434 |
* should free the memory. |
435 |
* |
436 |
* Results: |
437 |
* itemText points to the new text for the item. |
438 |
* |
439 |
* Side effects: |
440 |
* None. |
441 |
* |
442 |
*---------------------------------------------------------------------- |
443 |
*/ |
444 |
|
445 |
static char * |
446 |
GetEntryText(mePtr) |
447 |
TkMenuEntry *mePtr; /* A pointer to the menu entry. */ |
448 |
{ |
449 |
char *itemText; |
450 |
|
451 |
if (mePtr->type == TEAROFF_ENTRY) { |
452 |
itemText = ckalloc(sizeof("(Tear-off)")); |
453 |
strcpy(itemText, "(Tear-off)"); |
454 |
} else if (mePtr->imagePtr != NULL) { |
455 |
itemText = ckalloc(sizeof("(Image)")); |
456 |
strcpy(itemText, "(Image)"); |
457 |
} else if (mePtr->bitmapPtr != NULL) { |
458 |
itemText = ckalloc(sizeof("(Pixmap)")); |
459 |
strcpy(itemText, "(Pixmap)"); |
460 |
} else if (mePtr->labelPtr == NULL || mePtr->labelLength == 0) { |
461 |
itemText = ckalloc(sizeof("( )")); |
462 |
strcpy(itemText, "( )"); |
463 |
} else { |
464 |
int i; |
465 |
char *label = (mePtr->labelPtr == NULL) ? "" |
466 |
: Tcl_GetStringFromObj(mePtr->labelPtr, NULL); |
467 |
char *accel = (mePtr->accelPtr == NULL) ? "" |
468 |
: Tcl_GetStringFromObj(mePtr->accelPtr, NULL); |
469 |
char *p, *next; |
470 |
Tcl_DString itemString; |
471 |
|
472 |
/* |
473 |
* We have to construct the string with an ampersand |
474 |
* preceeding the underline character, and a tab seperating |
475 |
* the text and the accel text. We have to be careful with |
476 |
* ampersands in the string. |
477 |
*/ |
478 |
|
479 |
Tcl_DStringInit(&itemString); |
480 |
|
481 |
for (p = label, i = 0; *p != '\0'; i++, p = next) { |
482 |
if (i == mePtr->underline) { |
483 |
Tcl_DStringAppend(&itemString, "&", 1); |
484 |
} |
485 |
if (*p == '&') { |
486 |
Tcl_DStringAppend(&itemString, "&", 1); |
487 |
} |
488 |
next = Tcl_UtfNext(p); |
489 |
Tcl_DStringAppend(&itemString, p, next - p); |
490 |
} |
491 |
if (mePtr->accelLength > 0) { |
492 |
Tcl_DStringAppend(&itemString, "\t", 1); |
493 |
for (p = accel, i = 0; *p != '\0'; i++, p = next) { |
494 |
if (*p == '&') { |
495 |
Tcl_DStringAppend(&itemString, "&", 1); |
496 |
} |
497 |
next = Tcl_UtfNext(p); |
498 |
Tcl_DStringAppend(&itemString, p, next - p); |
499 |
} |
500 |
} |
501 |
|
502 |
itemText = ckalloc(Tcl_DStringLength(&itemString) + 1); |
503 |
strcpy(itemText, Tcl_DStringValue(&itemString)); |
504 |
Tcl_DStringFree(&itemString); |
505 |
} |
506 |
return itemText; |
507 |
} |
508 |
|
509 |
/* |
510 |
*---------------------------------------------------------------------- |
511 |
* |
512 |
* ReconfigureWindowsMenu -- |
513 |
* |
514 |
* Tears down and rebuilds the platform-specific part of this menu. |
515 |
* |
516 |
* Results: |
517 |
* None. |
518 |
* |
519 |
* Side effects: |
520 |
* Configuration information get set for mePtr; old resources |
521 |
* get freed, if any need it. |
522 |
* |
523 |
*---------------------------------------------------------------------- |
524 |
*/ |
525 |
|
526 |
static void |
527 |
ReconfigureWindowsMenu( |
528 |
ClientData clientData) /* The menu we are rebuilding */ |
529 |
{ |
530 |
TkMenu *menuPtr = (TkMenu *) clientData; |
531 |
TkMenuEntry *mePtr; |
532 |
HMENU winMenuHdl = (HMENU) menuPtr->platformData; |
533 |
TCHAR *itemText = NULL; |
534 |
const TCHAR *lpNewItem; |
535 |
UINT flags; |
536 |
UINT itemID; |
537 |
int i, count, systemMenu = 0, base; |
538 |
int width, height; |
539 |
Tcl_DString translatedText; |
540 |
|
541 |
if (NULL == winMenuHdl) { |
542 |
return; |
543 |
} |
544 |
|
545 |
/* |
546 |
* Reconstruct the entire menu. Takes care of nasty system menu and index |
547 |
* problem. |
548 |
* |
549 |
*/ |
550 |
|
551 |
if ((menuPtr->menuType == MENUBAR) |
552 |
&& (menuPtr->parentTopLevelPtr != NULL)) { |
553 |
width = Tk_Width(menuPtr->parentTopLevelPtr); |
554 |
height = Tk_Height(menuPtr->parentTopLevelPtr); |
555 |
} |
556 |
|
557 |
base = (menuPtr->menuFlags & MENU_SYSTEM_MENU) ? 7 : 0; |
558 |
count = GetMenuItemCount(winMenuHdl); |
559 |
for (i = base; i < count; i++) { |
560 |
RemoveMenu(winMenuHdl, base, MF_BYPOSITION); |
561 |
} |
562 |
|
563 |
count = menuPtr->numEntries; |
564 |
for (i = 0; i < count; i++) { |
565 |
mePtr = menuPtr->entries[i]; |
566 |
lpNewItem = NULL; |
567 |
flags = MF_BYPOSITION; |
568 |
itemID = 0; |
569 |
Tcl_DStringInit(&translatedText); |
570 |
|
571 |
if ((menuPtr->menuType == MENUBAR) && (mePtr->type == TEAROFF_ENTRY)) { |
572 |
continue; |
573 |
} |
574 |
|
575 |
itemText = GetEntryText(mePtr); |
576 |
if ((menuPtr->menuType == MENUBAR) |
577 |
|| (menuPtr->menuFlags & MENU_SYSTEM_MENU)) { |
578 |
Tcl_UtfToExternalDString(NULL, itemText, -1, &translatedText); |
579 |
lpNewItem = Tcl_DStringValue(&translatedText); |
580 |
} else { |
581 |
lpNewItem = (LPCTSTR) mePtr; |
582 |
flags |= MF_OWNERDRAW; |
583 |
} |
584 |
|
585 |
/* |
586 |
* Set enabling and disabling correctly. |
587 |
*/ |
588 |
|
589 |
if (mePtr->state == ENTRY_DISABLED) { |
590 |
flags |= MF_DISABLED; |
591 |
} |
592 |
|
593 |
/* |
594 |
* Set the check mark for check entries and radio entries. |
595 |
*/ |
596 |
|
597 |
if (((mePtr->type == CHECK_BUTTON_ENTRY) |
598 |
|| (mePtr->type == RADIO_BUTTON_ENTRY)) |
599 |
&& (mePtr->entryFlags & ENTRY_SELECTED)) { |
600 |
flags |= MF_CHECKED; |
601 |
} |
602 |
|
603 |
if (mePtr->columnBreak) { |
604 |
flags |= MF_MENUBREAK; |
605 |
} |
606 |
|
607 |
itemID = (int) mePtr->platformEntryData; |
608 |
if ((mePtr->type == CASCADE_ENTRY) |
609 |
&& (mePtr->childMenuRefPtr != NULL) |
610 |
&& (mePtr->childMenuRefPtr->menuPtr != NULL)) { |
611 |
HMENU childMenuHdl = (HMENU) mePtr->childMenuRefPtr->menuPtr |
612 |
->platformData; |
613 |
if (childMenuHdl != NULL) { |
614 |
itemID = (UINT) childMenuHdl; |
615 |
flags |= MF_POPUP; |
616 |
} |
617 |
if ((menuPtr->menuType == MENUBAR) |
618 |
&& !(mePtr->childMenuRefPtr->menuPtr->menuFlags |
619 |
& MENU_SYSTEM_MENU)) { |
620 |
Tcl_DString ds; |
621 |
TkMenuReferences *menuRefPtr; |
622 |
TkMenu *systemMenuPtr = mePtr->childMenuRefPtr->menuPtr; |
623 |
|
624 |
Tcl_DStringInit(&ds); |
625 |
Tcl_DStringAppend(&ds, |
626 |
Tk_PathName(menuPtr->masterMenuPtr->tkwin), -1); |
627 |
Tcl_DStringAppend(&ds, ".system", 7); |
628 |
|
629 |
menuRefPtr = TkFindMenuReferences(menuPtr->interp, |
630 |
Tcl_DStringValue(&ds)); |
631 |
|
632 |
Tcl_DStringFree(&ds); |
633 |
|
634 |
if ((menuRefPtr != NULL) |
635 |
&& (menuRefPtr->menuPtr != NULL) |
636 |
&& (menuPtr->parentTopLevelPtr != NULL) |
637 |
&& (systemMenuPtr->masterMenuPtr |
638 |
== menuRefPtr->menuPtr)) { |
639 |
HMENU systemMenuHdl = |
640 |
(HMENU) systemMenuPtr->platformData; |
641 |
HWND wrapper = TkWinGetWrapperWindow(menuPtr |
642 |
->parentTopLevelPtr); |
643 |
if (wrapper != NULL) { |
644 |
DestroyMenu(systemMenuHdl); |
645 |
systemMenuHdl = GetSystemMenu(wrapper, FALSE); |
646 |
systemMenuPtr->menuFlags |= MENU_SYSTEM_MENU; |
647 |
systemMenuPtr->platformData = |
648 |
(TkMenuPlatformData) systemMenuHdl; |
649 |
if (!(systemMenuPtr->menuFlags |
650 |
& MENU_RECONFIGURE_PENDING)) { |
651 |
systemMenuPtr->menuFlags |
652 |
|= MENU_RECONFIGURE_PENDING; |
653 |
Tcl_DoWhenIdle(ReconfigureWindowsMenu, |
654 |
(ClientData) systemMenuPtr); |
655 |
} |
656 |
} |
657 |
} |
658 |
} |
659 |
if (mePtr->childMenuRefPtr->menuPtr->menuFlags |
660 |
& MENU_SYSTEM_MENU) { |
661 |
systemMenu++; |
662 |
} |
663 |
} |
664 |
if (!systemMenu) { |
665 |
InsertMenu(winMenuHdl, 0xFFFFFFFF, flags, itemID, lpNewItem); |
666 |
} |
667 |
Tcl_DStringFree(&translatedText); |
668 |
if (itemText != NULL) { |
669 |
ckfree(itemText); |
670 |
itemText = NULL; |
671 |
} |
672 |
} |
673 |
|
674 |
|
675 |
if ((menuPtr->menuType == MENUBAR) |
676 |
&& (menuPtr->parentTopLevelPtr != NULL)) { |
677 |
DrawMenuBar(TkWinGetWrapperWindow(menuPtr->parentTopLevelPtr)); |
678 |
Tk_GeometryRequest(menuPtr->parentTopLevelPtr, width, height); |
679 |
} |
680 |
|
681 |
menuPtr->menuFlags &= ~(MENU_RECONFIGURE_PENDING); |
682 |
} |
683 |
|
684 |
/* |
685 |
*---------------------------------------------------------------------- |
686 |
* |
687 |
* TkpPostMenu -- |
688 |
* |
689 |
* Posts a menu on the screen |
690 |
* |
691 |
* Results: |
692 |
* None. |
693 |
* |
694 |
* Side effects: |
695 |
* The menu is posted and handled. |
696 |
* |
697 |
*---------------------------------------------------------------------- |
698 |
*/ |
699 |
|
700 |
int |
701 |
TkpPostMenu(interp, menuPtr, x, y) |
702 |
Tcl_Interp *interp; |
703 |
TkMenu *menuPtr; |
704 |
int x; |
705 |
int y; |
706 |
{ |
707 |
HMENU winMenuHdl = (HMENU) menuPtr->platformData; |
708 |
int result, flags; |
709 |
RECT noGoawayRect; |
710 |
POINT point; |
711 |
Tk_Window parentWindow = Tk_Parent(menuPtr->tkwin); |
712 |
int oldServiceMode = Tcl_GetServiceMode(); |
713 |
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) |
714 |
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); |
715 |
|
716 |
tsdPtr->inPostMenu++; |
717 |
|
718 |
if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) { |
719 |
Tcl_CancelIdleCall(ReconfigureWindowsMenu, (ClientData) menuPtr); |
720 |
ReconfigureWindowsMenu((ClientData) menuPtr); |
721 |
} |
722 |
|
723 |
result = TkPreprocessMenu(menuPtr); |
724 |
if (result != TCL_OK) { |
725 |
tsdPtr->inPostMenu--; |
726 |
return result; |
727 |
} |
728 |
|
729 |
/* |
730 |
* The post commands could have deleted the menu, which means |
731 |
* we are dead and should go away. |
732 |
*/ |
733 |
|
734 |
if (menuPtr->tkwin == NULL) { |
735 |
tsdPtr->inPostMenu--; |
736 |
return TCL_OK; |
737 |
} |
738 |
|
739 |
if (NULL == parentWindow) { |
740 |
noGoawayRect.top = y - 50; |
741 |
noGoawayRect.bottom = y + 50; |
742 |
noGoawayRect.left = x - 50; |
743 |
noGoawayRect.right = x + 50; |
744 |
} else { |
745 |
int left, top; |
746 |
Tk_GetRootCoords(parentWindow, &left, &top); |
747 |
noGoawayRect.left = left; |
748 |
noGoawayRect.top = top; |
749 |
noGoawayRect.bottom = noGoawayRect.top + Tk_Height(parentWindow); |
750 |
noGoawayRect.right = noGoawayRect.left + Tk_Width(parentWindow); |
751 |
} |
752 |
|
753 |
Tcl_SetServiceMode(TCL_SERVICE_NONE); |
754 |
|
755 |
/* |
756 |
* Make an assumption here. If the right button is down, |
757 |
* then we want to track it. Otherwise, track the left mouse button. |
758 |
*/ |
759 |
|
760 |
flags = TPM_LEFTALIGN; |
761 |
if (GetSystemMetrics(SM_SWAPBUTTON)) { |
762 |
if (GetAsyncKeyState(VK_LBUTTON) < 0) { |
763 |
flags |= TPM_RIGHTBUTTON; |
764 |
} else { |
765 |
flags |= TPM_LEFTBUTTON; |
766 |
} |
767 |
} else { |
768 |
if (GetAsyncKeyState(VK_RBUTTON) < 0) { |
769 |
flags |= TPM_RIGHTBUTTON; |
770 |
} else { |
771 |
flags |= TPM_LEFTBUTTON; |
772 |
} |
773 |
} |
774 |
|
775 |
TrackPopupMenu(winMenuHdl, flags, x, y, 0, |
776 |
tsdPtr->menuHWND, &noGoawayRect); |
777 |
Tcl_SetServiceMode(oldServiceMode); |
778 |
|
779 |
GetCursorPos(&point); |
780 |
Tk_PointerEvent(NULL, point.x, point.y); |
781 |
|
782 |
if (tsdPtr->inPostMenu) { |
783 |
tsdPtr->inPostMenu = 0; |
784 |
} |
785 |
return TCL_OK; |
786 |
} |
787 |
|
788 |
/* |
789 |
*---------------------------------------------------------------------- |
790 |
* |
791 |
* TkpMenuNewEntry -- |
792 |
* |
793 |
* Adds a pointer to a new menu entry structure with the platform- |
794 |
* specific fields filled in. |
795 |
* |
796 |
* Results: |
797 |
* Standard TCL error. |
798 |
* |
799 |
* Side effects: |
800 |
* A new command ID is allocated and stored in the platformEntryData |
801 |
* field of mePtr. |
802 |
* |
803 |
*---------------------------------------------------------------------- |
804 |
*/ |
805 |
|
806 |
int |
807 |
TkpMenuNewEntry(mePtr) |
808 |
TkMenuEntry *mePtr; |
809 |
{ |
810 |
int commandID; |
811 |
TkMenu *menuPtr = mePtr->menuPtr; |
812 |
|
813 |
if (GetNewID(mePtr, &commandID) != TCL_OK) { |
814 |
return TCL_ERROR; |
815 |
} |
816 |
|
817 |
if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) { |
818 |
menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; |
819 |
Tcl_DoWhenIdle(ReconfigureWindowsMenu, (ClientData) menuPtr); |
820 |
} |
821 |
|
822 |
mePtr->platformEntryData = (TkMenuPlatformEntryData) commandID; |
823 |
|
824 |
return TCL_OK; |
825 |
} |
826 |
|
827 |
/* |
828 |
*---------------------------------------------------------------------- |
829 |
* |
830 |
* TkWinMenuProc -- |
831 |
* |
832 |
* The window proc for the dummy window we put popups in. This allows |
833 |
* is to post a popup whether or not we know what the parent window |
834 |
* is. |
835 |
* |
836 |
* Results: |
837 |
* Returns whatever is appropriate for the message in question. |
838 |
* |
839 |
* Side effects: |
840 |
* Normal side-effect for windows messages. |
841 |
* |
842 |
*---------------------------------------------------------------------- |
843 |
*/ |
844 |
|
845 |
static LRESULT CALLBACK |
846 |
TkWinMenuProc(hwnd, message, wParam, lParam) |
847 |
HWND hwnd; |
848 |
UINT message; |
849 |
WPARAM wParam; |
850 |
LPARAM lParam; |
851 |
{ |
852 |
LRESULT lResult; |
853 |
|
854 |
if (!TkWinHandleMenuEvent(&hwnd, &message, &wParam, &lParam, &lResult)) { |
855 |
lResult = DefWindowProc(hwnd, message, wParam, lParam); |
856 |
} |
857 |
return lResult; |
858 |
} |
859 |
|
860 |
/* |
861 |
*---------------------------------------------------------------------- |
862 |
* |
863 |
* TkWinHandleMenuEvent -- |
864 |
* |
865 |
* Filters out menu messages from messages passed to a top-level. |
866 |
* Will respond appropriately to WM_COMMAND, WM_MENUSELECT, |
867 |
* WM_MEASUREITEM, WM_DRAWITEM |
868 |
* |
869 |
* Result: |
870 |
* Returns 1 if this handled the message; 0 if it did not. |
871 |
* |
872 |
* Side effects: |
873 |
* All of the parameters may be modified so that the caller can |
874 |
* think it is getting a different message. plResult points to |
875 |
* the result that should be returned to windows from this message. |
876 |
* |
877 |
*---------------------------------------------------------------------- |
878 |
*/ |
879 |
|
880 |
int |
881 |
TkWinHandleMenuEvent(phwnd, pMessage, pwParam, plParam, plResult) |
882 |
HWND *phwnd; |
883 |
UINT *pMessage; |
884 |
WPARAM *pwParam; |
885 |
LPARAM *plParam; |
886 |
LRESULT *plResult; |
887 |
{ |
888 |
Tcl_HashEntry *hashEntryPtr; |
889 |
int returnResult = 0; |
890 |
TkMenu *menuPtr; |
891 |
TkMenuEntry *mePtr; |
892 |
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) |
893 |
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); |
894 |
|
895 |
switch (*pMessage) { |
896 |
case WM_INITMENU: |
897 |
TkMenuInit(); |
898 |
hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->winMenuTable, |
899 |
(char *) *pwParam); |
900 |
if (hashEntryPtr != NULL) { |
901 |
tsdPtr->oldServiceMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); |
902 |
menuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr); |
903 |
tsdPtr->modalMenuPtr = menuPtr; |
904 |
if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) { |
905 |
Tcl_CancelIdleCall(ReconfigureWindowsMenu, |
906 |
(ClientData) menuPtr); |
907 |
ReconfigureWindowsMenu((ClientData) menuPtr); |
908 |
} |
909 |
if (!tsdPtr->inPostMenu) { |
910 |
Tcl_Interp *interp; |
911 |
int code; |
912 |
|
913 |
interp = menuPtr->interp; |
914 |
Tcl_Preserve((ClientData)interp); |
915 |
code = TkPreprocessMenu(menuPtr); |
916 |
if ((code != TCL_OK) && (code != TCL_CONTINUE) |
917 |
&& (code != TCL_BREAK)) { |
918 |
Tcl_AddErrorInfo(interp, "\n (menu preprocess)"); |
919 |
Tcl_BackgroundError(interp); |
920 |
} |
921 |
Tcl_Release((ClientData)interp); |
922 |
} |
923 |
TkActivateMenuEntry(menuPtr, -1); |
924 |
*plResult = 0; |
925 |
returnResult = 1; |
926 |
} else { |
927 |
tsdPtr->modalMenuPtr = NULL; |
928 |
} |
929 |
break; |
930 |
|
931 |
case WM_SYSCOMMAND: |
932 |
case WM_COMMAND: { |
933 |
TkMenuInit(); |
934 |
if (HIWORD(*pwParam) != 0) { |
935 |
break; |
936 |
} |
937 |
hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->commandTable, |
938 |
(char *)LOWORD(*pwParam)); |
939 |
if (hashEntryPtr == NULL) { |
940 |
break; |
941 |
} |
942 |
mePtr = (TkMenuEntry *) Tcl_GetHashValue(hashEntryPtr); |
943 |
if (mePtr != NULL) { |
944 |
TkMenuReferences *menuRefPtr; |
945 |
TkMenuEntry *parentEntryPtr; |
946 |
Tcl_Interp *interp; |
947 |
int code; |
948 |
|
949 |
/* |
950 |
* We have to set the parent of this menu to be active |
951 |
* if this is a submenu so that tearoffs will get the |
952 |
* correct title. |
953 |
*/ |
954 |
|
955 |
menuPtr = mePtr->menuPtr; |
956 |
menuRefPtr = TkFindMenuReferences(menuPtr->interp, |
957 |
Tk_PathName(menuPtr->tkwin)); |
958 |
if ((menuRefPtr != NULL) |
959 |
&& (menuRefPtr->parentEntryPtr != NULL)) { |
960 |
char *name; |
961 |
|
962 |
for (parentEntryPtr = menuRefPtr->parentEntryPtr; |
963 |
; |
964 |
parentEntryPtr = |
965 |
parentEntryPtr->nextCascadePtr) { |
966 |
name = Tcl_GetStringFromObj( |
967 |
parentEntryPtr->namePtr, NULL); |
968 |
if (strcmp(name, Tk_PathName(menuPtr->tkwin)) |
969 |
== 0) { |
970 |
break; |
971 |
} |
972 |
} |
973 |
if (parentEntryPtr->menuPtr->entries[parentEntryPtr->index] |
974 |
->state != ENTRY_DISABLED) { |
975 |
TkActivateMenuEntry(parentEntryPtr->menuPtr, |
976 |
parentEntryPtr->index); |
977 |
} |
978 |
} |
979 |
|
980 |
interp = menuPtr->interp; |
981 |
Tcl_Preserve((ClientData)interp); |
982 |
code = TkInvokeMenu(interp, menuPtr, mePtr->index); |
983 |
if (code != TCL_OK && code != TCL_CONTINUE |
984 |
&& code != TCL_BREAK) { |
985 |
Tcl_AddErrorInfo(interp, "\n (menu invoke)"); |
986 |
Tcl_BackgroundError(interp); |
987 |
} |
988 |
Tcl_Release((ClientData)interp); |
989 |
} |
990 |
*plResult = 0; |
991 |
returnResult = 1; |
992 |
break; |
993 |
} |
994 |
|
995 |
|
996 |
case WM_MENUCHAR: { |
997 |
unsigned char menuChar = (unsigned char) LOWORD(*pwParam); |
998 |
hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->winMenuTable, |
999 |
(char *) *plParam); |
1000 |
if (hashEntryPtr != NULL) { |
1001 |
int i; |
1002 |
|
1003 |
*plResult = 0; |
1004 |
menuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr); |
1005 |
for (i = 0; i < menuPtr->numEntries; i++) { |
1006 |
int underline; |
1007 |
char *label; |
1008 |
|
1009 |
underline = menuPtr->entries[i]->underline; |
1010 |
if (menuPtr->entries[i]->labelPtr != NULL) { |
1011 |
label = Tcl_GetStringFromObj( |
1012 |
menuPtr->entries[i]->labelPtr, NULL); |
1013 |
} |
1014 |
if ((-1 != underline) |
1015 |
&& (NULL != menuPtr->entries[i]->labelPtr) |
1016 |
&& (CharUpper((LPTSTR) menuChar) |
1017 |
== CharUpper((LPTSTR) (unsigned char) |
1018 |
label[underline]))) { |
1019 |
*plResult = (2 << 16) | i; |
1020 |
returnResult = 1; |
1021 |
break; |
1022 |
} |
1023 |
} |
1024 |
} |
1025 |
break; |
1026 |
} |
1027 |
|
1028 |
case WM_MEASUREITEM: { |
1029 |
LPMEASUREITEMSTRUCT itemPtr = (LPMEASUREITEMSTRUCT) *plParam; |
1030 |
|
1031 |
if (itemPtr != NULL) { |
1032 |
mePtr = (TkMenuEntry *) itemPtr->itemData; |
1033 |
menuPtr = mePtr->menuPtr; |
1034 |
|
1035 |
TkRecomputeMenu(menuPtr); |
1036 |
itemPtr->itemHeight = mePtr->height; |
1037 |
itemPtr->itemWidth = mePtr->width; |
1038 |
if (mePtr->hideMargin) { |
1039 |
itemPtr->itemWidth += 2 - indicatorDimensions[1]; |
1040 |
} else { |
1041 |
int activeBorderWidth; |
1042 |
|
1043 |
Tk_GetPixelsFromObj(menuPtr->interp, menuPtr->tkwin, |
1044 |
menuPtr->activeBorderWidthPtr, |
1045 |
&activeBorderWidth); |
1046 |
itemPtr->itemWidth += 2 * activeBorderWidth; |
1047 |
} |
1048 |
*plResult = 1; |
1049 |
returnResult = 1; |
1050 |
} |
1051 |
break; |
1052 |
} |
1053 |
|
1054 |
case WM_DRAWITEM: { |
1055 |
TkWinDrawable *twdPtr; |
1056 |
LPDRAWITEMSTRUCT itemPtr = (LPDRAWITEMSTRUCT) *plParam; |
1057 |
Tk_FontMetrics fontMetrics; |
1058 |
|
1059 |
if (itemPtr != NULL) { |
1060 |
Tk_Font tkfont; |
1061 |
|
1062 |
mePtr = (TkMenuEntry *) itemPtr->itemData; |
1063 |
menuPtr = mePtr->menuPtr; |
1064 |
twdPtr = (TkWinDrawable *) ckalloc(sizeof(TkWinDrawable)); |
1065 |
twdPtr->type = TWD_WINDC; |
1066 |
twdPtr->winDC.hdc = itemPtr->hDC; |
1067 |
|
1068 |
if (mePtr->state != ENTRY_DISABLED) { |
1069 |
if (itemPtr->itemState & ODS_SELECTED) { |
1070 |
TkActivateMenuEntry(menuPtr, mePtr->index); |
1071 |
} else { |
1072 |
TkActivateMenuEntry(menuPtr, -1); |
1073 |
} |
1074 |
} |
1075 |
|
1076 |
tkfont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr); |
1077 |
Tk_GetFontMetrics(tkfont, &fontMetrics); |
1078 |
TkpDrawMenuEntry(mePtr, (Drawable) twdPtr, tkfont, |
1079 |
&fontMetrics, itemPtr->rcItem.left, |
1080 |
itemPtr->rcItem.top, itemPtr->rcItem.right |
1081 |
- itemPtr->rcItem.left, itemPtr->rcItem.bottom |
1082 |
- itemPtr->rcItem.top, 0, 0); |
1083 |
|
1084 |
ckfree((char *) twdPtr); |
1085 |
*plResult = 1; |
1086 |
returnResult = 1; |
1087 |
} |
1088 |
break; |
1089 |
} |
1090 |
|
1091 |
case WM_MENUSELECT: { |
1092 |
UINT flags = HIWORD(*pwParam); |
1093 |
|
1094 |
TkMenuInit(); |
1095 |
|
1096 |
if ((flags == 0xFFFF) && (*plParam == 0)) { |
1097 |
Tcl_SetServiceMode(tsdPtr->oldServiceMode); |
1098 |
if (tsdPtr->modalMenuPtr != NULL) { |
1099 |
RecursivelyClearActiveMenu(tsdPtr->modalMenuPtr); |
1100 |
} |
1101 |
} else { |
1102 |
menuPtr = NULL; |
1103 |
if (*plParam != 0) { |
1104 |
hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->winMenuTable, |
1105 |
(char *) *plParam); |
1106 |
if (hashEntryPtr != NULL) { |
1107 |
menuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr); |
1108 |
} |
1109 |
} |
1110 |
|
1111 |
if (menuPtr != NULL) { |
1112 |
mePtr = NULL; |
1113 |
if (flags != 0xFFFF) { |
1114 |
if (flags & MF_POPUP) { |
1115 |
mePtr = menuPtr->entries[LOWORD(*pwParam)]; |
1116 |
} else { |
1117 |
hashEntryPtr = Tcl_FindHashEntry( |
1118 |
&tsdPtr->commandTable, |
1119 |
(char *) LOWORD(*pwParam)); |
1120 |
if (hashEntryPtr != NULL) { |
1121 |
mePtr = (TkMenuEntry *) |
1122 |
Tcl_GetHashValue(hashEntryPtr); |
1123 |
} |
1124 |
} |
1125 |
} |
1126 |
|
1127 |
if ((mePtr == NULL) || (mePtr->state == ENTRY_DISABLED)) { |
1128 |
TkActivateMenuEntry(menuPtr, -1); |
1129 |
} else { |
1130 |
TkActivateMenuEntry(menuPtr, mePtr->index); |
1131 |
} |
1132 |
MenuSelectEvent(menuPtr); |
1133 |
Tcl_ServiceAll(); |
1134 |
} |
1135 |
} |
1136 |
} |
1137 |
} |
1138 |
return returnResult; |
1139 |
} |
1140 |
|
1141 |
/* |
1142 |
*---------------------------------------------------------------------- |
1143 |
* |
1144 |
* RecursivelyClearActiveMenu -- |
1145 |
* |
1146 |
* Recursively clears the active entry in the menu's cascade hierarchy. |
1147 |
* |
1148 |
* Results: |
1149 |
* None. |
1150 |
* |
1151 |
* Side effects: |
1152 |
* Generates <<MenuSelect>> virtual events. |
1153 |
* |
1154 |
*---------------------------------------------------------------------- |
1155 |
*/ |
1156 |
|
1157 |
void |
1158 |
RecursivelyClearActiveMenu( |
1159 |
TkMenu *menuPtr) /* The menu to reset. */ |
1160 |
{ |
1161 |
int i; |
1162 |
TkMenuEntry *mePtr; |
1163 |
|
1164 |
TkActivateMenuEntry(menuPtr, -1); |
1165 |
MenuSelectEvent(menuPtr); |
1166 |
for (i = 0; i < menuPtr->numEntries; i++) { |
1167 |
mePtr = menuPtr->entries[i]; |
1168 |
if (mePtr->type == CASCADE_ENTRY) { |
1169 |
if ((mePtr->childMenuRefPtr != NULL) |
1170 |
&& (mePtr->childMenuRefPtr->menuPtr != NULL)) { |
1171 |
RecursivelyClearActiveMenu(mePtr->childMenuRefPtr->menuPtr); |
1172 |
} |
1173 |
} |
1174 |
} |
1175 |
} |
1176 |
|
1177 |
/* |
1178 |
*---------------------------------------------------------------------- |
1179 |
* |
1180 |
* TkpSetWindowMenuBar -- |
1181 |
* |
1182 |
* Associates a given menu with a window. |
1183 |
* |
1184 |
* Results: |
1185 |
* None. |
1186 |
* |
1187 |
* Side effects: |
1188 |
* On Windows and UNIX, associates the platform menu with the |
1189 |
* platform window. |
1190 |
* |
1191 |
*---------------------------------------------------------------------- |
1192 |
*/ |
1193 |
|
1194 |
void |
1195 |
TkpSetWindowMenuBar(tkwin, menuPtr) |
1196 |
Tk_Window tkwin; /* The window we are putting the menubar into.*/ |
1197 |
TkMenu *menuPtr; /* The menu we are inserting */ |
1198 |
{ |
1199 |
HMENU winMenuHdl; |
1200 |
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) |
1201 |
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); |
1202 |
|
1203 |
if (menuPtr != NULL) { |
1204 |
Tcl_HashEntry *hashEntryPtr; |
1205 |
int newEntry; |
1206 |
|
1207 |
winMenuHdl = (HMENU) menuPtr->platformData; |
1208 |
hashEntryPtr = Tcl_FindHashEntry(&tsdPtr->winMenuTable, |
1209 |
(char *) winMenuHdl); |
1210 |
Tcl_DeleteHashEntry(hashEntryPtr); |
1211 |
DestroyMenu(winMenuHdl); |
1212 |
winMenuHdl = CreateMenu(); |
1213 |
hashEntryPtr = Tcl_CreateHashEntry(&tsdPtr->winMenuTable, |
1214 |
(char *) winMenuHdl, &newEntry); |
1215 |
Tcl_SetHashValue(hashEntryPtr, (char *) menuPtr); |
1216 |
menuPtr->platformData = (TkMenuPlatformData) winMenuHdl; |
1217 |
TkWinSetMenu(tkwin, winMenuHdl); |
1218 |
if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) { |
1219 |
Tcl_DoWhenIdle(ReconfigureWindowsMenu, (ClientData) menuPtr); |
1220 |
menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; |
1221 |
} |
1222 |
} else { |
1223 |
TkWinSetMenu(tkwin, NULL); |
1224 |
} |
1225 |
} |
1226 |
|
1227 |
|
1228 |
/* |
1229 |
*---------------------------------------------------------------------- |
1230 |
* |
1231 |
* TkpSetMainMenubar -- |
1232 |
* |
1233 |
* Puts the menu associated with a window into the menubar. Should |
1234 |
* only be called when the window is in front. |
1235 |
* |
1236 |
* Results: |
1237 |
* None. |
1238 |
* |
1239 |
* Side effects: |
1240 |
* The menubar is changed. |
1241 |
* |
1242 |
*---------------------------------------------------------------------- |
1243 |
*/ |
1244 |
void |
1245 |
TkpSetMainMenubar( |
1246 |
Tcl_Interp *interp, /* The interpreter of the application */ |
1247 |
Tk_Window tkwin, /* The frame we are setting up */ |
1248 |
char *menuName) /* The name of the menu to put in front. |
1249 |
* If NULL, use the default menu bar. |
1250 |
*/ |
1251 |
{ |
1252 |
/* |
1253 |
* Nothing to do. |
1254 |
*/ |
1255 |
} |
1256 |
|
1257 |
/* |
1258 |
*---------------------------------------------------------------------- |
1259 |
* |
1260 |
* GetMenuIndicatorGeometry -- |
1261 |
* |
1262 |
* Gets the width and height of the indicator area of a menu. |
1263 |
* |
1264 |
* Results: |
1265 |
* widthPtr and heightPtr are set. |
1266 |
* |
1267 |
* Side effects: |
1268 |
* None. |
1269 |
* |
1270 |
*---------------------------------------------------------------------- |
1271 |
*/ |
1272 |
|
1273 |
void |
1274 |
GetMenuIndicatorGeometry ( |
1275 |
TkMenu *menuPtr, /* The menu we are measuring */ |
1276 |
TkMenuEntry *mePtr, /* The entry we are measuring */ |
1277 |
Tk_Font tkfont, /* Precalculated font */ |
1278 |
CONST Tk_FontMetrics *fmPtr, /* Precalculated font metrics */ |
1279 |
int *widthPtr, /* The resulting width */ |
1280 |
int *heightPtr) /* The resulting height */ |
1281 |
{ |
1282 |
*heightPtr = indicatorDimensions[0]; |
1283 |
if (mePtr->hideMargin) { |
1284 |
*widthPtr = 0; |
1285 |
} else { |
1286 |
int borderWidth; |
1287 |
|
1288 |
Tk_GetPixelsFromObj(menuPtr->interp, menuPtr->tkwin, |
1289 |
menuPtr->borderWidthPtr, &borderWidth); |
1290 |
*widthPtr = indicatorDimensions[1] - borderWidth; |
1291 |
} |
1292 |
} |
1293 |
|
1294 |
/* |
1295 |
*---------------------------------------------------------------------- |
1296 |
* |
1297 |
* GetMenuAccelGeometry -- |
1298 |
* |
1299 |
* Gets the width and height of the indicator area of a menu. |
1300 |
* |
1301 |
* Results: |
1302 |
* widthPtr and heightPtr are set. |
1303 |
* |
1304 |
* Side effects: |
1305 |
* None. |
1306 |
* |
1307 |
*---------------------------------------------------------------------- |
1308 |
*/ |
1309 |
|
1310 |
void |
1311 |
GetMenuAccelGeometry ( |
1312 |
TkMenu *menuPtr, /* The menu we are measuring */ |
1313 |
TkMenuEntry *mePtr, /* The entry we are measuring */ |
1314 |
Tk_Font tkfont, /* The precalculated font */ |
1315 |
CONST Tk_FontMetrics *fmPtr, /* The precalculated font metrics */ |
1316 |
int *widthPtr, /* The resulting width */ |
1317 |
int *heightPtr) /* The resulting height */ |
1318 |
{ |
1319 |
*heightPtr = fmPtr->linespace; |
1320 |
if (mePtr->type == CASCADE_ENTRY) { |
1321 |
*widthPtr = 0; |
1322 |
} else if (mePtr->accelPtr == NULL) { |
1323 |
*widthPtr = 0; |
1324 |
} else { |
1325 |
char *accel = Tcl_GetStringFromObj(mePtr->accelPtr, NULL); |
1326 |
*widthPtr = Tk_TextWidth(tkfont, accel, mePtr->accelLength); |
1327 |
} |
1328 |
} |
1329 |
|
1330 |
/* |
1331 |
*---------------------------------------------------------------------- |
1332 |
* |
1333 |
* GetTearoffEntryGeometry -- |
1334 |
* |
1335 |
* Gets the width and height of the indicator area of a menu. |
1336 |
* |
1337 |
* Results: |
1338 |
* widthPtr and heightPtr are set. |
1339 |
* |
1340 |
* Side effects: |
1341 |
* None. |
1342 |
* |
1343 |
*---------------------------------------------------------------------- |
1344 |
*/ |
1345 |
|
1346 |
void |
1347 |
GetTearoffEntryGeometry ( |
1348 |
TkMenu *menuPtr, /* The menu we are measuring */ |
1349 |
TkMenuEntry *mePtr, /* The entry we are measuring */ |
1350 |
Tk_Font tkfont, /* The precalculated font */ |
1351 |
CONST Tk_FontMetrics *fmPtr, /* The precalculated font metrics */ |
1352 |
int *widthPtr, /* The resulting width */ |
1353 |
int *heightPtr) /* The resulting height */ |
1354 |
{ |
1355 |
if (menuPtr->menuType != MASTER_MENU) { |
1356 |
*heightPtr = 0; |
1357 |
} else { |
1358 |
*heightPtr = fmPtr->linespace; |
1359 |
} |
1360 |
*widthPtr = 0; |
1361 |
} |
1362 |
|
1363 |
/* |
1364 |
*---------------------------------------------------------------------- |
1365 |
* |
1366 |
* GetMenuSeparatorGeometry -- |
1367 |
* |
1368 |
* Gets the width and height of the indicator area of a menu. |
1369 |
* |
1370 |
* Results: |
1371 |
* widthPtr and heightPtr are set. |
1372 |
* |
1373 |
* Side effects: |
1374 |
* None. |
1375 |
* |
1376 |
*---------------------------------------------------------------------- |
1377 |
*/ |
1378 |
|
1379 |
void |
1380 |
GetMenuSeparatorGeometry ( |
1381 |
TkMenu *menuPtr, /* The menu we are measuring */ |
1382 |
TkMenuEntry *mePtr, /* The entry we are measuring */ |
1383 |
Tk_Font tkfont, /* The precalculated font */ |
1384 |
CONST Tk_FontMetrics *fmPtr, /* The precalcualted font metrics */ |
1385 |
int *widthPtr, /* The resulting width */ |
1386 |
int *heightPtr) /* The resulting height */ |
1387 |
{ |
1388 |
*widthPtr = 0; |
1389 |
*heightPtr = fmPtr->linespace; |
1390 |
} |
1391 |
|
1392 |
/* |
1393 |
*---------------------------------------------------------------------- |
1394 |
* |
1395 |
* DrawWindowsSystemBitmap -- |
1396 |
* |
1397 |
* Draws the windows system bitmap given by bitmapID into the rect |
1398 |
* given by rectPtr in the drawable. The bitmap is centered in the |
1399 |
* rectangle. It is not clipped, so if the bitmap is bigger than |
1400 |
* the rect it will bleed. |
1401 |
* |
1402 |
* Results: |
1403 |
* None. |
1404 |
* |
1405 |
* Side effects: |
1406 |
* Drawing occurs. Some storage is allocated and released. |
1407 |
* |
1408 |
*---------------------------------------------------------------------- |
1409 |
*/ |
1410 |
|
1411 |
static void |
1412 |
DrawWindowsSystemBitmap(display, drawable, gc, rectPtr, bitmapID, alignFlags) |
1413 |
Display *display; /* The display we are drawing into */ |
1414 |
Drawable drawable; /* The drawable we are working with */ |
1415 |
GC gc; /* The GC to draw with */ |
1416 |
CONST RECT *rectPtr; /* The rectangle to draw into */ |
1417 |
int bitmapID; /* The windows id of the system |
1418 |
* bitmap to draw. */ |
1419 |
int alignFlags; /* How to align the bitmap inside the |
1420 |
* rectangle. */ |
1421 |
{ |
1422 |
TkWinDCState state; |
1423 |
HDC hdc = TkWinGetDrawableDC(display, drawable, &state); |
1424 |
HDC scratchDC; |
1425 |
HBITMAP bitmap; |
1426 |
BITMAP bm; |
1427 |
POINT ptSize; |
1428 |
POINT ptOrg; |
1429 |
int topOffset, leftOffset; |
1430 |
|
1431 |
SetBkColor(hdc, gc->background); |
1432 |
SetTextColor(hdc, gc->foreground); |
1433 |
|
1434 |
scratchDC = CreateCompatibleDC(hdc); |
1435 |
bitmap = LoadBitmap(NULL, MAKEINTRESOURCE(bitmapID)); |
1436 |
|
1437 |
SelectObject(scratchDC, bitmap); |
1438 |
SetMapMode(scratchDC, GetMapMode(hdc)); |
1439 |
GetObject(bitmap, sizeof(BITMAP), &bm); |
1440 |
ptSize.x = bm.bmWidth; |
1441 |
ptSize.y = bm.bmHeight; |
1442 |
DPtoLP(hdc, &ptSize, 1); |
1443 |
|
1444 |
ptOrg.y = ptOrg.x = 0; |
1445 |
DPtoLP(hdc, &ptOrg, 1); |
1446 |
|
1447 |
if (alignFlags & ALIGN_BITMAP_TOP) { |
1448 |
topOffset = 0; |
1449 |
} else if (alignFlags & ALIGN_BITMAP_BOTTOM) { |
1450 |
topOffset = (rectPtr->bottom - rectPtr->top) - ptSize.y; |
1451 |
} else { |
1452 |
topOffset = (rectPtr->bottom - rectPtr->top) / 2 - (ptSize.y / 2); |
1453 |
} |
1454 |
|
1455 |
if (alignFlags & ALIGN_BITMAP_LEFT) { |
1456 |
leftOffset = 0; |
1457 |
} else if (alignFlags & ALIGN_BITMAP_RIGHT) { |
1458 |
leftOffset = (rectPtr->right - rectPtr->left) - ptSize.x; |
1459 |
} else { |
1460 |
leftOffset = (rectPtr->right - rectPtr->left) / 2 - (ptSize.x / 2); |
1461 |
} |
1462 |
|
1463 |
BitBlt(hdc, rectPtr->left + leftOffset, rectPtr->top + topOffset, ptSize.x, |
1464 |
ptSize.y, scratchDC, ptOrg.x, ptOrg.y, SRCCOPY); |
1465 |
DeleteDC(scratchDC); |
1466 |
DeleteObject(bitmap); |
1467 |
|
1468 |
TkWinReleaseDrawableDC(drawable, hdc, &state); |
1469 |
} |
1470 |
|
1471 |
/* |
1472 |
*---------------------------------------------------------------------- |
1473 |
* |
1474 |
* DrawMenuEntryIndicator -- |
1475 |
* |
1476 |
* This procedure draws the indicator part of a menu. |
1477 |
* |
1478 |
* Results: |
1479 |
* None. |
1480 |
* |
1481 |
* Side effects: |
1482 |
* Commands are output to X to display the menu in its |
1483 |
* current mode. |
1484 |
* |
1485 |
*---------------------------------------------------------------------- |
1486 |
*/ |
1487 |
void |
1488 |
DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont, fmPtr, x, |
1489 |
y, width, height) |
1490 |
TkMenu *menuPtr; /* The menu we are drawing */ |
1491 |
TkMenuEntry *mePtr; /* The entry we are drawing */ |
1492 |
Drawable d; /* What we are drawing into */ |
1493 |
GC gc; /* The gc we are drawing with */ |
1494 |
GC indicatorGC; /* The gc for indicator objects */ |
1495 |
Tk_Font tkfont; /* The precalculated font */ |
1496 |
CONST Tk_FontMetrics *fmPtr; /* The precalculated font metrics */ |
1497 |
int x; /* Left edge */ |
1498 |
int y; /* Top edge */ |
1499 |
int width; |
1500 |
int height; |
1501 |
{ |
1502 |
if ((mePtr->type == CHECK_BUTTON_ENTRY) |
1503 |
|| (mePtr->type == RADIO_BUTTON_ENTRY)) { |
1504 |
if (mePtr->indicatorOn && (mePtr->entryFlags & ENTRY_SELECTED)) { |
1505 |
RECT rect; |
1506 |
GC whichGC; |
1507 |
int borderWidth, activeBorderWidth; |
1508 |
if (mePtr->state != ENTRY_NORMAL) { |
1509 |
whichGC = gc; |
1510 |
} else { |
1511 |
whichGC = indicatorGC; |
1512 |
} |
1513 |
|
1514 |
rect.top = y; |
1515 |
rect.bottom = y + mePtr->height; |
1516 |
Tk_GetPixelsFromObj(menuPtr->interp, menuPtr->tkwin, |
1517 |
menuPtr->borderWidthPtr, &borderWidth); |
1518 |
Tk_GetPixelsFromObj(menuPtr->interp, menuPtr->tkwin, |
1519 |
menuPtr->activeBorderWidthPtr, &activeBorderWidth); |
1520 |
rect.left = borderWidth + activeBorderWidth + x; |
1521 |
rect.right = mePtr->indicatorSpace + x; |
1522 |
|
1523 |
if ((mePtr->state == ENTRY_DISABLED) |
1524 |
&& (menuPtr->disabledFgPtr != NULL)) { |
1525 |
RECT hilightRect; |
1526 |
COLORREF oldFgColor = whichGC->foreground; |
1527 |
|
1528 |
whichGC->foreground = GetSysColor(COLOR_3DHILIGHT); |
1529 |
hilightRect.top = rect.top + 1; |
1530 |
hilightRect.bottom = rect.bottom + 1; |
1531 |
hilightRect.left = rect.left + 1; |
1532 |
hilightRect.right = rect.right + 1; |
1533 |
DrawWindowsSystemBitmap(menuPtr->display, d, whichGC, |
1534 |
&hilightRect, OBM_CHECK, 0); |
1535 |
whichGC->foreground = oldFgColor; |
1536 |
} |
1537 |
|
1538 |
DrawWindowsSystemBitmap(menuPtr->display, d, whichGC, &rect, |
1539 |
OBM_CHECK, 0); |
1540 |
} |
1541 |
} |
1542 |
} |
1543 |
|
1544 |
/* |
1545 |
*---------------------------------------------------------------------- |
1546 |
* |
1547 |
* DrawMenuEntryAccelerator -- |
1548 |
* |
1549 |
* This procedure draws the accelerator part of a menu. We |
1550 |
* need to decide what to draw here. Should we replace strings |
1551 |
* like "Control", "Command", etc? |
1552 |
* |
1553 |
* Results: |
1554 |
* None. |
1555 |
* |
1556 |
* Side effects: |
1557 |
* Commands are output to X to display the menu in its |
1558 |
* current mode. |
1559 |
* |
1560 |
*---------------------------------------------------------------------- |
1561 |
*/ |
1562 |
|
1563 |
void |
1564 |
DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr, |
1565 |
activeBorder, x, y, width, height, drawArrow) |
1566 |
TkMenu *menuPtr; /* The menu we are drawing */ |
1567 |
TkMenuEntry *mePtr; /* The entry we are drawing */ |
1568 |
Drawable d; /* What we are drawing into */ |
1569 |
GC gc; /* The gc we are drawing with */ |
1570 |
Tk_Font tkfont; /* The precalculated font */ |
1571 |
CONST Tk_FontMetrics *fmPtr; /* The precalculated font metrics */ |
1572 |
Tk_3DBorder activeBorder; /* The border when an item is active */ |
1573 |
int x; /* left edge */ |
1574 |
int y; /* top edge */ |
1575 |
int width; /* Width of menu entry */ |
1576 |
int height; /* Height of menu entry */ |
1577 |
int drawArrow; /* For cascade menus, whether of not |
1578 |
* to draw the arraw. I cannot figure |
1579 |
* out Windows' algorithm for where |
1580 |
* to draw this. */ |
1581 |
{ |
1582 |
int baseline; |
1583 |
int leftEdge = x + mePtr->indicatorSpace + mePtr->labelWidth; |
1584 |
char *accel; |
1585 |
|
1586 |
if (mePtr->accelPtr != NULL) { |
1587 |
accel = Tcl_GetStringFromObj(mePtr->accelPtr, NULL); |
1588 |
} |
1589 |
|
1590 |
baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2; |
1591 |
|
1592 |
if ((mePtr->state == ENTRY_DISABLED) && (menuPtr->disabledFgPtr != NULL) |
1593 |
&& ((mePtr->accelPtr != NULL) |
1594 |
|| ((mePtr->type == CASCADE_ENTRY) && drawArrow))) { |
1595 |
COLORREF oldFgColor = gc->foreground; |
1596 |
|
1597 |
gc->foreground = GetSysColor(COLOR_3DHILIGHT); |
1598 |
if (mePtr->accelPtr != NULL) { |
1599 |
Tk_DrawChars(menuPtr->display, d, gc, tkfont, accel, |
1600 |
mePtr->accelLength, leftEdge + 1, baseline + 1); |
1601 |
} |
1602 |
|
1603 |
if (mePtr->type == CASCADE_ENTRY) { |
1604 |
RECT rect; |
1605 |
|
1606 |
rect.top = y + GetSystemMetrics(SM_CYBORDER) + 1; |
1607 |
rect.bottom = y + height - GetSystemMetrics(SM_CYBORDER) + 1; |
1608 |
rect.left = x + mePtr->indicatorSpace + mePtr->labelWidth + 1; |
1609 |
rect.right = x + width; |
1610 |
DrawWindowsSystemBitmap(menuPtr->display, d, gc, &rect, |
1611 |
OBM_MNARROW, ALIGN_BITMAP_RIGHT); |
1612 |
} |
1613 |
gc->foreground = oldFgColor; |
1614 |
} |
1615 |
|
1616 |
if (mePtr->accelPtr != NULL) { |
1617 |
Tk_DrawChars(menuPtr->display, d, gc, tkfont, accel, |
1618 |
mePtr->accelLength, leftEdge, baseline); |
1619 |
} |
1620 |
|
1621 |
if ((mePtr->type == CASCADE_ENTRY) && drawArrow) { |
1622 |
RECT rect; |
1623 |
|
1624 |
rect.top = y + GetSystemMetrics(SM_CYBORDER); |
1625 |
rect.bottom = y + height - GetSystemMetrics(SM_CYBORDER); |
1626 |
rect.left = x + mePtr->indicatorSpace + mePtr->labelWidth; |
1627 |
rect.right = x + width - 1; |
1628 |
DrawWindowsSystemBitmap(menuPtr->display, d, gc, &rect, OBM_MNARROW, |
1629 |
ALIGN_BITMAP_RIGHT); |
1630 |
} |
1631 |
} |
1632 |
|
1633 |
/* |
1634 |
*---------------------------------------------------------------------- |
1635 |
* |
1636 |
* DrawMenuSeparator -- |
1637 |
* |
1638 |
* The menu separator is drawn. |
1639 |
* |
1640 |
* Results: |
1641 |
* None. |
1642 |
* |
1643 |
* Side effects: |
1644 |
* Commands are output to X to display the menu in its |
1645 |
* current mode. |
1646 |
* |
1647 |
*---------------------------------------------------------------------- |
1648 |
*/ |
1649 |
void |
1650 |
DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height) |
1651 |
TkMenu *menuPtr; /* The menu we are drawing */ |
1652 |
TkMenuEntry *mePtr; /* The entry we are drawing */ |
1653 |
Drawable d; /* What we are drawing into */ |
1654 |
GC gc; /* The gc we are drawing with */ |
1655 |
Tk_Font tkfont; /* The precalculated font */ |
1656 |
CONST Tk_FontMetrics *fmPtr; /* The precalculated font metrics */ |
1657 |
int x; /* left edge */ |
1658 |
int y; /* top edge */ |
1659 |
int width; /* width of item */ |
1660 |
int height; /* height of item */ |
1661 |
{ |
1662 |
XPoint points[2]; |
1663 |
Tk_3DBorder border; |
1664 |
|
1665 |
points[0].x = x; |
1666 |
points[0].y = y + height / 2; |
1667 |
points[1].x = x + width - 1; |
1668 |
points[1].y = points[0].y; |
1669 |
border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr); |
1670 |
Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 2, 1, |
1671 |
TK_RELIEF_RAISED); |
1672 |
} |
1673 |
|
1674 |
/* |
1675 |
*---------------------------------------------------------------------- |
1676 |
* |
1677 |
* DrawMenuUnderline -- |
1678 |
* |
1679 |
* On appropriate platforms, draw the underline character for the |
1680 |
* menu. |
1681 |
* |
1682 |
* Results: |
1683 |
* None. |
1684 |
* |
1685 |
* Side effects: |
1686 |
* Commands are output to X to display the menu in its |
1687 |
* current mode. |
1688 |
* |
1689 |
*---------------------------------------------------------------------- |
1690 |
*/ |
1691 |
static void |
1692 |
DrawMenuUnderline( |
1693 |
TkMenu *menuPtr, /* The menu to draw into */ |
1694 |
TkMenuEntry *mePtr, /* The entry we are drawing */ |
1695 |
Drawable d, /* What we are drawing into */ |
1696 |
GC gc, /* The gc to draw into */ |
1697 |
Tk_Font tkfont, /* The precalculated font */ |
1698 |
CONST Tk_FontMetrics *fmPtr, /* The precalculated font metrics */ |
1699 |
int x, /* Left Edge */ |
1700 |
int y, /* Top Edge */ |
1701 |
int width, /* Width of entry */ |
1702 |
int height) /* Height of entry */ |
1703 |
{ |
1704 |
if (mePtr->underline >= 0) { |
1705 |
char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL); |
1706 |
char *start = Tcl_UtfAtIndex(label, mePtr->underline); |
1707 |
char *end = Tcl_UtfNext(start); |
1708 |
|
1709 |
Tk_UnderlineChars(menuPtr->display, d, |
1710 |
gc, tkfont, label, x + mePtr->indicatorSpace, |
1711 |
y + (height + fmPtr->ascent - fmPtr->descent) / 2, |
1712 |
start - label, end - label); |
1713 |
} |
1714 |
} |
1715 |
|
1716 |
/* |
1717 |
*-------------------------------------------------------------- |
1718 |
* |
1719 |
* MenuKeyBindProc -- |
1720 |
* |
1721 |
* This procedure is invoked when keys related to pulling |
1722 |
* down menus is pressed. The corresponding Windows events |
1723 |
* are generated and passed to DefWindowProc if appropriate. |
1724 |
* |
1725 |
* Results: |
1726 |
* Always returns TCL_OK. |
1727 |
* |
1728 |
* Side effects: |
1729 |
* The menu system may take over and process user events |
1730 |
* for menu input. |
1731 |
* |
1732 |
*-------------------------------------------------------------- |
1733 |
*/ |
1734 |
|
1735 |
static int |
1736 |
MenuKeyBindProc(clientData, interp, eventPtr, tkwin, keySym) |
1737 |
ClientData clientData; /* not used in this proc */ |
1738 |
Tcl_Interp *interp; /* The interpreter of the receiving window. */ |
1739 |
XEvent *eventPtr; /* The XEvent to process */ |
1740 |
Tk_Window tkwin; /* The window receiving the event */ |
1741 |
KeySym keySym; /* The key sym that is produced. */ |
1742 |
{ |
1743 |
UINT scanCode; |
1744 |
UINT virtualKey; |
1745 |
TkWindow *winPtr = (TkWindow *)tkwin; |
1746 |
int i; |
1747 |
|
1748 |
if (eventPtr->type == KeyPress) { |
1749 |
switch (keySym) { |
1750 |
case XK_Alt_L: |
1751 |
scanCode = MapVirtualKey(VK_LMENU, 0); |
1752 |
CallWindowProc(DefWindowProc, Tk_GetHWND(Tk_WindowId(tkwin)), |
1753 |
WM_SYSKEYDOWN, VK_MENU, (scanCode << 16) |
1754 |
| (1 << 29)); |
1755 |
break; |
1756 |
case XK_Alt_R: |
1757 |
scanCode = MapVirtualKey(VK_RMENU, 0); |
1758 |
CallWindowProc(DefWindowProc, Tk_GetHWND(Tk_WindowId(tkwin)), |
1759 |
WM_SYSKEYDOWN, VK_MENU, (scanCode << 16) |
1760 |
| (1 << 29) | (1 << 24)); |
1761 |
break; |
1762 |
case XK_F10: |
1763 |
scanCode = MapVirtualKey(VK_F10, 0); |
1764 |
CallWindowProc(DefWindowProc, Tk_GetHWND(Tk_WindowId(tkwin)), |
1765 |
WM_SYSKEYDOWN, VK_F10, (scanCode << 16)); |
1766 |
break; |
1767 |
default: |
1768 |
virtualKey = XKeysymToKeycode(winPtr->display, keySym); |
1769 |
scanCode = MapVirtualKey(virtualKey, 0); |
1770 |
if (0 != scanCode) { |
1771 |
CallWindowProc(DefWindowProc, Tk_GetHWND(Tk_WindowId(tkwin)), |
1772 |
WM_SYSKEYDOWN, virtualKey, ((scanCode << 16) |
1773 |
| (1 << 29))); |
1774 |
if (eventPtr->xkey.nbytes > 0) { |
1775 |
for (i = 0; i < eventPtr->xkey.nbytes; i++) { |
1776 |
CallWindowProc(DefWindowProc, |
1777 |
Tk_GetHWND(Tk_WindowId(tkwin)), |
1778 |
WM_SYSCHAR, |
1779 |
eventPtr->xkey.trans_chars[i], |
1780 |
((scanCode << 16) | (1 << 29))); |
1781 |
} |
1782 |
} |
1783 |
} |
1784 |
} |
1785 |
} else if (eventPtr->type == KeyRelease) { |
1786 |
switch (keySym) { |
1787 |
case XK_Alt_L: |
1788 |
scanCode = MapVirtualKey(VK_LMENU, 0); |
1789 |
CallWindowProc(DefWindowProc, Tk_GetHWND(Tk_WindowId(tkwin)), |
1790 |
WM_SYSKEYUP, VK_MENU, (scanCode << 16) |
1791 |
| (1 << 29) | (1 << 30) | (1 << 31)); |
1792 |
break; |
1793 |
case XK_Alt_R: |
1794 |
scanCode = MapVirtualKey(VK_RMENU, 0); |
1795 |
CallWindowProc(DefWindowProc, Tk_GetHWND(Tk_WindowId(tkwin)), |
1796 |
WM_SYSKEYUP, VK_MENU, (scanCode << 16) | (1 << 24) |
1797 |
| (0x111 << 29) | (1 << 30) | (1 << 31)); |
1798 |
break; |
1799 |
case XK_F10: |
1800 |
scanCode = MapVirtualKey(VK_F10, 0); |
1801 |
CallWindowProc(DefWindowProc, Tk_GetHWND(Tk_WindowId(tkwin)), |
1802 |
WM_SYSKEYUP, VK_F10, (scanCode << 16) |
1803 |
| (1 << 30) | (1 << 31)); |
1804 |
break; |
1805 |
default: |
1806 |
virtualKey = XKeysymToKeycode(winPtr->display, keySym); |
1807 |
scanCode = MapVirtualKey(virtualKey, 0); |
1808 |
if (0 != scanCode) { |
1809 |
CallWindowProc(DefWindowProc, Tk_GetHWND(Tk_WindowId(tkwin)), |
1810 |
WM_SYSKEYUP, virtualKey, ((scanCode << 16) |
1811 |
| (1 << 29) | (1 << 30) | (1 << 31))); |
1812 |
} |
1813 |
} |
1814 |
} |
1815 |
return TCL_OK; |
1816 |
} |
1817 |
|
1818 |
/* |
1819 |
*-------------------------------------------------------------- |
1820 |
* |
1821 |
* TkpInitializeMenuBindings -- |
1822 |
* |
1823 |
* For every interp, initializes the bindings for Windows |
1824 |
* menus. Does nothing on Mac or XWindows. |
1825 |
* |
1826 |
* Results: |
1827 |
* None. |
1828 |
* |
1829 |
* Side effects: |
1830 |
* C-level bindings are setup for the interp which will |
1831 |
* handle Alt-key sequences for menus without beeping |
1832 |
* or interfering with user-defined Alt-key bindings. |
1833 |
* |
1834 |
*-------------------------------------------------------------- |
1835 |
*/ |
1836 |
|
1837 |
void |
1838 |
TkpInitializeMenuBindings(interp, bindingTable) |
1839 |
Tcl_Interp *interp; /* The interpreter to set. */ |
1840 |
Tk_BindingTable bindingTable; /* The table to add to. */ |
1841 |
{ |
1842 |
Tk_Uid uid = Tk_GetUid("all"); |
1843 |
|
1844 |
/* |
1845 |
* We need to set up the bindings for menubars. These have to |
1846 |
* recreate windows events, so we need to have a C-level |
1847 |
* binding for this. We have to generate the WM_SYSKEYDOWNS |
1848 |
* and WM_SYSKEYUPs appropriately. |
1849 |
*/ |
1850 |
|
1851 |
TkCreateBindingProcedure(interp, bindingTable, (ClientData)uid, |
1852 |
"<Alt_L>", MenuKeyBindProc, NULL, NULL); |
1853 |
TkCreateBindingProcedure(interp, bindingTable, (ClientData)uid, |
1854 |
"<KeyRelease-Alt_L>", MenuKeyBindProc, NULL, NULL); |
1855 |
TkCreateBindingProcedure(interp, bindingTable, (ClientData)uid, |
1856 |
"<Alt_R>", MenuKeyBindProc, NULL, NULL); |
1857 |
TkCreateBindingProcedure(interp, bindingTable, (ClientData)uid, |
1858 |
"<KeyRelease-Alt_R>", MenuKeyBindProc, NULL, NULL); |
1859 |
TkCreateBindingProcedure(interp, bindingTable, (ClientData)uid, |
1860 |
"<Alt-KeyPress>", MenuKeyBindProc, NULL, NULL); |
1861 |
TkCreateBindingProcedure(interp, bindingTable, (ClientData)uid, |
1862 |
"<Alt-KeyRelease>", MenuKeyBindProc, NULL, NULL); |
1863 |
TkCreateBindingProcedure(interp, bindingTable, (ClientData)uid, |
1864 |
"<KeyPress-F10>", MenuKeyBindProc, NULL, NULL); |
1865 |
TkCreateBindingProcedure(interp, bindingTable, (ClientData)uid, |
1866 |
"<KeyRelease-F10>", MenuKeyBindProc, NULL, NULL); |
1867 |
} |
1868 |
|
1869 |
/* |
1870 |
*---------------------------------------------------------------------- |
1871 |
* |
1872 |
* DrawMenuEntryLabel -- |
1873 |
* |
1874 |
* This procedure draws the label part of a menu. |
1875 |
* |
1876 |
* Results: |
1877 |
* None. |
1878 |
* |
1879 |
* Side effects: |
1880 |
* Commands are output to X to display the menu in its |
1881 |
* current mode. |
1882 |
* |
1883 |
*---------------------------------------------------------------------- |
1884 |
*/ |
1885 |
|
1886 |
static void |
1887 |
DrawMenuEntryLabel( |
1888 |
TkMenu *menuPtr, /* The menu we are drawing */ |
1889 |
TkMenuEntry *mePtr, /* The entry we are drawing */ |
1890 |
Drawable d, /* What we are drawing into */ |
1891 |
GC gc, /* The gc we are drawing into */ |
1892 |
Tk_Font tkfont, /* The precalculated font */ |
1893 |
CONST Tk_FontMetrics *fmPtr, /* The precalculated font metrics */ |
1894 |
int x, /* left edge */ |
1895 |
int y, /* right edge */ |
1896 |
int width, /* width of entry */ |
1897 |
int height) /* height of entry */ |
1898 |
{ |
1899 |
int baseline; |
1900 |
int indicatorSpace = mePtr->indicatorSpace; |
1901 |
int activeBorderWidth; |
1902 |
int leftEdge; |
1903 |
int imageHeight, imageWidth; |
1904 |
|
1905 |
Tk_GetPixelsFromObj(menuPtr->interp, menuPtr->tkwin, |
1906 |
menuPtr->activeBorderWidthPtr, &activeBorderWidth); |
1907 |
leftEdge = x + indicatorSpace + activeBorderWidth; |
1908 |
|
1909 |
/* |
1910 |
* Draw label or bitmap or image for entry. |
1911 |
*/ |
1912 |
|
1913 |
baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2; |
1914 |
if (mePtr->image != NULL) { |
1915 |
Tk_SizeOfImage(mePtr->image, &imageWidth, &imageHeight); |
1916 |
if ((mePtr->selectImage != NULL) |
1917 |
&& (mePtr->entryFlags & ENTRY_SELECTED)) { |
1918 |
Tk_RedrawImage(mePtr->selectImage, 0, 0, |
1919 |
imageWidth, imageHeight, d, leftEdge, |
1920 |
(int) (y + (mePtr->height - imageHeight)/2)); |
1921 |
} else { |
1922 |
Tk_RedrawImage(mePtr->image, 0, 0, imageWidth, |
1923 |
imageHeight, d, leftEdge, |
1924 |
(int) (y + (mePtr->height - imageHeight)/2)); |
1925 |
} |
1926 |
} else if (mePtr->bitmapPtr != NULL) { |
1927 |
int width, height; |
1928 |
Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr); |
1929 |
Tk_SizeOfBitmap(menuPtr->display, bitmap, &width, &height); |
1930 |
XCopyPlane(menuPtr->display, bitmap, d, gc, 0, 0, (unsigned) width, |
1931 |
(unsigned) height, leftEdge, |
1932 |
(int) (y + (mePtr->height - height)/2), 1); |
1933 |
} else { |
1934 |
if (mePtr->labelLength > 0) { |
1935 |
char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL); |
1936 |
Tk_DrawChars(menuPtr->display, d, gc, tkfont, label, |
1937 |
mePtr->labelLength, leftEdge, baseline); |
1938 |
DrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, |
1939 |
width, height); |
1940 |
} |
1941 |
} |
1942 |
|
1943 |
if (mePtr->state == ENTRY_DISABLED) { |
1944 |
if (menuPtr->disabledFgPtr == NULL) { |
1945 |
XFillRectangle(menuPtr->display, d, menuPtr->disabledGC, x, y, |
1946 |
(unsigned) width, (unsigned) height); |
1947 |
} else if ((mePtr->image != NULL) |
1948 |
&& (menuPtr->disabledImageGC != None)) { |
1949 |
XFillRectangle(menuPtr->display, d, menuPtr->disabledImageGC, |
1950 |
leftEdge, |
1951 |
(int) (y + (mePtr->height - imageHeight)/2), |
1952 |
(unsigned) imageWidth, (unsigned) imageHeight); |
1953 |
} |
1954 |
} |
1955 |
} |
1956 |
|
1957 |
/* |
1958 |
*-------------------------------------------------------------- |
1959 |
* |
1960 |
* TkpComputeMenubarGeometry -- |
1961 |
* |
1962 |
* This procedure is invoked to recompute the size and |
1963 |
* layout of a menu that is a menubar clone. |
1964 |
* |
1965 |
* Results: |
1966 |
* None. |
1967 |
* |
1968 |
* Side effects: |
1969 |
* Fields of menu entries are changed to reflect their |
1970 |
* current positions, and the size of the menu window |
1971 |
* itself may be changed. |
1972 |
* |
1973 |
*-------------------------------------------------------------- |
1974 |
*/ |
1975 |
|
1976 |
void |
1977 |
TkpComputeMenubarGeometry(menuPtr) |
1978 |
TkMenu *menuPtr; /* Structure describing menu. */ |
1979 |
{ |
1980 |
TkpComputeStandardMenuGeometry(menuPtr); |
1981 |
} |
1982 |
|
1983 |
/* |
1984 |
*---------------------------------------------------------------------- |
1985 |
* |
1986 |
* DrawTearoffEntry -- |
1987 |
* |
1988 |
* This procedure draws the background part of a menu. |
1989 |
* |
1990 |
* Results: |
1991 |
* None. |
1992 |
* |
1993 |
* Side effects: |
1994 |
* Commands are output to X to display the menu in its |
1995 |
* current mode. |
1996 |
* |
1997 |
*---------------------------------------------------------------------- |
1998 |
*/ |
1999 |
|
2000 |
void |
2001 |
DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height) |
2002 |
TkMenu *menuPtr; /* The menu we are drawing */ |
2003 |
TkMenuEntry *mePtr; /* The entry we are drawing */ |
2004 |
Drawable d; /* The drawable we are drawing into */ |
2005 |
GC gc; /* The gc we are drawing with */ |
2006 |
Tk_Font tkfont; /* The font we are drawing with */ |
2007 |
CONST Tk_FontMetrics *fmPtr; /* The metrics we are drawing with */ |
2008 |
int x; |
2009 |
int y; |
2010 |
int width; |
2011 |
int height; |
2012 |
{ |
2013 |
XPoint points[2]; |
2014 |
int segmentWidth, maxX; |
2015 |
Tk_3DBorder border; |
2016 |
|
2017 |
if (menuPtr->menuType != MASTER_MENU) { |
2018 |
return; |
2019 |
} |
2020 |
|
2021 |
points[0].x = x; |
2022 |
points[0].y = y + height/2; |
2023 |
points[1].y = points[0].y; |
2024 |
segmentWidth = 6; |
2025 |
maxX = width - 1; |
2026 |
border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr); |
2027 |
|
2028 |
while (points[0].x < maxX) { |
2029 |
points[1].x = points[0].x + segmentWidth; |
2030 |
if (points[1].x > maxX) { |
2031 |
points[1].x = maxX; |
2032 |
} |
2033 |
Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 2, 1, |
2034 |
TK_RELIEF_RAISED); |
2035 |
points[0].x += 2*segmentWidth; |
2036 |
} |
2037 |
} |
2038 |
|
2039 |
/* |
2040 |
*---------------------------------------------------------------------- |
2041 |
* |
2042 |
* TkpConfigureMenuEntry -- |
2043 |
* |
2044 |
* Processes configurations for menu entries. |
2045 |
* |
2046 |
* Results: |
2047 |
* Returns standard TCL result. If TCL_ERROR is returned, then |
2048 |
* the interp's result contains an error message. |
2049 |
* |
2050 |
* Side effects: |
2051 |
* Configuration information get set for mePtr; old resources |
2052 |
* get freed, if any need it. |
2053 |
* |
2054 |
*---------------------------------------------------------------------- |
2055 |
*/ |
2056 |
|
2057 |
int |
2058 |
TkpConfigureMenuEntry(mePtr) |
2059 |
register TkMenuEntry *mePtr; /* Information about menu entry; may |
2060 |
* or may not already have values for |
2061 |
* some fields. */ |
2062 |
{ |
2063 |
TkMenu *menuPtr = mePtr->menuPtr; |
2064 |
|
2065 |
if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) { |
2066 |
menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; |
2067 |
Tcl_DoWhenIdle(ReconfigureWindowsMenu, (ClientData) menuPtr); |
2068 |
} |
2069 |
return TCL_OK; |
2070 |
} |
2071 |
|
2072 |
/* |
2073 |
*---------------------------------------------------------------------- |
2074 |
* |
2075 |
* TkpDrawMenuEntry -- |
2076 |
* |
2077 |
* Draws the given menu entry at the given coordinates with the |
2078 |
* given attributes. |
2079 |
* |
2080 |
* Results: |
2081 |
* None. |
2082 |
* |
2083 |
* Side effects: |
2084 |
* X Server commands are executed to display the menu entry. |
2085 |
* |
2086 |
*---------------------------------------------------------------------- |
2087 |
*/ |
2088 |
|
2089 |
void |
2090 |
TkpDrawMenuEntry(mePtr, d, tkfont, menuMetricsPtr, x, y, width, height, |
2091 |
strictMotif, drawArrow) |
2092 |
TkMenuEntry *mePtr; /* The entry to draw */ |
2093 |
Drawable d; /* What to draw into */ |
2094 |
Tk_Font tkfont; /* Precalculated font for menu */ |
2095 |
CONST Tk_FontMetrics *menuMetricsPtr; |
2096 |
/* Precalculated metrics for menu */ |
2097 |
int x; /* X-coordinate of topleft of entry */ |
2098 |
int y; /* Y-coordinate of topleft of entry */ |
2099 |
int width; /* Width of the entry rectangle */ |
2100 |
int height; /* Height of the current rectangle */ |
2101 |
int strictMotif; /* Boolean flag */ |
2102 |
int drawArrow; /* Whether or not to draw the cascade |
2103 |
* arrow for cascade items. Only applies |
2104 |
* to Windows. */ |
2105 |
{ |
2106 |
GC gc, indicatorGC; |
2107 |
TkMenu *menuPtr = mePtr->menuPtr; |
2108 |
Tk_3DBorder bgBorder, activeBorder; |
2109 |
CONST Tk_FontMetrics *fmPtr; |
2110 |
Tk_FontMetrics entryMetrics; |
2111 |
int padY = (menuPtr->menuType == MENUBAR) ? 3 : 0; |
2112 |
int adjustedY = y + padY; |
2113 |
int adjustedHeight = height - 2 * padY; |
2114 |
|
2115 |
/* |
2116 |
* Choose the gc for drawing the foreground part of the entry. |
2117 |
*/ |
2118 |
|
2119 |
if ((mePtr->state == ENTRY_ACTIVE) && !strictMotif) { |
2120 |
gc = mePtr->activeGC; |
2121 |
if (gc == NULL) { |
2122 |
gc = menuPtr->activeGC; |
2123 |
} |
2124 |
} else { |
2125 |
TkMenuEntry *cascadeEntryPtr; |
2126 |
int parentDisabled = 0; |
2127 |
char *name; |
2128 |
|
2129 |
for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr; |
2130 |
cascadeEntryPtr != NULL; |
2131 |
cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) { |
2132 |
name = Tcl_GetStringFromObj(cascadeEntryPtr->namePtr, NULL); |
2133 |
if (strcmp(name, Tk_PathName(menuPtr->tkwin)) == 0) { |
2134 |
if (mePtr->state == ENTRY_DISABLED) { |
2135 |
parentDisabled = 1; |
2136 |
} |
2137 |
break; |
2138 |
} |
2139 |
} |
2140 |
|
2141 |
if (((parentDisabled || (mePtr->state == ENTRY_DISABLED))) |
2142 |
&& (menuPtr->disabledFgPtr != NULL)) { |
2143 |
gc = mePtr->disabledGC; |
2144 |
if (gc == NULL) { |
2145 |
gc = menuPtr->disabledGC; |
2146 |
} |
2147 |
} else { |
2148 |
gc = mePtr->textGC; |
2149 |
if (gc == NULL) { |
2150 |
gc = menuPtr->textGC; |
2151 |
} |
2152 |
} |
2153 |
} |
2154 |
indicatorGC = mePtr->indicatorGC; |
2155 |
if (indicatorGC == NULL) { |
2156 |
indicatorGC = menuPtr->indicatorGC; |
2157 |
} |
2158 |
|
2159 |
bgBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin, |
2160 |
(mePtr->borderPtr == NULL) ? menuPtr->borderPtr |
2161 |
: mePtr->borderPtr); |
2162 |
if (strictMotif) { |
2163 |
activeBorder = bgBorder; |
2164 |
} else { |
2165 |
activeBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin, |
2166 |
(mePtr->activeBorderPtr == NULL) ? menuPtr->activeBorderPtr |
2167 |
: mePtr->activeBorderPtr); |
2168 |
} |
2169 |
|
2170 |
if (mePtr->fontPtr == NULL) { |
2171 |
fmPtr = menuMetricsPtr; |
2172 |
} else { |
2173 |
tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr); |
2174 |
Tk_GetFontMetrics(tkfont, &entryMetrics); |
2175 |
fmPtr = &entryMetrics; |
2176 |
} |
2177 |
|
2178 |
/* |
2179 |
* Need to draw the entire background, including padding. On Unix, |
2180 |
* for menubars, we have to draw the rest of the entry taking |
2181 |
* into account the padding. |
2182 |
*/ |
2183 |
|
2184 |
DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder, |
2185 |
bgBorder, x, y, width, height); |
2186 |
|
2187 |
if (mePtr->type == SEPARATOR_ENTRY) { |
2188 |
DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, |
2189 |
fmPtr, x, adjustedY, width, adjustedHeight); |
2190 |
} else if (mePtr->type == TEAROFF_ENTRY) { |
2191 |
DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY, |
2192 |
width, adjustedHeight); |
2193 |
} else { |
2194 |
DrawMenuEntryLabel(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY, |
2195 |
width, adjustedHeight); |
2196 |
DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr, |
2197 |
activeBorder, x, adjustedY, width, adjustedHeight, drawArrow); |
2198 |
if (!mePtr->hideMargin) { |
2199 |
DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont, |
2200 |
fmPtr, x, adjustedY, width, adjustedHeight); |
2201 |
} |
2202 |
} |
2203 |
} |
2204 |
|
2205 |
/* |
2206 |
*---------------------------------------------------------------------- |
2207 |
* |
2208 |
* GetMenuLabelGeometry -- |
2209 |
* |
2210 |
* Figures out the size of the label portion of a menu item. |
2211 |
* |
2212 |
* Results: |
2213 |
* widthPtr and heightPtr are filled in with the correct geometry |
2214 |
* information. |
2215 |
* |
2216 |
* Side effects: |
2217 |
* None. |
2218 |
* |
2219 |
*---------------------------------------------------------------------- |
2220 |
*/ |
2221 |
|
2222 |
static void |
2223 |
GetMenuLabelGeometry(mePtr, tkfont, fmPtr, widthPtr, heightPtr) |
2224 |
TkMenuEntry *mePtr; /* The entry we are computing */ |
2225 |
Tk_Font tkfont; /* The precalculated font */ |
2226 |
CONST Tk_FontMetrics *fmPtr; /* The precalculated metrics */ |
2227 |
int *widthPtr; /* The resulting width of the label |
2228 |
* portion */ |
2229 |
int *heightPtr; /* The resulting height of the label |
2230 |
* portion */ |
2231 |
{ |
2232 |
TkMenu *menuPtr = mePtr->menuPtr; |
2233 |
|
2234 |
if (mePtr->image != NULL) { |
2235 |
Tk_SizeOfImage(mePtr->image, widthPtr, heightPtr); |
2236 |
} else if (mePtr->bitmapPtr != NULL) { |
2237 |
Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr); |
2238 |
Tk_SizeOfBitmap(menuPtr->display, bitmap, widthPtr, heightPtr); |
2239 |
} else { |
2240 |
*heightPtr = fmPtr->linespace; |
2241 |
|
2242 |
if (mePtr->labelPtr != NULL) { |
2243 |
char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL); |
2244 |
|
2245 |
*widthPtr = Tk_TextWidth(tkfont, label, mePtr->labelLength); |
2246 |
} else { |
2247 |
*widthPtr = 0; |
2248 |
} |
2249 |
} |
2250 |
*heightPtr += 1; |
2251 |
} |
2252 |
|
2253 |
/* |
2254 |
*---------------------------------------------------------------------- |
2255 |
* |
2256 |
* DrawMenuEntryBackground -- |
2257 |
* |
2258 |
* This procedure draws the background part of a menu. |
2259 |
* |
2260 |
* Results: |
2261 |
* None. |
2262 |
* |
2263 |
* Side effects: |
2264 |
* Commands are output to X to display the menu in its |
2265 |
* current mode. |
2266 |
* |
2267 |
*---------------------------------------------------------------------- |
2268 |
*/ |
2269 |
|
2270 |
static void |
2271 |
DrawMenuEntryBackground( |
2272 |
TkMenu *menuPtr, /* The menu we are drawing. */ |
2273 |
TkMenuEntry *mePtr, /* The entry we are drawing. */ |
2274 |
Drawable d, /* What we are drawing into */ |
2275 |
Tk_3DBorder activeBorder, /* Border for active items */ |
2276 |
Tk_3DBorder bgBorder, /* Border for the background */ |
2277 |
int x, /* left edge */ |
2278 |
int y, /* top edge */ |
2279 |
int width, /* width of rectangle to draw */ |
2280 |
int height) /* height of rectangle to draw */ |
2281 |
{ |
2282 |
if (mePtr->state == ENTRY_ACTIVE) { |
2283 |
bgBorder = activeBorder; |
2284 |
} |
2285 |
Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, |
2286 |
x, y, width, height, 0, TK_RELIEF_FLAT); |
2287 |
} |
2288 |
|
2289 |
/* |
2290 |
*-------------------------------------------------------------- |
2291 |
* |
2292 |
* TkpComputeStandardMenuGeometry -- |
2293 |
* |
2294 |
* This procedure is invoked to recompute the size and |
2295 |
* layout of a menu that is not a menubar clone. |
2296 |
* |
2297 |
* Results: |
2298 |
* None. |
2299 |
* |
2300 |
* Side effects: |
2301 |
* Fields of menu entries are changed to reflect their |
2302 |
* current positions, and the size of the menu window |
2303 |
* itself may be changed. |
2304 |
* |
2305 |
*-------------------------------------------------------------- |
2306 |
*/ |
2307 |
|
2308 |
void |
2309 |
TkpComputeStandardMenuGeometry( |
2310 |
TkMenu *menuPtr) /* Structure describing menu. */ |
2311 |
{ |
2312 |
Tk_Font menuFont, tkfont; |
2313 |
Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr; |
2314 |
int x, y, height, width, indicatorSpace, labelWidth, accelWidth; |
2315 |
int windowWidth, windowHeight, accelSpace; |
2316 |
int i, j, lastColumnBreak = 0; |
2317 |
int activeBorderWidth, borderWidth; |
2318 |
|
2319 |
if (menuPtr->tkwin == NULL) { |
2320 |
return; |
2321 |
} |
2322 |
|
2323 |
Tk_GetPixelsFromObj(menuPtr->interp, menuPtr->tkwin, |
2324 |
menuPtr->borderWidthPtr, &borderWidth); |
2325 |
x = y = borderWidth; |
2326 |
indicatorSpace = labelWidth = accelWidth = 0; |
2327 |
windowHeight = 0; |
2328 |
|
2329 |
/* |
2330 |
* On the Mac especially, getting font metrics can be quite slow, |
2331 |
* so we want to do it intelligently. We are going to precalculate |
2332 |
* them and pass them down to all of the measuring and drawing |
2333 |
* routines. We will measure the font metrics of the menu once. |
2334 |
* If an entry does not have its own font set, then we give |
2335 |
* the geometry/drawing routines the menu's font and metrics. |
2336 |
* If an entry has its own font, we will measure that font and |
2337 |
* give all of the geometry/drawing the entry's font and metrics. |
2338 |
*/ |
2339 |
|
2340 |
menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr); |
2341 |
Tk_GetFontMetrics(menuFont, &menuMetrics); |
2342 |
accelSpace = Tk_TextWidth(menuFont, "M", 1); |
2343 |
Tk_GetPixelsFromObj(menuPtr->interp, menuPtr->tkwin, |
2344 |
menuPtr->activeBorderWidthPtr, &activeBorderWidth); |
2345 |
|
2346 |
for (i = 0; i < menuPtr->numEntries; i++) { |
2347 |
if (menuPtr->entries[i]->fontPtr == NULL) { |
2348 |
tkfont = menuFont; |
2349 |
fmPtr = &menuMetrics; |
2350 |
} else { |
2351 |
tkfont = Tk_GetFontFromObj(menuPtr->tkwin, |
2352 |
menuPtr->entries[i]->fontPtr); |
2353 |
Tk_GetFontMetrics(tkfont, &entryMetrics); |
2354 |
fmPtr = &entryMetrics; |
2355 |
} |
2356 |
if ((i > 0) && menuPtr->entries[i]->columnBreak) { |
2357 |
if (accelWidth != 0) { |
2358 |
labelWidth += accelSpace; |
2359 |
} |
2360 |
for (j = lastColumnBreak; j < i; j++) { |
2361 |
menuPtr->entries[j]->indicatorSpace = indicatorSpace; |
2362 |
menuPtr->entries[j]->labelWidth = labelWidth; |
2363 |
menuPtr->entries[j]->width = indicatorSpace + labelWidth |
2364 |
+ accelWidth + 2 * activeBorderWidth; |
2365 |
menuPtr->entries[j]->x = x; |
2366 |
menuPtr->entries[j]->entryFlags &= ~ENTRY_LAST_COLUMN; |
2367 |
} |
2368 |
x += indicatorSpace + labelWidth + accelWidth |
2369 |
+ 2 * borderWidth; |
2370 |
indicatorSpace = labelWidth = accelWidth = 0; |
2371 |
lastColumnBreak = i; |
2372 |
y = borderWidth; |
2373 |
} |
2374 |
|
2375 |
if (menuPtr->entries[i]->type == SEPARATOR_ENTRY) { |
2376 |
GetMenuSeparatorGeometry(menuPtr, menuPtr->entries[i], tkfont, |
2377 |
fmPtr, &width, &height); |
2378 |
menuPtr->entries[i]->height = height; |
2379 |
} else if (menuPtr->entries[i]->type == TEAROFF_ENTRY) { |
2380 |
GetTearoffEntryGeometry(menuPtr, menuPtr->entries[i], tkfont, |
2381 |
fmPtr, &width, &height); |
2382 |
menuPtr->entries[i]->height = height; |
2383 |
} else { |
2384 |
|
2385 |
/* |
2386 |
* For each entry, compute the height required by that |
2387 |
* particular entry, plus three widths: the width of the |
2388 |
* label, the width to allow for an indicator to be displayed |
2389 |
* to the left of the label (if any), and the width of the |
2390 |
* accelerator to be displayed to the right of the label |
2391 |
* (if any). These sizes depend, of course, on the type |
2392 |
* of the entry. |
2393 |
*/ |
2394 |
|
2395 |
GetMenuLabelGeometry(menuPtr->entries[i], tkfont, fmPtr, &width, |
2396 |
&height); |
2397 |
menuPtr->entries[i]->height = height; |
2398 |
if (width > labelWidth) { |
2399 |
labelWidth = width; |
2400 |
} |
2401 |
|
2402 |
GetMenuAccelGeometry(menuPtr, menuPtr->entries[i], tkfont, |
2403 |
fmPtr, &width, &height); |
2404 |
if (height > menuPtr->entries[i]->height) { |
2405 |
menuPtr->entries[i]->height = height; |
2406 |
} |
2407 |
if (width > accelWidth) { |
2408 |
accelWidth = width; |
2409 |
} |
2410 |
|
2411 |
GetMenuIndicatorGeometry(menuPtr, menuPtr->entries[i], tkfont, |
2412 |
fmPtr, &width, &height); |
2413 |
if (height > menuPtr->entries[i]->height) { |
2414 |
menuPtr->entries[i]->height = height; |
2415 |
} |
2416 |
if (width > indicatorSpace) { |
2417 |
indicatorSpace = width; |
2418 |
} |
2419 |
|
2420 |
menuPtr->entries[i]->height += 2 * activeBorderWidth + 1; |
2421 |
} |
2422 |
menuPtr->entries[i]->y = y; |
2423 |
y += menuPtr->entries[i]->height; |
2424 |
if (y > windowHeight) { |
2425 |
windowHeight = y; |
2426 |
} |
2427 |
} |
2428 |
|
2429 |
if (accelWidth != 0) { |
2430 |
labelWidth += accelSpace; |
2431 |
} |
2432 |
for (j = lastColumnBreak; j < menuPtr->numEntries; j++) { |
2433 |
menuPtr->entries[j]->indicatorSpace = indicatorSpace; |
2434 |
menuPtr->entries[j]->labelWidth = labelWidth; |
2435 |
menuPtr->entries[j]->width = indicatorSpace + labelWidth |
2436 |
+ accelWidth + 2 * activeBorderWidth; |
2437 |
menuPtr->entries[j]->x = x; |
2438 |
menuPtr->entries[j]->entryFlags |= ENTRY_LAST_COLUMN; |
2439 |
} |
2440 |
windowWidth = x + indicatorSpace + labelWidth + accelWidth + accelSpace |
2441 |
+ 2 * activeBorderWidth + 2 * borderWidth; |
2442 |
|
2443 |
|
2444 |
windowHeight += borderWidth; |
2445 |
|
2446 |
/* |
2447 |
* The X server doesn't like zero dimensions, so round up to at least |
2448 |
* 1 (a zero-sized menu should never really occur, anyway). |
2449 |
*/ |
2450 |
|
2451 |
if (windowWidth <= 0) { |
2452 |
windowWidth = 1; |
2453 |
} |
2454 |
if (windowHeight <= 0) { |
2455 |
windowHeight = 1; |
2456 |
} |
2457 |
menuPtr->totalWidth = windowWidth; |
2458 |
menuPtr->totalHeight = windowHeight; |
2459 |
} |
2460 |
|
2461 |
/* |
2462 |
*---------------------------------------------------------------------- |
2463 |
* |
2464 |
* MenuSelectEvent -- |
2465 |
* |
2466 |
* Generates a "MenuSelect" virtual event. This can be used to |
2467 |
* do context-sensitive menu help. |
2468 |
* |
2469 |
* Results: |
2470 |
* None. |
2471 |
* |
2472 |
* Side effects: |
2473 |
* Places a virtual event on the event queue. |
2474 |
* |
2475 |
*---------------------------------------------------------------------- |
2476 |
*/ |
2477 |
|
2478 |
static void |
2479 |
MenuSelectEvent( |
2480 |
TkMenu *menuPtr) /* the menu we have selected. */ |
2481 |
{ |
2482 |
XVirtualEvent event; |
2483 |
POINTS rootPoint; |
2484 |
DWORD msgPos; |
2485 |
|
2486 |
event.type = VirtualEvent; |
2487 |
event.serial = menuPtr->display->request; |
2488 |
event.send_event = 0; |
2489 |
event.display = menuPtr->display; |
2490 |
Tk_MakeWindowExist(menuPtr->tkwin); |
2491 |
event.event = Tk_WindowId(menuPtr->tkwin); |
2492 |
event.root = XRootWindow(menuPtr->display, 0); |
2493 |
event.subwindow = None; |
2494 |
event.time = TkpGetMS(); |
2495 |
|
2496 |
msgPos = GetMessagePos(); |
2497 |
rootPoint = MAKEPOINTS(msgPos); |
2498 |
event.x_root = rootPoint.x; |
2499 |
event.y_root = rootPoint.y; |
2500 |
event.state = TkWinGetModifierState(); |
2501 |
event.same_screen = 1; |
2502 |
event.name = Tk_GetUid("MenuSelect"); |
2503 |
Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL); |
2504 |
} |
2505 |
|
2506 |
/* |
2507 |
*---------------------------------------------------------------------- |
2508 |
* |
2509 |
* TkpMenuNotifyToplevelCreate -- |
2510 |
* |
2511 |
* This routine reconfigures the menu and the clones indicated by |
2512 |
* menuName becuase a toplevel has been created and any system |
2513 |
* menus need to be created. |
2514 |
* |
2515 |
* Results: |
2516 |
* None. |
2517 |
* |
2518 |
* Side effects: |
2519 |
* An idle handler is set up to do the reconfiguration. |
2520 |
* |
2521 |
*---------------------------------------------------------------------- |
2522 |
*/ |
2523 |
|
2524 |
void |
2525 |
TkpMenuNotifyToplevelCreate( |
2526 |
Tcl_Interp *interp, /* The interp the menu lives in. */ |
2527 |
char *menuName) /* The name of the menu to |
2528 |
* reconfigure. */ |
2529 |
{ |
2530 |
TkMenuReferences *menuRefPtr; |
2531 |
TkMenu *menuPtr; |
2532 |
|
2533 |
if ((menuName != NULL) && (menuName[0] != '\0')) { |
2534 |
menuRefPtr = TkFindMenuReferences(interp, menuName); |
2535 |
if ((menuRefPtr != NULL) && (menuRefPtr->menuPtr != NULL)) { |
2536 |
for (menuPtr = menuRefPtr->menuPtr->masterMenuPtr; menuPtr != NULL; |
2537 |
menuPtr = menuPtr->nextInstancePtr) { |
2538 |
if ((menuPtr->menuType == MENUBAR) |
2539 |
&& !(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) { |
2540 |
menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; |
2541 |
Tcl_DoWhenIdle(ReconfigureWindowsMenu, |
2542 |
(ClientData) menuPtr); |
2543 |
} |
2544 |
} |
2545 |
} |
2546 |
} |
2547 |
} |
2548 |
|
2549 |
/* |
2550 |
*---------------------------------------------------------------------- |
2551 |
* |
2552 |
* MenuExitHandler -- |
2553 |
* |
2554 |
* Throws away the utility window needed for menus and unregisters |
2555 |
* the class. |
2556 |
* |
2557 |
* Results: |
2558 |
* None. |
2559 |
* |
2560 |
* Side effects: |
2561 |
* Menus have to be reinitialized next time. |
2562 |
* |
2563 |
*---------------------------------------------------------------------- |
2564 |
*/ |
2565 |
|
2566 |
static void |
2567 |
MenuExitHandler( |
2568 |
ClientData clientData) /* Not used */ |
2569 |
{ |
2570 |
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) |
2571 |
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); |
2572 |
|
2573 |
DestroyWindow(tsdPtr->menuHWND); |
2574 |
UnregisterClass(MENU_CLASS_NAME, Tk_GetHINSTANCE()); |
2575 |
} |
2576 |
|
2577 |
/* |
2578 |
*---------------------------------------------------------------------- |
2579 |
* |
2580 |
* TkWinGetMenuSystemDefault -- |
2581 |
* |
2582 |
* Gets the Windows specific default value for a given X resource |
2583 |
* database name. |
2584 |
* |
2585 |
* Results: |
2586 |
* Returns a Tcl_Obj * with the default value. If there is no |
2587 |
* Windows-specific default for this attribute, returns NULL. |
2588 |
* This object has a ref count of 0. |
2589 |
* |
2590 |
* Side effects: |
2591 |
* Storage is allocated. |
2592 |
* |
2593 |
*---------------------------------------------------------------------- |
2594 |
*/ |
2595 |
|
2596 |
Tcl_Obj * |
2597 |
TkWinGetMenuSystemDefault( |
2598 |
Tk_Window tkwin, /* A window to use. */ |
2599 |
char *dbName, /* The option database name. */ |
2600 |
char *className) /* The name of the option class. */ |
2601 |
{ |
2602 |
Tcl_Obj *valuePtr = NULL; |
2603 |
|
2604 |
if ((strcmp(dbName, "activeBorderWidth") == 0) || |
2605 |
(strcmp(dbName, "borderWidth") == 0)) { |
2606 |
valuePtr = Tcl_NewIntObj(defaultBorderWidth); |
2607 |
} else if (strcmp(dbName, "font") == 0) { |
2608 |
valuePtr = Tcl_NewStringObj(Tcl_DStringValue(&menuFontDString), |
2609 |
-1); |
2610 |
} |
2611 |
|
2612 |
return valuePtr; |
2613 |
} |
2614 |
|
2615 |
/* |
2616 |
*---------------------------------------------------------------------- |
2617 |
* |
2618 |
* TkWinMenuSetDefaults -- |
2619 |
* |
2620 |
* Sets up the hash tables and the variables used by the menu package. |
2621 |
* |
2622 |
* Results: |
2623 |
* None. |
2624 |
* |
2625 |
* Side effects: |
2626 |
* lastMenuID gets initialized, and the parent hash and the command hash |
2627 |
* are allocated. |
2628 |
* |
2629 |
*---------------------------------------------------------------------- |
2630 |
*/ |
2631 |
|
2632 |
void |
2633 |
SetDefaults( |
2634 |
int firstTime) /* Is this the first time this |
2635 |
* has been called? */ |
2636 |
{ |
2637 |
char sizeString[TCL_INTEGER_SPACE]; |
2638 |
char faceName[LF_FACESIZE]; |
2639 |
HDC scratchDC; |
2640 |
Tcl_DString boldItalicDString; |
2641 |
int bold = 0; |
2642 |
int italic = 0; |
2643 |
TEXTMETRIC tm; |
2644 |
int pointSize; |
2645 |
HFONT menuFont; |
2646 |
NONCLIENTMETRICS ncMetrics; |
2647 |
|
2648 |
/* |
2649 |
* Set all of the default options. The loop will terminate when we run |
2650 |
* out of options via a break statement. |
2651 |
*/ |
2652 |
|
2653 |
defaultBorderWidth = GetSystemMetrics(SM_CXBORDER); |
2654 |
if (GetSystemMetrics(SM_CYBORDER) > defaultBorderWidth) { |
2655 |
defaultBorderWidth = GetSystemMetrics(SM_CYBORDER); |
2656 |
} |
2657 |
|
2658 |
scratchDC = CreateDC("DISPLAY", NULL, NULL, NULL); |
2659 |
if (!firstTime) { |
2660 |
Tcl_DStringFree(&menuFontDString); |
2661 |
} |
2662 |
Tcl_DStringInit(&menuFontDString); |
2663 |
|
2664 |
ncMetrics.cbSize = sizeof(ncMetrics); |
2665 |
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncMetrics), |
2666 |
&ncMetrics, 0); |
2667 |
menuFont = CreateFontIndirect(&ncMetrics.lfMenuFont); |
2668 |
SelectObject(scratchDC, menuFont); |
2669 |
GetTextMetrics(scratchDC, &tm); |
2670 |
GetTextFace(scratchDC, LF_FACESIZE, faceName); |
2671 |
pointSize = MulDiv(tm.tmHeight - tm.tmInternalLeading, |
2672 |
72, GetDeviceCaps(scratchDC, LOGPIXELSY)); |
2673 |
if (tm.tmWeight >= 700) { |
2674 |
bold = 1; |
2675 |
} |
2676 |
if (tm.tmItalic) { |
2677 |
italic = 1; |
2678 |
} |
2679 |
|
2680 |
SelectObject(scratchDC, GetStockObject(SYSTEM_FONT)); |
2681 |
DeleteDC(scratchDC); |
2682 |
|
2683 |
DeleteObject(menuFont); |
2684 |
|
2685 |
Tcl_DStringAppendElement(&menuFontDString, faceName); |
2686 |
sprintf(sizeString, "%d", pointSize); |
2687 |
Tcl_DStringAppendElement(&menuFontDString, sizeString); |
2688 |
|
2689 |
if (bold == 1 || italic == 1) { |
2690 |
Tcl_DStringInit(&boldItalicDString); |
2691 |
if (bold == 1) { |
2692 |
Tcl_DStringAppendElement(&boldItalicDString, "bold"); |
2693 |
} |
2694 |
if (italic == 1) { |
2695 |
Tcl_DStringAppendElement(&boldItalicDString, "italic"); |
2696 |
} |
2697 |
Tcl_DStringAppendElement(&menuFontDString, |
2698 |
Tcl_DStringValue(&boldItalicDString)); |
2699 |
} |
2700 |
|
2701 |
/* |
2702 |
* Now we go ahead and get the dimensions of the check mark and the |
2703 |
* appropriate margins. Since this is fairly hairy, we do it here |
2704 |
* to save time when traversing large sets of menu items. |
2705 |
* |
2706 |
* The code below was given to me by Microsoft over the phone. It |
2707 |
* is the only way to insure menu items lining up, and is not |
2708 |
* documented. |
2709 |
*/ |
2710 |
|
2711 |
if (TkWinGetPlatformId() == VER_PLATFORM_WIN32_WINDOWS) { |
2712 |
indicatorDimensions[0] = GetSystemMetrics(SM_CYMENUCHECK); |
2713 |
indicatorDimensions[1] = ((GetSystemMetrics(SM_CXFIXEDFRAME) + |
2714 |
GetSystemMetrics(SM_CXBORDER) |
2715 |
+ GetSystemMetrics(SM_CXMENUCHECK) + 7) & 0xFFF8) |
2716 |
- GetSystemMetrics(SM_CXFIXEDFRAME); |
2717 |
} else { |
2718 |
DWORD dimensions = GetMenuCheckMarkDimensions(); |
2719 |
indicatorDimensions[0] = HIWORD(dimensions); |
2720 |
indicatorDimensions[1] = LOWORD(dimensions); |
2721 |
} |
2722 |
} |
2723 |
|
2724 |
/* |
2725 |
*---------------------------------------------------------------------- |
2726 |
* |
2727 |
* TkpMenuInit -- |
2728 |
* |
2729 |
* Sets up the process-wide variables used by the menu package. |
2730 |
* |
2731 |
* Results: |
2732 |
* None. |
2733 |
* |
2734 |
* Side effects: |
2735 |
* lastMenuID gets initialized. |
2736 |
* |
2737 |
*---------------------------------------------------------------------- |
2738 |
*/ |
2739 |
|
2740 |
void |
2741 |
TkpMenuInit() |
2742 |
{ |
2743 |
WNDCLASS wndClass; |
2744 |
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) |
2745 |
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); |
2746 |
|
2747 |
wndClass.style = CS_OWNDC; |
2748 |
wndClass.lpfnWndProc = TkWinMenuProc; |
2749 |
wndClass.cbClsExtra = 0; |
2750 |
wndClass.cbWndExtra = 0; |
2751 |
wndClass.hInstance = Tk_GetHINSTANCE(); |
2752 |
wndClass.hIcon = NULL; |
2753 |
wndClass.hCursor = NULL; |
2754 |
wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); |
2755 |
wndClass.lpszMenuName = NULL; |
2756 |
wndClass.lpszClassName = MENU_CLASS_NAME; |
2757 |
RegisterClass(&wndClass); |
2758 |
|
2759 |
tsdPtr->menuHWND = CreateWindow(MENU_CLASS_NAME, "MenuWindow", WS_POPUP, |
2760 |
0, 0, 10, 10, NULL, NULL, Tk_GetHINSTANCE(), NULL); |
2761 |
|
2762 |
Tcl_CreateExitHandler(MenuExitHandler, (ClientData) NULL); |
2763 |
SetDefaults(1); |
2764 |
} |
2765 |
|
2766 |
/* |
2767 |
*---------------------------------------------------------------------- |
2768 |
* |
2769 |
* TkpMenuThreadInit -- |
2770 |
* |
2771 |
* Sets up the thread-local hash tables used by the menu module. |
2772 |
* |
2773 |
* Results: |
2774 |
* None. |
2775 |
* |
2776 |
* Side effects: |
2777 |
* Hash tables winMenuTable and commandTable are initialized. |
2778 |
* |
2779 |
*---------------------------------------------------------------------- |
2780 |
*/ |
2781 |
|
2782 |
void |
2783 |
TkpMenuThreadInit() |
2784 |
{ |
2785 |
ThreadSpecificData *tsdPtr = (ThreadSpecificData *) |
2786 |
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData)); |
2787 |
|
2788 |
Tcl_InitHashTable(&tsdPtr->winMenuTable, TCL_ONE_WORD_KEYS); |
2789 |
Tcl_InitHashTable(&tsdPtr->commandTable, TCL_ONE_WORD_KEYS); |
2790 |
} |
2791 |
|
2792 |
/* End of tkwinmenu.c */ |