/* $TOG: MenuB.c /main/6 1999/05/13 15:33:01 mgreess $ */ /* * @OPENGROUP_COPYRIGHT@ * COPYRIGHT NOTICE * Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc. * Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group * ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for * the full copyright text. * * This software is subject to an open license. It may only be * used on, with or for operating systems which are themselves open * source systems. You must contact The Open Group for a license * allowing distribution and sublicensing of this software on, with, * or for operating systems which are not Open Source programs. * * See http://www.opengroup.org/openmotif/license for full * details of the license agreement. Any use, reproduction, or * distribution of the program constitutes recipient's acceptance of * this agreement. * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS * PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY * WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY * OR FITNESS FOR A PARTICULAR PURPOSE * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT * NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE * EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. */ /* * HISTORY */ /************************************ WARNING ********************************** * * ExmMenuButton is a demonstration widget. OSF provides this widget * solely to teach programmers how to write their own Motif widgets. * OSF does not support this widget in any way * ************************************ WARNING *********************************/ /******************************************************************************* * * MenuB.c - ExmMenuButton widget. This widget serves as a menu * button. It has some features of the XmPushButton widget. * This widget can be a child of a RowColumn widget, * assuming that the XmNrowColumnType resource of the * RowColumn is set to something other than XmWORK_AREA. * ExmMenuButton is a subclass of ExmString and displays * one compound string. * The ExmMenuButton widget demonstrates how to * * install the XmQTmenuSavvy trait. * * call many of the trait methods of the XmQTmenuSystem * trait. * See the "OSF/Motif Widget Writer's Guide" for details. * *******************************************************************************/ /* Include appropriate header files. */ #include #include #include #include #include #include #include /* header file for XmBUTTON_RENDER_TABLE */ #include #include /* The VISUAL_DELAY holds a time in milliseconds. */ XmConst unsigned long VISUAL_DELAY=100; /* Declare all static functions. */ static void Initialize ( Widget request_w, Widget new_w, ArgList args, Cardinal *num_args); static void ClassInitialize(void); static void Destroy ( Widget w); static Boolean SetValues ( Widget old_w, Widget request_w, Widget new_w, ArgList args, Cardinal *num_args); static void BorderHighlight ( Widget w); static void BorderUnhighlight ( Widget w); static void DrawShadow ( Widget w); static void ArmAndActivate ( Widget w, XEvent *event, String *params, Cardinal *num_params); static void VisualDisarm ( XtPointer cd, XtIntervalId *id); static void BtnDown ( Widget w, XEvent *event, String *params, Cardinal *num_params); static void BtnUp ( Widget w, XEvent *event, String *params, Cardinal *num_params); static void MenuButtonEnter ( Widget w, XEvent *event, String *params, Cardinal *num_params); static void MenuButtonLeave ( Widget w, XEvent *event, String *params, Cardinal *num_params); static void MenuButtonHelp ( Widget w, XEvent *event, String *params, Cardinal *num_params); static void DisableCallback( Widget w, XtEnum value); static char* GetAccelerator( Widget w); static KeySym GetMnemonic( Widget w); static char* GetActivateCBName( void); static void DrawVisual( Widget w); static void CalcVisualSize ( Widget w); /* Define translations. */ static char defaultTranslations[] = ": MenuButtonEnter()\n\ : MenuButtonLeave()\n\ : BtnDown()\n\ : BtnUp()\n\ :osfActivate: ArmAndActivate()\n\ :osfCancel: MenuEscape()\n\ :osfHelp: MenuButtonHelp()\n\ ~s ~m ~a Return: ArmAndActivate()\n\ ~s ~m ~a space: ArmAndActivate()"; static char menuTraversalTranslations[] = ": Unmap()\n\ : FocusOut()\n\ : FocusIn()\n\ :osfCancel: MenuEscape()\n\ :osfLeft: MenuTraverseLeft()\n\ :osfRight: MenuTraverseRight()\n\ :osfUp: MenuTraverseUp()\n\ :osfDown: MenuTraverseDown()"; /* The following actions will be handled by code inside this file. */ static XtActionsRec Actions[] = { {"ArmAndActivate", ArmAndActivate}, {"BtnDown", BtnDown}, {"BtnUp", BtnUp}, {"MenuButtonEnter", MenuButtonEnter}, {"MenuButtonLeave", MenuButtonLeave}, {"MenuButtonHelp", MenuButtonHelp} }; /* Define the resources. The first four resource definitions are do not define new resources, they simply provide new default values for superclass resources. The only new resource is XmNactivateCallback. */ static XtResource resources[] = { { XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension, sizeof (Dimension), XtOffsetOf( ExmMenuButtonRec, primitive.shadow_thickness), XmRImmediate, (XtPointer) 2 }, { XmNhighlightThickness, XmCHighlightThickness, XmRHorizontalDimension, sizeof (Dimension), XtOffsetOf( ExmMenuButtonRec, primitive.highlight_thickness), XmRImmediate, (XtPointer) 0 }, { XmNtraversalOn, XmCTraversalOn, XmRBoolean, sizeof (Boolean), XtOffsetOf( ExmMenuButtonRec, primitive.traversal_on), XmRImmediate, (XtPointer) True }, { XmNalignment, XmCAlignment, XmRAlignment, sizeof(unsigned char), XtOffsetOf( ExmStringRec,string.alignment), XmRImmediate, (XtPointer) XmALIGNMENT_BEGINNING }, { XmNactivateCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffsetOf( ExmMenuButtonRec, menu_button.activate_callback), XmRPointer, (XtPointer) NULL }, { XmNmnemonic, XmCMnemonic, XmRKeySym, sizeof(KeySym), XtOffsetOf( ExmMenuButtonRec, menu_button.mnemonic), XmRImmediate, (XtPointer) XK_VoidSymbol }, { XmNaccelerator, XmCAccelerator, XmRString, sizeof(char *), XtOffsetOf(ExmMenuButtonRec, menu_button.accelerator), XmRImmediate, (XtPointer) NULL }, { XmNacceleratorText, XmCAcceleratorText, XmRXmString, sizeof(XmString), XtOffsetOf(ExmMenuButtonRec, menu_button.accelerator_text), XmRImmediate, (XtPointer) NULL }, { XmNmnemonicCharSet, XmCMnemonicCharSet, XmRString, sizeof(XmStringCharSet), XtOffsetOf(ExmMenuButtonRec, menu_button.mnemonic_charset), XmRImmediate, (XtPointer) XmFONTLIST_DEFAULT_TAG } }; /* No synthetic resources. */ /* Here is the class record. */ externaldef (exmmenubuttonclassrec) ExmMenuButtonClassRec exmMenuButtonClassRec = { { /* superclass */ (WidgetClass)&exmStringClassRec, /* class_name */ "ExmMenuButton", /* widget_size */ sizeof(ExmMenuButtonRec), /* class_initialize */ ClassInitialize, /* class_part_initialize */ NULL, /* class_inited */ FALSE, /* initialize */ Initialize, /* initialize_hook */ NULL, /* realize */ XtInheritRealize, /* actions */ Actions, /* num_actions */ XtNumber(Actions), /* resources */ resources, /* num_resources */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ TRUE, /* compress_exposure */ XtExposeCompressMaximal, /* compress_enterleave */ TRUE, /* visible_interest */ FALSE, /* destroy */ Destroy, /* resize */ XtInheritResize, /* expose */ XtInheritExpose, /* set_values */ SetValues, /* set_values_hook */ NULL, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ NULL, /* accept_focus */ NULL, /* version */ XtVersion, /* callback_private */ NULL, /* tm_table */ defaultTranslations, /* query_geometry */ XtInheritQueryGeometry, /* display_accelerator */ NULL, /* extension */ NULL, }, { /* XmPrimitive */ /* border_highlight */ BorderHighlight, /* border_unhighlight */ BorderUnhighlight, /* translations */ menuTraversalTranslations, #if 0 /* translations */ XtInheritTranslations, #endif /* arm_and_activate */ ArmAndActivate, /* syn_resources */ NULL, /* num_syn_resources */ 0, /* extension */ NULL, }, { /* ExmSimple */ /* draw_visual */ DrawVisual, /* draw_shadow */ DrawShadow, /* create_text_gc */ ExmInheritCreateGC, /* destroy_text_gc */ ExmInheritDestroyGC, /* select_text_gc */ ExmInheritSelectGC, /* calc_visual_size */ CalcVisualSize, /* calc_widget_size */ ExmInheritCalcWidgetSize, /* reconfigure */ ExmInheritReconfigure, /* extension */ NULL, }, { /* ExmString */ /* default_render_table_type */ XmBUTTON_RENDER_TABLE, /* extension */ NULL, }, { /* ExmMenuButton */ /* extension */ NULL, } }; /* Establish the widget class name as an externally accessible symbol. Use the "externaldef" macro rather than the "extern" keyword. */ externaldef( exmmenubuttonwidgetclass) WidgetClass exmMenuButtonWidgetClass = (WidgetClass) &exmMenuButtonClassRec; /* Define trait structure variables. */ /* We will need to tell XmRowColumn that ExmMenuButton can be a menu child. We will do that be setting the XmQTmenuSavvy trait on ExmMenuButton. In order to set this trait, we must define a trait record variable as follows: */ static XmConst XmMenuSavvyTraitRec menuSavvyTraitRec = { 0, /* Version */ (XmMenuSavvyDisableProc) DisableCallback, /* disableCallback */ GetAccelerator, /* getAccelerator */ GetMnemonic, /* getMnemonic */ GetActivateCBName, /* getActivateCBName */ }; /****************************************************************************** * * ClassInitialize: * Called by the Intrinsics the first time a widget of this class is * instantiated. * *****************************************************************************/ static void ClassInitialize( void ) { /* Install the menuSavvy trait so that the menu will know that this class has the right actions for menus */ XmeTraitSet(exmMenuButtonWidgetClass, XmQTmenuSavvy, (XtPointer) &menuSavvyTraitRec); } /****************************************************************************** * * Initialize * *****************************************************************************/ static void Initialize ( Widget request_w, Widget new_w, ArgList args, Cardinal *num_args ) { ExmMenuButtonWidgetClass wc =(ExmMenuButtonWidgetClass)XtClass(new_w); ExmMenuButtonWidget nw = (ExmMenuButtonWidget)new_w; nw->menu_button.armed = False; nw->menu_button.visual_timer = 0; nw->menu_button.skip_callback = False; /* Force traversal on, the menu system will break otherwise */ nw->primitive.traversal_on = True; nw->primitive.highlight_thickness = 0; if (wc->simple_class.calc_visual_size) (*(wc->simple_class.calc_visual_size))(new_w); if (wc->simple_class.reconfigure) (*(wc->simple_class.reconfigure))(exmMenuButtonWidgetClass, new_w, NULL); if (nw->menu_button.accelerator_text != NULL) nw->menu_button.accelerator_text = XmStringCopy(nw->menu_button.accelerator_text); } /****************************************************************************** * * Destroy * *****************************************************************************/ static void Destroy ( Widget w ) { ExmMenuButtonWidget mw = (ExmMenuButtonWidget)w; if (mw->menu_button.visual_timer != 0) XtRemoveTimeOut (mw->menu_button.visual_timer); } /****************************************************************************** * * SetValues * *****************************************************************************/ static Boolean SetValues ( Widget old_w, Widget request_w, Widget new_w, ArgList args, Cardinal *num_args ) { ExmMenuButtonWidgetClass wc =(ExmMenuButtonWidgetClass)XtClass(new_w); ExmMenuButtonWidget nw = (ExmMenuButtonWidget) new_w; ExmMenuButtonWidget cw = (ExmMenuButtonWidget) old_w; Boolean redisplayFlag = False; /* should we force these ? - probably to protect from *highlightThickness*/ nw->primitive.highlight_thickness = 0; nw->primitive.traversal_on = True; if (wc->simple_class.reconfigure) { (*(wc->simple_class.reconfigure))(exmMenuButtonWidgetClass, new_w, old_w); redisplayFlag = True; } if (nw->menu_button.accelerator_text != NULL) nw->menu_button.accelerator_text = XmStringCopy(nw->menu_button.accelerator_text); if ((nw->menu_button.accelerator_text != cw->menu_button.accelerator_text) || (nw->menu_button.mnemonic != cw->menu_button.mnemonic)) redisplayFlag = True; return (redisplayFlag); } /****************************************************************************** * * BorderHighlight * *****************************************************************************/ static void BorderHighlight ( Widget w ) { ExmMenuButtonWidgetClass wc = (ExmMenuButtonWidgetClass)XtClass(w); ExmMenuButtonWidget mw = (ExmMenuButtonWidget)w; if (mw->menu_button.armed == True) return; mw->menu_button.armed = True; if (wc->simple_class.draw_shadow) (*(wc->simple_class.draw_shadow)) ((Widget) mw); } /****************************************************************************** * * BorderUnhighlight: * Called when ... * *****************************************************************************/ static void BorderUnhighlight ( Widget w ) { ExmMenuButtonWidgetClass wc = (ExmMenuButtonWidgetClass)XtClass(w); ExmMenuButtonWidget mw = (ExmMenuButtonWidget)w; if (mw->menu_button.armed == False) return; mw->menu_button.armed = False; if (wc->simple_class.draw_shadow) (*(wc->simple_class.draw_shadow)) ((Widget) mw); } /****************************************************************************** * * DrawVisual * *****************************************************************************/ static void DrawVisual ( Widget w ) { ExmMenuButtonWidgetClass wc = (ExmMenuButtonWidgetClass)XtClass(w); ExmMenuButtonWidget mw = (ExmMenuButtonWidget)w; /* If the compound string is not NULL and if there is enough space in the widget to draw at least a little portion of the compound string, then render the string with XmStringDraw. */ if (mw->string.compound_string && (mw->simple.visual.width != 0) && (mw->simple.visual.height != 0)) { if (mw->menu_button.mnemonic != XK_VoidSymbol) { char mnemonic_str[2]; XmString tmp; mnemonic_str[0] = mw->menu_button.mnemonic & 0xFF; mnemonic_str[1] = 0; tmp = XmStringCreate(mnemonic_str, mw->menu_button.mnemonic_charset); XmStringDrawUnderline(XtDisplay(mw), XtWindow(mw), mw->string.render_table, mw->string.compound_string, wc->simple_class.select_gc(w), mw->simple.visual.x, mw->simple.visual.y, mw->simple.visual.width, mw->string.alignment, mw->primitive.layout_direction, NULL, tmp); XmStringFree(tmp); } else { XmStringDraw(XtDisplay(mw), XtWindow(mw), mw->string.render_table, mw->string.compound_string, wc->simple_class.select_gc(w), mw->simple.visual.x, mw->simple.visual.y, mw->simple.visual.width, mw->string.alignment, mw->primitive.layout_direction, NULL); } /* Draw the accelerator text */ if (mw->menu_button.accelerator_text) { Dimension height, width, offset; offset = mw->primitive.highlight_thickness + mw->primitive.shadow_thickness; XmStringExtent (mw->string.render_table, mw->menu_button.accelerator_text, &width, &height); XmStringDraw(XtDisplay(mw), XtWindow(mw), mw->string.render_table, mw->menu_button.accelerator_text, wc->simple_class.select_gc(w), XtWidth(w) - width - offset, mw->simple.visual.y, mw->simple.visual.width, mw->string.alignment, mw->primitive.layout_direction, NULL); } XmeClearBorder(XtDisplay(mw), XtWindow(mw), (int)0, (int)0, (Dimension)mw->core.width, (Dimension)mw->core.height, (Dimension)(mw->primitive.highlight_thickness + mw->primitive.shadow_thickness) ); } } /****************************************************************************** * * CalcVisualSize * *****************************************************************************/ static void CalcVisualSize ( Widget w ) { ExmMenuButtonWidget mw = (ExmMenuButtonWidget)w; /* Ideally, how much space would the compound string require? */ if (mw->string.compound_string && !XmStringEmpty(mw->string.compound_string)) XmStringExtent (mw->string.render_table, mw->string.compound_string, &(mw->simple.visual.width), &(mw->simple.visual.height)); else { /* The string is empty, so it requires no space. */ mw->simple.visual.width = 0; mw->simple.visual.height = 0; } /* Now add the space for the accelerator text */ if (mw->menu_button.accelerator_text) { Dimension height, width; int h_unit; Widget scr = XmGetXmScreen(XtScreen(w)); Arg args[1]; XtSetArg(args[0], XmNhorizontalFontUnit, &h_unit); XtGetValues(scr, args, 1); XmStringExtent (mw->string.render_table, mw->menu_button.accelerator_text, &width, &height); mw->simple.visual.width += width + (2 * h_unit); if (height > mw->simple.visual.height) mw->simple.visual.height = height; } } /************************************************************************ * * DrawShadow * ************************************************************************/ static void DrawShadow ( Widget w ) { ExmMenuButtonWidget mw = (ExmMenuButtonWidget)w; if (mw->core.width > 2 * mw->primitive.highlight_thickness && mw->core.height > 2 * mw->primitive.highlight_thickness && mw->primitive.shadow_thickness > 0) { if (mw->menu_button.armed) XmeDrawShadows (XtDisplay (mw), XtWindow (mw), mw->primitive.top_shadow_GC, mw->primitive.bottom_shadow_GC, mw->primitive.highlight_thickness, mw->primitive.highlight_thickness, mw->core.width - 2 * mw->primitive.highlight_thickness, mw->core.height - 2 * mw->primitive.highlight_thickness, mw->primitive.shadow_thickness, XmSHADOW_OUT); else XmeClearBorder (XtDisplay (mw), XtWindow(mw), mw->primitive.highlight_thickness, mw->primitive.highlight_thickness, mw->core.width - 2 * mw->primitive.highlight_thickness, mw->core.height - 2 * mw->primitive.highlight_thickness, mw->primitive.shadow_thickness); } } /********************************************************************** * * MenuButtonEnter * *********************************************************************/ static void MenuButtonEnter ( Widget w, XEvent *event, String *params, Cardinal *num_params ) { ExmMenuButtonWidgetClass wc = (ExmMenuButtonWidgetClass)XtClass(w); ExmMenuButtonWidget mw = (ExmMenuButtonWidget)w; XmMenuSystemTrait menuSTrait; int status; menuSTrait = (XmMenuSystemTrait) XmeTraitGet((XtPointer) XtClass(XtParent(w)), XmQTmenuSystem); if (! menuSTrait) return; status = menuSTrait -> status(XtParent(w)); if ((((ShellWidget) XtParent(XtParent(mw)))->shell.popped_up) && XmIsInDragMode(status)) { menuSTrait -> childFocus(w); mw->menu_button.armed = True; if (wc->simple_class.draw_shadow) (*(wc->simple_class.draw_shadow)) ((Widget) mw); } } /********************************************************************** * * MenuButtonLeave * *********************************************************************/ static void MenuButtonLeave ( Widget w, XEvent *event, String *params, Cardinal *num_params ) { ExmMenuButtonWidgetClass wc = (ExmMenuButtonWidgetClass)XtClass(w); ExmMenuButtonWidget mw = (ExmMenuButtonWidget)w; XmMenuSystemTrait menuSTrait; int status; menuSTrait = (XmMenuSystemTrait) XmeTraitGet((XtPointer) XtClass(XtParent(w)), XmQTmenuSystem); if (! menuSTrait) return; status = menuSTrait -> status(XtParent(w)); if (XmIsInDragMode(status) && mw->menu_button.armed && event->xcrossing.mode == NotifyNormal) { mw->menu_button.armed = False; if (wc->simple_class.draw_shadow) (*(wc->simple_class.draw_shadow)) ((Widget) mw); } } /********************************************************************** * * ArmAndActivate * *********************************************************************/ static void ArmAndActivate ( Widget w, XEvent *event, String *params, Cardinal *num_params ) { ExmMenuButtonWidget mw = (ExmMenuButtonWidget)w; Boolean already_armed = mw->menu_button.armed; XmAnyCallbackStruct cb; Boolean parent_is_torn = False; Boolean torn_has_focus = False; XmMenuSystemTrait menuSTrait; menuSTrait = (XmMenuSystemTrait) XmeTraitGet((XtPointer) XtClass(XtParent(w)), XmQTmenuSystem); if (menuSTrait == NULL) { /* We're in trouble. This isn't a valid menu that we're in and Arm and Activate has been called. Abort ! */ return; } if (!XmIsMenuShell(XtParent(XtParent(mw)))) { parent_is_torn = True; /* Because the pane is torn and the parent is a transient shell, * the shell's focal point should be valid * (as opposed to getting it from a MenuShell). */ if (XmeFocusIsInShell((Widget)mw)) { if (!XtIsSensitive((Widget)mw) || (!XtIsManaged((Widget)mw))) return; torn_has_focus = True; } } else { parent_is_torn = False; } mw->menu_button.armed = False; if (parent_is_torn && !torn_has_focus) { /* Freeze tear off visuals in case accelerators are not in * same context */ menuSTrait -> reparentToTearOffShell(XtParent(w), event); } if (torn_has_focus) menuSTrait -> popdown(XtParent(mw), event); else menuSTrait -> buttonPopdown(XtParent(mw), event); /* if its in a torn off menu pane, show depressed button briefly */ if (torn_has_focus) { /* Set the focus here. */ XmProcessTraversal ((Widget)mw, XmTRAVERSE_CURRENT); /* this should be done through draw-shadow!!!! */ XmeDrawShadows (XtDisplay(mw), XtWindow(mw), mw->primitive.bottom_shadow_GC, mw->primitive.top_shadow_GC, mw->primitive.highlight_thickness, mw->primitive.highlight_thickness, mw->core.width - 2 * mw->primitive.highlight_thickness, mw->core.height - 2 * mw->primitive.highlight_thickness, mw->primitive.shadow_thickness, XmSHADOW_OUT); } XFlush (XtDisplay(mw)); /* If the parent is a Menu, set the lastSelectToplevel before the arm. * It's ok if this is recalled later. */ menuSTrait -> getLastSelectToplevel(XtParent(mw)); cb.reason = XmCR_ACTIVATE; cb.event = event; /* if the parent is a Menu, notify it about the select */ menuSTrait -> entryCallback(XtParent(mw), (Widget) mw, &cb); if (! mw -> menu_button.skip_callback && mw->menu_button.activate_callback) { XFlush (XtDisplay (mw)); XtCallCallbackList ((Widget)mw, mw->menu_button.activate_callback, &cb); } mw->menu_button.armed = False; if (torn_has_focus) { /* Leave the focus widget in an armed state */ mw->menu_button.armed = True; } else { menuSTrait -> reparentToTearOffShell(XtParent(mw), event); } /* * If the button is still around, show it released, after a short delay. * This is done if the button is outside of a menus, or if in a torn * off menupane. */ if (torn_has_focus && mw->core.being_destroyed == False && mw->menu_button.visual_timer == 0) { mw->menu_button.visual_timer = XtAppAddTimeOut( XtWidgetToApplicationContext((Widget)mw), (unsigned long) VISUAL_DELAY, VisualDisarm, (XtPointer)(mw)); } } /********************************************************************** * * VisualDisarm: * * *********************************************************************/ static void VisualDisarm ( XtPointer cd, XtIntervalId *id ) { ExmMenuButtonWidget mw = (ExmMenuButtonWidget)cd; ExmMenuButtonWidgetClass wc = (ExmMenuButtonWidgetClass)XtClass(mw); mw->menu_button.visual_timer = 0; if (XtIsRealized((Widget)mw) && XtIsManaged((Widget)mw)) { /* When rapidly clicking, the focus may have moved away from this widget, so check before changing the shadow. */ if (XmeFocusIsInShell((Widget)mw) && (XmGetFocusWidget((Widget)mw) == (Widget)mw) ) { /* in a torn off menu, redraw shadows */ /* Draw a Motif-style shadow. */ XmeDrawShadows (XtDisplay(mw), XtWindow(mw), mw->primitive.top_shadow_GC, mw->primitive.bottom_shadow_GC, mw->primitive.highlight_thickness, mw->primitive.highlight_thickness, mw->core.width - (2 * mw->primitive.highlight_thickness), mw->core.height - (2 * mw->primitive.highlight_thickness), mw->primitive.shadow_thickness, XmSHADOW_OUT); } XFlush (XtDisplay(mw)); } } /********************************************************************** * * BtnDown * *********************************************************************/ static void BtnDown ( Widget w, XEvent *event, String *params, Cardinal *num_params ) { ExmMenuButtonWidgetClass wc = (ExmMenuButtonWidgetClass)XtClass(w); ExmMenuButtonWidget mw = (ExmMenuButtonWidget)w; XmAnyCallbackStruct cb; Boolean validButton; Boolean already_armed; ShellWidget popup; int status; XmMenuSystemTrait menuSTrait; menuSTrait = (XmMenuSystemTrait) XmeTraitGet((XtPointer) XtClass(XtParent(mw)), XmQTmenuSystem); if (menuSTrait == NULL) { /* We're in trouble. This isn't a valid menu that we're in. Abort! */ return; } XAllowEvents (XtDisplay(mw), SyncPointer, CurrentTime); if (event && (event->type == ButtonPress)) validButton = menuSTrait -> verifyButton(XtParent(mw), event); if (!validButton) return; menuSTrait -> controlTraversal(XtParent(mw), True); status = menuSTrait -> status(XtParent(w)); /* Popdown other popus that may be up */ if (!(popup = (ShellWidget) menuSTrait -> getPopupPosted (XtParent(mw)))) { if (!XmIsMenuShell (XtParent(XtParent(mw)))) { /* In case tear off not armed and no grabs in place, do it now. * Ok if already armed and grabbed - nothing done. */ menuSTrait -> tearOffArm(XtParent(mw)); } } if (popup) { Widget aw; if (popup->shell.popped_up) menuSTrait -> popdownEveryone((Widget) popup, event); /* If active_child is a cascade (highlighted), unhighlight it. */ aw = ((XmManagerWidget)XtParent(mw))->manager.active_child; if (aw && ((XmIsCascadeButton(aw) || XmIsCascadeButtonGadget(aw)))) XmCascadeButtonHighlight (aw, False); } /* Set focus to this pushbutton. This must follow the possible * unhighlighting of the CascadeButton else it'll screw up active_child. */ (void)XmProcessTraversal( (Widget)mw, XmTRAVERSE_CURRENT); /* get the location cursor - get consistent with Gadgets */ already_armed = mw->menu_button.armed; mw->menu_button.armed = True; _XmRecordEvent(event); } /********************************************************************** * * BtnUp * *********************************************************************/ static void BtnUp ( Widget w, XEvent *event, String *params, Cardinal *num_params ) { ExmMenuButtonWidget mw = (ExmMenuButtonWidget)w; Widget parent = XtParent(mw); XmAnyCallbackStruct cb; Boolean flushDone = False; Boolean validButton; Boolean popped_up; Widget shell = XtParent(XtParent(mw)); XmMenuSystemTrait menuSTrait; menuSTrait = (XmMenuSystemTrait) XmeTraitGet((XtPointer) XtClass(XtParent(w)), XmQTmenuSystem); if (menuSTrait == NULL) { /* We're in trouble. This isn't a valid menu that we're in and Arm and Activate has been called. Abort ! */ return; } if (event && (event->type == ButtonRelease)) validButton = menuSTrait -> verifyButton(parent, event); if (!validButton || (mw->menu_button.armed == False)) return; mw->menu_button.armed = False; if (!XmIsMenuShell(shell)) popped_up = menuSTrait -> popdown(parent, event); else popped_up = menuSTrait -> buttonPopdown(parent, event); _XmRecordEvent(event); /* XmMENU_POPDOWN left the menu posted on button click - don't activate! */ if (popped_up) return; cb.reason = XmCR_ACTIVATE; cb.event = event; menuSTrait -> entryCallback(parent, (Widget) mw, &cb); if (! mw -> menu_button.skip_callback && mw->menu_button.activate_callback) { XFlush (XtDisplay(mw)); flushDone = True; XtCallCallbackList ((Widget)mw, mw->menu_button.activate_callback, &cb); } /* If the original shell does not indicate an active menu, but rather a * tear off pane, leave the button in an armed state. Also, briefly * display the button as depressed to give the user some feedback of * the selection. */ if (!XmIsMenuShell(shell)) { XmeDrawShadows (XtDisplay (mw), XtWindow (mw), mw->primitive.bottom_shadow_GC, mw->primitive.top_shadow_GC, mw->primitive.highlight_thickness, mw->primitive.highlight_thickness, mw->core.width - 2 * mw->primitive.highlight_thickness, mw->core.height - 2 * mw->primitive.highlight_thickness, mw->primitive.shadow_thickness, XmSHADOW_OUT); XFlush (XtDisplay (mw)); flushDone = True; if (mw->core.being_destroyed == False && mw->menu_button.visual_timer == 0) { mw->menu_button.visual_timer = XtAppAddTimeOut ( XtWidgetToApplicationContext((Widget)mw), (unsigned long)VISUAL_DELAY, VisualDisarm, (XtPointer)mw); } mw->menu_button.armed = True; } else { menuSTrait -> reparentToTearOffShell(XtParent(mw), event); } menuSTrait -> controlTraversal(XtParent(mw), False); /* For the benefit of tear off menus, we must set the focus item * to this button. In normal menus, this would not be a problem * because the focus is cleared when the menu is unposted. */ if (!XmIsMenuShell(shell)) XmProcessTraversal ((Widget)mw, XmTRAVERSE_CURRENT); } /********************************************************************** * * MenuButtonHelp * *********************************************************************/ static void MenuButtonHelp ( Widget w, XEvent *event, String *params, Cardinal *num_params ) { ExmMenuButtonWidgetClass wc = (ExmMenuButtonWidgetClass)XtClass(w); ExmMenuButtonWidget mw = (ExmMenuButtonWidget)w; XmMenuSystemTrait menuSTrait; menuSTrait = (XmMenuSystemTrait) XmeTraitGet((XtPointer) XtClass(XtParent(w)), XmQTmenuSystem); if (menuSTrait == NULL) { /* We're in trouble. This isn't a valid menu that we're in and Arm and Activate has been called. Abort ! */ return; } menuSTrait -> buttonPopdown(XtParent(mw), event); XtCallActionProc ((Widget)mw, "PrimitiveHelp", event, params, *num_params); menuSTrait -> reparentToTearOffShell(XtParent(mw), event); } /***********************************************************/ /* Trait method which allows the menu system to control */ /* the button's activate callback. This is used in */ /* conjunction with the entryCallback in RowColumn. The */ /* RowColumn callback (or other menu which supports the */ /* menuSavvy trait) is called via the */ /* childsActivateCallback in the menuSystem trait. */ /***********************************************************/ static void DisableCallback( Widget w, XtEnum value) { ExmMenuButtonWidget mw = (ExmMenuButtonWidget)w; mw->menu_button.skip_callback = !( value == XmENABLE_ACTIVATE); } static char* GetAccelerator(Widget w) { ExmMenuButtonWidget mw = (ExmMenuButtonWidget)w; return(mw -> menu_button.accelerator); } static KeySym GetMnemonic(Widget w) { ExmMenuButtonWidget mw = (ExmMenuButtonWidget)w; return(mw -> menu_button.mnemonic); } static char* GetActivateCBName() { return(XmNactivateCallback); } /************************************************************************ * * ExmCreateMenuButton * Externally accessable function for creating a MenuButton widget * ************************************************************************/ Widget ExmCreateMenuButton ( Widget parent, char *name, Arg *arglist, Cardinal argCount ) { return (XtCreateWidget(name,exmMenuButtonWidgetClass, parent,arglist,argCount)); }