/**
 *
 * $Header: /cvsroot/hungry/lesstif/lib/Xm-2.0/GrabShell.c,v 1.11 1998/01/12 02:12:26 pgw Exp $
 *
 * Copyright (C) 1997 Free Software Foundation, Inc.
 *
 * This file is part of the GNU LessTif Library.
 *
 * 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.
 *
 **/

static char rcsid[] = "$Header: /cvsroot/hungry/lesstif/lib/Xm-2.0/GrabShell.c,v 1.11 1998/01/12 02:12:26 pgw Exp $";


#include <LTconfig.h>
#include <XmI/XmI.h>

#include <Xm/XmP.h>
#include <Xm/GrabShellP.h>
#include <Xm/MwmUtil.h>
#include <Xm/TransltnsP.h>
#include <Xm/MenuUtilP.h>

#include <XmI/PixConvI.h>

#include <XmI/MessagesI.h>
#include <XmI/DebugUtil.h>


/*
  MODULE: GrabShell.c
  DESCRIPTION:
  Contains the routines that compose the GrabShell widget.

  A grab shell can have multiple children.  The grab shell does not
  perform any special layouts on its children.  It leaves child placement
  up to its children.  The grab shell will remain visible until focus is lost.
  At which time it will pop itself down.

  The grab shell does not have any window manager decorations.  

  The grab shell determines its width and height from the first child only.

  The grab shell moves the first child to x,y = 2,2.  This is probably due to
  the shadow thickness which has a default value of 2.

  Warning, this widget does not do anything with the extension record yet.
  END:
*/

#define VALID(w) (w && XtIsManaged(w))
#define Unused(x) (void)(x)
#define superclass (&vendorShellClassRec)
#define Offset(field) XtOffsetOf(XmGrabShellRec, grab_shell.field)

/* Forward declarations */
static void BtnDown(Widget,XEvent *,String *,Cardinal *);
static void BtnUp(Widget,XEvent *,String *,Cardinal *);
static void ChangeManaged(Widget w);
static void ClassPartInitialize(WidgetClass class);
static void CreateBottomShadowGC(Widget w);
static void CreateTopShadowGC(Widget w);
static void Destroy(Widget w);
static void DoLayout(Widget w);
static void DrawBorder(Widget w, XEvent *xev, Region region);
static XtGeometryResult GeometryManager(Widget w, 
   XtWidgetGeometry *request, 
   XtWidgetGeometry *reply);
static void Initialize(Widget request, 
   Widget c_new,
   ArgList args,
   Cardinal *num_args);
static void MapNotifyHandler(Widget w, 
   XtPointer cdata, 
   XEvent *xev, 
   Boolean *pb);
static void Popdown(Widget,XEvent *,String *,Cardinal *);
static void Resize(Widget w);
static Boolean SetValues(Widget current, 
   Widget request, 
   Widget c_new, 
   ArgList args,
   Cardinal *num_args);
static void _XmAllowEvents(Widget w, int event_mode, Time _time);
static void _XmGrabShellFocus(Widget w, int operation, Time _time);
static void _XmGrabShellGrab(Widget w, Time _time);
static void _XmGrabShellUngrab(Widget w, Time _time);

enum {
  XmGRAB_SHELL_FOCUS_SAVE=0,
  XmGRAB_SHELL_FOCUS_RESTORE,
  XmGRAB_SHELL_FOCUS_SET
};

