/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkmenudraw.c
ViewVC logotype

Contents of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkmenudraw.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 69 - (show annotations) (download)
Sat Nov 5 10:54:17 2016 UTC (6 years, 3 months ago) by dashley
File MIME type: text/plain
File size: 30887 byte(s)
License and property (keyword) changes.
1 /* $Header$ */
2
3 /*
4 * tkMenuDraw.c --
5 *
6 * This module implements the platform-independent drawing and
7 * geometry calculations of menu widgets.
8 *
9 * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
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: tkmenudraw.c,v 1.1.1.1 2001/06/13 05:06:08 dtashley Exp $
15 */
16
17 #include "tkMenu.h"
18
19 /*
20 * Forward declarations for procedures defined later in this file:
21 */
22
23 static void AdjustMenuCoords _ANSI_ARGS_ ((TkMenu *menuPtr,
24 TkMenuEntry *mePtr, int *xPtr, int *yPtr,
25 char *string));
26 static void ComputeMenuGeometry _ANSI_ARGS_((
27 ClientData clientData));
28 static void DisplayMenu _ANSI_ARGS_((ClientData clientData));
29
30 /*
31 *----------------------------------------------------------------------
32 *
33 * TkMenuInitializeDrawingFields --
34 *
35 * Fills in drawing fields of a new menu. Called when new menu is
36 * created by MenuCmd.
37 *
38 * Results:
39 * None.
40 *
41 * Side effects:
42 * menuPtr fields are initialized.
43 *
44 *----------------------------------------------------------------------
45 */
46
47 void
48 TkMenuInitializeDrawingFields(menuPtr)
49 TkMenu *menuPtr; /* The menu we are initializing. */
50 {
51 menuPtr->textGC = None;
52 menuPtr->gray = None;
53 menuPtr->disabledGC = None;
54 menuPtr->activeGC = None;
55 menuPtr->indicatorGC = None;
56 menuPtr->disabledImageGC = None;
57 menuPtr->totalWidth = menuPtr->totalHeight = 0;
58 }
59
60 /*
61 *----------------------------------------------------------------------
62 *
63 * TkMenuInitializeEntryDrawingFields --
64 *
65 * Fills in drawing fields of a new menu entry. Called when an
66 * entry is created.
67 *
68 * Results:
69 * None.
70 *
71 * Side effects:
72 * None.
73 *
74 *----------------------------------------------------------------------
75 */
76
77 void
78 TkMenuInitializeEntryDrawingFields(mePtr)
79 TkMenuEntry *mePtr; /* The menu we are initializing. */
80 {
81 mePtr->width = 0;
82 mePtr->height = 0;
83 mePtr->x = 0;
84 mePtr->y = 0;
85 mePtr->indicatorSpace = 0;
86 mePtr->labelWidth = 0;
87 mePtr->textGC = None;
88 mePtr->activeGC = None;
89 mePtr->disabledGC = None;
90 mePtr->indicatorGC = None;
91 }
92
93 /*
94 *----------------------------------------------------------------------
95 *
96 * TkMenuFreeDrawOptions --
97 *
98 * Frees up any structures allocated for the drawing of a menu.
99 * Called when menu is deleted.
100 *
101 * Results:
102 * None.
103 *
104 * Side effects:
105 * Storage is released.
106 *
107 *----------------------------------------------------------------------
108 */
109
110 void
111 TkMenuFreeDrawOptions(menuPtr)
112 TkMenu *menuPtr;
113 {
114 if (menuPtr->textGC != None) {
115 Tk_FreeGC(menuPtr->display, menuPtr->textGC);
116 }
117 if (menuPtr->disabledImageGC != None) {
118 Tk_FreeGC(menuPtr->display, menuPtr->disabledImageGC);
119 }
120 if (menuPtr->gray != None) {
121 Tk_FreeBitmap(menuPtr->display, menuPtr->gray);
122 }
123 if (menuPtr->disabledGC != None) {
124 Tk_FreeGC(menuPtr->display, menuPtr->disabledGC);
125 }
126 if (menuPtr->activeGC != None) {
127 Tk_FreeGC(menuPtr->display, menuPtr->activeGC);
128 }
129 if (menuPtr->indicatorGC != None) {
130 Tk_FreeGC(menuPtr->display, menuPtr->indicatorGC);
131 }
132 }
133
134 /*
135 *----------------------------------------------------------------------
136 *
137 * TkMenuEntryFreeDrawOptions --
138 *
139 * Frees up drawing structures for a menu entry. Called when
140 * menu entry is freed.
141 *
142 * RESULTS:
143 * None.
144 *
145 * Side effects:
146 * Storage is freed.
147 *
148 *----------------------------------------------------------------------
149 */
150
151 void
152 TkMenuEntryFreeDrawOptions(mePtr)
153 TkMenuEntry *mePtr;
154 {
155 if (mePtr->textGC != None) {
156 Tk_FreeGC(mePtr->menuPtr->display, mePtr->textGC);
157 }
158 if (mePtr->disabledGC != None) {
159 Tk_FreeGC(mePtr->menuPtr->display, mePtr->disabledGC);
160 }
161 if (mePtr->activeGC != None) {
162 Tk_FreeGC(mePtr->menuPtr->display, mePtr->activeGC);
163 }
164 if (mePtr->indicatorGC != None) {
165 Tk_FreeGC(mePtr->menuPtr->display, mePtr->indicatorGC);
166 }
167 }
168
169 /*
170 *----------------------------------------------------------------------
171 *
172 * TkMenuConfigureDrawOptions --
173 *
174 * Sets the menu's drawing attributes in preparation for drawing
175 * the menu.
176 *
177 * RESULTS:
178 * None.
179 *
180 * Side effects:
181 * Storage is allocated.
182 *
183 *----------------------------------------------------------------------
184 */
185
186 void
187 TkMenuConfigureDrawOptions(menuPtr)
188 TkMenu *menuPtr; /* The menu we are configuring. */
189 {
190 XGCValues gcValues;
191 GC newGC;
192 unsigned long mask;
193 Tk_3DBorder border, activeBorder;
194 Tk_Font tkfont;
195 XColor *fg, *activeFg, *indicatorFg;
196
197 /*
198 * A few options need special processing, such as setting the
199 * background from a 3-D border, or filling in complicated
200 * defaults that couldn't be specified to Tk_ConfigureWidget.
201 */
202
203 border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr);
204 Tk_SetBackgroundFromBorder(menuPtr->tkwin, border);
205
206 tkfont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr);
207 gcValues.font = Tk_FontId(tkfont);
208 fg = Tk_GetColorFromObj(menuPtr->tkwin, menuPtr->fgPtr);
209 gcValues.foreground = fg->pixel;
210 gcValues.background = Tk_3DBorderColor(border)->pixel;
211 newGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCBackground|GCFont,
212 &gcValues);
213 if (menuPtr->textGC != None) {
214 Tk_FreeGC(menuPtr->display, menuPtr->textGC);
215 }
216 menuPtr->textGC = newGC;
217
218 gcValues.font = Tk_FontId(tkfont);
219 gcValues.background = Tk_3DBorderColor(border)->pixel;
220 if (menuPtr->disabledFgPtr != NULL) {
221 XColor *disabledFg;
222
223 disabledFg = Tk_GetColorFromObj(menuPtr->tkwin,
224 menuPtr->disabledFgPtr);
225 gcValues.foreground = disabledFg->pixel;
226 mask = GCForeground|GCBackground|GCFont;
227 } else {
228 gcValues.foreground = gcValues.background;
229 mask = GCForeground;
230 if (menuPtr->gray == None) {
231 menuPtr->gray = Tk_GetBitmap(menuPtr->interp, menuPtr->tkwin,
232 "gray50");
233 }
234 if (menuPtr->gray != None) {
235 gcValues.fill_style = FillStippled;
236 gcValues.stipple = menuPtr->gray;
237 mask = GCForeground|GCFillStyle|GCStipple;
238 }
239 }
240 newGC = Tk_GetGC(menuPtr->tkwin, mask, &gcValues);
241 if (menuPtr->disabledGC != None) {
242 Tk_FreeGC(menuPtr->display, menuPtr->disabledGC);
243 }
244 menuPtr->disabledGC = newGC;
245
246 gcValues.foreground = Tk_3DBorderColor(border)->pixel;
247 if (menuPtr->gray == None) {
248 menuPtr->gray = Tk_GetBitmap(menuPtr->interp, menuPtr->tkwin,
249 "gray50");
250 }
251 if (menuPtr->gray != None) {
252 gcValues.fill_style = FillStippled;
253 gcValues.stipple = menuPtr->gray;
254 newGC = Tk_GetGC(menuPtr->tkwin,
255 GCForeground|GCFillStyle|GCStipple, &gcValues);
256 }
257 if (menuPtr->disabledImageGC != None) {
258 Tk_FreeGC(menuPtr->display, menuPtr->disabledImageGC);
259 }
260 menuPtr->disabledImageGC = newGC;
261
262 gcValues.font = Tk_FontId(tkfont);
263 activeFg = Tk_GetColorFromObj(menuPtr->tkwin, menuPtr->activeFgPtr);
264 gcValues.foreground = activeFg->pixel;
265 activeBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin,
266 menuPtr->activeBorderPtr);
267 gcValues.background = Tk_3DBorderColor(activeBorder)->pixel;
268 newGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCBackground|GCFont,
269 &gcValues);
270 if (menuPtr->activeGC != None) {
271 Tk_FreeGC(menuPtr->display, menuPtr->activeGC);
272 }
273 menuPtr->activeGC = newGC;
274
275 indicatorFg = Tk_GetColorFromObj(menuPtr->tkwin,
276 menuPtr->indicatorFgPtr);
277 gcValues.foreground = indicatorFg->pixel;
278 gcValues.background = Tk_3DBorderColor(border)->pixel;
279 newGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCBackground|GCFont,
280 &gcValues);
281 if (menuPtr->indicatorGC != None) {
282 Tk_FreeGC(menuPtr->display, menuPtr->indicatorGC);
283 }
284 menuPtr->indicatorGC = newGC;
285 }
286
287 /*
288 *----------------------------------------------------------------------
289 *
290 * TkMenuConfigureEntryDrawOptions --
291 *
292 * Calculates any entry-specific draw options for the given menu
293 * entry.
294 *
295 * Results:
296 * Returns a standard Tcl error.
297 *
298 * Side effects:
299 * Storage may be allocated.
300 *
301 *----------------------------------------------------------------------
302 */
303
304 int
305 TkMenuConfigureEntryDrawOptions(mePtr, index)
306 TkMenuEntry *mePtr;
307 int index;
308 {
309
310 XGCValues gcValues;
311 GC newGC, newActiveGC, newDisabledGC, newIndicatorGC;
312 unsigned long mask;
313 Tk_Font tkfont;
314 TkMenu *menuPtr = mePtr->menuPtr;
315
316 tkfont = Tk_GetFontFromObj(menuPtr->tkwin,
317 (mePtr->fontPtr != NULL) ? mePtr->fontPtr : menuPtr->fontPtr);
318
319 if (mePtr->state == ENTRY_ACTIVE) {
320 if (index != menuPtr->active) {
321 TkActivateMenuEntry(menuPtr, index);
322 }
323 } else {
324 if (index == menuPtr->active) {
325 TkActivateMenuEntry(menuPtr, -1);
326 }
327 }
328
329 if ((mePtr->fontPtr != NULL)
330 || (mePtr->borderPtr != NULL)
331 || (mePtr->fgPtr != NULL)
332 || (mePtr->activeBorderPtr != NULL)
333 || (mePtr->activeFgPtr != NULL)
334 || (mePtr->indicatorFgPtr != NULL)) {
335 XColor *fg, *indicatorFg, *activeFg;
336 Tk_3DBorder border, activeBorder;
337
338 fg = Tk_GetColorFromObj(menuPtr->tkwin, (mePtr->fgPtr != NULL)
339 ? mePtr->fgPtr : menuPtr->fgPtr);
340 gcValues.foreground = fg->pixel;
341 border = Tk_Get3DBorderFromObj(menuPtr->tkwin,
342 (mePtr->borderPtr != NULL) ? mePtr->borderPtr
343 : menuPtr->borderPtr);
344 gcValues.background = Tk_3DBorderColor(border)->pixel;
345
346 gcValues.font = Tk_FontId(tkfont);
347
348 /*
349 * Note: disable GraphicsExpose events; we know there won't be
350 * obscured areas when copying from an off-screen pixmap to the
351 * screen and this gets rid of unnecessary events.
352 */
353
354 gcValues.graphics_exposures = False;
355 newGC = Tk_GetGC(menuPtr->tkwin,
356 GCForeground|GCBackground|GCFont|GCGraphicsExposures,
357 &gcValues);
358
359 indicatorFg = Tk_GetColorFromObj(menuPtr->tkwin,
360 (mePtr->indicatorFgPtr != NULL) ? mePtr->indicatorFgPtr
361 : menuPtr->indicatorFgPtr);
362 gcValues.foreground = indicatorFg->pixel;
363 newIndicatorGC = Tk_GetGC(menuPtr->tkwin,
364 GCForeground|GCBackground|GCGraphicsExposures,
365 &gcValues);
366
367 if ((menuPtr->disabledFgPtr != NULL) || (mePtr->image != NULL)) {
368 XColor *disabledFg;
369
370 disabledFg = Tk_GetColorFromObj(menuPtr->tkwin,
371 menuPtr->disabledFgPtr);
372 gcValues.foreground = disabledFg->pixel;
373 mask = GCForeground|GCBackground|GCFont|GCGraphicsExposures;
374 } else {
375 gcValues.foreground = gcValues.background;
376 gcValues.fill_style = FillStippled;
377 gcValues.stipple = menuPtr->gray;
378 mask = GCForeground|GCFillStyle|GCStipple;
379 }
380 newDisabledGC = Tk_GetGC(menuPtr->tkwin, mask, &gcValues);
381
382 activeFg = Tk_GetColorFromObj(menuPtr->tkwin,
383 (mePtr->activeFgPtr != NULL) ? mePtr->activeFgPtr
384 : menuPtr->activeFgPtr);
385 activeBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin,
386 (mePtr->activeBorderPtr != NULL) ? mePtr->activeBorderPtr
387 : menuPtr->activeBorderPtr);
388
389 gcValues.foreground = activeFg->pixel;
390 gcValues.background = Tk_3DBorderColor(activeBorder)->pixel;
391 newActiveGC = Tk_GetGC(menuPtr->tkwin,
392 GCForeground|GCBackground|GCFont|GCGraphicsExposures,
393 &gcValues);
394 } else {
395 newGC = None;
396 newActiveGC = None;
397 newDisabledGC = None;
398 newIndicatorGC = None;
399 }
400 if (mePtr->textGC != None) {
401 Tk_FreeGC(menuPtr->display, mePtr->textGC);
402 }
403 mePtr->textGC = newGC;
404 if (mePtr->activeGC != None) {
405 Tk_FreeGC(menuPtr->display, mePtr->activeGC);
406 }
407 mePtr->activeGC = newActiveGC;
408 if (mePtr->disabledGC != None) {
409 Tk_FreeGC(menuPtr->display, mePtr->disabledGC);
410 }
411 mePtr->disabledGC = newDisabledGC;
412 if (mePtr->indicatorGC != None) {
413 Tk_FreeGC(menuPtr->display, mePtr->indicatorGC);
414 }
415 mePtr->indicatorGC = newIndicatorGC;
416 return TCL_OK;
417 }
418
419 /*
420 *----------------------------------------------------------------------
421 *
422 * TkEventuallyRecomputeMenu --
423 *
424 * Tells Tcl to redo the geometry because this menu has changed.
425 *
426 * Results:
427 * None.
428 *
429 * Side effects:
430 * Menu geometry is recomputed at idle time, and the menu will be
431 * redisplayed.
432 *
433 *----------------------------------------------------------------------
434 */
435
436 void
437 TkEventuallyRecomputeMenu(menuPtr)
438 TkMenu *menuPtr;
439 {
440 if (!(menuPtr->menuFlags & RESIZE_PENDING)) {
441 menuPtr->menuFlags |= RESIZE_PENDING;
442 Tcl_DoWhenIdle(ComputeMenuGeometry, (ClientData) menuPtr);
443 }
444 }
445
446 /*
447 *----------------------------------------------------------------------
448 *
449 * TkRecomputeMenu --
450 *
451 * Tells Tcl to redo the geometry because this menu has changed.
452 * Does it now; removes any ComputeMenuGeometries from the idler.
453 *
454 * Results:
455 * None.
456 *
457 * Side effects:
458 * Menu geometry is immediately reconfigured.
459 *
460 *----------------------------------------------------------------------
461 */
462
463 void
464 TkRecomputeMenu(menuPtr)
465 TkMenu *menuPtr;
466 {
467 if (menuPtr->menuFlags & RESIZE_PENDING) {
468 Tcl_CancelIdleCall(ComputeMenuGeometry, (ClientData) menuPtr);
469 ComputeMenuGeometry((ClientData) menuPtr);
470 }
471 }
472
473 /*
474 *----------------------------------------------------------------------
475 *
476 * TkEventuallyRedrawMenu --
477 *
478 * Arrange for an entry of a menu, or the whole menu, to be
479 * redisplayed at some point in the future.
480 *
481 * Results:
482 * None.
483 *
484 * Side effects:
485 * A when-idle hander is scheduled to do the redisplay, if there
486 * isn't one already scheduled.
487 *
488 *----------------------------------------------------------------------
489 */
490
491 void
492 TkEventuallyRedrawMenu(menuPtr, mePtr)
493 register TkMenu *menuPtr; /* Information about menu to redraw. */
494 register TkMenuEntry *mePtr;/* Entry to redraw. NULL means redraw
495 * all the entries in the menu. */
496 {
497 int i;
498
499 if (menuPtr->tkwin == NULL) {
500 return;
501 }
502 if (mePtr != NULL) {
503 mePtr->entryFlags |= ENTRY_NEEDS_REDISPLAY;
504 } else {
505 for (i = 0; i < menuPtr->numEntries; i++) {
506 menuPtr->entries[i]->entryFlags |= ENTRY_NEEDS_REDISPLAY;
507 }
508 }
509 if (!Tk_IsMapped(menuPtr->tkwin)
510 || (menuPtr->menuFlags & REDRAW_PENDING)) {
511 return;
512 }
513 Tcl_DoWhenIdle(DisplayMenu, (ClientData) menuPtr);
514 menuPtr->menuFlags |= REDRAW_PENDING;
515 }
516
517 /*
518 *--------------------------------------------------------------
519 *
520 * ComputeMenuGeometry --
521 *
522 * This procedure is invoked to recompute the size and
523 * layout of a menu. It is called as a when-idle handler so
524 * that it only gets done once, even if a group of changes is
525 * made to the menu.
526 *
527 * Results:
528 * None.
529 *
530 * Side effects:
531 * Fields of menu entries are changed to reflect their
532 * current positions, and the size of the menu window
533 * itself may be changed.
534 *
535 *--------------------------------------------------------------
536 */
537
538 static void
539 ComputeMenuGeometry(clientData)
540 ClientData clientData; /* Structure describing menu. */
541 {
542 TkMenu *menuPtr = (TkMenu *) clientData;
543
544 if (menuPtr->tkwin == NULL) {
545 return;
546 }
547
548 if (menuPtr->menuType == MENUBAR) {
549 TkpComputeMenubarGeometry(menuPtr);
550 } else {
551 TkpComputeStandardMenuGeometry(menuPtr);
552 }
553
554 if ((menuPtr->totalWidth != Tk_ReqWidth(menuPtr->tkwin)) ||
555 (menuPtr->totalHeight != Tk_ReqHeight(menuPtr->tkwin))) {
556 Tk_GeometryRequest(menuPtr->tkwin, menuPtr->totalWidth,
557 menuPtr->totalHeight);
558 }
559
560 /*
561 * Must always force a redisplay here if the window is mapped
562 * (even if the size didn't change, something else might have
563 * changed in the menu, such as a label or accelerator). The
564 * resize will force a redisplay above.
565 */
566
567 TkEventuallyRedrawMenu(menuPtr, (TkMenuEntry *) NULL);
568
569 menuPtr->menuFlags &= ~RESIZE_PENDING;
570 }
571
572 /*
573 *----------------------------------------------------------------------
574 *
575 * TkMenuSelectImageProc --
576 *
577 * This procedure is invoked by the image code whenever the manager
578 * for an image does something that affects the size of contents
579 * of an image displayed in a menu entry when it is selected.
580 *
581 * Results:
582 * None.
583 *
584 * Side effects:
585 * Arranges for the menu to get redisplayed.
586 *
587 *----------------------------------------------------------------------
588 */
589
590 void
591 TkMenuSelectImageProc(clientData, x, y, width, height, imgWidth,
592 imgHeight)
593 ClientData clientData; /* Pointer to widget record. */
594 int x, y; /* Upper left pixel (within image)
595 * that must be redisplayed. */
596 int width, height; /* Dimensions of area to redisplay
597 * (may be <= 0). */
598 int imgWidth, imgHeight; /* New dimensions of image. */
599 {
600 register TkMenuEntry *mePtr = (TkMenuEntry *) clientData;
601
602 if ((mePtr->entryFlags & ENTRY_SELECTED)
603 && !(mePtr->menuPtr->menuFlags &
604 REDRAW_PENDING)) {
605 mePtr->menuPtr->menuFlags |= REDRAW_PENDING;
606 Tcl_DoWhenIdle(DisplayMenu, (ClientData) mePtr->menuPtr);
607 }
608 }
609
610 /*
611 *----------------------------------------------------------------------
612 *
613 * DisplayMenu --
614 *
615 * This procedure is invoked to display a menu widget.
616 *
617 * Results:
618 * None.
619 *
620 * Side effects:
621 * Commands are output to X to display the menu in its
622 * current mode.
623 *
624 *----------------------------------------------------------------------
625 */
626
627 static void
628 DisplayMenu(clientData)
629 ClientData clientData; /* Information about widget. */
630 {
631 register TkMenu *menuPtr = (TkMenu *) clientData;
632 register TkMenuEntry *mePtr;
633 register Tk_Window tkwin = menuPtr->tkwin;
634 int index, strictMotif;
635 Tk_Font tkfont;
636 Tk_FontMetrics menuMetrics;
637 int width;
638 int borderWidth;
639 Tk_3DBorder border;
640 int activeBorderWidth;
641 int relief;
642
643
644 menuPtr->menuFlags &= ~REDRAW_PENDING;
645 if ((menuPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
646 return;
647 }
648
649 Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
650 &borderWidth);
651 border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr);
652 Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
653 menuPtr->activeBorderWidthPtr, &activeBorderWidth);
654
655 if (menuPtr->menuType == MENUBAR) {
656 Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border, borderWidth,
657 borderWidth, Tk_Width(tkwin) - 2 * borderWidth,
658 Tk_Height(tkwin) - 2 * borderWidth, 0, TK_RELIEF_FLAT);
659 }
660
661 strictMotif = Tk_StrictMotif(menuPtr->tkwin);
662
663 /*
664 * See note in ComputeMenuGeometry. We don't want to be doing font metrics
665 * all of the time.
666 */
667
668 tkfont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr);
669 Tk_GetFontMetrics(tkfont, &menuMetrics);
670
671 /*
672 * Loop through all of the entries, drawing them one at a time.
673 */
674
675 for (index = 0; index < menuPtr->numEntries; index++) {
676 mePtr = menuPtr->entries[index];
677 if (menuPtr->menuType != MENUBAR) {
678 if (!(mePtr->entryFlags & ENTRY_NEEDS_REDISPLAY)) {
679 continue;
680 }
681 }
682 mePtr->entryFlags &= ~ENTRY_NEEDS_REDISPLAY;
683
684 if (menuPtr->menuType == MENUBAR) {
685 width = mePtr->width;
686 } else {
687 if (mePtr->entryFlags & ENTRY_LAST_COLUMN) {
688 width = Tk_Width(menuPtr->tkwin) - mePtr->x
689 - activeBorderWidth;
690 } else {
691 width = mePtr->width + borderWidth;
692 }
693 }
694 TkpDrawMenuEntry(mePtr, Tk_WindowId(menuPtr->tkwin), tkfont,
695 &menuMetrics, mePtr->x, mePtr->y, width,
696 mePtr->height, strictMotif, 1);
697 if ((index > 0) && (menuPtr->menuType != MENUBAR)
698 && mePtr->columnBreak) {
699 mePtr = menuPtr->entries[index - 1];
700 Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border,
701 mePtr->x, mePtr->y + mePtr->height,
702 mePtr->width,
703 Tk_Height(tkwin) - mePtr->y - mePtr->height -
704 activeBorderWidth, 0,
705 TK_RELIEF_FLAT);
706 }
707 }
708
709 if (menuPtr->menuType != MENUBAR) {
710 int x, y, height;
711
712 if (menuPtr->numEntries == 0) {
713 x = y = borderWidth;
714 width = Tk_Width(tkwin) - 2 * activeBorderWidth;
715 height = Tk_Height(tkwin) - 2 * activeBorderWidth;
716 } else {
717 mePtr = menuPtr->entries[menuPtr->numEntries - 1];
718 Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin),
719 border, mePtr->x, mePtr->y + mePtr->height, mePtr->width,
720 Tk_Height(tkwin) - mePtr->y - mePtr->height
721 - activeBorderWidth, 0,
722 TK_RELIEF_FLAT);
723 x = mePtr->x + mePtr->width;
724 y = mePtr->y + mePtr->height;
725 width = Tk_Width(tkwin) - x - activeBorderWidth;
726 height = Tk_Height(tkwin) - y - activeBorderWidth;
727 }
728 Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border, x, y,
729 width, height, 0, TK_RELIEF_FLAT);
730 }
731
732 Tk_GetReliefFromObj(NULL, menuPtr->reliefPtr, &relief);
733 Tk_Draw3DRectangle(menuPtr->tkwin, Tk_WindowId(tkwin),
734 border, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), borderWidth,
735 relief);
736 }
737
738 /*
739 *--------------------------------------------------------------
740 *
741 * TkMenuEventProc --
742 *
743 * This procedure is invoked by the Tk dispatcher for various
744 * events on menus.
745 *
746 * Results:
747 * None.
748 *
749 * Side effects:
750 * When the window gets deleted, internal structures get
751 * cleaned up. When it gets exposed, it is redisplayed.
752 *
753 *--------------------------------------------------------------
754 */
755
756 void
757 TkMenuEventProc(clientData, eventPtr)
758 ClientData clientData; /* Information about window. */
759 XEvent *eventPtr; /* Information about event. */
760 {
761 TkMenu *menuPtr = (TkMenu *) clientData;
762
763 if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
764 TkEventuallyRedrawMenu(menuPtr, (TkMenuEntry *) NULL);
765 } else if (eventPtr->type == ConfigureNotify) {
766 TkEventuallyRecomputeMenu(menuPtr);
767 TkEventuallyRedrawMenu(menuPtr, (TkMenuEntry *) NULL);
768 } else if (eventPtr->type == ActivateNotify) {
769 if (menuPtr->menuType == TEAROFF_MENU) {
770 TkpSetMainMenubar(menuPtr->interp, menuPtr->tkwin, NULL);
771 }
772 } else if (eventPtr->type == DestroyNotify) {
773 if (menuPtr->tkwin != NULL) {
774 TkDestroyMenu(menuPtr);
775 menuPtr->tkwin = NULL;
776 Tcl_DeleteCommandFromToken(menuPtr->interp, menuPtr->widgetCmd);
777 }
778 if (menuPtr->menuFlags & REDRAW_PENDING) {
779 Tcl_CancelIdleCall(DisplayMenu, (ClientData) menuPtr);
780 }
781 if (menuPtr->menuFlags & RESIZE_PENDING) {
782 Tcl_CancelIdleCall(ComputeMenuGeometry, (ClientData) menuPtr);
783 }
784 Tcl_EventuallyFree((ClientData) menuPtr, TCL_DYNAMIC);
785 }
786 }
787
788 /*
789 *----------------------------------------------------------------------
790 *
791 * TkMenuImageProc --
792 *
793 * This procedure is invoked by the image code whenever the manager
794 * for an image does something that affects the size of contents
795 * of an image displayed in a menu entry.
796 *
797 * Results:
798 * None.
799 *
800 * Side effects:
801 * Arranges for the menu to get redisplayed.
802 *
803 *----------------------------------------------------------------------
804 */
805
806 void
807 TkMenuImageProc(clientData, x, y, width, height, imgWidth,
808 imgHeight)
809 ClientData clientData; /* Pointer to widget record. */
810 int x, y; /* Upper left pixel (within image)
811 * that must be redisplayed. */
812 int width, height; /* Dimensions of area to redisplay
813 * (may be <= 0). */
814 int imgWidth, imgHeight; /* New dimensions of image. */
815 {
816 register TkMenu *menuPtr = ((TkMenuEntry *)clientData)->menuPtr;
817
818 if ((menuPtr->tkwin != NULL) && !(menuPtr->menuFlags
819 & RESIZE_PENDING)) {
820 menuPtr->menuFlags |= RESIZE_PENDING;
821 Tcl_DoWhenIdle(ComputeMenuGeometry, (ClientData) menuPtr);
822 }
823 }
824
825 /*
826 *----------------------------------------------------------------------
827 *
828 * TkPostTearoffMenu --
829 *
830 * Posts a menu on the screen. Used to post tearoff menus. On Unix,
831 * all menus are posted this way. Adjusts the menu's position
832 * so that it fits on the screen, and maps and raises the menu.
833 *
834 * Results:
835 * Returns a standard Tcl Error.
836 *
837 * Side effects:
838 * The menu is posted.
839 *
840 *----------------------------------------------------------------------
841 */
842
843 int
844 TkPostTearoffMenu(interp, menuPtr, x, y)
845 Tcl_Interp *interp; /* The interpreter of the menu */
846 TkMenu *menuPtr; /* The menu we are posting */
847 int x; /* The root X coordinate where we
848 * are posting */
849 int y; /* The root Y coordinate where we
850 * are posting */
851 {
852 int vRootX, vRootY, vRootWidth, vRootHeight;
853 int tmp, result;
854
855 TkActivateMenuEntry(menuPtr, -1);
856 TkRecomputeMenu(menuPtr);
857 result = TkPostCommand(menuPtr);
858 if (result != TCL_OK) {
859 return result;
860 }
861
862 /*
863 * The post commands could have deleted the menu, which means
864 * we are dead and should go away.
865 */
866
867 if (menuPtr->tkwin == NULL) {
868 return TCL_OK;
869 }
870
871 /*
872 * Adjust the position of the menu if necessary to keep it
873 * visible on the screen. There are two special tricks to
874 * make this work right:
875 *
876 * 1. If a virtual root window manager is being used then
877 * the coordinates are in the virtual root window of
878 * menuPtr's parent; since the menu uses override-redirect
879 * mode it will be in the *real* root window for the screen,
880 * so we have to map the coordinates from the virtual root
881 * (if any) to the real root. Can't get the virtual root
882 * from the menu itself (it will never be seen by the wm)
883 * so use its parent instead (it would be better to have an
884 * an option that names a window to use for this...).
885 * 2. The menu may not have been mapped yet, so its current size
886 * might be the default 1x1. To compute how much space it
887 * needs, use its requested size, not its actual size.
888 *
889 * Note that this code assumes square screen regions and all
890 * positive coordinates. This does not work on a Mac with
891 * multiple monitors. But then again, Tk has other problems
892 * with this.
893 */
894
895 Tk_GetVRootGeometry(Tk_Parent(menuPtr->tkwin), &vRootX, &vRootY,
896 &vRootWidth, &vRootHeight);
897 x += vRootX;
898 y += vRootY;
899 tmp = WidthOfScreen(Tk_Screen(menuPtr->tkwin))
900 - Tk_ReqWidth(menuPtr->tkwin);
901 if (x > tmp) {
902 x = tmp;
903 }
904 if (x < 0) {
905 x = 0;
906 }
907 tmp = HeightOfScreen(Tk_Screen(menuPtr->tkwin))
908 - Tk_ReqHeight(menuPtr->tkwin);
909 if (y > tmp) {
910 y = tmp;
911 }
912 if (y < 0) {
913 y = 0;
914 }
915 Tk_MoveToplevelWindow(menuPtr->tkwin, x, y);
916 if (!Tk_IsMapped(menuPtr->tkwin)) {
917 Tk_MapWindow(menuPtr->tkwin);
918 }
919 TkWmRestackToplevel((TkWindow *) menuPtr->tkwin, Above, NULL);
920 return TCL_OK;
921 }
922
923 /*
924 *--------------------------------------------------------------
925 *
926 * TkPostSubmenu --
927 *
928 * This procedure arranges for a particular submenu (i.e. the
929 * menu corresponding to a given cascade entry) to be
930 * posted.
931 *
932 * Results:
933 * A standard Tcl return result. Errors may occur in the
934 * Tcl commands generated to post and unpost submenus.
935 *
936 * Side effects:
937 * If there is already a submenu posted, it is unposted.
938 * The new submenu is then posted.
939 *
940 *--------------------------------------------------------------
941 */
942
943 int
944 TkPostSubmenu(interp, menuPtr, mePtr)
945 Tcl_Interp *interp; /* Used for invoking sub-commands and
946 * reporting errors. */
947 register TkMenu *menuPtr; /* Information about menu as a whole. */
948 register TkMenuEntry *mePtr; /* Info about submenu that is to be
949 * posted. NULL means make sure that
950 * no submenu is posted. */
951 {
952 int result, x, y;
953
954 if (mePtr == menuPtr->postedCascade) {
955 return TCL_OK;
956 }
957
958 if (menuPtr->postedCascade != NULL) {
959 char *name = Tcl_GetStringFromObj(menuPtr->postedCascade->namePtr,
960 NULL);
961
962 /*
963 * Note: when unposting a submenu, we have to redraw the entire
964 * parent menu. This is because of a combination of the following
965 * things:
966 * (a) the submenu partially overlaps the parent.
967 * (b) the submenu specifies "save under", which causes the X
968 * server to make a copy of the information under it when it
969 * is posted. When the submenu is unposted, the X server
970 * copies this data back and doesn't generate any Expose
971 * events for the parent.
972 * (c) the parent may have redisplayed itself after the submenu
973 * was posted, in which case the saved information is no
974 * longer correct.
975 * The simplest solution is just force a complete redisplay of
976 * the parent.
977 */
978
979 TkEventuallyRedrawMenu(menuPtr, (TkMenuEntry *) NULL);
980 result = Tcl_VarEval(interp, name, " unpost", (char *) NULL);
981 menuPtr->postedCascade = NULL;
982 if (result != TCL_OK) {
983 return result;
984 }
985 }
986
987 if ((mePtr != NULL) && (mePtr->namePtr != NULL)
988 && Tk_IsMapped(menuPtr->tkwin)) {
989 /*
990 * Position the cascade with its upper left corner slightly
991 * below and to the left of the upper right corner of the
992 * menu entry (this is an attempt to match Motif behavior).
993 *
994 * The menu has to redrawn so that the entry can change relief.
995 */
996
997 char string[TCL_INTEGER_SPACE * 2];
998 char *name;
999
1000 name = Tcl_GetStringFromObj(mePtr->namePtr, NULL);
1001 Tk_GetRootCoords(menuPtr->tkwin, &x, &y);
1002 AdjustMenuCoords(menuPtr, mePtr, &x, &y, string);
1003 result = Tcl_VarEval(interp, name, " post ", string, (char *) NULL);
1004 if (result != TCL_OK) {
1005 return result;
1006 }
1007 menuPtr->postedCascade = mePtr;
1008 TkEventuallyRedrawMenu(menuPtr, mePtr);
1009 }
1010 return TCL_OK;
1011 }
1012
1013 /*
1014 *----------------------------------------------------------------------
1015 *
1016 * AdjustMenuCoords --
1017 *
1018 * Adjusts the given coordinates down and the left to give a Motif
1019 * look.
1020 *
1021 * Results:
1022 * None.
1023 *
1024 * Side effects:
1025 * The menu is eventually redrawn if necessary.
1026 *
1027 *----------------------------------------------------------------------
1028 */
1029
1030 static void
1031 AdjustMenuCoords(menuPtr, mePtr, xPtr, yPtr, string)
1032 TkMenu *menuPtr;
1033 TkMenuEntry *mePtr;
1034 int *xPtr;
1035 int *yPtr;
1036 char *string;
1037 {
1038 if (menuPtr->menuType == MENUBAR) {
1039 *xPtr += mePtr->x;
1040 *yPtr += mePtr->y + mePtr->height;
1041 } else {
1042 int borderWidth, activeBorderWidth;
1043
1044 Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
1045 &borderWidth);
1046 Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
1047 menuPtr->activeBorderWidthPtr, &activeBorderWidth);
1048 *xPtr += Tk_Width(menuPtr->tkwin) - borderWidth - activeBorderWidth
1049 - 2;
1050 *yPtr += mePtr->y + activeBorderWidth + 2;
1051 }
1052 sprintf(string, "%d %d", *xPtr, *yPtr);
1053 }
1054
1055 /* End of tkmenudraw.c */

Properties

Name Value
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25