/*

 * compile by: cc -o mappingtest mappingtest.c -lXext -lX11 -lXi

 */

#include <X11/Xlib.h>

#include <X11/Xutil.h>

#include <X11/extensions/XInput.h>

#include <X11/extensions/SGIMisc.h>

#include <stdlib.h>

#include <stdio.h>





/* This sample code is to demonstrate the use of Wacom mapping ioctl's: 

 * input, output, and close for resize the tablet input area and 

 * the screeen display area. 

 * Please keep in mind that once the input/output ioctl's are issued, user

 * can not change the mappings from the Mapping Tab in Wacom Control Panel.

 * So, you must issue the close ioctl to close the context when you exit your

 * application. If you can use the Mapping Tab to set your screen/tablet area,

 * please don't use these ioctl's.

 * The use of Wacom multimode ioctl is also included

 */



#define MAX_WAC	5

int num_wac = 0;

XDeviceInfoPtr wac_list[MAX_WAC];



XDeviceInfoPtr 	list_wacom_tablets ();

Display *init_X(void);



main(int argc, char **argv)

{

	Display		*display;

	int 		ndevices;

	int		selectionNumber;

	char		selection[80];

	int		index;



	if ( (display = init_X()) == NULL )

	{

		printf ("No connection to server - aborting.\n");

		exit(1);

	}



	(void) list_wacom_tablets (display, &ndevices);





	if ( num_wac )

	{

		if (num_wac > 1)

		{

			while (1)

			{

				printf ("\nFound multiple tablets.  Select a number . . .\n");

				printf ("\t0.  exit\n");

				for (index = 1; index <= num_wac; index++)

				{

					printf ("\t%d.  %s\n", index, wac_list[index - 1]->name);

				}

				printf ("\n\tPlease select a number ==> ");

				gets (selection);

				selectionNumber = atoi(selection);

				if (selectionNumber == 0)

				{

					exit (0);

				}

				if (selectionNumber <= num_wac)

				{

					selectionNumber--;

					break;

				}

				printf ("Invalid selection\n");

			}

		}

		else

		{

			selectionNumber = num_wac - 1;

		}

	}

	exit (0);

}





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

 *

 * Find all the wacom tablets.  This builds a static list of wacom tablets.

 * This was quickly hacked from xlist, and that code remains as a useful

 * example.

 */



XDeviceInfoPtr

list_wacom_tablets (Display *display, int *ndevices)

