static void *
get_property (ClutterInputDevice *device,
              const gchar        *property,
              Atom                type,
              int                 format,
              gulong              nitems)
{
  MetaBackend *backend = meta_get_backend ();
  Display *xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
  gulong nitems_ret, bytes_after_ret;
  int rc, device_id, format_ret;
  Atom property_atom, type_ret;
  guchar *data_ret = NULL;

  property_atom = XInternAtom (xdisplay, property, False);
  device_id = clutter_input_device_get_device_id (device);

  rc = XIGetProperty (xdisplay, device_id, property_atom,
                      0, 10, False, type, &type_ret, &format_ret,
                      &nitems_ret, &bytes_after_ret, &data_ret);
  if (rc == Success && type_ret == type && format_ret == format && nitems_ret >= nitems)
    {
      if (nitems_ret > nitems)
        g_warning ("Property '%s' for device '%s' returned %lu items, expected %lu",
                   property, clutter_input_device_get_device_name (device), nitems_ret, nitems);
      return data_ret;
    }

  meta_XFree (data_ret);
  return NULL;
}
Exemple #2
0
int
xdevice_get_last_tool_id (int deviceid)
{
        Atom           prop;
        Atom           act_type;
        int            act_format;
        unsigned long  nitems, bytes_after;
        unsigned char *data, *ptr;
        int            id;

        id = 0x0;

        gdk_display_sync (gdk_display_get_default ());

        prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), WACOM_SERIAL_IDS_PROP, False);
        if (!prop)
                return id;

        gdk_error_trap_push ();

        if (!XIGetProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
                            deviceid, prop, 0, 1000, False,
                            AnyPropertyType, &act_type, &act_format,
                            &nitems, &bytes_after, &data) == Success) {
                gdk_error_trap_pop_ignored ();
                return 0x0;
        }

        if (gdk_error_trap_pop ())
                goto out;

	if (nitems != 4)
		goto out;

	if (act_type != XA_INTEGER)
		goto out;

	if (act_format != 32)
		goto out;

	/* item 0 = tablet ID
	 * item 1 = old device serial number (== last tool in proximity)
	 * item 2 = old hardware serial number (including tool ID)
	 * item 3 = current serial number (0 if no tool in proximity) */
	ptr = data;
	ptr += act_format/8 * 2;

	id = *((int32_t*)ptr);
	id = id & 0xfffff;

	/* That means that no tool was set down yet */
	if (id == STYLUS_DEVICE_ID ||
	    id == ERASER_DEVICE_ID)
		return 0x0;

out:
        XFree (data);
        return id;
}
static int
apply_matrix(Display *dpy, int deviceid, Matrix *m)
{
    Atom prop_float, prop_matrix;

    union {
        unsigned char *c;
        float *f;
    } data;
    int format_return;
    Atom type_return;
    unsigned long nitems;
    unsigned long bytes_after;

    int rc;

    prop_float = XInternAtom(dpy, "FLOAT", False);
    prop_matrix = XInternAtom(dpy, "Coordinate Transformation Matrix", False);

    if (!prop_float)
    {
        fprintf(stderr, "Float atom not found. This server is too old.\n");
        return EXIT_FAILURE;
    }
    if (!prop_matrix)
    {
        fprintf(stderr, "Coordinate transformation matrix not found. This "
                "server is too old\n");
        return EXIT_FAILURE;
    }

    rc = XIGetProperty(dpy, deviceid, prop_matrix, 0, 9, False, prop_float,
                       &type_return, &format_return, &nitems, &bytes_after,
                       &data.c);
    if (rc != Success || prop_float != type_return || format_return != 32 ||
        nitems != 9 || bytes_after != 0)
    {
        fprintf(stderr, "Failed to retrieve current property values\n");
        return EXIT_FAILURE;
    }

    memcpy(data.f, m->m, sizeof(m->m));

    XIChangeProperty(dpy, deviceid, prop_matrix, prop_float,
                     format_return, PropModeReplace, data.c, nitems);

    XFree(data.c);

    return EXIT_SUCCESS;
}
char *
xdevice_get_device_node (int deviceid)
{
    Atom           prop;
    Atom           act_type;
    int            act_format;
    unsigned long  nitems, bytes_after;
    unsigned char *data;
    char          *ret;

    gdk_display_sync (gdk_display_get_default ());

    prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), "Device Node", False);
    if (!prop)
        return NULL;

    gdk_error_trap_push ();

    if (!XIGetProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
                        deviceid, prop, 0, 1000, False,
                        AnyPropertyType, &act_type, &act_format,
                        &nitems, &bytes_after, &data) == Success) {
        gdk_error_trap_pop_ignored ();
        return NULL;
    }
    if (gdk_error_trap_pop ())
        goto out;

    if (nitems == 0)
        goto out;

    if (act_type != XA_STRING)
        goto out;

    /* Unknown string format */
    if (act_format != 8)
        goto out;

    ret = g_strdup ((char *) data);

    XFree (data);
    return ret;

