<commit_before>#include <stdio.h>
#include <X11/Xlib-xcb.h>
#include <stdbool.h>
#include "input.h"

static const CTMAffinity default_affinity = {
	.horizontal = HA_Left,
	.vertical = VA_Top
};

static const CTMConfiguration default_config = {
	.type = CTM_MatchWidth,
	.affinity = {
		.horizontal = HA_Left,
		.vertical = VA_Top
	}
};

void calculate_coordinate_transform_matrix(const Rectangle * region, const xcb_randr_screen_size_t * screen, float * matrix) {
	float x_scale = RECT_WIDTH(*region) / (float)screen->width;
	float y_scale = RECT_HEIGHT(*region) / (float)screen->height;

	float x_offset = region->top / (float)screen->width;
	float y_offset = region->left / (float)screen->height;

	matrix[0] = x_scale;
	matrix[1] = 0;
	matrix[2] = x_offset;

	matrix[3] = 0;
	matrix[4] = y_scale;
	matrix[5] = y_offset;

	matrix[6] = 0;
	matrix[7] = 0;
	matrix[8] = 1;
}

void rectangle_scale(const Rectangle * rectangle, const float x, const float y, Rectangle * result) {
	result->left = rectangle->left * x;
	result->right = rectangle->right * x;
	result->top = rectangle->top * y;
	result->bottom = rectangle->bottom * y;
}

float rectangle_select_ratio_preserve_aspect(const Rectangle * target, const Rectangle * original, const CTMAspectPreserveType type) {
	int target_width = RECT_WIDTH(*target);
	int target_height = RECT_HEIGHT(*target);

	float horizontal_ratio = (float)RECT_WIDTH(*target) / RECT_WIDTH(*original);
	float vertical_ratio = (float)RECT_HEIGHT(*target) / RECT_HEIGHT(*original);

	if (type == CTM_Fit) {
		if (horizontal_ratio > vertical_ratio) {
			return horizontal_ratio;
		} else {
			return vertical_ratio;
		}
	} else if (type == CTM_MatchWidth) {
		return horizontal_ratio;
	} else if (type == CTM_MatchHeight) {
		return vertical_ratio;
	} else {
		return 1; // FIXME: error somehow?
	}
}

float rectangle_scale_preserve_aspect(const Rectangle * target, const Rectangle * original, const CTMAspectPreserveType type, Rectangle * result) {
	float ratio = rectangle_select_ratio_preserve_aspect(target, original, type);

	int original_width = RECT_WIDTH(*original);
	int original_height = RECT_HEIGHT(*original);

	result->top = result->left = 0;
	result->right = original_width;
	result->bottom = original_height;
	rectangle_scale(result, ratio, ratio, result);

	return ratio;
}

void rectangle_align(const Rectangle * reference,
					 const Rectangle * alignee,
					 const CTMAffinity * affinity,
					 Rectangle * result) {
	int top = reference->top;
	int left = reference->left;

	int width = RECT_WIDTH(*alignee);
	int height = RECT_HEIGHT(*alignee);

	if (!affinity) {
		result->top = top;
		result->left = left;
		result->bottom = top + height;
		result->right = left + width;
	} else {
		int x_offset = (width - RECT_WIDTH(*reference));
		int y_offset = (height - RECT_WIDTH(*reference));

		result->top = reference->top;
		result->left = reference->left;
		result->bottom = reference->top + height;
		result->right = reference->left + width;

		if (affinity->horizontal == HA_Right) {
			result->left -= x_offset;
			result->right -= x_offset;
		} else if (affinity->horizontal == HA_Centered) {
			result->left -= x_offset / 2;
			result->right -= x_offset / 2;
		}

		if (affinity->vertical == VA_Bottom) {
			result->top -= y_offset;
			result->bottom -= y_offset;
		} else if (affinity->vertical == VA_Centered) {
			result->top -= y_offset / 2;
			result->bottom -= y_offset / 2;
		}
	}
}