/* Resources for the GrabShell class */
static XtResource resources[] = {

   {
     XmNbottomShadowColor,
     XmCBottomShadowColor,
     XmRPixel,
     sizeof(Pixel),
     Offset(bottom_shadow_color),
     XmRCallProc,
     (XtPointer)_XmBottomShadowColorDefault
   },

   {
     XmNbottomShadowPixmap,
     XmCBottomShadowPixmap,
     XmRBottomShadowPixmap,
     sizeof(Pixmap),
     Offset(bottom_shadow_pixmap),
     XmRImmediate,
     (XtPointer)XmUNSPECIFIED_PIXMAP
   },

   {
     XmNgrabStyle,
     XmCGrabStyle,
     XmRInt,
     sizeof(int),
     Offset(grab_style),
     XmRImmediate,
     (XtPointer)GrabModeAsync 
   },

   { 
     XmNoverrideRedirect,
     XmCOverrideRedirect,
     XmRBoolean,
     sizeof(Boolean),
     XtOffsetOf(XmGrabShellRec, shell.override_redirect),
     XmRImmediate,
     (XtPointer)True
   },

   {
     XmNownerEvents,
     XmCOwnerEvents,
     XmRBoolean,
     sizeof(Boolean),
     Offset(owner_events),
     XmRImmediate,
     (XtPointer)False
   },

   {
     XtNsaveUnder,
     XtCSaveUnder,
     XtRBoolean,
     sizeof(Boolean),
     XtOffsetOf(XmGrabShellRec, shell.save_under),
     XmRImmediate,
     (XtPointer)True
   },

   {
     XmNshadowThickness,
     XmCShadowThickness,
     XmRHorizontalDimension,
     sizeof(Dimension),
     Offset(shadow_thickness),
     XmRImmediate,
     (XtPointer)2
   },

   {
     XmNtopShadowColor,
     XmCTopShadowColor,
     XmRPixel,
     sizeof(Pixel),
     Offset(top_shadow_color),
     XmRCallProc,
     (XtPointer)_XmTopShadowColorDefault
   },

   {
     XmNtopShadowPixmap,
     XmCTopShadowPixmap,
     XmRTopShadowPixmap,
     sizeof(Pixmap),
     Offset(top_shadow_pixmap),
     XmRCallProc,
     (XtPointer)_XmTopShadowPixmapDefault
   }

};

/* Action table */
static XtActionsRec actionsList[] = {
   {"GrabShellBtnDown", (XtActionProc) BtnDown},
   {"GrabShellBtnUp", (XtActionProc) BtnUp},
   {"GrabShellPopdown", (XtActionProc) Popdown} 
};

/* ========================================================================== */
/* Class record */

XmGrabShellClassRec xmGrabShellClassRec = {
   /* Core class part */
   {
      (WidgetClass) &vendorShellClassRec,     /* superclass */
      "XmGrabShell",                          /* class_name */
      sizeof(XmGrabShellRec),                 /* widget_size */
      NULL,                                   /* class_initialize */
      ClassPartInitialize,                    /* class_part_initialize */
      FALSE,                                  /* class_inited */
      Initialize,                             /* initialize */
      NULL,                                   /* initialize_hook */
      XtInheritRealize,                       /* realize */
      actionsList,                            /* actions */
      XtNumber(actionsList),                  /* num_actions */
      resources,                              /* resources */
      XtNumber(resources),                    /* num_resources */
      NULLQUARK,                              /* xrm_class */
      TRUE,                                   /* compress_motion */
      XtExposeCompressMaximal,                /* compress_exposure */
      TRUE,                                   /* compress_enterleave */
      FALSE,                                  /* visible_interest */
      Destroy,                                /* destroy */
      Resize, /* XtInheritResize,  */         /* resize */
      DrawBorder, /* XtInheritExpose  */      /* expose */
      SetValues,                              /* set_values */
      NULL,                                   /* set_values_hook */
      XtInheritSetValuesAlmost,               /* set_values_almost */
      NULL,                                   /* get_values_hook */
      NULL,                                   /* accept_focus */
      XtVersion,                              /* version */
      NULL,                                   /* callback offsets */
      _XmGrabShell_translations,              /* tm_table */
      NULL,                                   /* query_geometry */
      NULL,                                   /* display_accelerator */
      NULL                                    /* extension */ 
   },
   /* Composite class part */
   {
      GeometryManager,        /* geometry manager */
      ChangeManaged,          /* ChangeManaged */
      XtInheritInsertChild,   /* insert_child */ 
      XtInheritDeleteChild,   /* delete_child */ 
      NULL                    /* extension */ 
   },
   /* Shell class part */
   {
      NULL                    /* extension */ 
   },
   /* WMShell class part */
   {
      NULL                    /* extension */ 
   },
   /* VendorShell class part */
   {
      NULL                    /* extension */ 
   },
   /* XmGrabShell class part */
   {
      NULL                    /* extension */ 
   }
};