out:
    XFree (data);
    return NULL;
}
Exemple #5
0
/**
 *  The return data type if 'char' must be convert to 'int8_t*'
 * if 'int' must be convert to 'int32_t*'
 * if 'float' must be convert to 'float*'
 **/
unsigned char*
get_prop(int id, const char* prop, int* nitems)
{
    if (!prop) {
        fprintf(stderr, "[get_prop] Empty property for %d\n", id);
        return NULL;
    }

    if (nitems == NULL) {
        fprintf(stderr, "[get_prop] Invalid item number for %d\n", id);
        return NULL;
    }

    Display* disp = XOpenDisplay(0);
    if (!disp) {
        fprintf(stderr, "[get_prop] Open display failed for %d\n", id);
        return NULL;
    }

    Atom prop_id = XInternAtom(disp, prop, True);
    if (prop_id == None) {
        XCloseDisplay(disp);
        fprintf(stderr, "[get_prop] Intern atom %s failed\n", prop);
        return NULL;
    }

    Atom act_type;
    int act_format;
    unsigned long num_items, bytes_after;
    unsigned char* data = NULL;
    int ret = XIGetProperty(disp, id, prop_id, 0, MAX_BUF_LEN, False,
                            AnyPropertyType, &act_type, &act_format,
                            &num_items, &bytes_after, &data);
    if (ret != Success) {
        XCloseDisplay(disp);
        fprintf(stderr, "[get_prop] Get %s data failed for %d\n", prop, id);
        return NULL;
    }

    *nitems = (int)num_items;
    XCloseDisplay(disp);
    return data;
}
Exemple #6
0
static int
set_prop_float (Display *disp, int deviceid,
                const char *prop_name, double value)
{
	if (!disp || !prop_name) {
		fprintf(stderr, "Args error in set_prop_float\n");
		return -1;
	}

	Atom prop = XInternAtom(
	                disp,
	                prop_name,
	                True);
	if (prop == None) {
		fprintf(stderr, "Get '%s' Atom Failed\n", prop_name);
		return -1;
	}

	Atom act_type;
	int act_format;
	unsigned long nitems, bytes_after;
	unsigned char *data;

	int rc = XIGetProperty(disp, deviceid, prop, 0, 1, False,
	                       AnyPropertyType, &act_type, &act_format,
	                       &nitems, &bytes_after, &data);
	if (rc != Success) {
		fprintf(stderr, "Get '%ld' property failed\n", prop);
		return -1;
	}

	Atom float_atom = XInternAtom(disp, "FLOAT", True);
	if (float_atom != None && act_type == float_atom && nitems == 1) {
		*(float*)data = (float)value;
		XIChangeProperty(disp, deviceid, prop, act_type, act_format,
		                 XIPropModeReplace, data, nitems);
	}
	XFree(data);

	return 0;
}
/* Reads the calibration data from evdev, should be self-explanatory. */
void readCalibrationData(int exitOnFail) {
	if(debugMode) {
		printf("Start calibration\n");
	}
	Atom retType;
	int retFormat;
	unsigned long retItems, retBytesAfter;
	unsigned int* data;
	if(XIGetProperty(display, deviceID, XInternAtom(display,
			"Evdev Axis Calibration", 0), 0, 4 * 32, False, XA_INTEGER,
			&retType, &retFormat, &retItems, &retBytesAfter,
			(unsigned char**) &data) != Success) {
		data = NULL;
	}

	if (data == NULL || retItems != 4 || data[0] == data[1] || data[2] == data[3]) {
		/* evdev might not be ready yet after resume. Let's wait a second and try again. */
		sleep(1);

		if(XIGetProperty(display, deviceID, XInternAtom(display,
				"Evdev Axis Calibration", 0), 0, 4 * 32, False, XA_INTEGER,
				&retType, &retFormat, &retItems, &retBytesAfter,
				(unsigned char**) &data) != Success) {
			return;
		}

		if (retItems != 4 || data[0] == data[1] || data[2] == data[3]) {

			if(debugMode) {
				printf("No calibration data found, use default values.\n");
			}

			/* Get minimum/maximum of axes */

			int nDev;
			XIDeviceInfo * deviceInfo = XIQueryDevice(display, deviceID, &nDev);

			int c;
			for(c = 0; c < deviceInfo->num_classes; c++) {
				if(deviceInfo->classes[c]->type == XIValuatorClass) {
					XIValuatorClassInfo* valuatorInfo = (XIValuatorClassInfo *) deviceInfo->classes[c];
					if(valuatorInfo->mode == XIModeAbsolute) {
						if(valuatorInfo->label == XInternAtom(display, "Abs X", 0)
						|| valuatorInfo->label == XInternAtom(display, "Abs MT Position X", 0)) 
						{
							calibMinX = valuatorInfo->min;
							calibMaxX = valuatorInfo->max;
						}
						else if(valuatorInfo->label == XInternAtom(display, "Abs Y", 0) 							|| valuatorInfo->label == XInternAtom(display, "Abs MT Position Y", 0))
						{
							calibMinY = valuatorInfo->min;
							calibMaxY = valuatorInfo->max;
						}
					}
				}
			}

			XIFreeDeviceInfo(deviceInfo);

		} else {
			calibMinX = data[0];
			calibMaxX = data[1];
			calibMinY = data[2];
			calibMaxY = data[3];
		}
	} else {
		calibMinX = data[0];
		calibMaxX = data[1];
		calibMinY = data[2];
		calibMaxY = data[3];
	}

	if(data != NULL) {
		XFree(data);
	}

	float * data4 = NULL;
	if(XIGetProperty(display, deviceID, XInternAtom(display,
			"Coordinate Transformation Matrix", 0), 0, 9 * 32, False, XInternAtom(display,
			"FLOAT", 0),
			&retType, &retFormat, &retItems, &retBytesAfter,
			(unsigned char **) &data4) != Success) {
		data4 = NULL;
	}
	calibMatrixUse = 0;
	if(data4 != NULL && retItems == 9) {
		int i;
		for(i = 0; i < 6; i++) {
			/* We only take the first two rows of the matrix, the rest is unimportant anyway */
			calibMatrix[i] = data4[i];
		}
		calibMatrixUse = 1;
	}
	if(data4 != NULL) {
		XFree(data4);
	}



	unsigned char* data2;

	if(XIGetProperty(display, deviceID, XInternAtom(display,
			"Evdev Axis Inversion", 0), 0, 2 * 8, False, XA_INTEGER, &retType,
			&retFormat, &retItems, &retBytesAfter, (unsigned char**) &data2) != Success) {
		return;
	}

	if (retItems != 2) {
		if (exitOnFail) {
			printf("No valid axis inversion data found.\n");
			exit(1);
		} else {
			return;
		}
	}

	calibSwapX = data2[0];
	calibSwapY = data2[1];

	XFree(data2);

	if(XIGetProperty(display, deviceID,
			XInternAtom(display, "Evdev Axes Swap", 0), 0, 8, False,
			XA_INTEGER, &retType, &retFormat, &retItems, &retBytesAfter,
			(unsigned char**) &data2) != Success) {
		return;
	}

	if (retItems != 1) {
		if (exitOnFail) {
			printf("No valid axes swap data found.\n");
			exit(1);
		} else {
			return;
		}
	}
	calibSwapAxes = data2[0];

	XFree(data2);

	if(debugMode)
	{
		printf("Calibration: MinX: %i; MaxX: %i; MinY: %i; MaxY: %i\n", calibMinX, calibMaxX, calibMinY, calibMaxY);
	}

}
int
xdevice_get_last_tool_id (int  deviceid)
{
    Atom           prop;
    Atom           act_type;
    int            act_format;
    unsigned long  nitems, bytes_after;
    unsigned char *data;
    int            id;

    id = -1;

    gdk_display_sync (gdk_display_get_default ());

    prop = XInternAtom (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), WACOM_SERIAL_IDS_PROP, False);
    if (!prop)
        return -1;

    data = NULL;

    gdk_error_trap_push ();

    if (XIGetProperty (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
                       deviceid, prop, 0, 1000, False,
                       AnyPropertyType, &act_type, &act_format,
                       &nitems, &bytes_after, &data) != Success) {
        gdk_error_trap_pop_ignored ();
        goto out;
    }

    if (gdk_error_trap_pop ())
        goto out;

    if (nitems != 4 && nitems != 5)
        goto out;

    if (act_type != XA_INTEGER)
        goto out;

    if (act_format != TOOL_ID_FORMAT_SIZE)
        goto out;

    /* item 0 = tablet ID
     * item 1 = old device serial number (== last tool in proximity)
     * item 2 = old hardware serial number (including tool ID)
     * item 3 = current serial number (0 if no tool in proximity)
     * item 4 = current tool ID (since Feb 2012)
     *
     * Get the current tool ID first, if available, then the old one */
    id = 0x0;
    if (nitems == 5)
        id = get_id_for_index (data, 4);
    if (id == 0x0)
        id = get_id_for_index (data, 2);

    /* That means that no tool was set down yet */
    if (id == STYLUS_DEVICE_ID ||
            id == ERASER_DEVICE_ID)
        id = 0x0;