XIDeviceInfo * find_device(Display * display, const XID id) {
    XIDeviceInfo *info;
    XIDeviceInfo *found = NULL;
    int ndevices;

	XIQueryDevice(display, id, &ndevices);

    for(int i = 0; i < ndevices; i++)
    {
        if (info[i].deviceid == id) {
			if (found) {
				// Found duplicate
				XIFreeDeviceInfo(info);
				return NULL;
			}
		} else {
			found = &info[i];
		}
	}
	return found;
}

int xi2_device_set_matrix(Display * display, const XID id, const float * matrix) {
	static Atom atoms[2] = {0};
	static char * names[] = {"Coordinate Transformation Matrix", "FLOAT"};

	if (atoms[0] == 0 && atoms[1] == 0) {
		if (!XInternAtoms(display, names, 2, True, atoms)) { // FIXME: test
			return EINTERN_FAILED; // FIXME: error message
		}
	}

	XIChangeProperty(display,
			id,
			atoms[0], // "Coordiante Transformation Matrix"
			atoms[1], // "FLOAT"
			32,
			PropModeReplace,
			(char *)matrix, 9);
	return 0;
}
<commit_msg>Fixed another place where axes were swapped. Added function to check if Coordinate Transform Matrix equals a provided matrix. Used to ensure changes stuck.<commit_after>#include <stdio.h>
#include <X11/Xlib-xcb.h>
#include <stdbool.h>
#include "input.h"

static const CTMAffinity default_affinity = {
	.horizontal = HA_Left,
	.vertical = VA_Top
};

static const CTMConfiguration default_config = {
	.type = CTM_MatchWidth,
	.affinity = {
		.horizontal = HA_Left,
		.vertical = VA_Top
	}
};

void calculate_coordinate_transform_matrix(const Rectangle * region, const xcb_randr_screen_size_t * screen, float * matrix) {
	float x_scale = RECT_WIDTH(*region) / (float)screen->width;
	float y_scale = RECT_HEIGHT(*region) / (float)screen->height;

	float x_offset = region->left / (float)screen->width;
	float y_offset = region->top / (float)screen->height;

	matrix[0] = x_scale;
	matrix[1] = 0;
	matrix[2] = x_offset;

	matrix[3] = 0;
	matrix[4] = y_scale;
	matrix[5] = y_offset;

	matrix[6] = 0;
	matrix[7] = 0;
	matrix[8] = 1;
}

void rectangle_scale(const Rectangle * rectangle, const float x, const float y, Rectangle * result) {
	result->left = rectangle->left * x;
	result->right = rectangle->right * x;
	result->top = rectangle->top * y;
	result->bottom = rectangle->bottom * y;
}

float rectangle_select_ratio_preserve_aspect(const Rectangle * target, const Rectangle * original, const CTMAspectPreserveType type) {
	int target_width = RECT_WIDTH(*target);
	int target_height = RECT_HEIGHT(*target);

	float horizontal_ratio = (float)RECT_WIDTH(*target) / RECT_WIDTH(*original);
	float vertical_ratio = (float)RECT_HEIGHT(*target) / RECT_HEIGHT(*original);

	if (type == CTM_Fit) {
		if (horizontal_ratio > vertical_ratio) {
			return horizontal_ratio;
		} else {
			return vertical_ratio;
		}
	} else if (type == CTM_MatchWidth) {
		return horizontal_ratio;
	} else if (type == CTM_MatchHeight) {
		return vertical_ratio;
	} else {
		return 1; // FIXME: error somehow?
	}
}

float rectangle_scale_preserve_aspect(const Rectangle * target, const Rectangle * original, const CTMAspectPreserveType type, Rectangle * result) {
	float ratio = rectangle_select_ratio_preserve_aspect(target, original, type);

	int original_width = RECT_WIDTH(*original);
	int original_height = RECT_HEIGHT(*original);

	result->top = result->left = 0;
	result->right = original_width;
	result->bottom = original_height;
	rectangle_scale(result, ratio, ratio, result);

	return ratio;
}