WidgetClass xmGrabShellWidgetClass = (WidgetClass) &xmGrabShellClassRec;

/*
  FUNCTION: BtnDown
  SYNOPSIS: static void BtnDown(Widget, XEvent *, String *, Cardinal *)
  DESCRIPTION:
  This function handles button down actions. 
  END:
*/
static void 
BtnDown(
   Widget w,
   XEvent * xev,
   String * params,
   Cardinal * num_params)
{
   int event_mode;
   XButtonEvent *bev;
   Position rootx_return, rooty_return;

   DEBUGOUT(XdbDebug(__FILE__, w, "BtnDown\n"));

   /* Check to see if mapped yet */
   if(GS_Mapped(w) == False)
   {
      return;
   }

   bev = (XButtonEvent *) xev;

   XtTranslateCoords(w, XtX(w), XtY(w), &rootx_return, &rooty_return);

   /* if within grab shell window then return */
   if ((bev->x_root >= rootx_return 
        && bev->x_root <= rootx_return + XtWidth(w))
       && (bev->y_root >= rooty_return 
           && bev->y_root <= rooty_return + XtHeight(w)))
   {
      DEBUGOUT(XdbDebug(__FILE__, w, "BtnDown: In grab shell window.\n"));

      event_mode = (GS_GrabStyle(w) == GrabModeSync) ? SyncBoth : AsyncBoth;
      _XmAllowEvents(w, event_mode, CurrentTime);

      return;
   }

   Popdown(w,xev,params,num_params);

   Unused(xev);
   Unused(params);
   Unused(num_params);
}

/*
  FUNCTION: BtnUp
  SYNOPSIS: static void BtnUp(Widget, XEvent *, String *, Cardinal *)
  DESCRIPTION:
  This function handles button up actions. 
  END:
*/
static void 
BtnUp(
   Widget w,
   XEvent * xev,
   String * params,
   Cardinal * num_params)
{
   int event_mode;

   DEBUGOUT(XdbDebug(__FILE__, w, "BtnUp\n"));

   /* Check to see if mapped yet */
   if(GS_Mapped(w) == False)
   {
      return;
   }

   event_mode = (GS_GrabStyle(w) == GrabModeSync) ? SyncBoth : AsyncBoth;
   _XmAllowEvents(w, event_mode, CurrentTime);

   Unused(xev);
   Unused(params);
   Unused(num_params);
}

/*
  FUNCTION: ChangeManaged
  SYNOPSIS: static void ChangeManaged(Widget w)
  DESCRIPTION:
  This function calls for a layout regardless if the grabshell is unmanaged.
  END:
*/
static void 
ChangeManaged(Widget w)
{

   DEBUGOUT(XdbDebug(__FILE__, w,
                     "ChangeManaged: dimensions are %d %d\n",
                      XtWidth(w), XtHeight(w)));

   DoLayout(w);

   if(!XtIsManaged(w))
   {

      DEBUGOUT(XdbDebug(__FILE__, w, 
                        "ChangeManaged: Not managed yet.\n"));
      return;
   }
}

/*
  FUNCTION: ClassPartInitialize
  SYNOPSIS: static void ClassPartInitialize(WidgetClass widget_class)
  DESCRIPTION:
  This function sets the XmGRAB_SHELL_BIT in the extension record.
  END:
*/
static void
ClassPartInitialize(WidgetClass widget_class)
{
#if 0
   /* FIXTHIS: Need to do something here with the extension pointer */
   XmGrabShellWidgetClass nbclass = (XmGrabShellWidgetClass)widget_class;
   XmVendorShellExtObjectClass ext, *extptr;
   extptr = (XmVendorShellExtObjectClass *)_XmGetClassExtensionPtr(
                    (XmGenericClassExt *)&(nbclass->vendor_class.extension),
                                                                   NULLQUARK);

#endif

   _XmFastSubclassInit(widget_class, XmGRAB_SHELL_BIT);

}