out:
    if (data != NULL)
        XFree (data);
    return id;
}
bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData)
{
    bool handled = true;
    Display *xDisplay = static_cast<Display *>(m_xlib_display);
    xXIGenericDeviceEvent *xiEvent = static_cast<xXIGenericDeviceEvent *>(event);
    switch (xiEvent->evtype) {
    case XI_ButtonPress: // stylus down
        if (reinterpret_cast<xXIDeviceEvent *>(event)->detail == 1) { // ignore the physical buttons on the stylus
            tabletData->down = true;
            xi2ReportTabletEvent(*tabletData, xiEvent);
        }
        break;
    case XI_ButtonRelease: // stylus up
        if (reinterpret_cast<xXIDeviceEvent *>(event)->detail == 1) {
            tabletData->down = false;
            xi2ReportTabletEvent(*tabletData, xiEvent);
        }
        break;
    case XI_Motion:
        // Report TabletMove only when the stylus is touching the tablet.
        // No possibility to report proximity motion (no suitable Qt event exists yet).
        if (tabletData->down)
            xi2ReportTabletEvent(*tabletData, xiEvent);
        break;
    case XI_PropertyEvent: {
        xXIPropertyEvent *ev = reinterpret_cast<xXIPropertyEvent *>(event);
        if (ev->what == XIPropertyModified) {
            if (ev->property == atom(QXcbAtom::WacomSerialIDs)) {
                Atom propType;
                int propFormat;
                unsigned long numItems, bytesAfter;
                unsigned char *data;
                if (XIGetProperty(xDisplay, tabletData->deviceId, ev->property, 0, 100,
                                  0, AnyPropertyType, &propType, &propFormat,
                                  &numItems, &bytesAfter, &data) == Success) {
                    if (propType == atom(QXcbAtom::INTEGER) && propFormat == 32) {
                        int *ptr = reinterpret_cast<int *>(data);
                        for (unsigned long i = 0; i < numItems; ++i)
                            tabletData->serialId |= qint64(ptr[i]) << (i * 32);
                    }
                    XFree(data);
                }
                // With recent-enough X drivers this property change event seems to come always
                // when entering and leaving proximity. Due to the lack of other options hook up
                // the enter/leave events to it.
                if (tabletData->inProximity) {
                    tabletData->inProximity = false;
                    QWindowSystemInterface::handleTabletLeaveProximityEvent(QTabletEvent::Stylus,
                                                                            tabletData->pointerType,
                                                                            tabletData->serialId);
                } else {
                    tabletData->inProximity = true;
                    QWindowSystemInterface::handleTabletEnterProximityEvent(QTabletEvent::Stylus,
                                                                            tabletData->pointerType,
                                                                            tabletData->serialId);
                }
            }
        }
        break;
    }
    default:
        handled = false;
        break;
    }
    return handled;
}
Exemple #10
0
static int
do_set_prop_xi2(Display *dpy, Atom type, int format, int argc, char **argv, char *n, char *desc)
{
    XIDeviceInfo *info;
    Atom          prop;
    Atom          old_type;
    char         *name;
    int           i;
    Atom          float_atom;
    int           old_format, nelements = 0;
    unsigned long act_nitems, bytes_after;
    char         *endptr;
    union {
        unsigned char *c;
        int16_t *s;
        int32_t *l;
    } data;

    if (argc < 3)
    {
        fprintf(stderr, "Usage: xinput %s %s\n", n, desc);
        return EXIT_FAILURE;
    }

    info = xi2_find_device_info(dpy, argv[0]);
    if (!info)
    {
        fprintf(stderr, "unable to find device %s\n", argv[0]);
        return EXIT_FAILURE;
    }

    name = argv[1];

    prop = parse_atom(dpy, name);

    if (prop == None) {
        fprintf(stderr, "invalid property %s\n", name);
        return EXIT_FAILURE;
    }

    float_atom = XInternAtom(dpy, "FLOAT", False);

    nelements = argc - 2;
    if (type == None || format == 0) {
        if (XIGetProperty(dpy, info->deviceid, prop, 0, 0, False,
                          AnyPropertyType, &old_type, &old_format, &act_nitems,
                          &bytes_after, &data.c) != Success) {
            fprintf(stderr, "failed to get property type and format for %s\n",
                    name);
            return EXIT_FAILURE;
        } else {
            if (type == None)
                type = old_type;
            if (format == 0)
                format = old_format;
        }

        XFree(data.c);
    }

    if (type == None) {
        fprintf(stderr, "property %s doesn't exist, you need to specify "
                "its type and format\n", name);
        return EXIT_FAILURE;
    }

    data.c = calloc(nelements, sizeof(int32_t));

    for (i = 0; i < nelements; i++)
    {
        if (type == XA_INTEGER) {
            switch (format)
            {
                case 8:
                    data.c[i] = atoi(argv[2 + i]);
                    break;
                case 16:
                    data.s[i] = atoi(argv[2 + i]);
                    break;
                case 32:
                    data.l[i] = atoi(argv[2 + i]);
                    break;
                default:
                    fprintf(stderr, "unexpected size for property %s", name);
                    return EXIT_FAILURE;
            }
        } else if (type == float_atom) {
            if (format != 32) {
                fprintf(stderr, "unexpected format %d for property %s\n",
                        format, name);
                return EXIT_FAILURE;
            }
            *(float *)(data.l + i) = strtod(argv[2 + i], &endptr);
            if (endptr == argv[2 + i]) {
                fprintf(stderr, "argument %s could not be parsed\n", argv[2 + i]);
                return EXIT_FAILURE;
            }
        } else if (type == XA_ATOM) {
            if (format != 32) {
                fprintf(stderr, "unexpected format %d for property %s\n",
                        format, name);
                return EXIT_FAILURE;
            }
            data.l[i] = parse_atom(dpy, argv[2 + i]);
        } else {
            fprintf(stderr, "unexpected type for property %s\n", name);
            return EXIT_FAILURE;
        }
    }

    XIChangeProperty(dpy, info->deviceid, prop, type, format, PropModeReplace,
                          data.c, nelements);
    free(data.c);
    return EXIT_SUCCESS;
}
Exemple #11
0
static void
print_property_xi2(Display *dpy, int deviceid, Atom property)
{
    Atom                act_type;
    char                *name;
    int                 act_format;
    unsigned long       nitems, bytes_after;
    unsigned char       *data, *ptr;
    int                 j, done = False;

    name = XGetAtomName(dpy, property);
    printf("\t%s (%ld):\t", name, property);

    if (XIGetProperty(dpy, deviceid, property, 0, 1000, False,
                           AnyPropertyType, &act_type, &act_format,
                           &nitems, &bytes_after, &data) == Success)
    {
        Atom float_atom = XInternAtom(dpy, "FLOAT", True);

        ptr = data;

        if (nitems == 0)
            printf("<no items>");

        for (j = 0; j < nitems; j++)
        {
            switch(act_type)
            {
                case XA_INTEGER:
                    switch(act_format)
                    {
                        case 8:
                            printf("%d", *((int8_t*)ptr));
                            break;
                        case 16:
                            printf("%d", *((int16_t*)ptr));
                            break;
                        case 32:
                            printf("%d", *((int32_t*)ptr));
                            break;
                    }
                    break;
                case XA_STRING:
                    if (act_format != 8)
                    {
                        printf("Unknown string format.\n");
                        done = True;
                        break;
                    }
                    printf("\"%s\"", ptr);
                    j += strlen((char*)ptr); /* The loop's j++ jumps over the
                                                terminating 0 */
                    ptr += strlen((char*)ptr); /* ptr += size below jumps over
                                                  the terminating 0 */
                    break;
                case XA_ATOM:
                    {
                        Atom a = *(uint32_t*)ptr;
                        printf("\"%s\" (%ld)",
                                (a) ? XGetAtomName(dpy, a) : "None",
                                a);
                        break;
                    }
                    break;
                default:
                    if (float_atom != None && act_type == float_atom)
                    {
                        printf("%f", *((float*)ptr));
                        break;
                    }

                    printf("\t... of unknown type %s\n",
                            XGetAtomName(dpy, act_type));
                    done = True;
                    break;
            }

            ptr += act_format/8;

            if (done == True)
                break;
            if (j < nitems - 1)
                printf(", ");
        }
        printf("\n");
        XFree(data);
    } else
        printf("\tFetch failure\n");

}
void setCalibration(int id, int minX, int maxX, int minY, int maxY, int axesSwap, int screenWidth, int screenHeight, int outputX, int outputY, int outputWidth, int outputHeight, int rotation) {

    float matrix[] = { 1., 0., 0.,    /* [0] [1] [2] */
                       0., 1., 0.,    /* [3] [4] [5] */
                       0., 0., 1.
                     };  /* [6] [7] [8] */

    int matrixMode = 0;
    /* Check if transformation matrix is supported */
    long l;
    if((sizeof l) == 4 || (sizeof l) == 8) {
        /* We only support matrix mode on systems where longs are 32 or 64 bits long */
        Atom retType;
        int retFormat;
        unsigned long retItems, retBytesAfter;
        unsigned char * data = NULL;
        if(XIGetProperty(display, id, XInternAtom(display,
                         "Coordinate Transformation Matrix", 0), 0, 9 * 32, False, floatAtom,
                         &retType, &retFormat, &retItems, &retBytesAfter,
                         &data) != Success) {
            data = NULL;
        }
        if(data != NULL && retItems == 9) {
            matrixMode = 1;
        }
        if(data != NULL) {
            XFree(data);
        }
    }

    unsigned char flipHoriz = 0, flipVerti = 0;

    if(matrixMode) {

        if(debugMode) printf("Use matrix method\n");

        /* Output rotation */
        if(rotation & RR_Rotate_180) {
            matrix[0] = -1.;
            matrix[4] = -1;
            matrix[2] = 1.;
            matrix[5] = 1.;
        } else if(rotation & RR_Rotate_90) {
            matrix[0] = 0.;
            matrix[1] = -1.;
            matrix[3] = 1.;
            matrix[4] = 0.;

            matrix[2] = 1.;
        } else if(rotation & RR_Rotate_270) {
            matrix[0] = 0.;
            matrix[1] = 1.;
            matrix[3] = -1.;
            matrix[4] = 0.;

            matrix[5] = 1.;
        }

        /* Output Reflection */
        if(rotation & RR_Reflect_X) {
            matrix[0]*= -1.;
            matrix[1]*= -1.;
            matrix[2]*= -1.;
            matrix[2]+= 1.;
        }
        if(rotation & RR_Reflect_Y) {
            matrix[3]*= -1.;
            matrix[4]*= -1.;
            matrix[5]*= -1.;
            matrix[5]+= 1.;
        }

        /* Output Size */
        float widthRel = outputWidth / (float) screenWidth;
        float heightRel = outputHeight / (float) screenHeight;
        matrix[0] *= widthRel;
        matrix[1] *= widthRel;
        matrix[2] *= widthRel;
        matrix[3] *= heightRel;
        matrix[4] *= heightRel;
        matrix[5] *= heightRel;

        /* Output Position */
        matrix[2] += outputX / (float) screenWidth;
        matrix[5] += outputY / (float) screenHeight;

    } else {

        if(debugMode) printf("Use legacy method\n");

        /* No support for transformations, so use legacy method */

        if(rotation & RR_Rotate_180) {
            flipHoriz = !flipHoriz;
            flipVerti = !flipVerti;

        } else if(rotation & RR_Rotate_90) {
            flipVerti = !flipVerti;
            axesSwap = !axesSwap;
        } else if(rotation & RR_Rotate_270) {
            flipHoriz = !flipHoriz;
            axesSwap = !axesSwap;
        }

        /* Output Reflection */
        if(rotation & RR_Reflect_X) {
            flipHoriz = !flipHoriz;
        }
        if(rotation & RR_Reflect_Y) {
            flipVerti = !flipVerti;
        }


        if(axesSwap) {
            swap(&maxX, &maxY);
            swap(&minX, &minY);
        }

        int leftSpace, rightSpace, topSpace, bottomSpace;
        leftSpace = outputX;
        rightSpace = screenWidth - outputX - outputWidth;

        topSpace = outputY;
        bottomSpace = screenHeight - outputY - outputHeight;

        if(flipHoriz) swap(&leftSpace, &rightSpace);
        if(flipVerti) swap(&topSpace, &bottomSpace);

        float fctX = ((float) (maxX - minX)) / ((float) outputWidth);
        float fctY = ((float) (maxY - minY)) / ((float) outputHeight);
        minX = minX - (int) (leftSpace * fctX);
        maxX = maxX + (int) (rightSpace * fctX);
        minY = minY - (int) (topSpace * fctY);
        maxY = maxY + (int) (bottomSpace * fctY);

    }

    XDevice *dev = XOpenDevice(display, id);
    if(dev) {
        if(matrixMode) {
            if((sizeof l) == 4) {
                XChangeDeviceProperty(display, dev, XInternAtom(display,
                                      "Coordinate Transformation Matrix", 0), floatAtom, 32, PropModeReplace, (unsigned char*) matrix, 9);
            } else if((sizeof l) == 8) {
                /* Xlib needs the floats long-aligned, so let's align them. */
                float matrix2[] = { matrix[0], 0., matrix[1], 0., matrix[2], 0.,
                                    matrix[3], 0., matrix[4], 0., matrix[5], 0.,
                                    matrix[6], 0., matrix[7], 0., matrix[8], 0.
                                  };
                XChangeDeviceProperty(display, dev, XInternAtom(display,
                                      "Coordinate Transformation Matrix", 0), floatAtom, 32, PropModeReplace, (unsigned char*) matrix2, 9);
            }
        }

        long calib[] = { minX, maxX, minY, maxY };
        //TODO instead of long, use platform 32 bit type
        XChangeDeviceProperty(display, dev, XInternAtom(display,
                              "Evdev Axis Calibration", 0), XA_INTEGER, 32, PropModeReplace, (unsigned char*) calib, 4);

        unsigned char flipData[] = {flipHoriz, flipVerti};
        XChangeDeviceProperty(display, dev, XInternAtom(display,
                              "Evdev Axis Inversion", 0), XA_INTEGER, 8, PropModeReplace, flipData, 2);

        unsigned char cAxesSwap = (unsigned char) axesSwap;
        XChangeDeviceProperty(display, dev, XInternAtom(display,
                              "Evdev Axes Swap", 0), XA_INTEGER, 8, PropModeReplace, &cAxesSwap, 1);

        XCloseDevice(display, dev);
    }
}