#include #include #include #include #include #include #include #include static void draw_needle(cairo_t *cr, double x, double y, double r, double min_angle, double max_angle, double value) { double angle = min_angle + ((max_angle - min_angle) * value) - (M_PI/2); cairo_move_to(cr, x, y); cairo_set_source_rgb(cr, 0, 0.25, 1.0); cairo_line_to(cr, x + r * cos(angle), y + r * sin(angle)); cairo_stroke(cr); } static void draw_face_number(cairo_t *cr, double x, double y, double r, double min_angle, double max_angle, double value, const char *text) { double angle = min_angle + ((max_angle - min_angle) * value) - 1.658; cairo_set_source_rgb(cr, 1, 1, 1); cairo_move_to(cr, x + r * cos(angle), y + r * sin(angle)); cairo_save(cr); cairo_rotate(cr, angle + 1.658); cairo_show_text(cr, text); cairo_restore(cr); } static void draw_tachometer(cairo_t *cr, double x, double y, double r) { int i; cairo_select_font_face(cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(cr, 24); cairo_set_source_rgb(cr, 1, 1, 1); cairo_arc(cr, x, y, r, 0, 2*M_PI); cairo_stroke(cr); /* * Draw face numbers */ for (i=0; i<=80; i+=10) { char text[4]; snprintf(text, 3, "%02d", i); draw_face_number(cr, x, y, 0.85 * r, 232 * (M_PI/180), 488 * (M_PI/180), i / 80.0, text); } /* * Draw a gauge needle */ draw_needle(cr, x, y, 0.77 * r, 232 * (M_PI/180), 488 * (M_PI/180), 0.0); /* * Draw a tiny boi circle */ cairo_set_source_rgb(cr, 1, 1, 1); cairo_arc(cr, x, y, 0.08 * r, 0, 2*M_PI); cairo_fill(cr); } static void draw_speedometer(cairo_t *cr, double x, double y, double r) { cairo_arc(cr, x, y, r, 0, 2*M_PI); cairo_stroke(cr); } static void draw_thermometer(cairo_t *cr, double x, double y, double r) { cairo_arc(cr, x, y, r, 0, 2*M_PI); cairo_stroke(cr); } static void draw_fuel_gauge(cairo_t *cr, double x, double y, double r) { cairo_arc(cr, x, y, r, 0, 2*M_PI); cairo_stroke(cr); } static void draw_mfd(cairo_t *cr, double x, double y, double width, double height) { cairo_set_source_rgb(cr, 0.75, 0, 0); cairo_move_to(cr, x, y); cairo_line_to(cr, x + width, y); cairo_line_to(cr, x + width, y + height); cairo_line_to(cr, x, y + height); cairo_line_to(cr, x, y); cairo_fill(cr); cairo_set_source_rgb(cr, 1, 1, 1); cairo_move_to(cr, x, y); cairo_line_to(cr, x + width, y); cairo_line_to(cr, x + width, y + height); cairo_line_to(cr, x, y + height); cairo_line_to(cr, x, y); cairo_stroke(cr); } static void draw_gauge_cluster(cairo_t *cr, double x, double y, double width, double height) { /* * Paint canvas black */ cairo_set_source_rgb(cr, 0, 0, 0); cairo_paint(cr); draw_tachometer(cr, x + width * 0.2, y + height * 0.5, height * 0.4); draw_speedometer(cr, x + width * 0.8, y + height * 0.5, height * 0.4); draw_thermometer(cr, x + width * 0.43, y + height * 0.76, height * 0.13); draw_fuel_gauge(cr, x + width * 0.57, y + height * 0.76, height * 0.13); draw_mfd(cr, x + width * 0.42, y + height * 0.1, width * 0.16, height * 0.5); } int main(int argc, char **argv) { Display *display; Window win; Pixmap buf; GC gc; int screen, width = 1024, height = 480; XGCValues values = { .foreground = 0x000000, .background = 0xffffff, .graphics_exposures = 0 }; cairo_surface_t *sfc; cairo_t *cr; XEvent e; if ((display = XOpenDisplay(NULL)) == NULL) exit(1); screen = DefaultScreen(display); win = XCreateSimpleWindow(display, DefaultRootWindow(display), 0, 0, width, height, 0, 0, 0); gc = XCreateGC(display, win, GCForeground | GCBackground | GCGraphicsExposures, &values); buf = XCreatePixmap(display, win, width, height, 24); XSelectInput(display, win, ExposureMask | ButtonPressMask | KeyPressMask); XMapWindow(display, win); sfc = cairo_xlib_surface_create(display, buf, DefaultVisual(display, screen), width, height); cairo_xlib_surface_set_size(sfc, width, height); cr = cairo_create(sfc); draw_gauge_cluster(cr, 0, 0, width, height); while (1) { XExposeEvent *expose; XNextEvent(cairo_xlib_surface_get_display(sfc), &e); switch (e.type) { case Expose: expose = (XExposeEvent *)&e; XCopyArea(display, buf, win, gc, expose->x, expose->y, expose->width, expose->height, expose->x, expose->y); break; case ButtonPress: case KeyPress: goto done; default: fprintf(stderr, "Dropping unhandled XEvent.type = %d.\n", e.type); } } done: cairo_destroy(cr); cairo_surface_destroy(sfc); XCloseDisplay(display); return 0; }