/*
* Copyright (c) 2005 X.Org Foundation L.L.C.
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* 
* Copyright (c) Applied Testing and Technology, Inc. 1995
* All Rights Reserved.
* 
* 
* Portions of this software are based on Xlib and X Protocol Test Suite.
* We have used this material under the terms of its copyright, which grants
* free use, subject to the conditions below.  Note however that those
* portions of this software that are based on the original Test Suite have
* been significantly revised and that all such revisions are copyright (c)
* 1995 Applied Testing and Technology, Inc.  Insomuch as the proprietary
* revisions cannot be separated from the freely copyable material, the net
* result is that use of this software is governed by the ApTest copyright.
* 
* Copyright (c) 1990, 1991  X Consortium
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
* X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* 
* Except as contained in this notice, the name of the X Consortium shall not be
* used in advertising or otherwise to promote the sale, use or other dealings
* in this Software without prior written authorization from the X Consortium.
* 
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation, and that the name of UniSoft not be
* used in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.  UniSoft
* makes no representations about the suitability of this software for any
* purpose.  It is provided "as is" without express or implied warranty.
* 
* Copyright (c) 2005 X.Org Foundation LLC
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* 
* Copyright (c) Applied Testing and Technology, Inc. 1995
* All Rights Reserved.
* 
* 
* Portions of this software are based on Xlib and X Protocol Test Suite.
* We have used this material under the terms of its copyright, which grants
* free use, subject to the conditions below.  Note however that those
* portions of this software that are based on the original Test Suite have
* been significantly revised and that all such revisions are copyright (c)
* 1995 Applied Testing and Technology, Inc.  Insomuch as the proprietary
* revisions cannot be separated from the freely copyable material, the net
* result is that use of this software is governed by the ApTest copyright.
* 
* Copyright (c) 1990, 1991  X Consortium
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
* X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* 
* Except as contained in this notice, the name of the X Consortium shall not be
* used in advertising or otherwise to promote the sale, use or other dealings
* in this Software without prior written authorization from the X Consortium.
* 
* Copyright 1990, 1991 by UniSoft Group Limited.
* 
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation, and that the name of UniSoft not be
* used in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.  UniSoft
* makes no representations about the suitability of this software for any
* purpose.  It is provided "as is" without express or implied warranty.
* 
* Copyright (c) 2005 X.Org Foundation LLC
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* 
* Copyright (c) Applied Testing and Technology, Inc. 1995
* All Rights Reserved.
* 
* 
* Portions of this software are based on Xlib and X Protocol Test Suite.
* We have used this material under the terms of its copyright, which grants
* free use, subject to the conditions below.  Note however that those
* portions of this software that are based on the original Test Suite have
* been significantly revised and that all such revisions are copyright (c)
* 1995 Applied Testing and Technology, Inc.  Insomuch as the proprietary
* revisions cannot be separated from the freely copyable material, the net
* result is that use of this software is governed by the ApTest copyright.
* 
* Copyright (c) 1990, 1991  X Consortium
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
* X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* 
* Except as contained in this notice, the name of the X Consortium shall not be
* used in advertising or otherwise to promote the sale, use or other dealings
* in this Software without prior written authorization from the X Consortium.
* 
* Copyright 1990, 1991 by UniSoft Group Limited.
* 
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation, and that the name of UniSoft not be
* used in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.  UniSoft
* makes no representations about the suitability of this software for any
* purpose.  It is provided "as is" without express or implied warranty.
* 
*/
/*
 * SYNOPSIS:
 *   void
 *   XUngrabKey(display, keycode, modifiers, grab_window)
 *   Display	*display;
 *   int 	keycode;
 *   unsigned int 	modifiers;
 *   Window	grab_window;
 */


#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include	<stdlib.h>
#include	<stdio.h>
#include	<string.h>
#include	"xtest.h"
#include	"X11/Xlib.h"
#include	"X11/Xutil.h"
#include	"X11/Xresource.h"
#include	"X11/keysym.h"
#include	"tet_api.h"
#include	"xtestlib.h"
#include	"pixval.h"
#ifdef INPUTEXTENSION
#include        "X11/extensions/XInput.h"
#include        "XItest.h"
#endif

extern	Display	*Dsp;
extern	Window	Win;

extern	Window	ErrdefWindow;
extern	Drawable ErrdefDrawable;
extern	GC		ErrdefGC;
extern	Colormap ErrdefColormap;
extern	Pixmap	ErrdefPixmap;
extern	Atom	ErrdefAtom;
extern	Cursor	ErrdefCursor;
extern	Font	ErrdefFont;


