/*********************************************************************
 *
 *         EZWGL, the EZ Widget and Graphics Library
 *
 *             Copyright (C) 1996, 1997  Maorong Zou
 *  
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **********************************************************************/
/*
 *  June 1996.  Beta Release.
 *  Sept 1996.  Release Version 1.0
 *  Dec 1996.  Release Version 1.1 Beta
 *  April 1997.  Release Version 1.2
 *  November 1997.  Release Version 1.3
 */
/*****************************************************************
 ***                                                           ***
 ***              Menu Bar                                     ***
 ***                                                           ***
 *****************************************************************/
#define _EZ_WIDGET_MBAR_C_

#include "EZ_Widget.h"
#include <ctype.h>

/*********************************************************************
 * 
 *  Functions implemented in this file:
 */
EZ_Widget        *EZ_CreateMBar MY_ANSIARGS((EZ_Widget *parent));
void              EZ_DrawWidgetMBar MY_ANSIARGS((EZ_Widget *widget));
void              EZ_ComputeWidgetMBarSize MY_ANSIARGS((EZ_Widget *widget, int *w, int *h));
void              EZ_FreeWidgetMBarData MY_ANSIARGS((EZ_Widget *widget));
void              EZ_MBarEventHandle MY_ANSIARGS((EZ_Widget *widget, XEvent *event));

EZ_Widget        *EZ_MenuBarAddItemAndMenu MY_ANSIARGS((EZ_Widget *widget, char *label, int ul, EZ_Widget *menu));
void              EZ_MenuBarSetItemMenu MY_ANSIARGS((EZ_Widget *widget, char *label, EZ_Widget *menu));
EZ_Widget         *EZ_MenuBarFindItemAtXY MY_ANSIARGS(( EZ_Widget *widget, int x, int y));
EZ_Widget         *EZ_MenuBarFindItemAndMenuAtXY MY_ANSIARGS(( EZ_Widget *widget, int x, int y, EZ_Widget **ret));
EZ_Widget         *EZ_MenuBarFindItem MY_ANSIARGS(( EZ_Widget *widget, char *name));
EZ_Widget         *EZ_MenuBarFindItemAndMenu MY_ANSIARGS(( EZ_Widget *widget, char *name, EZ_Widget **ret));
void              EZ_MenuBarDeleteItem MY_ANSIARGS((EZ_Widget *widget, char *label));
void              EZ_MenuBarDeleteItemAndMenu MY_ANSIARGS((EZ_Widget *widget, char *label));
void              EZ_MenuBarInsertItemAndMenu MY_ANSIARGS((EZ_Widget *mbar, char *label, int ul, EZ_Widget *menu,
							   char *ref, int where));
static EZ_Widget  *EZ_FindMBarMenu MY_ANSIARGS(( EZ_Widget *widget, int x, int y, EZ_Widget **l_ret));
static EZ_Widget  *FindAdjacentItem MY_ANSIARGS(( EZ_Widget *widget, int dir));
/*********************************************************************
 * 
 *  Local Variables.
 */
static EZ_WidgetHandle EZ_MBarHandle =
{ 
  EZ_ComputeWidgetMBarSize,
  EZ_DrawWidgetMBar,
  EZ_FreeWidgetMBarData,
  EZ_MBarEventHandle,
};

/*********************************************************************/

EZ_Widget  *EZ_CreateMBar(parent)
     EZ_Widget  *parent;     /* parent widget    */

{
  EZ_Widget  *wptr;

  wptr = EZ_CreateNewWidget(parent);
  /*--------------------------------------------------
   * Register the handling functions for CButton.
   *  has to be done after  EZ_CreateNewWidget.
   *-------------------------------------------------*/
  EZ_WidgetHandlingFunctions[EZ_WIDGET_MENU_BAR] = &EZ_MBarHandle;

  EZ_SetWidgetTypeAndNames(wptr,  EZ_WIDGET_MENU_BAR);
  EZ_WidgetFont(wptr) = EZ_GetFontFromId(EZ_BUTTON_FONT);
  EZ_WidgetStacking(wptr) = EZ_HORIZONTAL_LEFT;
  EZ_WidgetFillMode(wptr) = EZ_FILL_HORIZONTALLY;
  EZ_WidgetPadX(wptr) = EZ_WIDGET_DEFAULT_PADX;
  EZ_WidgetPadY(wptr) = 2;
  EZ_WidgetSepX(wptr) = EZ_WIDGET_DEFAULT_PADX;
  EZ_WidgetBorderWidth(wptr) = 2;
  EZ_WidgetBorderStyle(wptr)  = EZ_BORDER_UP;
  EZ_SetWidgetHeightSetFlag(wptr);
  EZ_MBarLastItem(wptr) = NULL;
  EZ_SetWidgetExpandFlag(wptr);
  return(wptr);
}

/********************************************************************
 *
 *  Figure out the dimension of a menu button
 */