void rectangle_align(const Rectangle * reference,
					 const Rectangle * alignee,
					 const CTMAffinity * affinity,
					 Rectangle * result) {
	int top = reference->top;
	int left = reference->left;

	int width = RECT_WIDTH(*alignee);
	int height = RECT_HEIGHT(*alignee);

	if (!affinity) {
		result->top = top;
		result->left = left;
		result->bottom = top + height;
		result->right = left + width;
	} else {
		int x_offset = (width - RECT_WIDTH(*reference));
		int y_offset = (height - RECT_WIDTH(*reference));

		result->top = reference->top;
		result->left = reference->left;
		result->bottom = reference->top + height;
		result->right = reference->left + width;

		if (affinity->horizontal == HA_Right) {
			result->left -= x_offset;
			result->right -= x_offset;
		} else if (affinity->horizontal == HA_Centered) {
			result->left -= x_offset / 2;
			result->right -= x_offset / 2;
		}

		if (affinity->vertical == VA_Bottom) {
			result->top -= y_offset;
			result->bottom -= y_offset;
		} else if (affinity->vertical == VA_Centered) {
			result->top -= y_offset / 2;
			result->bottom -= y_offset / 2;
		}
	}
}

XIDeviceInfo * find_device(Display * display, const XID id) {
    XIDeviceInfo *info;
    XIDeviceInfo *found = NULL;
    int ndevices;

	XIQueryDevice(display, id, &ndevices);

    for(int i = 0; i < ndevices; i++)
    {
        if (info[i].deviceid == id) {
			if (found) {
				// Found duplicate
				XIFreeDeviceInfo(info);
				return NULL;
			}
		} else {
			found = &info[i];
		}
	}
	return found;
}

int xi2_device_set_matrix(Display * display, const XID id, const float * matrix) {
	static Atom atoms[2] = {0};
	static char * names[] = {"Coordinate Transformation Matrix", "FLOAT"};

	if (atoms[0] == 0 && atoms[1] == 0) {
		if (!XInternAtoms(display, names, 2, True, atoms)) { // FIXME: test
			return EINTERN_FAILED; // FIXME: error message
		}
	}

	XIChangeProperty(display,
			id,
			atoms[0], // "Coordinate Transformation Matrix"
			atoms[1], // "FLOAT"
			32,
			PropModeReplace,
			(char *)matrix, 9);
	return 0;
}

int xi2_device_check_matrix(Display * display, const XID id, const float * matrix) {
	static Atom atoms[2] = {0};
	static char * names[] = {"Coordinate Transformation Matrix", "FLOAT"};

	if (atoms[0] == 0 && atoms[1] == 0) {
		if (!XInternAtoms(display, names, 2, True, atoms)) { // FIXME: test
			return EINTERN_FAILED; // FIXME: error message
		}
	}

	Atom type_return;
	int format_return;
	unsigned long num_items_return, bytes_after_return;
	unsigned char * data;
	Status result = XIGetProperty(display,
								  id,
								  atoms[0],
								  0, 9 /* Length in 32 bit words */,
								  False,
								  atoms[1],
								  &type_return, &format_return,
								  &num_items_return, &bytes_after_return,
								  &data);

	if (result != Success) {
		return -1; // TODO: select error code
	} else if (format_return != 32 && num_items_return != 9 && bytes_after_return != 0) {
		return -1; // TODO: select error code
	}

	float * retrieved_matrix = (float *)data;

	for (int i = 0; i < 9; i++) {
		if (retrieved_matrix[i] != matrix[i]) {
			return -1; // TODO: select error code
		}
	}

	XFree(data);

	return 0;
}

{'fraction_non_alphanumeric': 0.13596491228070176, 'fraction_numerical': 0.009768740031897927, 'mean_word_length': 3.802776448061273, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 99, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '286033', 'n_tokens_mistral': 3802, 'n_tokens_neox': 3416, 'n_words': 861}