#include /* getenv(), etc. */ #include /* sleep(), etc. */ #include #include #include #include #include #include #include #include #include #include #include /* BitmapOpenFailed, etc. */ #include /* pre-defined crusor shapes */ #include "ev_calibrate.h" #include "config.h" #ifndef CURSORDIRECTORY #define CURSORDIRECTORY "" #endif pthread_mutex_t got_min_max_mtx; pthread_mutex_t min_max_mtx; const int BUF_SIZE = 20; int marker_coordinates[10][2] = { {X_BORDER, Y_BORDER}, {0, Y_BORDER}, {0, Y_BORDER}, {X_BORDER, 0}, {0, 0}, {0, 0}, {X_BORDER, 0}, {0, 0}, {0, 0}, {~0, ~0} }; int click_coordinates[10][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {~0, ~0} }; typedef struct _min_max_t { int min_x; int min_y; int max_x; int max_y; int cur_x; int cur_y; } min_max_t; void xy_reader(void *_min_max) { min_max_t *min_max; int fifo; int x, y; min_max=(min_max_t*)_min_max; /*init min_max*/ min_max->min_x = 20000; min_max->min_y = 20000; min_max->max_x = 0; min_max->max_y = 0; fifo = open ("/tmp/ev_calibrate", O_RDONLY/* |O_NONBLOCK */); if (fifo<=0) { printf("Error opening FIFO \"/tmp/ev_calibrate\"\n"); exit (-1); } /* Do as long as mutex is not locked by main thread ... If mutex is locked by main thread, the min and max values for x and y are fixed and the proram is in the next phase. --> xy-reader-thread can exit. */ while (pthread_mutex_trylock(&got_min_max_mtx) != EBUSY) { pthread_mutex_unlock(&got_min_max_mtx); if ( (read (fifo, &x, sizeof(x))>0) && (read (fifo, &y, sizeof(y))>0) ) { /* flush(fifo); */ pthread_mutex_lock(&min_max_mtx); if (min_max->min_x > x) min_max->min_x = x; if (min_max->min_y > y) min_max->min_y = y; if (min_max->max_x < x) min_max->max_x = x; if (min_max->max_y < y) min_max->max_y = y; min_max->cur_x=x; min_max->cur_y=y; pthread_mutex_unlock(&min_max_mtx); } } close(fifo); } void init_marker_coordinates(int screen_width, int screen_height) { marker_coordinates[1][0] = screen_width/2; marker_coordinates[2][0] = screen_width-X_BORDER; marker_coordinates[3][1] = screen_height/2; marker_coordinates[4][0] = screen_width/2; marker_coordinates[4][1] = screen_height/2; marker_coordinates[5][0] = screen_width-X_BORDER; marker_coordinates[5][1] = screen_height/2; marker_coordinates[6][1] = screen_height-Y_BORDER; marker_coordinates[7][0] = screen_width/2; marker_coordinates[7][1] = screen_height-Y_BORDER; marker_coordinates[8][0] = screen_width-X_BORDER; marker_coordinates[8][1] = screen_height-Y_BORDER; } void draw_cross(Display *disp, Window win, GC gc, int x, int y) { XDrawLine(disp, win, gc, x-5, y-5, x+5, y+5); XDrawLine(disp, win, gc, x-5, y+5, x+5, y-5); XFlush(disp); } void draw_markers(Display *disp, Window win, GC gc, int screen_width, int screen_height) { int i = 0; for (i=0; ( (marker_coordinates[i][0] != ~0) && (marker_coordinates[i][1] != ~0) ); i++) { draw_cross(disp, win, gc, marker_coordinates[i][0], marker_coordinates[i][1]); } XFlush(disp); } void refresh_screen(Display* display, Screen* screen, Window win, GC gc, GC red_gc, int screen_width, int screen_height, int cross_no) { draw_markers(display, win, gc, screen_width, screen_height); XFlush(display); draw_cross(display, win, red_gc, marker_coordinates[cross_no][0], marker_coordinates[cross_no][1]); XFlush(display); } int main (void) { Time lb_down_time; pthread_t xy_reader_thread; /* Thread-Attributes NULL means default */ pthread_attr_t attr; pthread_mutexattr_t *p_mtx_attr = NULL; min_max_t min_max; int xy_ring_buf[BUF_SIZE][2]; FILE* out_file; Display* display; Screen* screen; Window win; GC gc, red_gc; XEvent event; Colormap cmap; XColor active_col, exact_col; Cursor cursor; Pixmap cursor_pic; XColor cursor_fg, cursor_bg; XFontStruct* font_info; char* font_name = "*freemono*"; char str[256]; unsigned int cursor_width, cursor_height; int hotspot_x, hotspot_y; int string_width, font_height; int rc; int i, ring_buf_pos; int finished = 0; int got_min_max = 0; XGCValues values; unsigned long valuemask = 0; unsigned int line_width = 2; /* line width for the GC. */ int line_style = LineSolid; /* style for lines drawing and */ int cap_style = CapButt; /* style of the line's edje and */ int join_style = JoinBevel; /* joined lines. */ int event_mask = ExposureMask | ButtonReleaseMask | PointerMotionMask | KeyPressMask; int depth; int screen_num; int screen_width; int screen_height; Window root_window; /* these variables will be used to store the IDs of the black and white colors of the given screen. More on this will be explained later. */ unsigned long white_pixel; unsigned long black_pixel; display = XOpenDisplay(getenv("DISPLAY")); if (display == NULL) { fprintf(stderr, "Cannot connect to X server %s\n", ":0"); exit(-1); } /* check the number of the default screen for our X server. */ screen_num = DefaultScreen(display); /* find the width of the default screen of our X server, in pixels. */ screen_width = DisplayWidth(display, screen_num); /* find the height of the default screen of our X server, in pixels. */ screen_height = DisplayHeight(display, screen_num); /* find the ID of the root window of the screen. */ root_window = RootWindow(display, screen_num); /* find the value of a white pixel on this screen. */ white_pixel = WhitePixel(display, screen_num); /* find the value of a black pixel on this screen. */ black_pixel = BlackPixel(display, screen_num); init_marker_coordinates(screen_width, screen_height); win = XCreateSimpleWindow(display, RootWindow(display, screen_num), 0, 0, screen_width, screen_height, 2, BlackPixel(display, screen_num), WhitePixel(display, screen_num)); /*XQueryTree(display, win, &root_win, &parent_win, &child_windows, &num_child_windows); XFree(child_windows);*/ screen = DefaultScreenOfDisplay(display); cmap = DefaultColormapOfScreen(screen); depth = XDefaultDepth(display, screen_num); font_info = XLoadQueryFont(display, font_name); if (!font_info) { fprintf(stderr, "XLoadQueryFont: failed loading font '%s'\n", font_name); exit (-1); } rc = XReadBitmapFile(display, win, CURSORDIRECTORY"/empty_cursor.xbm", &cursor_width, &cursor_height, &cursor_pic, &hotspot_x, &hotspot_y); /* check for failure or success. */ switch (rc) { case BitmapOpenFailed: fprintf(stderr, "XReadBitmapFile - could not open file '%s/empty_cursor.xbm'.\n", CURSORDIRECTORY); break; case BitmapFileInvalid: fprintf(stderr, "XReadBitmapFile - file '%s' doesn't contain a valid bitmap.\n", "empty_cursor.xbm"); break; case BitmapNoMemory: fprintf(stderr, "XReadBitmapFile - not enough memory.\n"); break; } /* allocate black and white colors. */ rc = XAllocNamedColor(display, cmap, "black", &cursor_fg, &cursor_fg); if (rc == 0) { fprintf(stderr, "XAllocNamedColor - canot allocate 'black' ?!?\n"); exit(1); } rc = XAllocNamedColor(display, cmap, "white", &cursor_bg, &cursor_bg); if (rc == 0) { fprintf(stderr, "XAllocNamedColor - canot allocate 'white' ?!?\n"); exit(1); } cursor = XCreatePixmapCursor(display, cursor_pic, cursor_pic, &cursor_bg, &cursor_fg, 0, 0); XDefineCursor(display, win, cursor); XSync(display, False); XMapWindow(display, win); /* flush all pending requests to the X server, and wait until */ /* they are processed by the X server. */ XSync(display, False); /* these variables are used to specify various attributes for the GC. initial values for the GC. */ /*values = CapButt;*/ /* which values in 'values' to check when creating the GC. */ /*valuemask= GCCapStyle | GCJoinStyle;*/ rc = XAllocNamedColor(display, cmap, "red", &active_col, &exact_col); /* create a new graphical context. (for the black crosses)*/ gc = XCreateGC(display, win, valuemask, &values); if (gc < 0) { fprintf(stderr, "XCreateGC: \n"); } /* Assign font to GC */ XSetFont(display, gc, font_info->fid); /* change the foreground color of this GC to white. */ XSetForeground(display, gc, BlackPixel(display, screen_num)); /* change the background color of this GC to black. */ XSetBackground(display, gc, WhitePixel(display, screen_num)); /* define the style of lines that will be drawn using this GC. */ XSetLineAttributes(display, gc, line_width, line_style, cap_style, join_style); /* define the fill style for the GC. to be 'solid filling'. */ XSetFillStyle(display, gc, FillSolid); /* define graphical context for red crosses */ red_gc = XCreateGC(display, win, valuemask, &values); XSetForeground(display, red_gc, active_col.pixel); XSetBackground(display, red_gc, active_col.pixel); XSetLineAttributes(display, gc, line_width, line_style, cap_style, join_style); XSetFillStyle(display, gc, FillSolid); draw_markers(display, win, gc, screen_width, screen_height); i = 0; XFlush(display); XSelectInput(display, win, event_mask); string_width = 0; font_height = font_info->ascent + font_info->descent; /* Start own own thread to read x and y coordinates for determining min and max. */ pthread_mutex_init(&got_min_max_mtx, NULL); pthread_mutex_init(&min_max_mtx, NULL); pthread_attr_init(&attr); pthread_create(&xy_reader_thread, &attr, (void *)xy_reader, &min_max); ring_buf_pos=0; while (!finished) { XNextEvent(display, &event); switch (event.type) { case MotionNotify: if (got_min_max==0) { XSetForeground( display, gc, WhitePixel(display, screen_num) ); XFillRectangle( display, win, gc, 90, 90, string_width+50, font_height+90 ); /*XFlush(display);*/ XSetForeground(display, gc, BlackPixel(display, screen_num)); if (got_min_max==0) usleep(20000); pthread_mutex_lock(&min_max_mtx); sprintf(str, "Min: (%u/%u) Max: (%u/%u)", min_max.min_x, min_max.min_y, min_max.max_x, min_max.max_y); string_width = XTextWidth(font_info, str, strlen(str)); XDrawString(display, win, gc, 100, 100, str, strlen(str)); sprintf(str, "min_max.cur_x: %d, min_max.cur_y: %d", min_max.cur_x, min_max.cur_y); string_width = XTextWidth(font_info, str, strlen(str)); XDrawString(display, win, gc, 100, 120, str, strlen(str)); pthread_mutex_unlock(&min_max_mtx); XFlush(display); } break; case Expose: /* if we have several other expose events waiting, don't redraw. */ /* we will do the redrawing when we receive the last of them. */ if (event.xexpose.count > 1) break; draw_markers(display, win, gc, screen_width, screen_height); if (got_min_max==1) { draw_cross(display, win, red_gc, marker_coordinates[i][0], marker_coordinates[i][1]); } XFlush(display); break; case ButtonPress: if (event.xbutton.button == 1) { lb_down_time = event.xbutton.time; } break; case ButtonRelease: /* Save RAW coordinates of Button-Release */ if (event.xbutton.button == 1) { if ( (got_min_max == 1) ) { pthread_mutex_lock(&min_max_mtx); click_coordinates[i][0]=min_max.cur_x; click_coordinates[i][1]=min_max.cur_y; pthread_mutex_unlock(&min_max_mtx); i++; refresh_screen(display, screen, win, gc, red_gc, screen_width, screen_height, i); if (i==9) finished = 1; } lb_down_time=0; } if (event.xbutton.button==3) { if (i==0) got_min_max=0; if (i>0) i--; refresh_screen(display, screen, win, gc, red_gc, screen_width, screen_height, i); } break; case KeyPress: win = event.xkey.window; { /* translate the key code to a key symbol. */ KeySym key_symbol = XKeycodeToKeysym(display, event.xkey.keycode, 0); switch (key_symbol) { case XK_Return: /* set got_min_max to 1 --> getting min/max-coordinate values is finished */ got_min_max = 1; refresh_screen(display, screen, win, gc, red_gc, screen_width, screen_height, i); break; case XK_BackSpace: pthread_mutex_lock(&min_max_mtx); xy_ring_buf[ring_buf_pos][0] = min_max.cur_x; xy_ring_buf[ring_buf_pos][1] = min_max.cur_y; ring_buf_pos = (ring_buf_pos+1) % BUF_SIZE; pthread_mutex_unlock(&min_max_mtx); break; default: break; } } break; default: /* unknown/unhandled event type - ignore it. */ break; } } XCloseDisplay(display); pthread_mutex_lock(&got_min_max_mtx); /* Put results to file and screen */ out_file = fopen("/etc/evtouch/config", "w"); /* TODO: Error Handling !!! */ printf("min = (%d/%d) max =(%d/%d)\n\n", min_max.min_x, min_max.min_y, min_max.max_x, min_max.max_y); fprintf(out_file, "MINX=\"%d\"\n", min_max.min_x); fprintf(out_file, "MINY=\"%d\"\n", min_max.min_y); fprintf(out_file, "MAXX=\"%d\"\n", min_max.max_x); fprintf(out_file, "MAXY=\"%d\"\n", min_max.max_y); for (i=0; i<9; i++) { /* lbtouch.c does it this way: v0 = ( ((float)v0/max_x)*priv->screen_width ) + dx; v1 = ( priv->screen_height - ((float)v1/max_y)*priv->screen_height ) + dy; */ click_coordinates[i][0]=click_coordinates[i][0]-min_max.min_x; click_coordinates[i][1]=click_coordinates[i][1]-min_max.min_y; /* Scale Axis like it is done in the driver */ click_coordinates[i][0] = ( ((float) click_coordinates[i][0] / (min_max.max_x-min_max.min_x)) * screen_width ); click_coordinates[i][1] = ( ((float) click_coordinates[i][1] / (min_max.max_y-min_max.min_y)) * screen_height ); printf("(X%d/Y%d) = (%d, %d)\t\t\n", i, i, click_coordinates[i][0], click_coordinates[i][1]); printf("=> dx%d = %d / dy%d = %d\n", i, marker_coordinates[i][0]-click_coordinates[i][0], i, marker_coordinates[i][1]-click_coordinates[i][1]); fprintf(out_file, "X%d=\"%d\"\nY%d=\"%d\"\n", i, marker_coordinates[i][0]-click_coordinates[i][0], i, marker_coordinates[i][1]-click_coordinates[i][1]); } for (i=0; i