void EZ_ComputeWidgetMBarSize(widget, w, h)
     EZ_Widget *widget;
     int       *w, *h;
{
  int  cw, ch;;
  
  if(!(EZ_GetWidgetSizeComputedFlag(widget)))
    { EZ_SetWidgetSizeComputedFlag(widget); }
  cw = EZ_WidgetPadX(widget) + EZ_WidgetBorderWidth(widget) + EZ_WidgetPadB(widget);
  ch = EZ_WidgetPadY(widget) + EZ_WidgetBorderWidth(widget) + EZ_WidgetPadB(widget);
  ch = ch + ch + 8;
  cw = cw + cw + 16;

  *w = cw;
  *h = ch;
}

/******************************************************************************
 *
 *  Free allocated data for a menu button.
 */

void EZ_FreeWidgetMBarData(mbtn)
     EZ_Widget *mbtn;
{
}

/******************************************************************************
 *
 *  Draw a menu button
 */

void EZ_DrawWidgetMBar(wptr)
     EZ_Widget *wptr;
{
  int             w, h, padb, padb2, filled = 0;
  Pixmap          pixmap;
  Window          win;
  GC              gc;
  unsigned long   bgpv, bgpva;

  win = EZ_WidgetWindow(wptr);
  w   = EZ_WidgetWidth(wptr);
  h   = EZ_WidgetHeight(wptr);
  padb = EZ_WidgetPadB(wptr);
  padb2 = padb + padb;

  /*-----------------------------------------------------------
   *  Create a pixmap, draw into this pixmap in background and
   *  copy to the button window when finished.
   *----------------------------------------------------------*/
  pixmap = XCreatePixmap(EZ_DisplayForWidgets, win, w, h, EZ_DepthForWidgets);    
  if(padb > 0)
    {
      EZ_GetParentBgGCN(wptr, &gc,&bgpva);
      XFillRectangle(EZ_DisplayForWidgets, pixmap, gc, 0,0, w, h); 
      filled = 1;
    }
  else bgpva = 0;
  EZ_GetBackgroundGC(wptr, &gc, &bgpv, 1,0);  
  if(filled == 0 || bgpv != bgpva)
    XFillRectangle(EZ_DisplayForWidgets, pixmap, gc, padb,padb, w-padb2, h-padb2); 


  /*============================================================
   * menu labels are NW labels.
   */
  {
    EZ_Widget *children = EZ_WidgetChildren(wptr);
    if(children && EZ_WidgetType(children) == EZ_WIDGET_NW_LABEL)
      {
	EZ_DisplayNWLabel(children, pixmap, EZ_WidgetForeground(wptr), bgpv,
			  EZ_GetWidgetDisabledFlag(wptr), 0,
			  0, 0, 0, 1);
      }
  }
  /*============================================================*/  


  /*------------------------------------
   *  Now the real border.
   *-----------------------------------*/
  EZ_DrawRectBorder(wptr, pixmap);
  XCopyArea(EZ_DisplayForWidgets,pixmap,win, EZ_WRITABLEGC,0,0,w,h,0,0); 
  XFreePixmap(EZ_DisplayForWidgets, pixmap); 
}

/*************************************************************************
 *
 *  Event handling, tricky!
 */