#define T_XUngrabKey	1
char    *TestName = "XUngrabKey";

/*
 * Defines for different argument types
 */
#define A_DISPLAY display
#define A_WINDOW grab_window
#define A_DRAWABLE grab_window


/*
 * Arguments to the XUngrabKey function
 */
static Display	*display;
static int 	keycode;
static unsigned int 	modifiers;
static Window	grab_window;



static int minkc = -1,maxkc = -1;

static void set_kcs(dpy)
	Display *dpy;
{
	int kmin, kmax;

	if (minkc >= 8)
		return;
	XDisplayKeycodes(dpy, &kmin, &kmax);
	if (kmin < 8)
		kmin = 8;	/* For buggy servers */
	if (kmin >= kmax) {
		delete("Could not find two distinct key codes\n");
		delete("\t(min=%d, max=%d)\n", kmin, kmax);
		return;
	}
	minkc = kmin;
	maxkc = kmax;
}

#define	NMODS	8	/* Number of modifiers */

static int grab_key_code(dpy)
	Display *dpy;
{
	XModifierKeymap	*curmap;
	int i,key;

	set_kcs(dpy);
	curmap = XGetModifierMapping(dpy);
	for (key=minkc;key<=maxkc;key++) {
	    for (i = NMODS*curmap->max_keypermod; --i >= 0; )
		if (curmap->modifiermap[i] == key)
		    break;
	    if (i < 0) /* not a modifier, return it*/
		return key;
	}
	return minkc;
}

static int nongrab_key_code(dpy)
	Display *dpy;
{
	set_kcs(dpy);
	return (keycode == maxkc) ? minkc : maxkc;
}

#define	ACTPOSX	3
#define	ACTPOSY	6
/*
 * Warp to the grab_window and press the keys in modifiers and then press
 * the keycode in the 'keycode' arg.
 * (This activates the previously set up grab if the arg variables
 * have not been changed.)
 */
static void
activate_press()
{
	XSetInputFocus(display, grab_window, RevertToPointerRoot, CurrentTime);
	if (modifiers)
		modpress(display, modifiers);
	keypress(display, keycode);
}

/*
 * As above, but release (all) keys.
 */
static void
activate_release()
{
	XSetInputFocus(display, grab_window, RevertToPointerRoot, CurrentTime);
	keyrel(display, keycode);
	if (modifiers)
		modrel(display, modifiers);
}

/*
 * Returns True if the keyboard is grabbed.  This is not a general purpose
 * routine since it knows about the Grab Key args.
 * When the keyboard is grabbed then keyboard events are not reported to
 * non-grabbing clients. The grab client gets all keyboard events with
 * event window depending on owner_events and clients event mask.
 */
static
kgrabbed_check(client2)
Display	*client2;
{
XEvent	ev;
int	saved_keyc = keycode;

	XSelectInput(client2, grab_window, KeyPressMask|KeyReleaseMask);
	/* Flush events for client2 */
	XSync(client2, True);

	/*
	 * Ensure another-key press release pair in grab_window.
	 */
	keycode = nongrab_key_code(display);
	activate_press();
	activate_release();
	keycode = saved_keyc;

	XSync(client2, False);
	if (getevent(client2, &ev)) {
		/*
		 * An event was reported - keyboard isn't grabbed, do a sanity
		 * check on the type of event.
		 */
		if (ev.type != KeyPress && ev.type != KeyRelease) {
			delete("Unexpected event received in kgrabbed()");
			delete("  event type %s", eventname(ev.type));
		}
		return(False);
	} else {
		return(True);
	}
}

/*
 * as for kgrabbed_check() but used where number of fd's consumed by
 * multiple calls doesn't outweigh convenience of avoiding extra arg.
 */
static
kgrabbed()
{
Display	*client2;

	client2 = opendisplay();
	return kgrabbed_check(client2);
}



/* Value list for use in test t006 */
static unsigned long	modifiersvallist[] = {
	ShiftMask,
	LockMask,
	ControlMask,
	Mod1Mask,
	Mod2Mask,
	Mod3Mask,
	Mod4Mask,
	Mod5Mask,
	AnyModifier,
};


int 	tet_thistest;

/*
 * Called at the beginning of each test purpose to reset the
 * arguments to their initial values
 */
static void
setargs()
{
	display = Dsp;
	keycode = grab_key_code(display);
	modifiers = 0;
	grab_window = defwin(display);
}

