/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* $TOG: MenuButton.c /main/9 1998/04/09 17:51:40 mgreess $ * * (c) Copyright 1996 Digital Equipment Corporation. * (c) Copyright 1996 Hewlett-Packard Company. * (c) Copyright 1996 International Business Machines Corp. * (c) Copyright 1986, 1991, 1996 Sun Microsystems, Inc. * (c) Copyright 1996 Novell, Inc. * (c) Copyright 1996 FUJITSU LIMITED. * (c) Copyright 1996 Hitachi. */ /* * Copyright (C) 1986,1991 Sun Microsystems, Inc * All rights reserved. * Notice of copyright on this source code * product does not indicate publication. * * RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by * the U.S. Government is subject to restrictions as set forth * in subparagraph (c)(1)(ii) of the Rights in Technical Data * and Computer Software Clause at DFARS 252.227-7013 (Oct. 1988) * and FAR 52.227-19 (c) (June 1987). * * Sun Microsystems, Inc., 2550 Garcia Avenue, * Mountain View, California 94043. * */ /* * The DtMenuButton widget is rigged with the Motif widget binary compatibilit * mechanism. All Motif-specific changes for this mechanism are preceded * by a comment including the string "MotifBc". * * For a description of the Motif widget binary compatibility mechanism * see the reference manual entry on XmResolveAllPartOffsets(). * */ #include
#include "MenuButtonP.h" #include #include #include #include #include /* _XmRecordEvent, _XmSetInDragMode, ... */ #include #include "DtWidgetI.h" /* * MotifBc */ #define DtMenuButtonIndex (XmLabelIndex + 1) static XmOffsetPtr ipot; /* Instance part offset table */ static XmOffsetPtr cpot; /* Constraint part offset table */ #ifndef Max #define Max(x, y) (((x) > (y)) ? (x) : (y)) #endif #define GLYPH_PIX_SPACE 4 /* pixels between label and bit map */ /* * MotifBc */ #define CascadingCallback(w) XmField(w,ipot,DtMenuButton,cascading_callback,XtCallbackList) #define MenuRect(w) XmField(w,ipot,DtMenuButton,menu_rect,XRectangle) #define LNormalGC(w) XmField(w,ipot,XmLabel,normal_GC,GC) #define LAlignment(w) XmField(w,ipot,XmLabel,alignment,unsigned char) #define LRecomputeSize(w) XmField(w,ipot,XmLabel,recompute_size,Boolean) #define LLabelType(w) XmField(w,ipot,XmLabel,label_type,unsigned char) /* Access macro definitions */ #define MB_PVT_SMENU(mb) XmField(mb,ipot,DtMenuButton,private_submenu,Boolean) #define MB_LAST_TIMESTAMP(mb) XmField(mb,ipot,DtMenuButton,last_timestamp,Time) #define MB_SMENU(mb) XmField(mb,ipot,DtMenuButton,submenu,Widget) #define MB_PIXMAP(mb) XmField(mb,ipot,DtMenuButton,menu_pixmap,Pixmap) #define MB_GLYPH_X(mb) (XmField(mb,ipot,DtMenuButton,menu_rect,XRectangle)).x #define MB_GLYPH_Y(mb) (XmField(mb,ipot,DtMenuButton,menu_rect,XRectangle)).y #define MB_GLYPH_WIDTH(mb) (XmField(mb,ipot,DtMenuButton,menu_rect,XRectangle)).width #define MB_GLYPH_HEIGHT(mb) (XmField(mb,ipot,DtMenuButton,menu_rect,XRectangle)).height #define MB_ARMED(mb) XmField(mb,ipot,DtMenuButton,armed,Boolean) #define MB_POPPED_UP(mb) XmField(mb,ipot,DtMenuButton,popped_up,Boolean) #define MB_GC(mb) XmField(mb,ipot,DtMenuButton,gc,GC) /******** Static Function Declarations ********/ static void ClassInitialize (void); static void AdjustMenuButtonSize( DtMenuButtonWidget menubtn, Boolean adjustWidth, Boolean adjustHeight) ; static void Arm( DtMenuButtonWidget mb) ; static void ArmAndActivate( Widget wid, XEvent *event, String *params, Cardinal *num_params) ; static void CalculateMenuGlyphSize( DtMenuButtonWidget menubtn) ; static void CallCascadingCallbacks( Widget w, XEvent *event) ; static void Destroy( Widget wid) ; static void Disarm( DtMenuButtonWidget mb, Boolean pop_down) ; static void DrawArrow( Widget wid); static void Draw3DShadows( DtMenuButtonWidget mb) ; static void DrawMenuGlyph( DtMenuButtonWidget mb) ; static void GetGC( DtMenuButtonWidget mb); static void Initialize( Widget w_req, Widget w_new, ArgList args, Cardinal *num_args) ; static void LocateMenuGlyph( DtMenuButtonWidget menubtn) ; static void MenuButtonHandler( Widget wid, XtPointer cd, XEvent *event, Boolean *cont_to_dispatch) ; static void Popup( DtMenuButtonWidget mb, XEvent *event, Boolean call_cbacks ); static void Redisplay( Widget mb, XEvent *event, Region region) ; static void Resize( Widget mb) ; static void Select( Widget wid, XEvent *event, String *param, Cardinal *num_param) ; static Boolean SetValues( Widget cw, Widget rw, Widget nw, ArgList args, Cardinal *num_args) ; static void GetTopManager( Widget w, Widget *topManager) ; /******** End Static Function Declarations ********/ /* * event translation tables for menubutton. */ static char menuButton_translations[] = "\ space:Select()\n\ osfSelect:Select()"; static XtActionsRec menuButton_actions [] = { {"Select", Select} }; /* MotifBc */ #define DtOffset(field) XmPartOffset(DtMenuButton,field) #define XmPrimOffset(field) XmPartOffset(XmPrimitive,field) #define XmLabelOffset(field) XmPartOffset(XmLabel,field) static XmPartResource resources[] = { { DtNcascadingCallback, DtCCallback, XmRCallback, sizeof (XtCallbackList), DtOffset(cascading_callback), XmRCallback, NULL }, { DtNsubMenuId, DtCMenuWidget, /* submenu */ XmRMenuWidget, sizeof (Widget), DtOffset(submenu), XmRMenuWidget, (XtPointer) NULL }, { DtNcascadePixmap, DtCPixmap, XmRPrimForegroundPixmap, sizeof(Pixmap), DtOffset(menu_pixmap), XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP }, { XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension, sizeof (Dimension), XmPrimOffset(shadow_thickness), XmRImmediate, (XtPointer) 2 }, { XmNtraversalOn, XmCTraversalOn, XmRBoolean, sizeof(Boolean), XmPrimOffset(traversal_on), XmRImmediate, (XtPointer) TRUE }, { XmNhighlightThickness, XmCHighlightThickness, XmRHorizontalDimension, sizeof (Dimension), XmPrimOffset(highlight_thickness), XmRImmediate, (XtPointer) 2 }, { XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension, sizeof (Dimension), XmLabelOffset(margin_width), XmRImmediate, (XtPointer)6 }, }; externaldef(xmmenubuttonclassrec) DtMenuButtonClassRec dtMenuButtonClassRec = { { /* core class record */ (WidgetClass) &xmLabelClassRec, /* superclass ptr */ "DtMenuButton", /* class_name */ sizeof(DtMenuButtonPart), /* size of Pulldown widget */ (XtProc)ClassInitialize, /* class init proc */ NULL, /* chained class init */ FALSE, /* class is not init'ed */ Initialize, /* widget init proc */ NULL, /* init_hook proc */ XtInheritRealize, /* widget realize proc */ menuButton_actions, /* class action table */ XtNumber (menuButton_actions), /* num of actions */ (XtResourceList)resources, /* this class's resource list*/ XtNumber (resources), /* resource_count */ NULLQUARK, /* xrm_class */ TRUE, /* compress motion */ XtExposeCompressMaximal, /* compress exposure */ TRUE, /* compress enter-leave */ FALSE, /* no VisibilityNotify */ Destroy, /* class destroy proc */ Resize, /* class resize proc */ Redisplay, /* expose proc */ SetValues, /* set_value proc */ NULL, /* set_value_hook proc */ XtInheritSetValuesAlmost, /* set_value_almost proc */ NULL, /* get_values_hook */ NULL, /* class accept focus proc */ XtVersionDontCheck, /* current version */ NULL, /* callback offset list */ menuButton_translations, /* default translation table */ XtInheritQueryGeometry, /* query geo proc */ NULL, /* display accelerator*/ (XtPointer)NULL, /* extension */ }, { /* Primitive Class record */ XmInheritWidgetProc, /* border_highlight */ XmInheritWidgetProc, /* border_uhighlight */ XtInheritTranslations, /* translations */ ArmAndActivate, /* arm & activate */ NULL, /* get resources */ 0, /* num get_resources */ (XtPointer)NULL, /* extension */ }, { /* Label Class record */ XmInheritWidgetProc, /* set override callback */ XmInheritMenuProc, /* menu procedures */ XtInheritTranslations, /* menu traversal xlation */ NULL, /* extension */ }, { /* menu_button class record */ NULL, /* extension */ } }; /* * Now make a public symbol that points to this class record. */ externaldef(dtmenubuttonwidgetclass) WidgetClass dtMenuButtonWidgetClass = (WidgetClass) &dtMenuButtonClassRec; /* * MotifBc, to calculate offset var. ipot */ static void ClassInitialize(void) { XmResolveAllPartOffsets(dtMenuButtonWidgetClass, &ipot, &cpot); } static void Draw3DShadows( DtMenuButtonWidget mb ) { if (XtIsRealized((Widget)mb)) XmeDrawShadows (XtDisplay (mb), XtWindow (mb), mb->primitive.top_shadow_GC, mb->primitive.bottom_shadow_GC, mb->primitive.highlight_thickness, mb->primitive.highlight_thickness, mb->core.width - 2 * mb->primitive.highlight_thickness, mb->core.height - 2 * mb->primitive.highlight_thickness, mb->primitive.shadow_thickness, (MB_ARMED(mb) == TRUE) ? XmSHADOW_IN: XmSHADOW_OUT); } static void DrawMenuGlyph( DtMenuButtonWidget mb ) { if ((MB_GLYPH_WIDTH(mb) != 0)){ if(MB_PIXMAP(mb) != XmUNSPECIFIED_PIXMAP) XCopyArea (XtDisplay(mb), MB_PIXMAP(mb), XtWindow(mb), LNormalGC(mb), 0, 0, MB_GLYPH_WIDTH(mb), MB_GLYPH_HEIGHT(mb), MB_GLYPH_X(mb), MB_GLYPH_Y(mb)); else DrawArrow((Widget)mb); } } /* * Redisplay the widget. */ static void Redisplay( Widget mb, XEvent *event, Region region ) { if (XtIsRealized (mb)) { /* Label expose method does the initial work */ XtExposeProc expose; _DtProcessLock(); expose = xmLabelClassRec.core_class.expose; _DtProcessUnlock(); (* expose)(mb, event, region) ; DrawMenuGlyph((DtMenuButtonWidget) mb); Draw3DShadows ((DtMenuButtonWidget) mb); } } static void Arm( DtMenuButtonWidget mb ) { XmProcessTraversal( (Widget) mb, XmTRAVERSE_CURRENT); if (MB_ARMED(mb) == FALSE) { MB_ARMED(mb) = TRUE; DrawMenuGlyph(mb); Draw3DShadows (mb); } } static void ArmAndActivate( Widget wid, XEvent *event, String *params, Cardinal *num_params ) { DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ; if(MB_SMENU(mb) == (Widget)NULL || event == (XEvent*) NULL) return; if (!_XmIsEventUnique(event)) return; Popup(mb, event, TRUE); _XmSetInDragMode((Widget)mb,FALSE); if (!XmProcessTraversal(MB_SMENU(mb), XmTRAVERSE_CURRENT)) XtSetKeyboardFocus(XtParent(MB_SMENU(mb)), MB_SMENU(mb)); _XmRecordEvent(event); } static void Disarm( DtMenuButtonWidget mb, Boolean pop_down ) { if (MB_ARMED(mb) == TRUE) { MB_ARMED(mb) = FALSE; if (pop_down == TRUE && MB_SMENU(mb) != (Widget)NULL) XtUnmanageChild(MB_SMENU(mb)); Draw3DShadows(mb); DrawMenuGlyph(mb); } } /*ARGSUSED*/ static void Select( Widget wid, XEvent *event, String *param, Cardinal *num_param ) { DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ; XtActionProc arm_and_activate; if(MB_POPPED_UP(mb) == TRUE) { Disarm(mb,TRUE); return; } _DtProcessLock(); arm_and_activate = ((DtMenuButtonClassRec *)(mb->core.widget_class))-> primitive_class.arm_and_activate; _DtProcessUnlock(); (* arm_and_activate) ((Widget) mb, event, NULL, NULL); } static void PreMenuButtonHandler( Widget wid, XtPointer cd, XEvent *event, Boolean *cont_to_dispatch) { DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ; if(MB_SMENU(mb) == (Widget)NULL || event->xany.type != ButtonPress || event->xbutton.time <= MB_LAST_TIMESTAMP(mb)) return; if(event->xbutton.button==Button1||event->xbutton.button==Button3) { String btnstr=NULL; XtVaGetValues(MB_SMENU(mb), XmNmenuPost, &btnstr, NULL); if (btnstr==NULL || !strcmp(btnstr,"") || !strcmp(btnstr, "")) event->xbutton.button=Button3; else if (!strcmp(btnstr, "")) event->xbutton.button=Button1; else XtWarning(MB_POST); } } static void MenuButtonHandler( Widget wid, XtPointer cd, XEvent *event, Boolean *cont_to_dispatch) { DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ; if(MB_SMENU(mb) == (Widget)NULL || event->xany.type != ButtonPress || event->xbutton.time <= MB_LAST_TIMESTAMP(mb)) return; else MB_LAST_TIMESTAMP(mb) = event->xbutton.time; Popup (mb, event, TRUE); } static void CallCascadingCallbacks( Widget w, XEvent *event ) { DtMenuButtonWidget mb = (DtMenuButtonWidget)w; XmAnyCallbackStruct cback; if(MB_POPPED_UP(mb) == TRUE) return; cback.reason = DtCR_CASCADING; cback.event = event; XtCallCallbackList ((Widget) mb, CascadingCallback(mb), &cback); } static void PopdownCallback(Widget w, XtPointer client_data, XtPointer call_data) { DtMenuButtonWidget mb = (DtMenuButtonWidget)client_data; Disarm(mb,FALSE); MB_POPPED_UP(mb) = FALSE; MB_LAST_TIMESTAMP(mb) = XtLastTimestampProcessed(XtDisplay(mb)); } static void PopupCallback(Widget w, XtPointer client_data, XtPointer call_data) { DtMenuButtonWidget mb = (DtMenuButtonWidget)client_data; Arm(mb); MB_POPPED_UP(mb) = TRUE; } /* * Call the cascading callbacks and popup any submenu. */ static void Popup( DtMenuButtonWidget mb, XEvent *event, Boolean call_cbacks ) { Position x=0, y=0; Position root_x=0, root_y=0; Position save_x = 0, save_y = 0; Dimension sw=0, sh=0; int dx = 0, dy = 0; Screen *screen; if((MB_SMENU(mb) == (Widget)NULL) || (MB_POPPED_UP(mb) == TRUE)) return; if (call_cbacks) CallCascadingCallbacks((Widget)mb, event); x = (Position)((int)XtWidth((Widget)mb) - (int)XtWidth(MB_SMENU(mb)))/2; y = XtHeight((Widget)mb) - mb->primitive.highlight_thickness + 1; XtTranslateCoords((Widget)mb, x,y, &root_x, &root_y); /* Check if not completely on the screen */ screen = XtScreen(mb); sw = WidthOfScreen(screen); sh = HeightOfScreen(screen); if((dx = root_x - sw + XtWidth(MB_SMENU(mb))) > 0) root_x -= dx; if((dy = root_y - sh + XtHeight(MB_SMENU(mb))) > 0) { root_y -= (2 - (mb->primitive.highlight_thickness<<1)); root_y -= (XtHeight(mb) + XtHeight(MB_SMENU(mb))); } save_x = event->xbutton.x_root; save_y = event->xbutton.y_root; event->xbutton.x_root = root_x; event->xbutton.y_root = root_y; /* Position the menu */ XmMenuPosition(MB_SMENU(mb),(XButtonPressedEvent*)event); event->xbutton.x_root = save_x; event->xbutton.y_root = save_y; XtManageChild(MB_SMENU(mb)); } /* * Get the menu glyph size set up. */ static void CalculateMenuGlyphSize( DtMenuButtonWidget menubtn ) { Window rootwin; int x,y; /* must be int */ unsigned int width, height, border, depth; /* must be int */ if (MB_PIXMAP(menubtn) != XmUNSPECIFIED_PIXMAP) { XGetGeometry(XtDisplay(menubtn), MB_PIXMAP(menubtn), &rootwin, &x, &y, &width, &height, &border, &depth); MB_GLYPH_WIDTH(menubtn) = (Dimension) width; MB_GLYPH_HEIGHT(menubtn) = (Dimension) height; } else { int ht, st; Dimension side; unsigned int text_height; ht = menubtn->primitive.highlight_thickness; st = menubtn->primitive.shadow_thickness; text_height = Lab_TextRect_height(menubtn); side = Max( (text_height * 2 / 3) + 2 * (ht + st), (2*(ht + (st-1) +1)) +1 ); MB_GLYPH_WIDTH(menubtn) = MB_GLYPH_HEIGHT(menubtn) = side; } } /* * Set up the menu glyph location. */ static void LocateMenuGlyph( DtMenuButtonWidget menubtn ) { Dimension buffer; MB_GLYPH_X(menubtn) = XtWidth (menubtn) - menubtn->primitive.highlight_thickness - menubtn->primitive.shadow_thickness - Lab_MarginWidth(menubtn) - MB_GLYPH_WIDTH(menubtn); buffer = menubtn->primitive.highlight_thickness + menubtn->primitive.shadow_thickness + Lab_MarginHeight(menubtn); MB_GLYPH_Y(menubtn) = (Position)((int)buffer + (((int)XtHeight(menubtn) - 2*(int)buffer) - (int)MB_GLYPH_HEIGHT(menubtn)) / 2); } /* * Make room for menu glyph in menu button. */ static void AdjustMenuButtonSize( DtMenuButtonWidget menubtn, Boolean adjustWidth, Boolean adjustHeight ) { Dimension delta; /* * Modify the size of the menubutton to acommadate the menu. * The menu should fit inside MarginRight. */ if ((int)(MB_GLYPH_WIDTH(menubtn) + GLYPH_PIX_SPACE) > (int)Lab_MarginRight(menubtn)) { delta = MB_GLYPH_WIDTH(menubtn) + GLYPH_PIX_SPACE - Lab_MarginRight(menubtn); Lab_MarginRight(menubtn) += delta; if (adjustWidth) XtWidth(menubtn) += delta; else { if (LAlignment(menubtn) == XmALIGNMENT_END) Lab_TextRect_x(menubtn) -= delta; else if (LAlignment(menubtn) == XmALIGNMENT_CENTER) Lab_TextRect_x(menubtn) -= delta/2; } } /* * the menu height should fit inside of * TextRect + marginTop + marginBottom */ delta = MB_GLYPH_HEIGHT(menubtn) + 2 * (Lab_MarginHeight(menubtn) + menubtn->primitive.shadow_thickness + menubtn->primitive.highlight_thickness); if (delta > XtHeight(menubtn)) { delta -= XtHeight(menubtn); Lab_MarginTop(menubtn) += delta/2; Lab_TextRect_y(menubtn) += delta/2; Lab_MarginBottom(menubtn) += delta - (delta/2); if (adjustHeight) XtHeight(menubtn) += delta; } LocateMenuGlyph(menubtn); } /* * Destroy the widget */ static void Destroy( Widget wid ) { DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ; XmRowColumnWidget submenu = (XmRowColumnWidget) MB_SMENU(mb); Widget shell; XtRemoveAllCallbacks ((Widget) mb, DtNcascadingCallback); if(submenu != (XmRowColumnWidget)NULL) { shell = XtParent((Widget)submenu); XtRemoveCallback(shell, XtNpopupCallback,PopupCallback, (XtPointer)mb); XtRemoveCallback(shell, XtNpopdownCallback, PopdownCallback,(XtPointer)mb); } if(MB_PVT_SMENU(mb) == TRUE) { XtDestroyWidget((Widget)submenu); MB_SMENU(mb) = NULL; MB_PVT_SMENU(mb) = FALSE; } } /* * Resize Method. */ static void Resize( Widget mb ) { if (mb != (Widget)NULL) { /* Label resize method lays out the label string */ XtWidgetProc resize; _DtProcessLock(); resize = xmLabelClassRec.core_class.resize; _DtProcessUnlock(); (* resize) (mb); LocateMenuGlyph ((DtMenuButtonWidget) mb); } } /* * Set Values Method. */ static Boolean SetValues( Widget cw, Widget rw, Widget nw, ArgList args, Cardinal *num_args ) { DtMenuButtonWidget old = (DtMenuButtonWidget) cw ; DtMenuButtonWidget requested = (DtMenuButtonWidget) rw ; DtMenuButtonWidget new_w = (DtMenuButtonWidget) nw ; Boolean flag = FALSE; Boolean adjustWidth = FALSE; Boolean adjustHeight = FALSE; unsigned char rowcol_type = 0; Boolean menu_glyph_changed = FALSE; if (MB_SMENU(new_w) != (Widget)NULL) { XtVaGetValues(MB_SMENU(new_w), XmNrowColumnType, &rowcol_type, NULL); if(rowcol_type != XmMENU_POPUP) { MB_SMENU(new_w) = NULL; XtError(MB_SUBMENU); } } /* Never let traversal become FALSE */ new_w->primitive.traversal_on = TRUE; if ((LRecomputeSize(new_w)) || (requested->core.width <= 0)) adjustWidth = TRUE; if ((LRecomputeSize(new_w)) || (requested->core.height <= 0)) adjustHeight = TRUE; /* get new pixmap size */ if ((MB_PIXMAP(old) != MB_PIXMAP (new_w)) || (Lab_TextRect_height(old) != Lab_TextRect_height(new_w))) { CalculateMenuGlyphSize (new_w); menu_glyph_changed = TRUE; } if ((old->primitive.foreground != new_w->primitive.foreground) || (old->core.background_pixel != new_w->core.background_pixel)) { menu_glyph_changed = TRUE; GetGC(new_w); } /* * Resize widget if submenu appeared or disappeared, or if the * menu glyph changed. */ if ( menu_glyph_changed == TRUE || (LLabelType(old) != LLabelType(new_w)) || (MB_SMENU(old) != MB_SMENU(new_w))) { AdjustMenuButtonSize (new_w, adjustWidth, adjustHeight); flag = TRUE; if ((MB_SMENU(old) != MB_SMENU(new_w))) { if(MB_SMENU(new_w)) { XtRemoveEventHandler((Widget)new_w, ButtonPressMask, False, PreMenuButtonHandler, MB_SMENU(old)); XtInsertEventHandler((Widget)new_w, ButtonPressMask, False, PreMenuButtonHandler, MB_SMENU(new_w), XtListHead); XtAddCallback(XtParent( MB_SMENU(new_w)), XtNpopdownCallback, PopdownCallback, (XtPointer)new_w); XtAddCallback(XtParent( MB_SMENU(new_w)), XtNpopupCallback, PopupCallback, (XtPointer)new_w); } if(MB_PVT_SMENU(old) == TRUE) { XtDestroyWidget(MB_SMENU(old)); MB_PVT_SMENU(new_w) = FALSE; } } } else if ((new_w->primitive.highlight_thickness != old->primitive.highlight_thickness) || (new_w->primitive.shadow_thickness != old->primitive.shadow_thickness) || (Lab_MarginRight (new_w) != Lab_MarginRight (old)) || (Lab_MarginHeight (new_w) != Lab_MarginHeight (old)) || (Lab_MarginTop (new_w) != Lab_MarginTop (old)) || (Lab_MarginBottom (new_w) != Lab_MarginBottom (old))) { CalculateMenuGlyphSize (new_w); AdjustMenuButtonSize (new_w,adjustWidth, adjustHeight); flag = TRUE; } else if ((Lab_MarginWidth(new_w) != Lab_MarginWidth(old)) || (new_w->core.width != old->core.width) || (new_w->core.height != old->core.height)) { LocateMenuGlyph (new_w); flag = TRUE; } return (flag); } /* * Initialize */ static void Initialize( Widget w_req, Widget w_new, ArgList args, Cardinal *num_args ) { DtMenuButtonWidget req = (DtMenuButtonWidget) w_req ; DtMenuButtonWidget new_w = (DtMenuButtonWidget) w_new ; Widget topManager; Boolean adjustWidth = FALSE; Boolean adjustHeight = FALSE; Widget parent = XtParent(new_w); unsigned char rowcol_type = 0; char *name = NULL; if ((XmIsRowColumn (parent))) { XtVaGetValues(parent, XmNrowColumnType, &rowcol_type, NULL); if(rowcol_type != XmWORK_AREA) XtError(MB_PARENT); } name = XtMalloc(10 + strlen(new_w->core.name)); sprintf(name,"submenu_%s",new_w->core.name); GetTopManager(w_new,&topManager); MB_SMENU(new_w) = XmCreatePopupMenu(topManager, name, NULL, 0); /* Remove our passive grab */ XtUngrabButton(topManager, RC_PostButton(MB_SMENU(new_w)), AnyModifier); MB_PVT_SMENU(new_w) = TRUE; MB_ARMED(new_w) = FALSE; MB_POPPED_UP(new_w) = FALSE; MB_LAST_TIMESTAMP(new_w) = 0; MB_GC(new_w) = (GC)NULL; if (req->core.width <= 0) adjustWidth = TRUE; if (req->core.height <= 0) adjustHeight = TRUE; CalculateMenuGlyphSize (new_w); AdjustMenuButtonSize (new_w, adjustWidth, adjustHeight); GetGC(new_w); new_w->primitive.traversal_on = TRUE; if(MB_SMENU(new_w) != (Widget)NULL) { XtInsertEventHandler((Widget)new_w, ButtonPressMask, False, PreMenuButtonHandler, MB_SMENU(new_w), XtListHead); XtAddEventHandler((Widget)new_w, ButtonPressMask, FALSE, MenuButtonHandler, MB_SMENU(new_w)); XtAddCallback(XtParent(MB_SMENU(new_w)), XtNpopdownCallback, PopdownCallback, (XtPointer)new_w); XtAddCallback(XtParent(MB_SMENU(new_w)), XtNpopupCallback, PopupCallback, (XtPointer)new_w); } XtFree(name); } static void DrawArrow( Widget wid ) { GC gc, tsGC, bsGC; Pixel tsc, bsc; int ht,st; unsigned int text_height; DtMenuButtonWidget mb = (DtMenuButtonWidget) wid ; Window win = XtWindow(wid); Display *dpy = XtDisplay(wid); ht = mb->primitive.highlight_thickness; st = mb->primitive.shadow_thickness; text_height = Lab_TextRect_height(mb); tsc = mb->primitive.top_shadow_color; bsc = mb->primitive.bottom_shadow_color; tsGC = mb->primitive.top_shadow_GC; bsGC = mb->primitive.bottom_shadow_GC; gc = MB_GC(mb); /* armed arrow */ if(MB_ARMED(mb) == TRUE) { XFillRectangle(dpy, win, gc, MB_GLYPH_X(mb), MB_GLYPH_Y(mb), MB_GLYPH_WIDTH(mb), MB_GLYPH_HEIGHT(mb)); XmeDrawArrow(dpy, win, bsGC, tsGC, gc, MB_GLYPH_X(mb) + ht + st - 1, MB_GLYPH_Y(mb) + ht + st - 1, MB_GLYPH_WIDTH(mb) - 2*(ht + st - 1), MB_GLYPH_HEIGHT(mb) - 2*(ht + st - 1), st, XmARROW_DOWN); } else { /* standard (unarmed) arrow */ XFillRectangle(dpy, win, gc, MB_GLYPH_X(mb), MB_GLYPH_Y(mb), MB_GLYPH_WIDTH(mb), MB_GLYPH_HEIGHT(mb)); XmeDrawArrow(dpy, win, tsGC, bsGC, gc, MB_GLYPH_X(mb) + ht + st - 1, MB_GLYPH_Y(mb) + ht + st - 1, MB_GLYPH_WIDTH(mb) - 2*(ht + st - 1), MB_GLYPH_HEIGHT(mb) - 2*(ht + st - 1), st, XmARROW_DOWN); } } static void GetGC( DtMenuButtonWidget mb) { XGCValues values; Pixel bg; if(MB_GC(mb) != (GC)NULL) { XtReleaseGC((Widget)mb, MB_GC(mb)); MB_GC(mb) = (GC)NULL; } bg = mb->core.background_pixel; values.foreground = values.background = bg; values.graphics_exposures = FALSE; MB_GC(mb) = XtGetGC ((Widget) mb, GCForeground | GCBackground | GCGraphicsExposures, &values); } /* ************************************************************************* * * Public Routines * ************************************************************************* */ Widget DtCreateMenuButton( Widget parent, char *name, ArgList al, Cardinal ac ) { return XtCreateWidget(name,dtMenuButtonWidgetClass,parent, al, ac); } static void GetTopManager( Widget w, Widget *topManager ) { while (XmIsManager(XtParent(w))) w = XtParent(w); * topManager = w; }