void  EZ_MBarEventHandle(widget, event)
     EZ_Widget *widget;
     XEvent    *event;
{
  EZ_Widget *mmenu, *theBtn = NULL;
  int bx, by;

  if(widget == (EZ_Widget *)NULL) return;
  if(event->type == Expose)   EZ_DrawWidget(widget);      
  if( EZ_GetWidgetDisabledFlag(widget) ) return;

  switch(event->type)
    {
    case ButtonPress:
      if(event->xbutton.button == EZ_Btn1)      
	{
	  bx = event->xbutton.x;
	  by = event->xbutton.y;
	  mmenu = EZ_FindMBarMenu(widget, bx, by, &theBtn);
	  
	  if(EZ_CurrentPopupMenu != (EZ_Widget *)NULL)
	    {
	      if(mmenu == EZ_CurrentPopupMenu) return;
	      else EZ_HideCurrentPopupMenu();
	    }
	  /*-----------------------------------------------------
	   * Now we do a popup. Grab the pointer and wait for
	   * a selection.
	   *----------------------------------------------------*/
	startagain:
	  if( mmenu  && EZ_WidgetNumChildren(mmenu) == 0) mmenu = NULL;
	  if(mmenu == NULL) return;
	  
	  if(1)
	    { 
	      int          rx,ry,x,y, itmp;
	      unsigned int mask;
	      Window       root,win;
	      
	      /* first set the background ptr */
	      if(mmenu)
		{
		  if(EZ_WidgetBackground(widget)) EZ_WidgetParentBG(mmenu) =
						    &(EZ_WidgetBackground(widget));
		  else   EZ_WidgetParentBG(mmenu) = EZ_WidgetParentBG(widget);
		}
	      
	      /*-----------------------------------------------------------
	       * find out the position to popup the menu and do the popup.
	       *----------------------------------------------------------*/
	      if(mmenu)
		{
		  XQueryPointer(EZ_Display, EZ_WidgetWindow(widget),
				&root,                                    /* root return win */
				&win,                                     /* child ret win   */
				&rx, &ry,                                 /* x, y in root    */
				&x,&y,                                    /* x, y in win     */
				&mask
				);
		  itmp = (EZ_WidgetHeight(widget) -y);
		  rx = rx - x + EZ_WidgetOriginX(theBtn);
		  ry = ry + itmp;
		  {
		    int ww, hh;
		    if( !(EZ_GetWidgetSizeComputedFlag(mmenu)) )
		      {
			EZ_MarkAllChildrenWidgetSizeChanged(mmenu,0);
			EZ_ComputeWidgetWindowSize(mmenu, &ww, &hh, NULL);
		      }
		    else
		      {
			ww = EZ_WidgetWidth(mmenu);
			hh = EZ_WidgetHeight(mmenu);
		      }
		    if(rx < 0) rx = 0;
		    else if(rx + ww > EZ_XDisplayWidth)  rx = (int)EZ_XDisplayWidth - ww;
		    if(ry < 0) ry = 0;
		    else if(ry + hh > EZ_XDisplayHeight) ry = (int)EZ_XDisplayHeight - hh;
		  }
		  EZ_SetWidgetHighlightFlag(theBtn);
		  EZ_MBarLastItem(widget) = theBtn;
		  EZ_WidgetBorderStyle(theBtn) = EZ_BORDER_UP;
		  EZ_DrawWidget(widget);
		  EZ_SetupPopup(mmenu);
		  EZ_DisplayPopup(mmenu, rx, ry);
		}
	      /*
	       * Now wait until a selection is made.
	       */
	      {
		XEvent          xevent;
		Window          event_window;
		EZ_Widget *tmp, *cmenu, *the_popup = EZ_CurrentPopupMenu;
		EZ_Widget *shortcutItem, *CurrentItem;
		EZ_Widget *out, *sitem;
		int             done = 0, xx=0, yy=0;
		
		XGrabPointer(EZ_Display,
			     EZ_WidgetWindow(the_popup),
			     True,
			     ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|PointerMotionMask,
			     GrabModeAsync,
			     GrabModeAsync, 
			     None,
			     EZ_GetCursor(EZ_C_RIGHT_PTR),
			     CurrentTime);
	      
		/*
		 * fvwm eats some keystrokes, so...
		 */

		XGrabKeyboard(EZ_Display,
			      EZ_WidgetWindow(the_popup),
			      True,
			      GrabModeAsync,
			      GrabModeAsync, 
			      CurrentTime);
		
		cmenu = the_popup;
		/* if the menu is poped via key press, select the first item */
		if(event->xbutton.send_event)
		  {
		    CurrentItem = EZ_FirstMenuItem(cmenu);
		    event->xbutton.send_event = False;
		  }
		else CurrentItem = NULL;
		EZ_PopupLink2(cmenu) = CurrentItem;
		while(1)
		  {
		    EZ_TFEvents();
		    XNextEvent(EZ_Display, &xevent);
		    EZ_FilterEvent(&xevent);
		    event_window = xevent.xany.window;
		    tmp = EZ_LookupWidgetFromMappedHT(event_window);

		    /*---------------------------------------------------------
		     * Handle KeyPress first.
		     *--------------------------------------------------------*/
		    if(xevent.type == KeyPress)
		      {
#define TEMP_BUFFER_SIZE    32
			int               count,modifiers;
			KeySym            keysym;
			XComposeStatus    compose; 
			char              tmpbuffer[TEMP_BUFFER_SIZE];
			int               buffersize = TEMP_BUFFER_SIZE;
			int               x_move, y_move;
#undef TEMP_BUFFER_SIZE
			shortcutItem = NULL;
			sitem = NULL;
			out = NULL;
			modifiers = xevent.xkey.state & (ShiftMask | ControlMask | Mod1Mask);
			
			xevent.xkey.state &= ~modifiers;
			count = XLookupString(&(xevent.xkey), tmpbuffer, buffersize, &keysym, &compose);
			tmpbuffer[count] = '\0'; 


			if(modifiers == 0 || count == 0 ||
			   (EZ_LookForPopupShortCuts(EZ_CurrentPopupMenu,
						     modifiers, tmpbuffer,&x_move, &y_move,
						     &shortcutItem) == 0 &&
			    EZ_GetGlobalKeyEvent(modifiers, tmpbuffer, NULL, &out, &xx, &yy) == 0))
			  {
			    switch(keysym)
			      {
			      case XK_Up:  case XK_k:  case XK_p: case XK_K:  case XK_P:
#ifdef XK_KP_Up
			      case XK_KP_Up:
#endif				
				CurrentItem = EZ_MoveMenuSelection(cmenu, CurrentItem, 1);
				EZ_PopupLink2(cmenu) = CurrentItem;
				break;
			      case XK_Down: case XK_n: case XK_j: case XK_N: case XK_J:  
#ifdef XK_KP_Down
			      case XK_KP_Down:
#endif
				CurrentItem = EZ_MoveMenuSelection(cmenu, CurrentItem, -1);
				EZ_PopupLink2(cmenu) = CurrentItem;
				break;
			      case XK_Tab: 
#ifdef XK_KP_Tab
			      case XK_KP_Tab:
#endif
				CurrentItem = EZ_MoveMenuSelection(cmenu, CurrentItem, 
								   (modifiers&ShiftMask)==0? -1: 1);
				EZ_PopupLink2(cmenu) = CurrentItem;
				break;
			      case XK_Left: case XK_b:  case XK_h: case XK_B:  case XK_H: 
#ifdef XK_KP_Left
			      case XK_KP_Left:
#endif
				{
				  EZ_Widget *tmpa = EZ_PopupLink1(cmenu);
				  if(tmpa)
				    {
				      cmenu = tmpa;
				      EZ_DeselectCurrentMenuItem(CurrentItem);
				      CurrentItem = EZ_MoveMenuSelection(cmenu, EZ_PopupLink2(cmenu), 0);
				    }
				  else
				    {
				      EZ_Widget *tmpBB, *mu, *bn = NULL;
				      EZ_HideCurrentPopupMenuA();
				      XUngrabPointer(EZ_Display, CurrentTime); 
				      XUngrabKeyboard(EZ_Display,CurrentTime); 
				      tmpBB = FindAdjacentItem(theBtn, -1);
				      if(tmpBB && tmpBB != theBtn)
					{
					  int cx = EZ_WidgetOriginX(tmpBB);
					  int cy = EZ_WidgetOriginY(tmpBB);
					  mu = EZ_FindMBarMenu(widget, cx, cy, &bn);
					  if(mu)
					    {
					      /*
					      event->xbutton.x = cx; 
					      event->xbutton.y = cy;
					      */
					      EZ_ClearWidgetHighlightFlag(theBtn);
					      EZ_WidgetBorderStyle(theBtn) = EZ_BORDER_NONE;
					      theBtn = bn;
					      mmenu = mu;
					      goto startagain;
					    }
					}
				      }
				}
				break;
			      case XK_Right: case XK_f: case XK_l: case XK_F: case XK_L: 
#ifdef XK_KP_Right
			      case XK_KP_Right:
#endif
				if(CurrentItem && EZ_WidgetType(CurrentItem) == EZ_WIDGET_MENU_SUBMENU)
				  {
				    EZ_Widget *tmenu = EZ_SubMenuTheMenu(CurrentItem);
				    if(tmenu )
				      {
					if(! EZ_WidgetMapped(tmenu)) EZ_DisplayPopupSubMenuOf(CurrentItem);
					EZ_DeselectCurrentMenuItem(CurrentItem);
					EZ_PopupLink1(tmenu) = cmenu;
					cmenu = tmenu;
					CurrentItem = EZ_MoveMenuSelection(cmenu, EZ_PopupLink2(cmenu), 0);
					EZ_PopupLink2(cmenu) = CurrentItem;			    
				      }
				  }
				else
				  {
				    EZ_Widget *tmpBB, *mu, *bn = NULL;
				    EZ_HideCurrentPopupMenuA();
				    XUngrabPointer(EZ_Display, CurrentTime); 
				    XUngrabKeyboard(EZ_Display,CurrentTime); 
				    tmpBB = FindAdjacentItem(theBtn, 1);
				    if(tmpBB && tmpBB != theBtn)
				      {
					int cx = EZ_WidgetOriginX(tmpBB);
					int cy = EZ_WidgetOriginY(tmpBB);
					mu = EZ_FindMBarMenu(widget, cx, cy, &bn);
					if(mu)
					  {
					    /*
					      event->xbutton.x = cx; 
					      event->xbutton.y = cy; 
					      */
					    EZ_ClearWidgetHighlightFlag(theBtn);
					    EZ_WidgetBorderStyle(theBtn) = EZ_BORDER_NONE;
					    theBtn = bn;
					    mmenu = mu;
					    goto startagain;
					  }
				      }
				  }
				break;
			      case XK_Return: case XK_Linefeed: case XK_space:  
#ifdef XK_KP_Enter
			      case XK_KP_Enter:
#endif
				if(CurrentItem && EZ_WidgetType(CurrentItem) == EZ_WIDGET_MENU_SUBMENU)
				  {
				    EZ_Widget *tmenu = EZ_SubMenuTheMenu(CurrentItem);
				    if(tmenu)
				      {
					if(! EZ_WidgetMapped(tmenu)) EZ_DisplayPopupSubMenuOf(CurrentItem);
					EZ_PopupLink1(tmenu) = cmenu;
					cmenu = tmenu;
					CurrentItem = EZ_MoveMenuSelection(cmenu, EZ_PopupLink2(cmenu), 0);
					EZ_PopupLink2(cmenu) = CurrentItem;			    
				      }
				  }
				else
				  {
				    sitem = CurrentItem;
				    done = 1;
				  }
				break;	
			      default:
				break;
			      }
			  }
			/*--------------------------------------------
			 * if a selection has been made, finish up
			 *-------------------------------------------*/
			if(shortcutItem) 
			  {
			    EZ_DeselectCurrentMenuItem(CurrentItem);
			    CurrentItem = shortcutItem;
			    sitem = shortcutItem;
			  }
			if(sitem)
			  {
			    done = 1;
			    if(EZ_GetWidgetDisabledFlag(sitem) == 0)
			      {
				int doit = 1;
				
				switch(EZ_WidgetType(sitem))
				  {
				  case EZ_WIDGET_MENU_CHECK_BUTTON:
				    if( EZ_CButtonOn(sitem) )
				      {  EZ_CButtonSetOffValue(sitem);}
				    else { EZ_CButtonSetOnValue(sitem);}
				    break;
				  case EZ_WIDGET_MENU_RADIO_BUTTON:	  
				    if( !( EZ_RButtonOn(sitem)) )
				      {
					EZ_RButtonList  *friends;
					EZ_Widget *old = (EZ_Widget *)NULL;
					friends = EZ_RButtonGroup(sitem)->list;
					while(friends)
					  {
					    if( EZ_RButtonOn( friends->rbutton) )
					      {
						old = friends->rbutton;  /* currently checked  */
						break;
					      }
					    friends = friends->next;
					  }
					EZ_RButtonSetValue(sitem);
					if(old && EZ_WidgetMapped(old)) EZ_DrawWidget(old);
				      }
				    break;
				  case EZ_WIDGET_MENU_NORMAL_BUTTON:
				  case EZ_WIDGET_MENU_TEAR_OFF_BAR:
				    break;
				  case EZ_WIDGET_MENU_SUBMENU:
				    EZ_DisplayPopupSubMenuOf(sitem);
				    doit = 0;
				    done = 0;
				    break;
				  default:
				    doit = 0;
				    break;
				  }
				if(doit)
				  {
				    EZ_WidgetBorderStyle(sitem) = EZ_BORDER_UP;
				    EZ_DrawWidget(sitem);
				    
				    if(EZ_CurrentPopupMenu != (EZ_Widget *)NULL)
				      {  /* return value */
					EZ_WidgetRetData(EZ_CurrentPopupMenu) = EZ_WidgetRetData(sitem);
				 	/* this is the selected item     */
					EZ_PopupLSItem(EZ_CurrentPopupMenu) = sitem;  
				      }
				  }
			      }
			  }
			else if(out) /* get out */
			  {
			    XButtonEvent xbevent;
			    xbevent.type = ButtonRelease;
			    xbevent.button = EZ_Btn1;
			    xbevent.display = EZ_Display;
			    xbevent.window = EZ_WidgetWindow(out);
			    xbevent.time = CurrentTime;
			    xbevent.x=xx; xbevent.y=yy;
			    XSendEvent(EZ_Display, EZ_WidgetWindow(out),
				       False, ButtonReleaseMask, (XEvent *)&xbevent);
			    EZ_HandleGlobalKeyEvent(out, xx, yy);
			    done = 1;
			  }
		      } /* KeyPress */
		    else
		      {
			/*---------------------------------------------------------
			 *  Non KeyPress Events.
			 *--------------------------------------------------------*/
			if(tmp == (EZ_Widget *)NULL) continue;
			else if(tmp == widget) /* event on menubar */
			  {  
			    if(xevent.type == ButtonPress || xevent.type == ButtonRelease)
			      {
				int x = xevent.xbutton.x;
				int y = xevent.xbutton.y;
				EZ_Widget *bn;
				if( x < 0 || x > EZ_WidgetWidth(tmp) ||
				    y < 0 || y > EZ_WidgetHeight(tmp) ||
				    EZ_FindMBarMenu(widget, x, y, &bn) == NULL)
				  done = 1;
			      }
			    else if(xevent.type == MotionNotify)   /* 'cause of the grab */
			      {
				int x = xevent.xmotion.x;
				int y = xevent.xmotion.y;
				EZ_Widget *mu, *bn;
				mu = EZ_FindMBarMenu(widget, x, y, &bn);
				if(mu && mu != mmenu)
				  {
				    EZ_ClearWidgetHighlightFlag(theBtn);
				    EZ_WidgetBorderStyle(theBtn) = EZ_BORDER_NONE;
				    EZ_HideCurrentPopupMenuA();
				    XUngrabPointer(EZ_Display, CurrentTime); 
				    XUngrabKeyboard(EZ_Display,CurrentTime); 
				    theBtn = bn;
				    mmenu = mu;
				    event->xbutton.x = x;
				    event->xbutton.y = x;
				    goto startagain;
				  }
			      }
			  }
			else  /* event happend on some other widgets */
			  {
			    if(xevent.type == Expose)
			      EZ_HandleWidgetWindowEvent(tmp, &xevent);
			    else if(xevent.type == EnterNotify)
			      {
				if(EZ_WidgetType(tmp) == EZ_WIDGET_MENU_BUTTON)
				  {
				    EZ_WidgetBorderStyle(theBtn) = EZ_BORDER_NONE;
				    EZ_ClearWidgetHighlightFlag(theBtn);
				    EZ_DrawWidget(widget);

				    /* if we get here, we've entered into another
				     * menu-button. Just start over again.
				     */
				    if(xevent.xcrossing.mode != NotifyGrab  &&
				       xevent.xcrossing.mode != NotifyUngrab)
				      {
					EZ_HideCurrentPopupMenuA();
					XUngrabPointer(EZ_Display, CurrentTime); 
					XUngrabKeyboard(EZ_Display,CurrentTime); 
					event->xbutton.window = EZ_WidgetWindow(tmp);
					event->xbutton.x = event->xbutton.y = 1;
					EZ_WidgetBorderStyle(theBtn) = EZ_BORDER_NONE;
					EZ_ClearWidgetHighlightFlag(theBtn);
					EZ_DrawWidget(widget);
					EZ_HandleWidgetWindowEvent(tmp, &xevent);
					return;
				      }
				  }
				else if(EZ_GetWidgetIsCloneFlag(tmp) == 0)
				  {
				    int type = EZ_WidgetType(tmp);
				    if(type == EZ_WIDGET_MENU_TEAR_OFF_BAR ||
				       (type >= EZ_WIDGET_MENU_SEPARATOR &&
					type <= EZ_WIDGET_MENU_RADIO_BUTTON))
				      {
					if(xevent.xcrossing.mode != NotifyGrab  &&
					   xevent.xcrossing.mode != NotifyUngrab)
					  {
					    EZ_DeselectCurrentMenuItem(CurrentItem);
					    EZ_HandleWidgetWindowEvent(tmp, &xevent);
					    CurrentItem = tmp;
					  }
				      }
				  }
			      }
			    else if(xevent.type == LeaveNotify)
			      {
				if(EZ_WidgetType(tmp) == EZ_WIDGET_MENU_BUTTON)
				  {
				    EZ_WidgetBorderStyle(tmp) = EZ_BORDER_NONE;
				    EZ_ClearWidgetHighlightFlag(tmp);
				    EZ_DrawWidget(tmp);
				  }
				else if(EZ_GetWidgetIsCloneFlag(tmp) == 0)
				  {
				    int type = EZ_WidgetType(tmp);
				    if(type == EZ_WIDGET_MENU_TEAR_OFF_BAR ||
				       (type >= EZ_WIDGET_MENU_SEPARATOR &&
					type <= EZ_WIDGET_MENU_RADIO_BUTTON))
				      {
					if(xevent.xcrossing.mode != NotifyGrab  &&
					   xevent.xcrossing.mode != NotifyUngrab)
					  {
					    EZ_DeselectCurrentMenuItem(CurrentItem);
					    CurrentItem = (EZ_Widget *)NULL;
					    EZ_HandleWidgetWindowEvent(tmp, &xevent);
					  }
				      }
				  }
			      }
			    else if(xevent.type == FocusIn || xevent.type == FocusOut)
			      EZ_HandleWidgetWindowEvent(tmp, &xevent);
			    else if(xevent.type == ButtonPress || xevent.type == ButtonRelease)
			      {
				if(xevent.type == ButtonRelease &&
				   (EZ_WidgetType(tmp) != EZ_WIDGET_MENU_SUBMENU)) done = 1;
				if(EZ_GetWidgetIsCloneFlag(tmp) == 0)
				  {
				    int type = EZ_WidgetType(tmp);
				    if(type == EZ_WIDGET_MENU_TEAR_OFF_BAR ||
				       (type >= EZ_WIDGET_MENU_SEPARATOR &&
					type <= EZ_WIDGET_MENU_RADIO_BUTTON))
				      EZ_HandleWidgetWindowEvent(tmp, &xevent);
				  }
			      }
			  }
		      } 
		    if(done) break;
		  }
		EZ_HideCurrentPopupMenu();
		XUngrabPointer(EZ_Display, CurrentTime); 
		XUngrabKeyboard(EZ_Display,CurrentTime); 
		/*------------------------------------------------------
		 * Callbacks. 
		 *  handle popup menu callback first, and
		 *  handle menu-buttoncallback the second.
		 *-----------------------------------------------------*/
		if(the_popup)
		  {
		    EZ_Widget *lsitem = EZ_PopupLSItem(the_popup);
		    if(lsitem)
		      {
			EZ_ClearWidgetHighlightFlag(lsitem);
			EZ_WidgetBorderStyle(lsitem) = EZ_BORDER_NONE;

			EZ_HandlePopupCallBack(the_popup); /* popup callback */
		      }
		  }
	      }
	    }
	  if(theBtn)
	    {
	      EZ_WidgetBorderStyle(theBtn) = EZ_BORDER_NONE;
	      EZ_ClearWidgetHighlightFlag(theBtn);
	    }
	  EZ_DrawWidget(widget);
	}
      else if(event->xbutton.button == EZ_Btn3)
	{
#include "EZ_DnDHandler1.c"
	  EZ_DnDEventHandler1(widget, event);
	}      
      break;
    case MotionNotify:
      {
	int x = event->xmotion.x;
	int y = event->xmotion.y;
	EZ_Widget *bn = NULL, *last, *nmenu;
	nmenu = EZ_FindMBarMenu(widget, x, y, &bn);
	if(bn != NULL)
	  {
	    last = EZ_MBarLastItem(widget);
	    if(bn != last)
	      {
		if(EZ_LookupWidgetFromAllHT(last))
		  EZ_ClearWidgetHighlightFlag(last);
		if(nmenu)
		  {
		    EZ_MBarLastItem(widget) = bn;
		    EZ_SetWidgetHighlightFlag(bn);
		  }
		else EZ_MBarLastItem(widget) = NULL;
		EZ_DrawWidget(widget);
	      }
	  }
      }
    break;
    case EnterNotify:
      break;
    case LeaveNotify:
      {
	EZ_Widget *last = EZ_MBarLastItem(widget);
	if(EZ_LookupWidgetFromAllHT(last))
	  {
	    EZ_ClearWidgetHighlightFlag(last);
	    EZ_MBarLastItem(widget) = NULL;
	    EZ_DrawWidget(widget);
	  }
      }
    break;
    default:
      break;
    }
}
/********************************************************************************/
void EZ_MenuBarDeleteItem(mbar, label)
     EZ_Widget *mbar; char *label;
{
  EZ_DestroyWidget(EZ_MenuBarFindItem(mbar, label));
}