{

    /* most of the variables are left over from xlist */

    int					i,j,k;

    XDeviceInfoPtr	list, slist;

    XAnyClassPtr		any;

    XKeyInfoPtr		K;

    XButtonInfoPtr	b;

    XValuatorInfoPtr	v;

    XAxisInfoPtr		a;

    char				rtrn[SGIDeviceRtrnLen];



    /* find all input devices */

    list = (XDeviceInfoPtr) XListInputDevices (display, ndevices);

    slist = list;

    /* Apply heuristic to select devices; frequently, X devices are 

     * selected by list->name.  Users/applications (e.g., Alias) can change

     * name, so that isn't the best stratgy.  Here we use a

     * query that most things won't respond to, and we hope that nobody

     * else identifies themselves as "Wacom ..."!  But this takes far too

     * long to complete (devices take a while to fail the query).  Probably

     * should check first list->name for either "wacom" or "tablet" (Alias),

     * and then "model" query to rule out other manufacturers.

     */



	printf ("Checking for Tablets ...  \n");

	for (i = 0; i < *ndevices; i++, list++)

	{

		printf("\tchecking %d of %d (%s) . . . ", i+1, *ndevices, list->name);

		fflush(stdout);

		if (!XSGIDeviceQuery(display, list->id, "model", rtrn))

		{

			printf("model infomation not available\n");

			continue;

		}

		else

		{

			if (!strncmp(rtrn, "Wacom", 5))

			{ /* found one */

				printf("model:  %s \n", rtrn);

				wac_list[num_wac++] = list;

				i = *ndevices;

			}

			else

			{

				printf("device model '%s'\n", rtrn);

				continue;

			}

		}



		/* Get the tablet display area. The return value is

		* 		(tabletLeft, tabletTop, tabletRight, tabletBottom)

		* If you need tabletXsize and tabletYsize, use the following

		* formula to convert them

		* 		tabletXsize = tabletRight - tabletLeft

		* 		tabletYsize = tabletBottom - tabletTop

		*/

		XSGIDeviceQuery(display, list->id, "input", rtrn);

		printf ("\t\tTablet input area is %s\n",rtrn);

				

		/*	Set the tablet (left, top) to (500,500)

		 * Set its (Xsize,Ysize) to (10000,10000)

		 * i.e., the  tablet (left,top,right,bottom) is (500,500,10500,10500)

		 */

		XSGIDeviceControl(display, list->id, "input", "500,500,10500,10500");



		XSGIDeviceQuery(display, list->id, "input", rtrn);

		printf ("\t\tTablet input area set to %s\n\n",rtrn);





		/* Get the Screen Size. The return value is 

		 *		(screenLeft, screenTop, screenRight, screenBottom)

		 * If you need screenXsize and screenYsize, use the following

		 * formula to convert them

		 * 		screenXsize = screenRight - screenLeft

		 * 		screenYsize = screenBottom - screenTop

		 */

		XSGIDeviceQuery(display, list->id, "output", rtrn);

		printf ("\t\tScreen output area is %s\n",rtrn);



		/*	Set the Screen (left, top) to (200,200)

		 * Set its (Xsize,Ysize) to (600,600)

		 * i.e., the screen (left,top,right,bottom) is (200,200,800,800)

		 */

		XSGIDeviceControl(display, list->id, "output", "-100,-100,1479,1223");



		XSGIDeviceQuery(display, list->id, "output", rtrn);

		printf ("\t\tScreen output area set to %s\n\n",rtrn);



		/* You MUST close the context before exiting your application

		 * if you resized the screen display area or tablet input area

		 * by the output/input ioctl's. The ioctl's opened a context

		 * for you when you resize screen/tablet. But there is no way 

		 * for the driver to tell that your application is exiting.

		 * If you don't issue the close ioctl before exiting your 

		 * application, the screen/tablet area will remain in your

		 * settings except someone change it by input/output ioctl.

		 */

		XSGIDeviceQuery(display, list->id, "close", rtrn);

		printf ("\t\tApplication specific mapping removed\n\n");



		XSGIDeviceQuery(display, list->id, "input", rtrn);

		printf ("\t\tTablet input area is %s\n",rtrn);

		XSGIDeviceQuery(display, list->id, "output", rtrn);

		printf ("\t\tScreen output area is %s\n\n",rtrn);





		/* Get the current multimode */ 

		XSGIDeviceQuery(display, list->id, "multimode", rtrn);

		printf("\t\tCurrent multimode is %s\n",  rtrn);



		/*	Change the multimode to first-new */

		XSGIDeviceControl(display, list->id, "multimode", "first");

		XSGIDeviceControl(display, list->id, "multimode", "new");



		XSGIDeviceQuery(display, list->id, "multimode", rtrn);

		printf("\t\tThe multimode is changed to %s\n", rtrn);

	}

	return (slist);

}



/*

 * SGI initialization; open display, check extensions, etc.

 */

Display *

init_X()

{

    Display			*dpy;

    int				tmp;

    int				ieMajor, ieFEV, ieFER;



	if ((dpy = XOpenDisplay(NULL)) == NULL)

	{

		fprintf(stderr, "Can't connect to server.\n");

		return NULL;

	}



	XSynchronize(dpy,1);

	if (!XQueryExtension(dpy, INAME, &ieMajor, &ieFEV, &ieFER)) {

		fprintf(stderr, "Server doesn't support the input extension.\n");

		XCloseDisplay(dpy);

		return NULL;

	}



	if (!XSGIMiscQueryExtension(dpy,&tmp,&tmp)) {

		fprintf(stderr, "Server doesn't support the SGI misc extension.\n");

		XCloseDisplay(dpy);

		return NULL;

	}

	return dpy;

}