/*
 * Set the arguments to default values for error tests
 */
static void
seterrdef()
{
}

static void t001(){

int 	pass = 0, fail = 0;

 	report_purpose(1);

	report_assertion("Assertion XUngrabKey-1.(B)");
	report_assertion("When the specified key/modifier combination has been");
	report_assertion("grabbed by this client, then a call to XUngrabKey releases");
	report_assertion("the grab.");
	report_assertion("Reason for omission: There is no known reliable test method for this assertion");

	report_strategy("If extension available:");
	report_strategy("  Setup up grab on specified key/modifier combination using XGrabKey.");
	report_strategy("  Activate grab.");
	report_strategy("  Check keyboard grabbed.");
	report_strategy("  Deactivate grab.");
	report_strategy("  Check keyboard not grabbed.");
	report_strategy("  Call XUngrabKey to release grab.");
	report_strategy("  Attempt to reactivate Grab.");
	report_strategy("  Check keyboard still not grabbed.");
	report_strategy("  Release keys.");
	report_strategy("else");
	report_strategy("  Grab key.");
	report_strategy("  Touch test.");
	report_strategy("  Report untested.");

	tpstartup();
	setargs();
	XGrabKey(display, keycode, modifiers, grab_window, False,
		GrabModeAsync, GrabModeAsync);

	if (noext(0)) {
		startcall(display);
		if (isdeleted())
			return;
		XUngrabKey(display, keycode, modifiers, grab_window);
		endcall(display);
		if (geterr() != Success) {
			report("Got %s, Expecting Success", errorname(geterr()));
			FAIL;
		}
		report("There is no reliable test method, but a touch test was performed");
		return;
	} else
		CHECK;

	activate_press();
	if (!kgrabbed()) {
		delete("Failed to activate grab on keycode %d.", keycode);
		relalldev();
		return;
	} else
		CHECK;

	activate_release();
	if (kgrabbed()) {
		delete("Failed to deactivate grab on keycode %d.", keycode);
		relalldev();
		return;
	} else
		CHECK;

	startcall(display);
	if (isdeleted())
		return;
	XUngrabKey(display, keycode, modifiers, grab_window);
	endcall(display);
	if (geterr() != Success) {
		report("Got %s, Expecting Success", errorname(geterr()));
		FAIL;
	}

	activate_press();
	if (kgrabbed()) {
		report("Failed to release initial grab on keycode %d.", keycode);
		FAIL;
	} else
		CHECK;
	relalldev();

	CHECKPASS(4);

	tpcleanup();
	pfcount(pass, fail);
}