/*
  FUNCTION: CreateBottomShadowGC
  SYNOPSIS: static void CreateBottomShadowGC(Widget w)
  DESCRIPTION:
  This function creates the bottom shadow GC for the widget.
  This is performed by calling _XmGetPixmapBasedGC.
  END:
*/
static void
CreateBottomShadowGC(Widget w)
{
   XGCValues values;
   XtGCMask mask;

   mask = GCLineWidth;
   values.line_width = 1;
   GS_BottomShadowGC(w) = _XmGetPixmapBasedGC(w,
      GS_BottomShadowPixmap(w),
      GS_BottomShadowColor(w),
      mask,
      &values);
}

/*
  FUNCTION: CreateTopShadowGC
  SYNOPSIS: static void CreateTopShadowGC(Widget w)
  DESCRIPTION:
  This function creates the top shadow GC for the widget.
  This is performed by calling _XmGetPixmapBasedGC.
  END:
*/
static void
CreateTopShadowGC(Widget w)
{
   XGCValues values;
   XtGCMask mask;

   /* get top shadow GC values */
   mask = GCLineWidth | GCLineStyle | GCJoinStyle | GCCapStyle;
   values.line_width = 1;
   values.line_style = LineSolid;
   values.join_style = JoinMiter;
   values.cap_style = CapButt;

   GS_TopShadowGC(w) = _XmGetPixmapBasedGC(w,
      GS_TopShadowPixmap(w),
      GS_TopShadowColor(w),
      mask,
      &values);
}

/*
  FUNCTION: Destroy
  SYNOPSIS: static void Destroy(Widget w)
  DESCRIPTION:
  This function releases allocated memory done by the widgets instance. 
  END:
*/
static void
Destroy(Widget w)
{
   Unused(w);

   /* release GC's */
   XtReleaseGC(w,GS_TopShadowGC(w));
   XtReleaseGC(w,GS_BottomShadowGC(w));
}

/*
  FUNCTION: DoLayout
  SYNOPSIS: static void DoLayout(Widget w)
  DESCRIPTION:
  This function resizes the window according to its childs geometry.
  END:
*/
static void
DoLayout(Widget w)
{
   Widget child = NULL;

   DEBUGOUT(XdbDebug(__FILE__, w, "DoLayout ...\n"));

   /* 
      REMARK: 
      Using MGR_* macros does a cast to a structure we are not using.  
      However, the pointer ends up pointing to what we want since we
      are accessing the composite structure.  See the macros MGR_NumChildren
      and MGR_Children in MacrosI.h if you don't understand this.  
      Does anyone see a problem with this? 
      END:
   */
   if(MGR_NumChildren(w) > 0)
   {
      child = MGR_Children(w)[0]; /* take first child */
   }

   /* 
      REMARK: 
      Use dimensions of first child to determine width and height.
      If dimensions of child are 0x0 then set to 1x1.
      END:
   */
   if(child != NULL)
   {
      int adjustment;

      adjustment = GS_ShadowThickness(w); 

      XtWidth(w) = XtWidth(child) == 0 ? 1 : XtWidth(child) + (2*adjustment);
      XtHeight(w) = XtHeight(child) == 0 ? 1 : XtHeight(child) + (2*adjustment);

      DEBUGOUT(XdbDebug(__FILE__, w,
                        "DoLayout: dimensions changed to %d %d\n",
                        XtWidth(w), XtHeight(w)));

      /* change childs x,y */
      XtX(child) = adjustment;
      XtY(child) = adjustment;
   }
}

/*
  FUNCTION: DrawBorder
  SYNOPSIS: static void DrawBorder(Widget w)
  DESCRIPTION:
  This function draws the widget border.
  END:
*/
static void
DrawBorder(Widget w, XEvent *xev, Region region)
{
   DEBUGOUT(XdbDebug(__FILE__, w, "DrawBorder ...\n"));

   XmeDrawShadows(XtDisplayOfObject(w),       /* display */
                  XtWindowOfObject(w),        /* window */
                  GS_TopShadowGC(w),          /* top gc */
                  GS_BottomShadowGC(w),       /* bottom gc */
                  0,                          /* position x */
                  0,                          /* position y */
                  XtWidth(w),                 /* width */
                  XtHeight(w),                /* height */
                  GS_ShadowThickness(w),      /* shadow thickness */
                  (unsigned int) XmSHADOW_OUT);       /* shadow type */

   Unused(w);
   Unused(xev);
   Unused(region);
}

