/* 
 *  @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
*/ 
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$XConsortium: ReleasButton.c /main/8 1995/07/14 11:42:29 drk $"
#endif
#endif
/***********************************************************************
  	@(#)ReleasButton.c	1.5.1.1	Date:1/22/91
  	Author: TAT
	History:
            06/07/90 SJS add event mask for release event. This determines
                         if the send_object should get the event or not.
	Calls:

	Summary:
            Simulates the user releasing the specified mouse button. 

        INPUTS:
            none
        
        OUTPUTS:
            none

        RETURNS:
            nothing
************************************************************************/

#include <AutoMessages.h>
#include <X11/IntrinsicP.h>
#include "xislib.h"
#include "mvslib.h"

void xisReleaseMouseButton(modifier_keys,button_num)
unsigned int modifier_keys;
int button_num;
{
    static char routine_name[] = "xisReleaseMouseButton";
    XisObjectRecord *object, *current_object, *send_object, *action_object;
    int root_x,root_y;        /* Pointer position relative to root and window */
    Time time;
    short pursue;
    int x, y;
    XisObjectRecord *menu_object;
    Widget menu_widget, orig_widget;
    char *menu_class = NULL;
    MvsWidgetInfoRecord *menu_info;
    Boolean menu_manager = False;
    Boolean menu_release = False;
    Boolean menu_invalid = False;
    char msg_string[125];


    (*xisTraceMsg)("Got send_event_request = ReleaseMouseButton\n");
    xisUseSessionInfo(routine_name);
    xisUpdateObjectAttributes();

    /* First make sure this button is not already released */

    if ( !(xisState.mod_button_state & xisMouseButtonMask[button_num])) {
        sprintf (msg_string, _AutoMessages[WARNMSG59], button_num);
	AutoMessage(msg_string);

        return;
    }

    /* Then look up which object the pointer is over or is already grabbed */

    xisGetPointerLocation(&root_x,&root_y);
    xisInform.pointer_obj = xisFindObjectAtLocation(root_x,root_y);

    /* If Grab Window still exists, then ... */

    if (xisPointerGrabbed && xisWindowExists(xisGrabPointerWindow)) {
        
        /* Call all relavent InformExpectedActions functions */
  
        object = xisFindObject(xisState.selected_widget,
                               xisState.selected_object_type,
                               xisState.selected_instance);

        if (object == NULL) 
            object = xisFindObjectFromWindow(xisGrabPointerWindow);

        if (object == NULL)
            AutoMessage(_AutoMessages[WARNMSG21]);

        xisInform.is_valid = 1;        
        xisInform.action_obj = object;
        xisInform.modifier_key_status = modifier_keys;
        xisInform.button_num = button_num;
        xisInform.edge_code = 0;
        xisInform.key_code = 0;
        xisInform.event_code = EventMouseButtonUp;
        xisInform.num_clicks = 0;

        current_object = object;

        while (current_object != NULL) {

            if (current_object->proc_InformExpectedActions != NULL) {
                xisInform.current_obj = current_object;

                (*current_object->proc_InformExpectedActions)(EventMouseButtonUp); 
	    }
            current_object = current_object->parent;
	}

        xisInform.is_valid = 0;

        /* Send Synthesized Button Release Event */

        send_object = action_object = object;

/* Automation Added */

	xisGetPointerLocation(&x,&y);
	menu_object = xisFindObjectAtLocation(x,y);

	menu_widget = (Widget) menu_object->id.widget;
	orig_widget = menu_widget;

	while(! menu_invalid && menu_widget != NULL) {
		if (XmIsManager(menu_widget)) {
			menu_manager = True;
			menu_invalid = True;
		}
		if (XtIsShell(menu_widget)) {
			menu_invalid = True;
			menu_manager = False;
		}
		else 
			if (! menu_invalid)
				menu_widget = XtParent(menu_widget);
	}

	if (menu_manager) {
		menu_info = mvsWidgetToWidgetInfo(menu_widget);
		menu_class = menu_info->widget_class_info->class_name;
	}

	if (menu_manager &&
	    ((strcmp(menu_class, "XmPulldownMenu") == 0) 	||
	    (strcmp(menu_class, "XmPopupMenu") == 0)		||
	    (strcmp(menu_class, "XmMenuBar") == 0)		||
	    (strcmp(menu_class, "XmCascadeButton") == 0)	||
	    (strcmp(menu_class, "XmCascadeButtonGadget") == 0)	||
	    (strcmp(menu_class, "XmOptionMenu") == 0))) {
		/* insure that the object is not a gadget, if you use
		   parent as send_object since it has a valid window */
		if (XmIsGadget(orig_widget))
			menu_object = menu_object->parent;
		send_object = menu_object;
		menu_release = True;
	}
	else {
		menu_release = False;
		send_object = action_object = object;
	}

/* End Automation Added */

        /* Use parent object if in a region. Regions do not have windows */

        while (send_object != (XisObjectRecord *) NULL &&
	       send_object->id.window == (Window) NULL)
            send_object = send_object->parent;

        while (send_object != NULL) {
            if (((send_object->your_event_mask&ButtonReleaseMask) ||
		 menu_release)					  &&
                (send_object->visibility_state != IsUnmapped)) {
                pursue = 1;
                break;
            }

            if ((send_object->do_not_propagate_mask&ButtonReleaseMask) &&
                (send_object->visibility_state != IsUnmapped)            ) {
                pursue = 0;
                break;
            }
            send_object = send_object->parent;
        }

        if( (send_object != NULL) && pursue) {
            (*xisTraceMsg)("    Action_object = %s\n",
                           xisGetObjectName(action_object));
            (*xisTraceMsg)("    Send_object = %s\n",
                           xisGetObjectName(send_object));

            time = xisGetServerTime(xisMultiClickTime);
	    /* Won't perform any time delay */

/* Automation Added */

	    if (menu_release)
            	xisSendEvent(XtWindow(send_object->id.widget),
			  xisGrabPointerSubwindow,
               	          ButtonRelease,
               	          time,
               	          root_x - send_object->x,
               	          root_y - send_object->y, 
               	          root_x, root_y, modifier_keys,
               	          xisMouseButtonDetail[button_num]);
	    else

/* Automation end Added */

            	xisSendEvent(xisGrabPointerWindow,
			  xisGrabPointerSubwindow,
               	          ButtonRelease,
               	          time,
               	          root_x - send_object->x,
               	          root_y - send_object->y, 
               	          root_x, root_y, modifier_keys,
               	          xisMouseButtonDetail[button_num]);
		
        }

        /* Alter local info about which mouse buttons are down */

        xisState.mod_button_state &= (~xisMouseButtonMask[button_num]) &
                                     (~modifier_keys);

        /* If all mouse buttons are released, then ungrab pointer */

        if (xisState.mod_button_state == 0 &&
	    xisPointerGrabMode == POINTER_GRAB_CONTROLLED) {
/*****NoteGrab****/
            XUngrabPointer(xisDisplay,CurrentTime);
/*****/
            xisGrabPointerWindow = 0;
            xisPointerGrabbed = 0;
	}

        /* And, finally, process all related events */

        xisProcessEvents(NULL,0);
    }

    /* Make sure no matter if the pointer is grabbed or not that this
       buttons bit is released.                                       */

    xisState.mod_button_state &= (~xisMouseButtonMask[button_num]) &
                                 (~modifier_keys);
    xisPointerGrabbed = 0;
    xisGrabPointerWindow = 0;
    xisState.selected_widget = 0;
    xisState.selected_object_type = 0;
    xisState.selected_instance = 0;

} /* End xisReleaseMouseButton() */