static void t002(){

unsigned int 	mods;
int 	pass = 0, fail = 0;

 	report_purpose(2);

	report_assertion("Assertion XUngrabKey-2.(B)");
	report_assertion("A modifiers argument of AnyModifier releases all grabs by");
	report_assertion("this client for the specified key and all possible modifier");
	report_assertion("combinations.");
	report_assertion("Reason for omission: There is no known reliable test method for this assertion");

	report_strategy("If extensions are available:");
	report_strategy("  Place passive grab with a bunch of modifier keys.");
	report_strategy("  Activate grab.");
	report_strategy("  Check keyboard grabbed.");
	report_strategy("  Deactivate grab.");
	report_strategy("  Check keyboard not grabbed.");
	report_strategy("  Call XUngrabKey with a modifiers of AnyModifier.");
	report_strategy("  Attempt to reactivate Grab.");
	report_strategy("  Check keyboard still not grabbed.");
	report_strategy("  Release keys.");
	report_strategy("");
	report_strategy("  Place passive grab with just keycode (no modifiers).");
	report_strategy("  Activate grab.");
	report_strategy("  Check keyboard grabbed.");
	report_strategy("  Deactivate grab.");
	report_strategy("  Check keyboard not grabbed.");
	report_strategy("  Call XUngrabKey with a modifiers of AnyModifier.");
	report_strategy("  Attempt to reactivate Grab.");
	report_strategy("  Check keyboard still not grabbed.");
	report_strategy("  Release keys.");
	report_strategy("else");
	report_strategy("  Report untested.");

	tpstartup();
	setargs();
	if (noext(0)) {
		return;
	} else
		CHECK;

	modifiers = mods = wantmods(display, 4);

	XGrabKey(display, keycode, mods, grab_window, False,
		GrabModeAsync, GrabModeAsync);

	activate_press();
	if (!kgrabbed()) {
		delete("Failed to activate grab on keycode %d.", keycode);
		delete("  Modifiers used %s", keymaskname((unsigned long)mods));
		relalldev();
		return;
	} else
		CHECK;

	activate_release();
	if (kgrabbed()) {
		delete("Failed to deactivate grab on keycode %d.", keycode);
		delete("  Modifiers used %s", keymaskname((unsigned long)mods));
		relalldev();
		return;
	} else
		CHECK;

	modifiers = AnyModifier;
	startcall(display);
	if (isdeleted())
		return;
	XUngrabKey(display, keycode, modifiers, grab_window);
	endcall(display);
	if (geterr() != Success) {
		report("Got %s, Expecting Success", errorname(geterr()));
		FAIL;
	}

	modifiers = mods;
	activate_press();
	if (!kgrabbed())
		CHECK;
	else {
		report("Grab not released for AnyModifier on keycode %d", keycode);
		report("  Modifier keys used %s", keymaskname((unsigned long)mods));
		FAIL;
	}
	relalldev();

	if (kgrabbed()) { /* releasing keys may have done the job. */
		delete("Could not release grab for second part of test");
		return;
	} else
		CHECK;

	XGrabKey(display, keycode, 0, grab_window, False,
		GrabModeAsync, GrabModeAsync);

	modifiers = 0;
	activate_press();
	if (!kgrabbed()) {
		delete("Failed to activate grab on keycode %d.", keycode);
		relalldev();
		return;
	} else
		CHECK;

	activate_release();
	if (kgrabbed()) {
		delete("Failed to deactivate grab on keycode %d.", keycode);
		relalldev();
		return;
	} else
		CHECK;

	modifiers = AnyModifier;
	startcall(display);
	if (isdeleted())
		return;
	XUngrabKey(display, keycode, modifiers, grab_window);
	endcall(display);
	if (geterr() != Success) {
		report("Got %s, Expecting Success", errorname(geterr()));
		FAIL;
	}

	modifiers = 0;
	activate_press();
	if (!kgrabbed())
		CHECK;
	else {
		report("Grab with no modifier and keycode %d was not released.", keycode);
		FAIL;
	}

	relalldev();

	CHECKPASS(8);
	tpcleanup();
	pfcount(pass, fail);
}

static void t003(){

unsigned int 	mods;
int	i;
int 	minkc, maxkc;
Display	*client2;
int	keycount = 0;
int 	pass = 0, fail = 0;

 	report_purpose(3);

	report_assertion("Assertion XUngrabKey-3.(B)");
	report_assertion("A keycode argument of AnyKey releases all grabs by this");
	report_assertion("client for the specified modifiers and all keys.");
	report_assertion("Reason for omission: There is no known reliable test method for this assertion");

	report_strategy("If extensions are available:");
	report_strategy("  Place passive grab with a bunch of modifier keys and given keycode.");
	report_strategy("  Activate grab.");
	report_strategy("  Check keyboard grabbed.");
	report_strategy("  Deactivate grab.");
	report_strategy("  Check keyboard not grabbed.");
	report_strategy("  Call XUngrabKey with a keycode of AnyKey.");
	report_strategy("  Attempt to reactivate Grab.");
	report_strategy("  Check keyboard still not grabbed.");
	report_strategy("  Release keys.");
	report_strategy("  Repeat for all keycodes in the range min_keycode to max_keycode");
	report_strategy("	except for those in the modifier bunch.");
	report_strategy("");
	report_strategy("else");
	report_strategy("  Report untested.");

	tpstartup();
	setargs();
	client2 = opendisplay();

	XDisplayKeycodes(display, &minkc, &maxkc);

	if (noext(0)) {
		return;
	} else
		CHECK;

	modifiers = mods = wantmods(display, 4);

	for(keycount=0, i = minkc; i <= maxkc; i++) {
		if (ismodkey(mods, i))
			continue;
		keycount++;
		XGrabKey(display, i, mods, grab_window, False,
			GrabModeAsync, GrabModeAsync);

		keycode = i;
		activate_press();
		if (!kgrabbed_check(client2)) {
			delete("Failed to activate grab on keycode %d.", keycode);
			delete("  Modifiers used %s", keymaskname((unsigned long)mods));
			relalldev();
			return;
		} else
			CHECK;

		activate_release();
		if (kgrabbed_check(client2)) {
			delete("Failed to deactivate grab on keycode %d.", keycode);
			delete("  Modifiers used %s", keymaskname((unsigned long)mods));
			relalldev();
			return;
		} else
			CHECK;

		keycode = AnyKey;
		startcall(display);
		if (isdeleted())
			return;
		XUngrabKey(display, keycode, modifiers, grab_window);
		endcall(display);
		if (geterr() != Success) {
			report("Got %s, Expecting Success", errorname(geterr()));
			FAIL;
		}

		keycode = i;
		activate_press();
		if (!kgrabbed_check(client2))
			CHECK;
		else {
			report("Grab not released for AnyKey on keycode %d", i);
			report("  Modifier keys used %s", keymaskname((unsigned long)mods));
			FAIL;
		}
		relalldev();

		if (kgrabbed_check(client2)) { /* releasing keys may have done the job. */
			delete("Could not release grab for second part of test");
			return;
		} else
			CHECK;

		relalldev();
	}
	trace("Tested on %d non-modifier keys, with %d modifiers - all from %d keys (%d to %d).",
		keycount, bitcount((unsigned long)mods), 
		1+maxkc-minkc, minkc, maxkc);

	relalldev();

	CHECKPASS(1+4*keycount);
	tpcleanup();
	pfcount(pass, fail);
}