/*
  FUNCTION: GeometryManager
  SYNOPSIS: static XtGeometryResult(Widget, XtWidgetGeometry *, XtWidgetGeometry *)
  DESCRIPTION:
  This function handles geometry requests by children.  It does this by calling
  _XmMakeGeometryRequest and then resetting the width and height.  It always
  returns XtGeometryYes.
  END:
*/
static XtGeometryResult 
GeometryManager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply)
{
   XtGeometryResult res;
   XtWidgetGeometry wants;
   Widget me = XtParent(w);

   DEBUGOUT(XdbDebug(__FILE__, me,
                     "geometry_manager: request %s, allow_shell_resize %s\n",
                     XdbWidgetGeometry2String(request),
                     ((XmGrabShellWidget)me)->shell.allow_shell_resize
                     ? "True"
                     : "False"));

   if ((request->request_mode & (CWWidth | CWHeight)) == 0)
   {
       return XtGeometryYes;
   }


   DEBUGOUT(XdbDebug(__FILE__, me,
                     "geometry_manager: %s\n",
                     XdbWidgetGeometry2String(request)));

   wants = *request;

   res = _XmMakeGeometryRequest(me, &wants);

   if (res == XtGeometryNo)
   {
      DEBUGOUT(XdbDebug(__FILE__, w,
                        "XtGeometryNo returned... THIS SHOULD NOT HAPPEN\n"));
   }
   *reply = wants;

   XtWidth(w) = wants.width;
   XtHeight(w) = wants.height;

   DEBUGOUT(XdbDebug(__FILE__, w,
                     "geometry_manager: size %dx%d => Yes\n",
                     reply->width, reply->height));

   return XtGeometryYes;
}

/*
  FUNCTION: Initialize
  SYNOPSIS: static void Initialize(Widget,Widget,ArgList,Cardinal *)
  DESCRIPTION:
  This function initializes the instance data.  It calls routines to
  setup the top and bottom shadow GC.  Sets up an event handler by calling
  XtAddEventHandler for MapNotify events with the parameter mask 
  StructureNotifyMask.  This routine also sets the widgets width and height 
  to 1 if 0 (see macro FAKE_NONZERO in code).
  END:
*/
static void
Initialize(Widget request,
           Widget c_new,
           ArgList args,
           Cardinal *num_args)
{
   Unused(request);
   Unused(c_new);
   Unused(args);
   Unused(num_args);

   if (!XtIsSubclass(c_new, shellWidgetClass))
   {
      XmeWarning(c_new, _XmMsgGrabS_0000);
   }

   CreateBottomShadowGC(c_new);
   CreateTopShadowGC(c_new);

   /* setup map notify handler */
   XtAddEventHandler(c_new, 
                     /* MapNotify Events */
                     StructureNotifyMask, 
#if 0
                     SubstructureNotifyMask | StructureNotifyMask, 
#endif
                     False, 
                     (XtEventHandler) MapNotifyHandler, 
                     (XtPointer) NULL);

#define FAKE_NONZERO
#ifdef  FAKE_NONZERO
   if (XtWidth(c_new) == 0 || XtHeight(c_new) == 0)
   {
      DEBUGOUT(XdbDebug(__FILE__, c_new,
                        "Initialize: dimensions %d %d changed to 1x1\n",
                        XtWidth(c_new), XtHeight(c_new)));

      XtWidth(c_new) = XtHeight(c_new) = 1;
   }
#endif
}

