libDtSvc: Change to ANSI function definitions
[oweals/cde.git] / cde / lib / DtWidget / MenuButton.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: MenuButton.c /main/9 1998/04/09 17:51:40 mgreess $
24  *
25  * (c) Copyright 1996 Digital Equipment Corporation.
26  * (c) Copyright 1996 Hewlett-Packard Company.
27  * (c) Copyright 1996 International Business Machines Corp.
28  * (c) Copyright 1986, 1991, 1996 Sun Microsystems, Inc.
29  * (c) Copyright 1996 Novell, Inc. 
30  * (c) Copyright 1996 FUJITSU LIMITED.
31  * (c) Copyright 1996 Hitachi.
32  */
33
34 /*
35  *        Copyright (C) 1986,1991  Sun Microsystems, Inc
36  *                    All rights reserved.
37  *          Notice of copyright on this source code
38  *          product does not indicate publication.
39  *
40  * RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by
41  * the U.S. Government is subject to restrictions as set forth
42  * in subparagraph (c)(1)(ii) of the Rights in Technical Data
43  * and Computer Software Clause at DFARS 252.227-7013 (Oct. 1988)
44  * and FAR 52.227-19 (c) (June 1987).
45  *
46  *    Sun Microsystems, Inc., 2550 Garcia Avenue,
47  *    Mountain View, California 94043.
48  *
49  */
50 /*
51  * The DtMenuButton widget is rigged with the Motif widget binary compatibilit
52  * mechanism. All Motif-specific changes for this mechanism are preceded
53  * by a comment including the string "MotifBc".
54  *
55  * For a description of the Motif widget binary compatibility mechanism
56  * see the reference manual entry on XmResolveAllPartOffsets().
57  *
58  */
59
60 #include <Dt/DtMsgsP.h>
61 #include "MenuButtonP.h"
62
63 #include <Xm/LabelP.h>
64 #include <Xm/MenuUtilP.h>
65 #include <Xm/DrawP.h>
66 #include <Xm/XmP.h>
67
68 #include <Xm/XmPrivate.h>   /* _XmRecordEvent, _XmSetInDragMode, ... */
69
70 #include <X11/keysymdef.h>
71 #include "DtWidgetI.h"
72
73 /*
74  * MotifBc
75  */
76 #define DtMenuButtonIndex (XmLabelIndex + 1)
77 static XmOffsetPtr ipot; /* Instance part offset table */
78 static XmOffsetPtr cpot; /* Constraint part offset table */
79
80 #ifndef Max
81 #define Max(x, y)       (((x) > (y)) ? (x) : (y))
82 #endif
83
84 #define GLYPH_PIX_SPACE    4     /* pixels between label and bit map */
85
86 /*
87  * MotifBc
88  */
89 #define CascadingCallback(w) XmField(w,ipot,DtMenuButton,cascading_callback,XtCallbackList)
90 #define MenuRect(w) XmField(w,ipot,DtMenuButton,menu_rect,XRectangle)
91 #define LNormalGC(w) XmField(w,ipot,XmLabel,normal_GC,GC)
92 #define LAlignment(w) XmField(w,ipot,XmLabel,alignment,unsigned char)
93 #define LRecomputeSize(w) XmField(w,ipot,XmLabel,recompute_size,Boolean)
94 #define LLabelType(w) XmField(w,ipot,XmLabel,label_type,unsigned char)
95
96 /* Access macro definitions */
97 #define MB_PVT_SMENU(mb)        XmField(mb,ipot,DtMenuButton,private_submenu,Boolean)
98 #define MB_LAST_TIMESTAMP(mb)   XmField(mb,ipot,DtMenuButton,last_timestamp,Time)
99 #define MB_SMENU(mb)            XmField(mb,ipot,DtMenuButton,submenu,Widget)
100 #define MB_PIXMAP(mb)           XmField(mb,ipot,DtMenuButton,menu_pixmap,Pixmap)
101 #define MB_GLYPH_X(mb)          (XmField(mb,ipot,DtMenuButton,menu_rect,XRectangle)).x
102 #define MB_GLYPH_Y(mb)          (XmField(mb,ipot,DtMenuButton,menu_rect,XRectangle)).y
103 #define MB_GLYPH_WIDTH(mb)      (XmField(mb,ipot,DtMenuButton,menu_rect,XRectangle)).width
104 #define MB_GLYPH_HEIGHT(mb)     (XmField(mb,ipot,DtMenuButton,menu_rect,XRectangle)).height
105 #define MB_ARMED(mb)            XmField(mb,ipot,DtMenuButton,armed,Boolean)
106 #define MB_POPPED_UP(mb)        XmField(mb,ipot,DtMenuButton,popped_up,Boolean)
107 #define MB_GC(mb)               XmField(mb,ipot,DtMenuButton,gc,GC)
108
109
110 /********    Static Function Declarations    ********/
111 static void     ClassInitialize (void);
112
113 static void AdjustMenuButtonSize( 
114         DtMenuButtonWidget menubtn,
115         Boolean adjustWidth,
116         Boolean adjustHeight) ;
117 static void Arm( 
118         DtMenuButtonWidget mb) ;
119 static void ArmAndActivate( 
120         Widget wid,
121         XEvent *event,
122         String *params,
123         Cardinal *num_params) ;
124
125 static void CalculateMenuGlyphSize( 
126         DtMenuButtonWidget menubtn) ;
127 static void CallCascadingCallbacks( 
128         Widget w,
129         XEvent *event) ;
130
131 static void Destroy( 
132         Widget wid) ;
133 static void Disarm( 
134         DtMenuButtonWidget mb,
135         Boolean pop_down) ;
136 static void DrawArrow(
137         Widget wid);
138 static void Draw3DShadows( 
139         DtMenuButtonWidget mb) ;
140 static void DrawMenuGlyph( 
141         DtMenuButtonWidget mb) ;
142
143 static void GetGC(
144         DtMenuButtonWidget mb);
145
146 static void Initialize( 
147         Widget w_req,
148         Widget w_new,
149         ArgList args,
150         Cardinal *num_args) ;
151
152 static void LocateMenuGlyph( 
153         DtMenuButtonWidget menubtn) ;
154
155 static void MenuButtonHandler( 
156         Widget wid,
157         XtPointer cd,   
158         XEvent *event,
159         Boolean *cont_to_dispatch) ;
160
161 static void Popup(
162         DtMenuButtonWidget mb,
163         XEvent *event,
164         Boolean call_cbacks );
165
166 static void Redisplay( 
167         Widget mb,
168         XEvent *event,
169         Region region) ;
170 static void Resize( 
171         Widget mb) ;
172
173 static void Select( 
174         Widget wid,
175         XEvent *event,
176         String *param,
177         Cardinal *num_param) ;
178 static Boolean SetValues( 
179         Widget cw,
180         Widget rw,
181         Widget nw,
182         ArgList args,
183         Cardinal *num_args) ;
184 static void GetTopManager(
185         Widget w,
186         Widget *topManager) ;
187
188
189 /********    End Static Function Declarations    ********/
190
191
192 /*
193  * event translation tables for menubutton.
194  */
195
196 static char menuButton_translations[] = "\
197         <Key>space:Select()\n\
198         <Key>osfSelect:Select()";
199
200 static XtActionsRec menuButton_actions [] = {
201         {"Select",      Select}
202 };
203         
204 /* MotifBc */
205 #define DtOffset(field) XmPartOffset(DtMenuButton,field)
206 #define XmPrimOffset(field) XmPartOffset(XmPrimitive,field)
207 #define XmLabelOffset(field) XmPartOffset(XmLabel,field)
208 static XmPartResource resources[] = {
209         {       
210         DtNcascadingCallback, 
211         DtCCallback, 
212         XmRCallback,
213         sizeof (XtCallbackList),
214         DtOffset(cascading_callback), 
215         XmRCallback,
216         NULL
217         },
218         {       
219         DtNsubMenuId, 
220         DtCMenuWidget,                          /* submenu */
221         XmRMenuWidget, 
222         sizeof (Widget),
223         DtOffset(submenu), 
224         XmRMenuWidget, 
225         (XtPointer) NULL
226         },
227         {       
228         DtNcascadePixmap, 
229         DtCPixmap, 
230         XmRPrimForegroundPixmap,
231         sizeof(Pixmap),
232         DtOffset(menu_pixmap), 
233         XmRImmediate,
234         (XtPointer) XmUNSPECIFIED_PIXMAP
235         },
236         {
237         XmNshadowThickness,
238         XmCShadowThickness,
239         XmRHorizontalDimension,
240         sizeof (Dimension),
241         XmPrimOffset(shadow_thickness),
242         XmRImmediate,
243         (XtPointer) 2
244         },
245         {
246         XmNtraversalOn,
247         XmCTraversalOn,
248         XmRBoolean,
249         sizeof(Boolean),
250         XmPrimOffset(traversal_on),
251         XmRImmediate,
252         (XtPointer) TRUE
253         },
254         {
255         XmNhighlightThickness,
256         XmCHighlightThickness,
257         XmRHorizontalDimension,
258         sizeof (Dimension),
259         XmPrimOffset(highlight_thickness),
260         XmRImmediate,
261         (XtPointer) 2
262         },
263         {
264         XmNmarginWidth, 
265         XmCMarginWidth, 
266         XmRHorizontalDimension, 
267         sizeof (Dimension),
268         XmLabelOffset(margin_width), 
269         XmRImmediate,
270         (XtPointer)6 
271         },
272         };       
273         
274 externaldef(xmmenubuttonclassrec) 
275         DtMenuButtonClassRec dtMenuButtonClassRec = {
276         {                       /* core class record */
277         (WidgetClass) &xmLabelClassRec,         /* superclass ptr       */
278         "DtMenuButton",                         /* class_name   */
279         sizeof(DtMenuButtonPart),               /* size of Pulldown widget */
280         (XtProc)ClassInitialize,                /* class init proc */
281         NULL,                                   /* chained class init */
282         FALSE,                                  /* class is not init'ed */
283         Initialize,                             /* widget init proc */
284         NULL,                                   /* init_hook proc */
285         XtInheritRealize,                       /* widget realize proc */
286         menuButton_actions,                     /* class action table */
287         XtNumber (menuButton_actions),          /* num of actions */
288         (XtResourceList)resources,              /* this class's resource list*/
289         XtNumber (resources),                   /* resource_count */
290         NULLQUARK,                              /* xrm_class            */
291         TRUE,                                   /* compress motion */
292         XtExposeCompressMaximal,                /* compress exposure */
293         TRUE,                                   /* compress enter-leave */
294         FALSE,                                  /* no VisibilityNotify */
295         Destroy,                                /* class destroy proc */
296         Resize,                                 /* class resize proc */
297         Redisplay,                              /* expose proc */
298         SetValues,                              /* set_value proc */
299         NULL,                                   /* set_value_hook proc */
300         XtInheritSetValuesAlmost,               /* set_value_almost proc */
301         NULL,                                   /* get_values_hook */
302         NULL,                                   /* class accept focus proc */
303         XtVersionDontCheck,                     /* current version */
304         NULL,                                   /* callback offset list */
305         menuButton_translations,                /* default translation table */
306         XtInheritQueryGeometry,                 /* query geo proc */
307         NULL,                                   /* display accelerator*/
308         (XtPointer)NULL,                        /* extension */
309         },
310         {
311                         /* Primitive Class record */
312         XmInheritWidgetProc,                    /* border_highlight */
313         XmInheritWidgetProc,                    /* border_uhighlight */
314         XtInheritTranslations,                  /* translations */
315         ArmAndActivate,                         /* arm & activate */
316         NULL,                                   /* get resources */
317         0,                                      /* num get_resources */
318         (XtPointer)NULL,                        /* extension */
319         },
320         {                       /* Label Class record */
321         XmInheritWidgetProc,                    /* set override callback */
322         XmInheritMenuProc,                      /* menu procedures       */
323         XtInheritTranslations,                  /* menu traversal xlation */
324         NULL,                                   /* extension */
325         },
326         {                       /* menu_button class record */
327             NULL,                               /* extension */  
328         }
329 };
330         
331         
332 /*
333  * Now make a public symbol that points to this class record.
334  */
335         
336 externaldef(dtmenubuttonwidgetclass) 
337         WidgetClass dtMenuButtonWidgetClass = 
338                 (WidgetClass) &dtMenuButtonClassRec;
339         
340 /*
341  * MotifBc, to calculate offset var. ipot
342  */
343 static void
344 ClassInitialize(void)
345 {
346     XmResolveAllPartOffsets(dtMenuButtonWidgetClass, &ipot, &cpot);
347 }
348
349 static void 
350 Draw3DShadows(
351     DtMenuButtonWidget mb )
352 {
353         if (XtIsRealized((Widget)mb))
354           XmeDrawShadows (XtDisplay (mb), XtWindow (mb),
355                 mb->primitive.top_shadow_GC,
356                 mb->primitive.bottom_shadow_GC,
357                 mb->primitive.highlight_thickness,
358                 mb->primitive.highlight_thickness,
359                 mb->core.width - 2 * 
360                 mb->primitive.highlight_thickness,
361                 mb->core.height - 2 * 
362                 mb->primitive.highlight_thickness,
363                 mb->primitive.shadow_thickness,
364                 (MB_ARMED(mb) == TRUE) ? XmSHADOW_IN: XmSHADOW_OUT);
365 }
366         
367         
368 static void 
369 DrawMenuGlyph(
370     DtMenuButtonWidget mb )
371 {
372         if ((MB_GLYPH_WIDTH(mb) != 0)){
373                 if(MB_PIXMAP(mb) != XmUNSPECIFIED_PIXMAP) 
374                         XCopyArea (XtDisplay(mb), 
375                                 MB_PIXMAP(mb), 
376                                 XtWindow(mb),
377                                 LNormalGC(mb), 0, 0, 
378                                 MB_GLYPH_WIDTH(mb), MB_GLYPH_HEIGHT(mb),
379                                 MB_GLYPH_X(mb), MB_GLYPH_Y(mb));
380                 else 
381                         DrawArrow((Widget)mb);
382         }
383 }
384         
385 /*
386  * Redisplay the widget.
387  */
388 static void 
389 Redisplay(
390     Widget mb,
391     XEvent *event,
392     Region region )
393 {
394         if (XtIsRealized (mb)) {
395                 /* Label expose method does the initial work */
396                 XtExposeProc expose;
397                 _DtProcessLock();
398                 expose = xmLabelClassRec.core_class.expose;
399                 _DtProcessUnlock();
400                 (* expose)(mb, event, region) ;
401         
402                 DrawMenuGlyph((DtMenuButtonWidget) mb);
403                 Draw3DShadows ((DtMenuButtonWidget) mb);
404         }
405 }
406
407 static void 
408 Arm(
409     DtMenuButtonWidget mb )
410 {
411         XmProcessTraversal( (Widget) mb, XmTRAVERSE_CURRENT);
412         if (MB_ARMED(mb) == FALSE) {
413                 MB_ARMED(mb) =  TRUE;
414                 DrawMenuGlyph(mb);
415                 Draw3DShadows (mb);
416         }
417 }
418
419 static void 
420 ArmAndActivate(
421     Widget wid,
422     XEvent *event,
423     String *params,
424     Cardinal *num_params )
425 {
426         DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ;
427         
428         if(MB_SMENU(mb) == (Widget)NULL ||
429                 event == (XEvent*) NULL)
430                 return;
431
432         if (!_XmIsEventUnique(event))
433            return;
434         
435         Popup(mb, event, TRUE);
436         _XmSetInDragMode((Widget)mb,FALSE);
437         if (!XmProcessTraversal(MB_SMENU(mb), XmTRAVERSE_CURRENT))
438                    XtSetKeyboardFocus(XtParent(MB_SMENU(mb)), MB_SMENU(mb));
439
440         _XmRecordEvent(event);
441 }
442
443
444 static void 
445 Disarm(
446     DtMenuButtonWidget mb,
447     Boolean pop_down )
448 {
449         if (MB_ARMED(mb) == TRUE) {
450                 MB_ARMED(mb) =  FALSE;
451         
452                 if (pop_down == TRUE    && 
453                         MB_SMENU(mb) != (Widget)NULL)
454                                 XtUnmanageChild(MB_SMENU(mb));
455         
456                 Draw3DShadows(mb);
457                 DrawMenuGlyph(mb);
458         }
459 }
460
461 /*ARGSUSED*/
462 static void 
463 Select(
464     Widget wid,
465     XEvent *event,
466     String *param,
467     Cardinal *num_param )
468 {
469         DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ;
470         XtActionProc arm_and_activate;
471         
472         if(MB_POPPED_UP(mb) == TRUE) {
473                 Disarm(mb,TRUE);
474                 return;
475         }
476         
477         _DtProcessLock();
478         arm_and_activate = ((DtMenuButtonClassRec *)(mb->core.widget_class))->
479                 primitive_class.arm_and_activate;
480         _DtProcessUnlock();
481         (* arm_and_activate) ((Widget) mb, event, NULL, NULL);
482 }
483
484 static void
485 PreMenuButtonHandler(
486     Widget wid,
487     XtPointer cd,
488     XEvent *event,
489 Boolean *cont_to_dispatch)
490 {
491        DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ;
492         
493         if(MB_SMENU(mb) == (Widget)NULL                         ||
494                 event->xany.type != ButtonPress                 ||
495                 event->xbutton.time <= MB_LAST_TIMESTAMP(mb))
496                         return;
497
498         if(event->xbutton.button==Button1||event->xbutton.button==Button3)
499         {
500                 String btnstr=NULL;
501                 XtVaGetValues(MB_SMENU(mb), XmNmenuPost, &btnstr, NULL);
502                 if (btnstr==NULL || !strcmp(btnstr,"") || 
503                     !strcmp(btnstr, "<Btn3Down>"))
504                         event->xbutton.button=Button3;
505                 else if (!strcmp(btnstr, "<Btn1Down>"))
506                         event->xbutton.button=Button1;
507                 else
508                         XtWarning(MB_POST);
509         }
510 }
511
512 static void 
513 MenuButtonHandler(
514     Widget wid,
515     XtPointer cd,
516     XEvent *event,
517 Boolean *cont_to_dispatch)
518 {
519         DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ;
520         
521
522         if(MB_SMENU(mb) == (Widget)NULL                         ||
523                 event->xany.type != ButtonPress                 || 
524                 event->xbutton.time <= MB_LAST_TIMESTAMP(mb))
525                         return;
526         else
527                 MB_LAST_TIMESTAMP(mb) = event->xbutton.time;
528         
529         Popup (mb, event, TRUE);
530
531 }
532
533
534 static void 
535 CallCascadingCallbacks(
536     Widget w,
537     XEvent *event )
538 {
539         DtMenuButtonWidget mb = (DtMenuButtonWidget)w;
540         XmAnyCallbackStruct cback;
541         
542         if(MB_POPPED_UP(mb) == TRUE)
543                 return;
544         
545         cback.reason = DtCR_CASCADING;
546         cback.event = event;
547         
548         XtCallCallbackList ((Widget) mb, 
549                 CascadingCallback(mb), &cback);
550 }
551
552 static void
553 PopdownCallback(Widget w, XtPointer client_data, XtPointer call_data)
554 {
555         DtMenuButtonWidget mb = (DtMenuButtonWidget)client_data;
556
557         Disarm(mb,FALSE);
558         MB_POPPED_UP(mb) = FALSE;
559         MB_LAST_TIMESTAMP(mb) =  XtLastTimestampProcessed(XtDisplay(mb));
560 }
561
562 static void
563 PopupCallback(Widget w, XtPointer client_data, XtPointer call_data)
564 {
565         DtMenuButtonWidget mb = (DtMenuButtonWidget)client_data;
566
567         Arm(mb);
568         MB_POPPED_UP(mb) = TRUE;
569 }
570
571 /*
572  * Call the cascading callbacks and popup any submenu. 
573  */
574
575 static void 
576 Popup(
577     DtMenuButtonWidget mb,
578     XEvent *event,
579     Boolean call_cbacks )
580 {
581         Position x=0, y=0; 
582         Position root_x=0, root_y=0; 
583         Position save_x = 0, save_y = 0;
584         Dimension sw=0, sh=0;
585         int dx = 0, dy = 0;
586         Screen *screen;
587
588         if((MB_SMENU(mb) == (Widget)NULL)       || 
589                 (MB_POPPED_UP(mb) == TRUE))
590                 return;
591         
592         if (call_cbacks)
593                 CallCascadingCallbacks((Widget)mb, event);
594         
595         x =  (Position)((int)XtWidth((Widget)mb) - (int)XtWidth(MB_SMENU(mb)))/2;
596         y  = XtHeight((Widget)mb) - mb->primitive.highlight_thickness + 1;
597         XtTranslateCoords((Widget)mb, x,y, &root_x, &root_y);
598         
599         /* Check if not completely on the screen */
600         screen = XtScreen(mb);
601         sw = WidthOfScreen(screen);
602         sh = HeightOfScreen(screen);
603
604         if((dx = root_x - sw + XtWidth(MB_SMENU(mb))) > 0)
605                 root_x -= dx; 
606         if((dy = root_y - sh + XtHeight(MB_SMENU(mb))) > 0) {
607                 root_y -= (2 - (mb->primitive.highlight_thickness<<1));
608                 root_y -= (XtHeight(mb) + XtHeight(MB_SMENU(mb)));
609         }
610         
611         save_x = event->xbutton.x_root;
612         save_y = event->xbutton.y_root;
613         
614         event->xbutton.x_root = root_x;
615         event->xbutton.y_root = root_y;
616
617         /* Position the menu */
618         XmMenuPosition(MB_SMENU(mb),(XButtonPressedEvent*)event);
619
620         event->xbutton.x_root = save_x;
621         event->xbutton.y_root = save_y;
622         
623         XtManageChild(MB_SMENU(mb));
624 }
625
626 /*
627  * Get the menu glyph size set up.
628  */
629 static void 
630 CalculateMenuGlyphSize(
631     DtMenuButtonWidget menubtn )
632 {
633         Window rootwin;
634         int x,y; /* must be int */
635         unsigned int width, height, border, depth; /* must be int */
636         
637         if (MB_PIXMAP(menubtn) != XmUNSPECIFIED_PIXMAP) {
638            XGetGeometry(XtDisplay(menubtn), MB_PIXMAP(menubtn),
639                         &rootwin, &x, &y, &width, &height,
640                         &border, &depth);
641         
642            MB_GLYPH_WIDTH(menubtn) = (Dimension) width;
643            MB_GLYPH_HEIGHT(menubtn) = (Dimension) height;
644         } else {
645                 int ht, st;
646                 Dimension side;
647                 unsigned int text_height;
648         
649                 ht = menubtn->primitive.highlight_thickness;
650                 st = menubtn->primitive.shadow_thickness;
651                 text_height = Lab_TextRect_height(menubtn);
652         
653                 side = Max( (text_height * 2 / 3) + 2 * (ht + st),
654                    (2*(ht + (st-1) +1)) +1 );
655                 MB_GLYPH_WIDTH(menubtn) = 
656                 MB_GLYPH_HEIGHT(menubtn) = side;
657         }
658 }
659
660 /*
661  * Set up the menu glyph location.  
662  */
663 static void 
664 LocateMenuGlyph(
665     DtMenuButtonWidget menubtn )
666 {
667         Dimension buffer;
668         
669         MB_GLYPH_X(menubtn) = 
670                 XtWidth (menubtn) -
671                 menubtn->primitive.highlight_thickness -
672                 menubtn->primitive.shadow_thickness -
673                 Lab_MarginWidth(menubtn) -
674                 MB_GLYPH_WIDTH(menubtn);
675         
676         buffer = menubtn->primitive.highlight_thickness +
677                          menubtn->primitive.shadow_thickness +
678                          Lab_MarginHeight(menubtn);
679         
680         MB_GLYPH_Y(menubtn) = (Position)((int)buffer +
681                 (((int)XtHeight(menubtn) -  2*(int)buffer) - 
682                         (int)MB_GLYPH_HEIGHT(menubtn)) / 2);
683 }
684
685 /*
686  * Make room for  menu glyph  in menu button.
687  */
688 static void 
689 AdjustMenuButtonSize(
690     DtMenuButtonWidget menubtn,
691     Boolean adjustWidth,
692     Boolean adjustHeight )
693 {
694         Dimension delta;
695         
696         /*
697          *  Modify the size of the menubutton to acommadate the menu.
698          *  The menu should fit inside MarginRight.
699          */
700         if ((int)(MB_GLYPH_WIDTH(menubtn) + GLYPH_PIX_SPACE) >
701                                         (int)Lab_MarginRight(menubtn)) {
702                 delta = MB_GLYPH_WIDTH(menubtn) + GLYPH_PIX_SPACE -
703                 Lab_MarginRight(menubtn);
704                 Lab_MarginRight(menubtn) += delta;
705         
706                 if (adjustWidth)
707                         XtWidth(menubtn) += delta;
708                 else {
709                         if (LAlignment(menubtn) == XmALIGNMENT_END)
710                                 Lab_TextRect_x(menubtn) -= delta;
711                         else 
712                                 if (LAlignment(menubtn) == XmALIGNMENT_CENTER)
713                                         Lab_TextRect_x(menubtn) -= delta/2;
714                 }
715         }
716         
717         /*
718          * the menu height should fit inside of 
719          * TextRect + marginTop + marginBottom
720          */
721         delta = MB_GLYPH_HEIGHT(menubtn) +
722                 2 * (Lab_MarginHeight(menubtn) +
723                 menubtn->primitive.shadow_thickness +
724                 menubtn->primitive.highlight_thickness);
725         
726         if (delta > XtHeight(menubtn)) {
727                 delta -= XtHeight(menubtn);
728                 Lab_MarginTop(menubtn) += delta/2;
729                 Lab_TextRect_y(menubtn) += delta/2;
730                 Lab_MarginBottom(menubtn) += delta - (delta/2);
731          
732                 if (adjustHeight)
733                         XtHeight(menubtn) += delta;
734         }
735         
736         LocateMenuGlyph(menubtn);
737 }
738
739 /*
740  * Destroy the widget
741  */
742 static void 
743 Destroy(
744     Widget wid )
745 {
746         DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ;
747         XmRowColumnWidget submenu = (XmRowColumnWidget) MB_SMENU(mb);
748         Widget shell;
749         
750         XtRemoveAllCallbacks ((Widget) mb, DtNcascadingCallback);
751         
752         if(submenu != (XmRowColumnWidget)NULL) {
753                 shell = XtParent((Widget)submenu);
754                 XtRemoveCallback(shell, XtNpopupCallback,PopupCallback, (XtPointer)mb);
755                 XtRemoveCallback(shell, XtNpopdownCallback, PopdownCallback,(XtPointer)mb);
756         }
757         
758         if(MB_PVT_SMENU(mb) == TRUE) {
759                 XtDestroyWidget((Widget)submenu);
760                 MB_SMENU(mb) = NULL;
761                 MB_PVT_SMENU(mb) = FALSE;
762         }
763 }
764                      
765 /*
766  * Resize Method.
767  */
768 static void 
769 Resize(
770     Widget mb )
771 {
772         if (mb != (Widget)NULL) {
773                 /* Label resize method lays out the label string */
774                 XtWidgetProc resize;
775                 _DtProcessLock();
776                 resize = xmLabelClassRec.core_class.resize;
777                 _DtProcessUnlock();
778                 (* resize) (mb);
779
780                 LocateMenuGlyph ((DtMenuButtonWidget) mb);
781         }
782 }
783
784 /*
785  * Set Values Method.
786  */
787 static Boolean 
788 SetValues(
789     Widget cw,
790     Widget rw,
791     Widget nw,
792     ArgList args,
793     Cardinal *num_args )
794 {
795         DtMenuButtonWidget old = (DtMenuButtonWidget) cw ;
796         DtMenuButtonWidget requested = (DtMenuButtonWidget) rw ;
797         DtMenuButtonWidget new_w = (DtMenuButtonWidget) nw ;
798         Boolean flag = FALSE;
799         Boolean adjustWidth = FALSE;
800         Boolean adjustHeight = FALSE;
801         unsigned char rowcol_type = 0;
802         Boolean menu_glyph_changed = FALSE;
803         
804         if (MB_SMENU(new_w) != (Widget)NULL) {
805                 XtVaGetValues(MB_SMENU(new_w), XmNrowColumnType, 
806                                         &rowcol_type, NULL);
807                 if(rowcol_type != XmMENU_POPUP) {
808                         MB_SMENU(new_w) = NULL;
809                         XtError(MB_SUBMENU);
810                 }
811         }
812         
813         /* Never let traversal become FALSE */
814         new_w->primitive.traversal_on = TRUE;
815         
816         if ((LRecomputeSize(new_w))     || 
817                 (requested->core.width <= 0))
818                         adjustWidth = TRUE;
819         
820         if ((LRecomputeSize(new_w))     || 
821                 (requested->core.height <= 0))
822                         adjustHeight = TRUE;
823         
824         /* get new pixmap size */
825         if ((MB_PIXMAP(old) != MB_PIXMAP (new_w)) ||
826                 (Lab_TextRect_height(old) != Lab_TextRect_height(new_w))) {
827                         CalculateMenuGlyphSize (new_w);
828                         menu_glyph_changed = TRUE;
829         }
830
831         if ((old->primitive.foreground != 
832                 new_w->primitive.foreground)    ||
833                 (old->core.background_pixel != 
834                         new_w->core.background_pixel)) {
835                                 menu_glyph_changed = TRUE;
836                                 GetGC(new_w);
837         }
838
839         /*
840          * Resize widget if submenu appeared or disappeared, or if the
841          * menu glyph changed.
842          */
843         
844         if ( menu_glyph_changed == TRUE ||
845                 (LLabelType(old) != LLabelType(new_w)) ||
846                 (MB_SMENU(old) != MB_SMENU(new_w))) {
847         
848                 AdjustMenuButtonSize (new_w, adjustWidth, adjustHeight);
849         
850                 flag = TRUE;
851         
852                 if ((MB_SMENU(old) != MB_SMENU(new_w))) {
853         
854                         if(MB_SMENU(new_w)) {
855                                 XtRemoveEventHandler((Widget)new_w,
856                                         ButtonPressMask, False, 
857                                         PreMenuButtonHandler, MB_SMENU(old));
858                                 XtInsertEventHandler((Widget)new_w,
859                                         ButtonPressMask, False, 
860                                         PreMenuButtonHandler, MB_SMENU(new_w), 
861                                         XtListHead);
862                                 XtAddCallback(XtParent(
863                                         MB_SMENU(new_w)), 
864                                         XtNpopdownCallback, 
865                                         PopdownCallback, (XtPointer)new_w);
866                                 XtAddCallback(XtParent(
867                                         MB_SMENU(new_w)), 
868                                         XtNpopupCallback, 
869                                         PopupCallback, (XtPointer)new_w);
870                         }
871         
872                         if(MB_PVT_SMENU(old) == TRUE) {
873                                 XtDestroyWidget(MB_SMENU(old));
874                                 MB_PVT_SMENU(new_w) = FALSE;
875                         }
876         
877                 }
878         
879         } else  if ((new_w->primitive.highlight_thickness !=
880                                 old->primitive.highlight_thickness)               ||
881                                 (new_w->primitive.shadow_thickness !=
882                                 old->primitive.shadow_thickness)                  ||
883                                 (Lab_MarginRight (new_w) != Lab_MarginRight (old))   ||
884                                 (Lab_MarginHeight (new_w) != Lab_MarginHeight (old)) ||
885                                 (Lab_MarginTop (new_w) != Lab_MarginTop (old))   ||
886                                 (Lab_MarginBottom (new_w) != Lab_MarginBottom (old))) {
887                                         CalculateMenuGlyphSize (new_w);
888                                         AdjustMenuButtonSize (new_w,adjustWidth, adjustHeight);
889                                         flag = TRUE;
890                         } else if ((Lab_MarginWidth(new_w) != Lab_MarginWidth(old)) ||
891                                         (new_w->core.width != old->core.width)           ||
892                                         (new_w->core.height != old->core.height)) {
893                                                 LocateMenuGlyph (new_w);
894                                                 flag = TRUE;
895                         }
896         
897         return (flag);
898 }
899
900 /*
901  * Initialize
902  */
903 static void 
904 Initialize(
905     Widget w_req,
906     Widget w_new,
907     ArgList args,
908     Cardinal *num_args )
909 {
910         DtMenuButtonWidget  req = (DtMenuButtonWidget) w_req ;
911         DtMenuButtonWidget  new_w = (DtMenuButtonWidget) w_new ;
912         Widget topManager;
913         Boolean adjustWidth = FALSE;
914         Boolean adjustHeight = FALSE;
915         Widget    parent = XtParent(new_w);
916         unsigned char rowcol_type = 0;
917         char *name = NULL;
918         
919         if ((XmIsRowColumn (parent))) {
920                 XtVaGetValues(parent, XmNrowColumnType, 
921                         &rowcol_type, NULL);
922                 if(rowcol_type != XmWORK_AREA)
923                         XtError(MB_PARENT);
924         }
925
926         name = XtMalloc(10 + strlen(new_w->core.name));
927         sprintf(name,"submenu_%s",new_w->core.name);
928         
929         GetTopManager(w_new,&topManager);
930         MB_SMENU(new_w) = XmCreatePopupMenu(topManager, name, NULL, 0);
931         /* Remove our passive grab */
932         XtUngrabButton(topManager, RC_PostButton(MB_SMENU(new_w)), AnyModifier);
933
934         MB_PVT_SMENU(new_w) = TRUE;
935         
936         MB_ARMED(new_w) =  FALSE;
937         MB_POPPED_UP(new_w) = FALSE;
938         MB_LAST_TIMESTAMP(new_w) = 0;
939         MB_GC(new_w) = (GC)NULL;
940         
941         if (req->core.width <= 0)
942                 adjustWidth = TRUE;
943         
944         if (req->core.height <= 0)
945                 adjustHeight = TRUE;
946         
947         CalculateMenuGlyphSize (new_w);
948         AdjustMenuButtonSize (new_w, adjustWidth, adjustHeight);
949         GetGC(new_w);
950         
951         new_w->primitive.traversal_on = TRUE;
952         
953         if(MB_SMENU(new_w) != (Widget)NULL) {
954                 XtInsertEventHandler((Widget)new_w, ButtonPressMask,
955                      False, PreMenuButtonHandler, MB_SMENU(new_w), XtListHead);
956                 XtAddEventHandler((Widget)new_w, ButtonPressMask,
957                         FALSE, MenuButtonHandler, MB_SMENU(new_w));
958                 XtAddCallback(XtParent(MB_SMENU(new_w)), XtNpopdownCallback, 
959                                 PopdownCallback, (XtPointer)new_w);
960                 XtAddCallback(XtParent(MB_SMENU(new_w)), XtNpopupCallback, 
961                                 PopupCallback, (XtPointer)new_w);
962         }
963
964         XtFree(name);
965 }
966
967
968 static void 
969 DrawArrow(
970     Widget wid )
971 {
972         GC gc, tsGC, bsGC;
973         Pixel tsc, bsc;
974         int ht,st;
975         unsigned int text_height;
976
977         DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ;
978         Window win = XtWindow(wid);
979         Display *dpy = XtDisplay(wid);
980         
981         ht = mb->primitive.highlight_thickness;
982         st = mb->primitive.shadow_thickness;
983         text_height = Lab_TextRect_height(mb);
984
985         tsc =  mb->primitive.top_shadow_color;
986         bsc =  mb->primitive.bottom_shadow_color;
987
988         tsGC = mb->primitive.top_shadow_GC;
989         bsGC = mb->primitive.bottom_shadow_GC;
990         gc = MB_GC(mb);
991
992         /* armed arrow */
993         if(MB_ARMED(mb) == TRUE) {
994                 XFillRectangle(dpy, win, gc, 
995                         MB_GLYPH_X(mb), MB_GLYPH_Y(mb), 
996                         MB_GLYPH_WIDTH(mb), MB_GLYPH_HEIGHT(mb));
997                 XmeDrawArrow(dpy, win,
998                         bsGC, tsGC, gc,
999                         MB_GLYPH_X(mb) + ht + st - 1,
1000                         MB_GLYPH_Y(mb) + ht + st - 1,
1001                         MB_GLYPH_WIDTH(mb) - 2*(ht + st - 1),
1002                         MB_GLYPH_HEIGHT(mb) - 2*(ht + st - 1),
1003                         st, XmARROW_DOWN);
1004         } else {
1005                 /* standard (unarmed) arrow */
1006         
1007                 XFillRectangle(dpy, win, gc, 
1008                         MB_GLYPH_X(mb), MB_GLYPH_Y(mb),
1009                         MB_GLYPH_WIDTH(mb), MB_GLYPH_HEIGHT(mb));
1010                 XmeDrawArrow(dpy, win,
1011                         tsGC, bsGC, gc, 
1012                         MB_GLYPH_X(mb) + ht + st - 1, 
1013                         MB_GLYPH_Y(mb) + ht + st - 1, 
1014                         MB_GLYPH_WIDTH(mb) - 2*(ht + st - 1),
1015                         MB_GLYPH_HEIGHT(mb) - 2*(ht + st - 1), 
1016                         st, XmARROW_DOWN);
1017         }
1018
1019 }
1020
1021 static void
1022 GetGC(
1023         DtMenuButtonWidget mb)    
1024 {
1025         XGCValues values;
1026         Pixel bg;
1027
1028         if(MB_GC(mb) != (GC)NULL) {
1029                 XtReleaseGC((Widget)mb, MB_GC(mb));
1030                 MB_GC(mb) = (GC)NULL;
1031         }
1032
1033         bg = mb->core.background_pixel;
1034         values.foreground = values.background = bg;
1035         values.graphics_exposures = FALSE;
1036         MB_GC(mb)  = XtGetGC ((Widget) mb,
1037                 GCForeground | GCBackground | GCGraphicsExposures, &values);
1038 }
1039
1040 /*
1041  *************************************************************************
1042  *
1043  * Public Routines                                                        
1044  *
1045  *************************************************************************
1046  */
1047
1048 Widget 
1049 DtCreateMenuButton(
1050     Widget parent,
1051     char *name,
1052     ArgList al,
1053     Cardinal ac )
1054 {
1055         return XtCreateWidget(name,dtMenuButtonWidgetClass,parent, al, ac);
1056 }
1057
1058 static void
1059 GetTopManager(
1060         Widget w,
1061         Widget *topManager )
1062 {
1063    while (XmIsManager(XtParent(w)))
1064        w = XtParent(w);
1065  
1066    * topManager = w;
1067 }
1068  
1069