static void t004(){

int 	pass = 0, fail = 0;

 	report_purpose(4);

	report_assertion("Assertion XUngrabKey-4.(B)");
	report_assertion("A call to XUngrabKey has no effect on an active grab.");
	report_assertion("Reason for omission: There is no known reliable test method for this assertion");

	report_strategy("If extension available:");
	report_strategy("  Set passive grab.");
	report_strategy("  Activate it.");
	report_strategy("  Check keyboard is grabbed.");
	report_strategy("  Call XUngrabKey to attempt to release grab.");
	report_strategy("  Check keyboard still grabbed.");
	report_strategy("  Release keys to release grab.");
	report_strategy("  If still grabbed:");
	report_strategy("    Delete with message.");
	report_strategy("  else");
	report_strategy("    Call XUngrabKey to attempt to release grab.");
	report_strategy("    Attempt to activate grab.");
	report_strategy("    Check keyboard still not grabbed.");
	report_strategy("  Release keys.");
	report_strategy("else");
	report_strategy("  Report untested.");

	tpstartup();
	setargs();
	if (noext(0)) {
		return;
	} else
		CHECK;
	XGrabKey(display, keycode, modifiers, grab_window, False, GrabModeAsync, GrabModeAsync);

	activate_press();

	if (!kgrabbed()) {
		delete("Failed to set initial grab.");
		return;
	} else
		CHECK;

	startcall(display);
	if (isdeleted())
		return;
	XUngrabKey(display, keycode, modifiers, grab_window);
	endcall(display);
	if (geterr() != Success) {
		report("Got %s, Expecting Success", errorname(geterr()));
		FAIL;
	}

	if (!kgrabbed()) {
		report("Released active grab.");
		FAIL;
	} else
		CHECK;

	relalldev(); /* should release grab, allowing a final test */

	if (kgrabbed()) {
		delete("grab still active after key release.");
		return;
	} else
		CHECK;

	startcall(display);
	if (isdeleted())
		return;
	XUngrabKey(display, keycode, modifiers, grab_window);
	endcall(display);
	if (geterr() != Success) {
		report("Got %s, Expecting Success", errorname(geterr()));
		FAIL;
	}

	activate_press();
	if (kgrabbed()) {
		report("Couldn't release grab when inactive.");
		FAIL;
	} else
		CHECK;

	CHECKPASS(5);

	tpcleanup();
	pfcount(pass, fail);
}

static void t005(){

int 	minkc, maxkc;
int 	pass = 0, fail = 0;

 	report_purpose(5);

	report_assertion("Assertion XUngrabKey-5.(A)");
	report_assertion("When the specified keycode is not in the range specified by");
	report_assertion("min_keycode and max_keycode in the connection setup or");
	report_assertion("AnyKey, then a BadValue error occurs.");

	report_strategy("Get min and max keycodes.");
	report_strategy("Attempt to grab key less than the minimum.");
	report_strategy("Verify that a BadValue error occurs.");
	report_strategy("If the maximum is less than 255");
	report_strategy("  Attempt to grab key greater than the maximum");
	report_strategy("  Verify a BadValue error occurs.");

	tpstartup();
	setargs();
	XDisplayKeycodes(display, &minkc, &maxkc);

	keycode = minkc - 1;
	startcall(display);
	if (isdeleted())
		return;
	XUngrabKey(display, keycode, modifiers, grab_window);
	endcall(display);
	if (geterr() != BadValue) {
		report("Got %s, Expecting BadValue", errorname(geterr()));
		FAIL;
	}

	if (geterr() == BadValue)
		CHECK;

	if (maxkc < 255) {
		keycode = maxkc + 1;

		startcall(display);
		if (isdeleted())
			return;
		XUngrabKey(display, keycode, modifiers, grab_window);
		endcall(display);
		if (geterr() != BadValue) {
			report("Got %s, Expecting BadValue", errorname(geterr()));
			FAIL;
		}

		if (geterr() == BadValue)
			CHECK;
	} else
		CHECK;

	CHECKPASS(2);
	tpcleanup();
	pfcount(pass, fail);
}