void EZ_MenuBarDeleteItemAndMenu(mbar, label)
     EZ_Widget *mbar; char *label;
{
  EZ_Widget *item = EZ_MenuBarFindItem(mbar, label);
  if(item)
    {
      EZ_DestroyWidget(EZ_LabelMenu(item));
      EZ_DestroyWidget(item);
    }
}
/********************************************************************************/
EZ_Widget *EZ_MenuBarAddItemAndMenu(mbar, label, ul, menu)
     EZ_Widget *mbar, *menu; char *label; int ul;
{
  if(mbar && EZ_WidgetType(mbar) == EZ_WIDGET_MENU_BAR)
    {
      EZ_Widget *tmp = EZ_CreateNWLabel(mbar, label);
      EZ_WidgetBorderWidth(tmp) = 2;
      EZ_WidgetPadX(tmp)  = 4;
      EZ_WidgetPadY(tmp)  = 3;
      if(label && label[0] != '\0') {EZ_SetWidgetWidthSetFlag(tmp);}
      EZ_WidgetBorderStyle(tmp) = EZ_BORDER_NONE;
      if(label && ul >= 0 && ul < EZ_LabelLineLength(tmp) && isprint(label[ul]))
	{
	  EZ_LabelUnderline(tmp) = ul;
	  EZ_LabelModifiers(tmp) = Mod1Mask;
	  EZ_LabelShortcut(tmp)  = (EZ_LabelString(tmp) + ul);
	  EZ_InsertGlobalKeyPressEvent(tmp, Mod1Mask, (label+ ul));
	}
      if(label) EZ_LabelMenu(tmp) = menu;
      return(tmp);
    }
  return(NULL);
}