/*
  FUNCTION: MapNotifyHandler
  SYNOPSIS: static void MapNotifyHandler(Widget w, XtPointer cdata, XEvent *xev, Boolean *pb);
  DESCRIPTION:
  This function handles MapNotify events.  If the grab shell is in the process
  of popping up onto the screen then this routine will perform a grab.  It also
  will save the current focus state and then set the focus on the grab shell.
  END:
*/
static void 
MapNotifyHandler(Widget w, XtPointer cdata, XEvent *xev, Boolean *pb)
{
   int event_mode;

   *pb = TRUE;

   /* Do we have a map notify event */
   if (xev->type != MapNotify)
   {
      return;
   }

   /* Have we already done what we wanted to do */
   if (GS_Mapped(w) != False)
   {
      return;
   }

   DEBUGOUT(XdbDebug(__FILE__, w,
                     "MapNotifyHandler ...\n"));

   /* Set internal flag to on.  Shut it off in popdown */
   GS_Mapped(w) = True;

   /* Save post time. */
   GS_PostTime(w) = XtLastTimestampProcessed(XtDisplay(w));

   _XmGrabShellGrab(w, GS_PostTime(w));

   /* Only needed if using GrabModeSync..I think */
   event_mode = (GS_GrabStyle(w) == GrabModeSync) ? SyncBoth : AsyncBoth;
   _XmAllowEvents(w, event_mode, GS_PostTime(w));

   _XmGrabShellFocus(w, XmGRAB_SHELL_FOCUS_SAVE, GS_PostTime(w));
   _XmGrabShellFocus(w, XmGRAB_SHELL_FOCUS_SET, CurrentTime);

}

/*
  FUNCTION: Popdown
  SYNOPSIS: static void Popdown(Widget, XEvent *, String *, Cardinal *)
  DESCRIPTION:
  This function handles popdown actions.  It resets the focus and then
  replays the pointer event.  May need to put a check in here to not
  replay the last pointer event if it wasn't a pointer event.  
  END:
*/
static void 
Popdown(
   Widget w,
   XEvent * xev,
   String * params,
   Cardinal * num_params)
{
   DEBUGOUT(XdbDebug(__FILE__, w, "Popdown\n"));

   /* Check to see if mapped yet */
   if(GS_Mapped(w) == False)
   {
      return;
   }

   /* Get unpost time stamp */
   GS_UnpostTime(w) = XtLastTimestampProcessed(XtDisplay(w));

   _XmAllowEvents(w, ReplayPointer, GS_UnpostTime(w));

   _XmGrabShellUngrab(w, GS_UnpostTime(w));

   /* popdown the shell */
   XtPopdown(w);

   /* Unlock map notify handler */
   GS_Mapped(w) = False;

   /* restore focus */
   _XmGrabShellFocus(w, XmGRAB_SHELL_FOCUS_RESTORE, GS_UnpostTime(w));

   /* Should I sync here? */
   XSync(XtDisplay(w),False);

   Unused(xev);
   Unused(params);
   Unused(num_params);
}

/* 
  FUNCTION: Resize
  SYNOPSIS: static void Resize(Widget w)
  DESCRIPTION:
  This routine handles resizing by calling DoLayout and then the core classes
  resize method.
  END:
*/
static void 
Resize(Widget w)
{
   DEBUGOUT(XdbDebug(__FILE__, w, "Resize ...\n"));

   if(XtIsRealized(w))
   {  /* widgets must be resized */
      DoLayout(w);
   }

   (*superclass->core_class.resize)(w);
}

/* 
  FUNCTION: SetValues
  SYNOPSIS: static Boolean SetValues(Widget,Widget,Widget,ArgList,Cardinal *)
  DESCRIPTION:
  This routine handles the setting of widget resources.
  END:
*/
static Boolean 
SetValues(Widget old, 
          Widget request, 
          Widget c_new, 
          ArgList args,
          Cardinal *num_args)
{
   XmGrabShellWidget ow = (XmGrabShellWidget) old;
   XmGrabShellWidget nw = (XmGrabShellWidget) c_new;
   Boolean need_refresh = False;

   /* FIXTHIS: SetValues is not implemented yet. */

   DEBUGOUT(XdbDebug(__FILE__, old, "SetValues ...\n"));

   Unused(request);
   Unused(args);
   Unused(num_args);
   Unused(ow);
   Unused(nw);

   return need_refresh;
}

/*
  FUNCTION: _XmAllowEvents
  SYNOPSIS: static void _XmAllowEvents(Widget w, int event_mode, Time _time)
  DESCRIPTION:
  This function releases any queued events since the last grab by calling
  XAllowEvents.
  END:
*/
static void
_XmAllowEvents(Widget w, int event_mode, Time _time)
{
   XAllowEvents(XtDisplay(w), event_mode, _time);
}