/* Including from file Mval.tmc.2212 */
/* End of included file Mval.tmc.2212 */

/* Including from file error/EVal.mc */
static void t006(){

#undef	VALUE_ARG
#define	VALUE_ARG modifiers
#undef	VALUE_LIST
#define	VALUE_LIST modifiersvallist
#undef NOTMEMTYPE
#define NOTMEMTYPE unsigned
#undef	NOTMEMBER
#define	NOTMEMBER notmaskmember
int 	i;
int 	n;
NOTMEMTYPE
long	vals[NM_LEN];
int 	pass = 0, fail = 0;

 	report_purpose(6);

	report_assertion("Assertion XUngrabKey-6.(A)");
	report_assertion("When the value of modifiers is not a bitwise combination of");
	report_assertion("ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask,");
	report_assertion("Mod3Mask, Mod4Mask, Mod5Mask or AnyModifier, then a");
	report_assertion("BadValue error occurs.");

	report_strategy("Obtain a sequence of values which are not in the list specified by VALUE_LIST.");
	report_strategy("For each value:");
	report_strategy("  Call test function with this value in the VALUE_ARG argument.");
	report_strategy("  Verify that a BadValue error occurs.");

	tpstartup();
	setargs();
	seterrdef();

	n = NOTMEMBER(VALUE_LIST, NELEM(VALUE_LIST), vals);

	for (i = 0; i < n; i++) {

		debug(1, "Trying arg of %d", vals[i]);

		VALUE_ARG = vals[i];
		startcall(display);
		if (isdeleted())
			return;
		XUngrabKey(display, keycode, modifiers, grab_window);
		endcall(display);
		if (geterr() != BadValue) {
			report("Got %s, Expecting BadValue", errorname(geterr()));
			FAIL;
		}

		if (geterr() == BadValue)
			CHECK;
		else {
			trace("Value of %d did not give BadValue", vals[i]);
			FAIL;
		}
	}

	CHECKPASS(n);
	tpcleanup();
	pfcount(pass, fail);
}

/* End of included file error/EVal.mc */

/* Including from file error/EWin.mc */
/* End of included file error/EWin.mc */

/* Including from file error/EWin.mc */
static void t007(){

int 	pass = 0, fail = 0;

 	report_purpose(7);

	report_assertion("Assertion XUngrabKey-7.(A)");
	report_assertion("When a window argument does not name a valid Window, then a");
	report_assertion("BadWindow error occurs.");

	report_strategy("Create a bad window by creating and destroying a window.");
	report_strategy("Call test function using bad window as the window argument.");
	report_strategy("Verify that a BadWindow error occurs.");

	tpstartup();
	setargs();
	seterrdef();

	A_WINDOW = badwin(A_DISPLAY);

	startcall(display);
	if (isdeleted())
		return;
	XUngrabKey(display, keycode, modifiers, grab_window);
	endcall(display);
	if (geterr() != BadWindow) {
		report("Got %s, Expecting BadWindow", errorname(geterr()));
		FAIL;
	}

	if (geterr() == BadWindow)
		PASS;
	else
		FAIL;

	tpcleanup();
	pfcount(pass, fail);
}

/* End of included file error/EWin.mc */

/* End of Test Cases */


struct tet_testlist tet_testlist[] = {
	{ t001, 1 },
	{ t002, 2 },
	{ t003, 3 },
	{ t004, 4 },
	{ t005, 5 },
	{ t006, 6 },
	{ t007, 7 },
	{ NULL, 0 }
};

int 	ntests = sizeof(tet_testlist)/sizeof(struct tet_testlist)-1;

void	(*tet_startup)() = focusstartup;
void	(*tet_cleanup)() = focuscleanup;