/************************************************************************************/
void EZ_MenuBarSetItemMenu(mbar, label, menu)
     EZ_Widget *mbar, *menu; char *label;
{
  if(label && mbar && EZ_WidgetType(mbar) == EZ_WIDGET_MENU_BAR)
    {
      EZ_Widget *tmp = EZ_MenuBarFindItem(mbar, label);
      if(tmp) { EZ_LabelMenu(tmp) = menu;}
    }
}
/************************************************************************************/
EZ_Widget *EZ_MenuBarFindItem(mbar, label)
     EZ_Widget *mbar; char *label;
{
  if(mbar && EZ_WidgetType(mbar) == EZ_WIDGET_MENU_BAR)
    {
      EZ_Widget *child = EZ_WidgetChildren(mbar);
      while(child)
	{
	  char *str = EZ_LabelString(child);
	  if(label == NULL) {if(str[0] == '\0') return(child);}
	  else if(!strcmp(label, str)) return(child);
	  child = EZ_WidgetSibling(child);
	}
    }
  return(NULL);
}
EZ_Widget *EZ_MenuBarFindItemAndMenu(mbar, label, ret)
     EZ_Widget *mbar, **ret; char *label;     
{
  EZ_Widget *lab = EZ_MenuBarFindItem(mbar, label);
  if(lab && ret) *ret = EZ_LabelMenu(lab);
  return(lab);
}
/************************************************************************************/
EZ_Widget *EZ_MenuBarFindItemAtXY(widget, x, y)
     EZ_Widget *widget; int x,y;
{
  EZ_Widget *tmp = NULL;
  EZ_FindMBarMenu(widget, x, y, &tmp);
  return(tmp);
}
EZ_Widget *EZ_FindMBarItemAndMenuAtXY(widget, x, y, ret)
     EZ_Widget *widget; int x,y; EZ_Widget **ret;
{
  EZ_Widget *lab = NULL;
  EZ_Widget *menu = EZ_FindMBarMenu(widget, x, y, &lab);
  if(ret) *ret = menu;
  return(lab);
}
/*****************************************************************/
static EZ_Widget *EZ_FindMBarMenu(widget, x, y, nwlab_ret) 
     EZ_Widget *widget; int x,y; EZ_Widget **nwlab_ret; 
{
  if(widget && EZ_WidgetType(widget) == EZ_WIDGET_MENU_BAR)
    {
      EZ_Widget *child = EZ_WidgetChildren(widget);
      while(child)
	{
	  int x0 = EZ_WidgetOriginX(child);
	  int y0 = EZ_WidgetOriginY(child);
	  int w0 = EZ_WidgetWidth(child);	  
	  int h0 = EZ_WidgetHeight(child);	
	  /* printf("[%d %d]x[%d %d]==> %d %d\n",x0, x0+w0, y0, y0+h0, x, y);*/
	  if(x >= x0 && x < x0 + w0 && y >= y0 && y < y0 + h0) break;
	  child = EZ_WidgetSibling(child);
	}
      if(child)
	{
	  if(EZ_WidgetType(child) == EZ_WIDGET_NW_LABEL)
	    {
	      if(nwlab_ret) *nwlab_ret = child;
	      return(EZ_LabelMenu(child));
	    }
	}
    }
  return(NULL);
}
/************************************************************************************/
void EZ_MenuBarInsertItemAndMenu(mbar, label, ul, menu, ref, where)
     EZ_Widget *mbar, *menu; char *label, *ref; int ul, where;
{
  if(mbar && EZ_WidgetType(mbar) == EZ_WIDGET_MENU_BAR)  
    {
      EZ_Widget *ritem = EZ_MenuBarFindItem(mbar, ref);
      if(ritem == NULL)
	{
	  EZ_Widget *tmp = EZ_MenuBarAddItemAndMenu(mbar, label, ul, menu);
	  if(where < 0) 
	    {
	      EZ_Widget *chase, *head = EZ_WidgetChildren(mbar);
	      if(head != tmp)
		{
		  chase = head;
		  while(EZ_WidgetSibling(chase) != tmp) chase = EZ_WidgetSibling(chase);
		  EZ_WidgetSibling(chase) = NULL;
		  EZ_WidgetSibling(tmp) = head;
		  EZ_WidgetChildren(mbar) = tmp;
		}
	    }
	}
      else
	{
	  EZ_Widget *tmp = EZ_MenuBarAddItemAndMenu(mbar, label, ul, menu);
	  EZ_Widget *chase, *head = EZ_WidgetChildren(mbar);
	  /* remove tmp */
	  chase = head;
	  while(EZ_WidgetSibling(chase) != tmp) chase = EZ_WidgetSibling(chase);
	  EZ_WidgetSibling(chase) = NULL;

	  if(where < 0) 
	    {

	      if(head != ritem)
		{
		  chase = head;
		  while(EZ_WidgetSibling(chase) != ritem) chase = EZ_WidgetSibling(chase);
		  EZ_WidgetSibling(tmp) = ritem;
		  EZ_WidgetSibling(chase) = tmp;
		}
	      else
		{
		  EZ_WidgetSibling(tmp) = ritem;
		  EZ_WidgetChildren(mbar) = tmp;		  
		}
	    }
	  else
	    {
	      EZ_WidgetSibling(tmp) = EZ_WidgetSibling(ritem);
	      EZ_WidgetSibling(ritem) = tmp;		  
	    }	      
	}
    }
}
/************************************************************************************/
static EZ_Widget *FindAdjacentItem(widget, dir)
     EZ_Widget *widget; int dir;
{
  EZ_Widget *parent;
  if(widget && (parent = EZ_WidgetParent(widget)) != NULL)
    {
      if(dir == 1) /* move right */
	{
	  EZ_Widget *next = EZ_WidgetSibling(widget);
	  while(next != widget)
	    {
	      if(next == NULL) next = EZ_WidgetChildren(parent);
	      if(EZ_WidgetType(next) == EZ_WIDGET_NW_LABEL &&
		 EZ_LabelMenu(next) != NULL)
		return(next);
	      else next = EZ_WidgetSibling(next);
	    }
	  return(widget);
	}
      else
	{
	  EZ_Widget *widgets[64];
	  int idx=0, cnt = 0;
	  EZ_Widget *next = EZ_WidgetChildren(parent);
	  while(next)
	    {
	      if(EZ_WidgetType(next) == EZ_WIDGET_NW_LABEL &&
		 EZ_LabelMenu(next) != NULL)	      
		{ 
		  if(next == widget) idx = cnt;
		  widgets[cnt++] = next;
		}
	      next = EZ_WidgetSibling(next);
	    }
	  if(idx > 0) return(widgets[idx-1]);
	  else if(cnt > 0) return(widgets[cnt-1]);
	  else return(widget);
	}
    }
  return(NULL);
}

/************************************************************************************/
#undef _EZ_WIDGET_MBAR_C_