/*
  FUNCTION: _XmGrabShellFocus
  SYNOPSIS: static void _XmGrabShellFocus(Widget w, int operation, Time _time);
  DESCRIPTION:
  This function handles focus operations for the grab shell.
  This is similar to _XmMenuFocus routine.  Only difference is the grab shell
  does not use the state structure (at least for now).  
  END:
*/
static void
_XmGrabShellFocus(Widget w, int operation, Time _time)
{
   Window window_return;
   int revert_to_return;

   switch (operation)
   {
   case XmGRAB_SHELL_FOCUS_SAVE:
      XGetInputFocus(XtDisplay(w),
                     &GS_OldFocus(w),
                     &GS_OldRevertTo(w));
      break;


   case XmGRAB_SHELL_FOCUS_RESTORE:
      XSetInputFocus(XtDisplay(w),
                     GS_OldFocus(w),
                     GS_OldRevertTo(w),
                     _time);

      XGetInputFocus(XtDisplay(w),
                     &window_return,
                     &revert_to_return);

      if (GS_OldFocus(w) != window_return
          || GS_OldRevertTo(w) != revert_to_return)
      {
         DEBUGOUT(XdbDebug(__FILE__, w, "  SetInputFocus call failed.\n"));
      }
      break;

   case XmGRAB_SHELL_FOCUS_SET:
      XSetInputFocus(XtDisplay(w),
                     XtWindow(w),
                     RevertToPointerRoot,
                     _time);

      XGetInputFocus(XtDisplay(w),
                     &window_return,
                     &revert_to_return);

      if (window_return != XtWindow(w)
          || revert_to_return != RevertToPointerRoot)
      {
          DEBUGOUT(XdbDebug(__FILE__, w, "  setting input focus failed\n"));
          _XmUngrabKeyboard(w, _time);
          return;
      }

      break;
   }
}

/*
  FUNCTION: _XmGrabShellGrab
  SYNOPSIS: static void _XmGrabShellGrab(Widget w)
  DESCRIPTION:
  This function handles grab operations for the grab shell.  This is performed
  by calling _XmGrabKeyboard and _XmGrabPointer.
  END:
*/
static void
_XmGrabShellGrab(Widget w, Time _time)
{
   Display *dpy;
   unsigned int mask;

   dpy = XtDisplayOfObject(w);

   _XmGrabKeyboard(w, 
                   GS_OwnerEvents(w),   /* Owner events */
                   GrabModeAsync,       /* Pointer mode */ 
#if 0
                   GS_GrabStyle(w),     /* Pointer mode */
#endif
                   GS_GrabStyle(w),     /* Keyboard mode */
                   _time);        /* Time */


   mask = ButtonPressMask | ButtonReleaseMask; 
#if 0
          | EnterWindowMask | LeaveWindowMask;  
#endif

   _XmGrabPointer(w, 
                  GS_OwnerEvents(w),    /* Owner events */
                  mask,                 /* Event mask */
                  GS_GrabStyle(w),      /* Pointer mode */
                  GrabModeAsync,        /* Keyboard mode */ 
#if 0
                  GS_GrabStyle(w),      /* Keyboard mode */
#endif
                  None,                 /* Confine to */
                  XmGetMenuCursor(dpy), /* Cursor */
                  _time);         /* Time */
}

/*
  FUNCTION: _XmGrabShellUngrab
  SYNOPSIS: static void _XmGrabShellUngrab(Widget w)
  DESCRIPTION:
  This function handles ungrab operations for the grab shell.  This is performed
  by calling _XmUngrabKeyboard and _XmUngrabPointer.
  END:
*/
static void
_XmGrabShellUngrab(Widget w, Time _time)
{
   _XmUngrabPointer(w, _time);
   _XmUngrabKeyboard(w, _time);
}

/* Public routines */
/*
  FUNCTION: XmCreateGrabShell
  SYNOPSIS: Widget XmCreateGrabShell(Widget,char *,ArgList,Cardinal)
  DESCRIPTION:
  Creates an instance of a XmGrabShellWidget.
  END:
*/
Widget
XmCreateGrabShell(Widget parent, char *name, ArgList arglist,
                 Cardinal cnt)
{

   return XtCreatePopupShell(name,
                             xmGrabShellWidgetClass,
                             parent,
                             arglist,
                             cnt);

}


