diff options
Diffstat (limited to 'dynamicbox_service/src/util_x11.c')
-rw-r--r-- | dynamicbox_service/src/util_x11.c | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/dynamicbox_service/src/util_x11.c b/dynamicbox_service/src/util_x11.c new file mode 100644 index 0000000..e3efe4d --- /dev/null +++ b/dynamicbox_service/src/util_x11.c @@ -0,0 +1,355 @@ +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <unistd.h> // access +#include <stdlib.h> // free + +#include <X11/X.h> +#include <X11/Xlib.h> + +#include <dlog.h> + +#include <sqlite3.h> +#include <unicode/uloc.h> + +#include "dynamicbox_errno.h" +#include "util.h" +#include "dynamicbox_service.h" +#include "debug.h" + +#define CONF_PATH_FORMAT "/usr/share/data-provider-master/%dx%d/resolution.ini" + +int errno; + +static struct { + unsigned int w; + unsigned int h; + int res_resolved; +} s_info = { + .w = 0, + .h = 0, + .res_resolved = 0, +}; + +static int update_info(struct supported_size_list *SIZE_LIST, int width_type, int height_type, int width, int height) +{ + int idx; + + if (width_type == 1 && height_type == 1) { + idx = 0; + } else if (width_type == 2 && height_type == 1) { + idx = 1; + } else if (width_type == 2 && height_type == 2) { + idx = 2; + } else if (width_type == 4 && height_type == 1) { + idx = 3; + } else if (width_type == 4 && height_type == 2) { + idx = 4; + } else if (width_type == 4 && height_type == 3) { + idx = 5; + } else if (width_type == 4 && height_type == 4) { + idx = 6; + } else if (width_type == 4 && height_type == 5) { + idx = 7; + } else if (width_type == 4 && height_type == 6) { + idx = 8; + } else if (width_type == 21 && height_type == 21) { + idx = 9; + } else if (width_type == 23 && height_type == 21) { + idx = 10; + } else if (width_type == 23 && height_type == 23) { + idx = 11; + } else if (width_type == 0 && height_type == 0) { + idx = 12; + } else { + ErrPrint("Unknown size type: %dx%d (%dx%d)\n", width_type, height_type, width, height); + return 0; + } + + SIZE_LIST[idx].w = width; + SIZE_LIST[idx].h = height; + return 1; +} + +static inline int update_from_file(struct service_info *info, struct supported_size_list *SIZE_LIST) +{ + FILE *fp; + int updated; + int width_type; + int height_type; + int width; + int height; + char buffer[MAX_COLUMN]; + int ch; + int idx; + enum status { + START = 0x0, + TYPE = 0x01, + SIZE = 0x02, + COMMENT = 0x03, + ERROR = 0x04, + EOL = 0x05, + TYPE_END = 0x06, + SIZE_START = 0x07 + } status; + + fp = fopen(info->conf_file, "r"); + if (!fp) { + ErrPrint("Open failed: %s\n", strerror(errno)); + return DBOX_STATUS_ERROR_IO_ERROR; + } + + updated = 0; + status = START; + idx = 0; + do { + ch = fgetc(fp); + + if (idx == MAX_COLUMN) { + ErrPrint("Buffer overflow. Too long line. LINE MUST BE SHOT THAN %d\n", MAX_COLUMN); + status = ERROR; + } + + switch (status) { + case START: + if (isspace(ch) || ch == EOF) { + continue; + } + + info->base_parse = 0; + + if (ch == '#') { + status = COMMENT; + } else { + status = TYPE; + idx = 0; + ungetc(ch, fp); + } + break; + case TYPE: + if (isblank(ch)) { + buffer[idx] = '\0'; + status = TYPE_END; + if (sscanf(buffer, "%dx%d", &width_type, &height_type) != 2) { + if (!strcasecmp(buffer, "base")) { + info->base_parse = 1; + } else { + ErrPrint("Invalid syntax: [%s]\n", buffer); + status = ERROR; + } + } + break; + } else if (ch == '=') { + buffer[idx] = '\0'; + status = SIZE_START; + if (sscanf(buffer, "%dx%d", &width_type, &height_type) != 2) { + if (!strcasecmp(buffer, "base")) { + info->base_parse = 1; + } else { + ErrPrint("Invalid syntax: [%s]\n", buffer); + status = ERROR; + } + } + break; + } else if (ch == EOF) { + ErrPrint("Invalid Syntax\n"); + status = ERROR; + continue; + } + buffer[idx++] = ch; + break; + case TYPE_END: + if (ch == '=') { + status = SIZE_START; + } + break; + case SIZE_START: + if (isspace(ch) || ch == EOF) { + continue; + } + + status = SIZE; + idx = 0; + ungetc(ch, fp); + break; + case SIZE: + if (isspace(ch) || ch == EOF) { + buffer[idx] = '\0'; + status = EOL; + + if (sscanf(buffer, "%dx%d", &width, &height) != 2) { + if (!strncasecmp(buffer, "screen", strlen("screen"))) { + width = s_info.w; + height = s_info.h; + DbgPrint("Select screen size: %dx%d\n", width, height); + } else { + ErrPrint("Invalid syntax: [%s]\n", buffer); + status = ERROR; + } + } + + if (status != ERROR && ch == EOF) { + if (info->base_parse) { + info->base_w = width; + info->base_h = height; + } else { + updated += update_info(SIZE_LIST, width_type, height_type, width, height); + } + } + break; + } + buffer[idx++] = ch; + break; + case EOL: + if (!info->base_parse) { + updated += update_info(SIZE_LIST, width_type, height_type, width, height); + } else { + info->base_w = width; + info->base_h = height; + } + status = START; + ungetc(ch, fp); + break; + case ERROR: + if (ch == '\n' || ch == '\r' || ch == '\f') { + status = START; + } + break; + case COMMENT: + if (ch == '\n' || ch == '\r' || ch == '\f') { + status = START; + } + break; + default: + ErrPrint("Unknown status. couldn't be reach to here\n"); + break; + } + } while (!feof(fp)); + + if (fclose(fp) != 0) { + ErrPrint("fclose: %s\n", strerror(errno)); + } + + return DBOX_NR_OF_SIZE_LIST - updated; +} + +/* + * Find proper configuration and install(link) it to conf path. + */ +static char *conf_path(void) +{ + char *path; + int length; + + length = strlen(CONF_PATH_FORMAT) + 12; // 12 == RESERVED SPACE + path = calloc(1, length); + if (!path) { + ErrPrint("calloc: %s\n", strerror(errno)); + return NULL; + } + + if (s_info.w == 0 || s_info.h == 0) { + /* Try to update resolution first if it is not initialized */ + util_screen_size_get(NULL, NULL); + } + + snprintf(path, length, CONF_PATH_FORMAT, s_info.w, s_info.h); + DbgPrint("Selected conf file: %s\n", path); + if (access(path, F_OK) != 0) { + ErrPrint("Fallback to default, access: %s\n", strerror(errno)); + strncpy(path, RESOLUTION_FILE, length); + if (access(path, F_OK) != 0) { + ErrPrint("Serious error - there is no conf file, use default setting: %s\n", strerror(errno)); + free(path); + path = NULL; + } + } + + return path; +} + +int util_screen_size_get(unsigned int *width, unsigned int *height) +{ + Display *disp; + Window root; + Window dummy; + unsigned int border; + unsigned int depth; + int x; + int y; + int ret; + unsigned int _width; + unsigned int _height; + + if (!width) { + width = &_width; + } + + if (!height) { + height = &_height; + } + + if (s_info.w != 0 && s_info.h != 0) { + DbgPrint("Already prepared (%dx%d)\n", s_info.w, s_info.h); + goto out; + } + + disp = XOpenDisplay(NULL); + if (!disp) { + ErrPrint("Failed to open a display\n"); + return DBOX_STATUS_ERROR_FAULT; + } + + root = XDefaultRootWindow(disp); + ret = XGetGeometry(disp, root, &dummy, &x, &y, &s_info.w, &s_info.h, &border, &depth); + XCloseDisplay(disp); + if (!ret) { + ErrPrint("Failed to get geometry\n"); + return DBOX_STATUS_ERROR_FAULT; + } + +out: + *width = s_info.w; + *height = s_info.h; + return DBOX_STATUS_ERROR_NONE; +} + +int util_update_resolution(struct service_info *info, struct supported_size_list *SIZE_LIST) +{ + if (s_info.res_resolved) { + return DBOX_STATUS_ERROR_NONE; + } + + if (!info->conf_file) { + info->conf_file = conf_path(); + } + + if (info->conf_file) { + register int i; + unsigned int width; + unsigned int height; + + i = util_screen_size_get(&width, &height); + if (i != DBOX_STATUS_ERROR_NONE) { + return i; + } + + if (update_from_file(info, SIZE_LIST) == 0) { + DbgPrint("Resolution info is all updated by file\n"); + } + + if (width != info->base_w) { + for (i = 0; i < DBOX_NR_OF_SIZE_LIST; i++) { + SIZE_LIST[i].w = (unsigned int)((double)SIZE_LIST[i].w * (double)width / (double)info->base_w); + SIZE_LIST[i].h = (unsigned int)((double)SIZE_LIST[i].h * (double)width / (double)info->base_w); + } + } + } else { + DbgPrint("Conf file is not loaded\n"); + } + + s_info.res_resolved = 1; + return DBOX_STATUS_ERROR_NONE; +} + +/* End of a file */ |