diff options
Diffstat (limited to 'abs/core-testing/LinHES-timezone/linhes_timezone.c')
-rw-r--r-- | abs/core-testing/LinHES-timezone/linhes_timezone.c | 779 |
1 files changed, 779 insertions, 0 deletions
diff --git a/abs/core-testing/LinHES-timezone/linhes_timezone.c b/abs/core-testing/LinHES-timezone/linhes_timezone.c new file mode 100644 index 0000000..024560f --- /dev/null +++ b/abs/core-testing/LinHES-timezone/linhes_timezone.c @@ -0,0 +1,779 @@ +#include <stdio.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <strings.h> +#include <X11/Xlib.h> +#include <X11/Intrinsic.h> +#include <X11/IntrinsicI.h> +#include <lirc/lirc_client.h> +#include <pthread.h> + +#include "timezone_map.h" + +Display *display; +Window window; +GC gc; +int screen; +int selected_zone; +int selected_place; +Pixmap pixmap; +XColor ocean; +XColor land[8]; +XColor border; +XColor selected_border; +XColor selected_land; +XColor name_colour; +XColor location_dot; +XColor lat_lon; +XColor tux_yellow; +Dimension screen_width = 1920; +Dimension screen_height = 1080; +Dimension width = 1920; +Dimension height = 1080; +Position x = 0; +Position y = 0; +XFontStruct *font; +XPoint xpoints[1000]; +int radius; + +double target_lat; +double target_lon; + +double displayed_lat; +double displayed_lon; + +double lon_rotate[2] = {1, 0}; +double lat_rotate[2] = {1, 0}; + +double acceleration = 0.01; +char input_keys[200]; + +int translate_point (vect_type *v, XPoint *p) +{ + vect_type v2; + vect_type v3; + + v2.x = v->x * lon_rotate[0] + v->y * lon_rotate[1]; + v2.y = v->x * -1.0 * lon_rotate[1] + v->y * lon_rotate[0]; + v2.z = v->z; + + v3.x = v2.x * lat_rotate[0] + v2.z * lat_rotate[1]; + v3.y = v2.y * radius; + v3.z = v2.x * -1.0 * lat_rotate[1] + v2.z * lat_rotate[0]; + + + // If the point is behind the face of the globe, project it to the edge. + if (v3.x < 0) + { + p->x = width /2 + radius * sin (atan2 (v3.y,v3.z)); + p->y = height/2 - radius * cos (atan2 (v3.y,v3.z)); + } + else + { + p->x = width /2 + lrint (v3.y); + p->y = height/2 - lrint (v3.z); + } + + // Return a value indicating if it is on the front of the world. + return (v3.x >= 0); +} + +void draw_zone ( + Drawable d, + int zone, + int fill, + int selected) +{ + int boundary = 0; + int num_points = 0; + int all_on_back = 1; + + if (selected && fill) + XSetForeground (display, gc, selected_land.pixel); + + while (boundary < zone_data[zone].num_boundary_points) + { + if (zone_data[zone].boundary_points[boundary].x < -9) + { + + if ((num_points > 1) && !all_on_back) + { + if (fill) + { + if (!selected) + { + if (zone == NUM_ZONES - 1) + { + if (boundary < 380) + XSetForeground (display, gc, WhitePixel (display, screen)); + else if (boundary < 470) + XSetForeground (display, gc, tux_yellow.pixel); + else if (boundary < 1120) + XSetForeground (display, gc, BlackPixel (display, screen)); + else + XSetForeground (display, gc, WhitePixel (display, screen)); + } + else + { + XSetForeground (display, gc, + land[boundary % XtNumber (land)].pixel); + } + } + + XFillPolygon ( + display, d, gc, + xpoints, + num_points, Complex, CoordModeOrigin); + } + else + XDrawLines ( + display, d, gc, + xpoints, + num_points, CoordModeOrigin); + } + + boundary++; + num_points = 0; + all_on_back = 1; + } + else + { + if (translate_point (&zone_data[zone].boundary_points[boundary], + &xpoints[num_points])) + all_on_back = 0; + + num_points++; + boundary++; + } + } +} + +void draw_string (int x, int y, char*s, unsigned long colour) +{ + XSetForeground (display, gc, BlackPixel (display, screen)); + for (int x_pos = x - 3; x_pos <= x + 3; x_pos++) + for (int y_pos = y - 3; y_pos <= y + 3; y_pos++) + XDrawString (display, pixmap, gc, x_pos, y_pos, s, strlen (s)); + + XSetForeground (display, gc, colour); + XDrawString (display, pixmap, gc, x, y, s, strlen (s)); +} + +void draw_point (XPoint p, char *s) +{ + int text_width; + + int dot_size = ceil (sqrt (height) / 6.0); + + if (s) + dot_size += 2; + + XSetForeground (display, gc, + s ? WhitePixel (display, screen) : location_dot.pixel); + XFillRectangle (display, pixmap, gc, + p.x - dot_size / 2, p.y - dot_size / 2, dot_size, dot_size); + + XSetForeground (display, gc, BlackPixel (display, screen)); + XSetLineAttributes (display, gc, 2, LineSolid, CapRound, JoinRound); + XDrawRectangle (display, pixmap, gc, + p.x - dot_size / 2, p.y - dot_size / 2, dot_size, dot_size); + + if (s) + { + int text_x; + int text_y; + + text_width = XTextWidth (font, s, strlen (s)); + + if (p.x + text_width + 30 > width) + { + text_x = p.x - text_width - 6; + text_y = p.y + 10; + } + else + { + text_x = p.x + 6; + text_y = p.y + 10; + } + + draw_string (text_x, text_y, s, name_colour.pixel); + } +} + +void redraw_map () +{ + XPoint selected_point; + char selected_name[100]; + + lon_rotate[0] = cos (displayed_lon); + lon_rotate[1] = sin (displayed_lon); + + lat_rotate[1] = cos (displayed_lat) * radius; + lat_rotate[0] = sin (displayed_lat) * radius; + + /* Draw the map into the pixmap. */ + + XSetForeground (display, gc, BlackPixel (display, screen)); + XFillRectangle (display, pixmap, gc, 0, 0, width, height); + + XSetForeground (display, gc, ocean.pixel); + XFillArc (display, pixmap, gc, + width / 2 - radius, height / 2 - radius, + radius * 2, radius * 2, 0, 360 * 64); + + XSetForeground (display, gc, lat_lon.pixel); + XSetLineAttributes (display, gc, 2, LineSolid, CapRound, JoinRound); + + for (int lon = 0; lon < 24; lon++) + for (int lat = 0; lat < 12 * 3; lat++) + { + XPoint line[2]; + vect_type v; + v.x = cos (lon * 15 * M_PI / 180) * cos ((90 - lat * 5) * M_PI / 180); + v.y = sin (lon * 15 * M_PI / 180) * cos ((90 - lat * 5) * M_PI / 180); + v.z = sin ((90 - lat * 5) / 180.0 * M_PI); + line[0] = line[1]; + if (translate_point (&v, &line[1]) && (lat > 0)) + XDrawLines (display, pixmap, gc, line, 2, CoordModeOrigin); + } + + for (int lat = 0; lat < 12; lat++) + for (int lon = 0; lon <= 24 * 3; lon++) + { + XPoint line[2]; + vect_type v; + v.x = cos (lon * 5 * M_PI / 180) * cos ((90 - lat * 15) * M_PI / 180); + v.y = sin (lon * 5 * M_PI / 180) * cos ((90 - lat * 15) * M_PI / 180); + v.z = sin ((90 - lat * 15) / 180.0 * M_PI); + line[0] = line[1]; + if (translate_point (&v, &line[1]) && (lon > 0)) + XDrawLines (display, pixmap, gc, line, 2, CoordModeOrigin); + } + + for (int zone = 0; zone < NUM_ZONES; zone++) + draw_zone (pixmap, zone, 1, 0); + + XSetLineAttributes (display, gc, 2, LineSolid, CapRound, JoinRound); + XSetForeground (display, gc, border.pixel); + for (int zone = 0; zone < NUM_ZONES - 1; zone++) + draw_zone (pixmap, zone, 0, 0); + + draw_zone (pixmap, selected_zone, 1, 1); + XSetForeground (display, gc, selected_border.pixel); + draw_zone (pixmap, selected_zone, 0, 1); + + for (int place = 0; place < zone_data[selected_zone].num_places; place++) + { + XPoint point; + + translate_point (&zone_data[selected_zone].place_info[place].v, &point); + + draw_point (point, NULL); + + if (place == selected_place) + { + char *underscore; + selected_point = point; + strcpy (selected_name, strchr (zone_data[selected_zone].place_info[place].zonename, '/') + 1); + while (underscore = strchr (selected_name, '_')) + underscore[0] = ' '; + } + } + + draw_point (selected_point, selected_name); + + { + char zone_offset[100]; + sprintf (zone_offset, "UTC%s", zone_data[selected_zone].offset); + draw_string ( + ((width * 0.95 - XTextWidth (font, zone_offset, strlen (zone_offset))) + + ((width / 2) + radius / sqrt (2))) / 2, + ((lrint (height * 0.05) + font->ascent) + + (height / 2 - radius / sqrt (2))) / 2, + zone_offset, name_colour.pixel); + } + + XCopyArea (display, pixmap, window, gc, 0, 0, width, height, 0, 0); +} + +void select_place (int place) +{ + target_lon = atan2 (zone_data[selected_zone].place_info[place].v.y, + zone_data[selected_zone].place_info[place].v.x); + target_lat = acos (zone_data[selected_zone].place_info[place].v.z /2); + + selected_place = place; +} + +int nearest_z (double near_z) +{ + double min_delta = + fabs (near_z - zone_data[selected_zone].place_info[0].v.z); + int min_delta_place = 0; + + for (int place = 1; place < zone_data[selected_zone].num_places; place++) + { + double delta = + fabs (near_z - zone_data[selected_zone].place_info[place].v.z); + + if (delta < min_delta) + { + min_delta_place = place; + min_delta = delta; + } + } + + return min_delta_place; +} + +void handle_key (char key) +{ + double selected_z; + + selected_z = zone_data[selected_zone].place_info[selected_place].v.z; + + switch (key) + { + case 'U': + select_place ((selected_place + + zone_data[selected_zone].num_places - 1) % + zone_data[selected_zone].num_places); + break; + + case 'D': + select_place ((selected_place + 1) % + zone_data[selected_zone].num_places); + break; + + case 'L': + selected_zone = (selected_zone + NUM_ZONES - 1) % NUM_ZONES; + select_place (nearest_z (selected_z)); + break; + + case 'R': + selected_zone = (selected_zone + 1) % NUM_ZONES; + select_place (nearest_z (selected_z)); + break; + + case 'X': + printf ("%s\n", zone_data[selected_zone].place_info[selected_place].zonename); + exit (0); + + case 'E': + exit(1); + } +} + +void handle_event (XEvent *xevent) +{ + switch (xevent->type) + { + case Expose: + redraw_map (); + break; + + case KeyPress: + switch (XLookupKeysym (&xevent->xkey, 0)) + { + case XK_Up: + handle_key ('U'); + break; + + case XK_Down: + handle_key ('D'); + break; + + case XK_Left: + handle_key ('L'); + break; + + case XK_Right: + handle_key ('R'); + break; + + case XK_Return: + handle_key ('X'); + break; + + case XK_Escape: + handle_key('E'); + break; + } + + break; + } +} + +Bool event_predicate (Display *display, XEvent *xevent, XPointer unused) +{ + return (xevent->type == KeyPress) || (xevent->type == Expose); +} + +void next_view () +{ + static double step_size = 0.01; + double error_total; + double lat_error = target_lat - displayed_lat; + double lon_error = target_lon - displayed_lon; + + lat_error = atan2 (sin (lat_error), cos( lat_error)); + lon_error = atan2 (sin (lon_error), cos (lon_error)); + + error_total = sqrt (lat_error * lat_error + lon_error * lon_error); + + if (error_total < acceleration) + { + displayed_lat = target_lat; + displayed_lon = target_lon; + } + else + { + if (error_total > (step_size + acceleration) * + (step_size + acceleration) / acceleration / 2) + step_size += acceleration; + else + step_size -= acceleration; + + if (step_size < acceleration) + step_size = acceleration; + + displayed_lat += step_size * (lat_error / error_total); + displayed_lon += step_size * (lon_error / error_total); + } + +} + +void *lirc_thread (void *unused) +{ + int lirc_fd; + struct lirc_config *lirc_config; + char *lirc_code; + + if ((lirc_fd = lirc_init ("mythtv",0)) == -1) + fprintf (stderr,"Error initialising lirc\n"); + else + { + int readc_status; + + if (readc_status = lirc_readconfig (NULL, &lirc_config, NULL)) + { + fprintf (stderr,"Error loading lirc config file %d %p\n", readc_status, lirc_config); + } + } + + while ((lirc_nextcode (&lirc_code) == 0) && (lirc_code != NULL)) + { + char *action; + + while ((lirc_code2char (lirc_config, lirc_code, &action) == 0) && + (action != NULL)) + { + if (strcasecmp (action, "down") == 0) + strcat (input_keys, "D"); + + if (strcasecmp (action, "up") == 0) + strcat (input_keys, "U"); + + if (strcasecmp (action, "left") == 0) + strcat (input_keys, "L"); + + if (strcasecmp (action, "right") == 0) + strcat (input_keys, "R"); + + if (strcasecmp (action, "return") == 0) + strcat (input_keys, "X"); + + if (strcasecmp (action, "Esc") == 0) + strcat (input_keys, "E"); + } + + free (lirc_code); + lirc_code = NULL; + } +} + +void remove_titlebar_and_borders () +{ + XClassHint* classHint; + char* appname; + appname="look fo rme"; + XStoreName (display, window, appname); + + /* Set the name and class hints for the window manager to use. */ + + classHint = XAllocClassHint (); + if (classHint) + { + classHint->res_name = appname; + classHint->res_class = "MoonRoot"; + } + + XSetClassHint (display, window, classHint); + XFree (classHint); + + typedef struct + { + CARD32 flags; + CARD32 functions; + CARD32 decorations; + INT32 input_mode; + CARD32 status; + } MotifWmHints, MwmHints; + + #define MWM_HINTS_DECORATIONS (1L << 1) + + + Atom XA_MOTIF_WM_HINTS = XInternAtom (display, "_MOTIF_WM_HINTS", False); + MotifWmHints mwm_hints; + + mwm_hints.flags = MWM_HINTS_DECORATIONS; + mwm_hints.decorations = 0; + + XChangeProperty ( + display, window, + XA_MOTIF_WM_HINTS, XA_MOTIF_WM_HINTS, + 32, PropModeReplace, + (char *) &mwm_hints, 5); +} + +int main (int argc, char *argv[]) +{ + XEvent xevent; + Colormap cmap; + XColor color, colorrgb; + pthread_t tid; + int opt; + int arg_width = -1; + int arg_height = -1; + char arg_zone[100] = {0}; + + if (getenv ("ACCEL")) + acceleration = atof (getenv ("ACCEL")); + + while ((opt = getopt (argc, argv, "z:w:h:a:")) != -1) + { + switch (opt) + { + case 'z': + strncpy (arg_zone, optarg, sizeof (arg_zone) - 1); + break; + + case 'w': + arg_width = atoi (optarg); + break; + + case 'h': + arg_height = atoi (optarg); + break; + + case 'a': + acceleration = atof (optarg); + break; + + case '?': + printf ("usage: %s [-a accelleration] [-z timezone] " + "[-w width] [-h height]\n" + "e.g. linhes_timezone -w 1920 -h 1090 -z Australia/Adelaide\n", + argv[0]); + exit (0); + break; + } + } + + + pthread_create (&tid, NULL, lirc_thread, NULL); + + /* Connect to the X server. */ + + display = XOpenDisplay (""); + + if (display == NULL) + { + fprintf (stderr, "cannot connect to server\n"); + exit (EXIT_FAILURE); + } + + /* Get default screen. */ + + screen = DefaultScreen (display); + screen_width = XWidthOfScreen (DefaultScreenOfDisplay (display)); + screen_height = XHeightOfScreen (DefaultScreenOfDisplay (display)); + + if ((arg_width <= 0) && (arg_height > 0)) + arg_width == arg_height; + + if (arg_width > 0) + { + width = arg_width; + + if (arg_height <= 0) + height = width; + else + height = arg_height; + + x = (screen_width - width) / 2; + y = (screen_height - height) / 2; + } + else + { + width = screen_width; + height = screen_height; + x = 0; + y = 0; + } + + if (width < height) + radius = width; + else + radius = height; + + radius = 0.96 * radius / 2; + + window = XCreateSimpleWindow (display, + DefaultRootWindow(display), x, y, width, height, 0, + land[0].pixel, ocean.pixel); + + remove_titlebar_and_borders (); + + + if (!window) + { + fprintf (stderr, "cannot open window\n"); + exit (EXIT_FAILURE); + } + + /* set graphics context of rectangle to red */ + gc= XCreateGC (display, window, 0, 0); + cmap = DefaultColormap (display, screen); + + // Load the font. + + font = XLoadQueryFont (display, (width > 800) ? "-*-lucida-bold-r-*-*-34-*-*-*-*-*-*-*" : + "-*-lucida-bold-r-*-*-20-*-*-*-*-*-*-*"); + if (!font) + fprintf (stderr,"error loading font\n"); + + XSetFont (display, gc, font->fid); + + pixmap = + XCreatePixmap (display, window, width, height, + DefaultDepth (display, DefaultScreen (display))); + + ocean.flags = DoRed | DoGreen | DoBlue; + ocean.red = 40 * 256; + ocean.green = 41 * 256; + ocean.blue = 72 * 256; + if (XAllocColor (display, cmap, &ocean) == 0) + printf ("Cant allocate color\n"); + + lat_lon.flags = DoRed | DoGreen | DoBlue; + lat_lon.red = 0 * 256; + lat_lon.green = 0 * 256; + lat_lon.blue = 86 * 256; + if (XAllocColor (display, cmap, &lat_lon) == 0) + printf ("Cant allocate color\n"); + + tux_yellow.flags = DoRed | DoGreen | DoBlue; + tux_yellow.red = 248 * 256; + tux_yellow.green = 191 * 256; + tux_yellow.blue = 17 * 256; + if (XAllocColor (display, cmap, &tux_yellow) == 0) + printf ("Cant allocate color\n"); + + for (int land_col = 0; land_col < XtNumber (land); land_col++) + { + land[land_col].flags = DoRed | DoGreen | DoBlue; + land[land_col].red = (120 + 9 * land_col) * 256; + land[land_col].green = (40 + 3 * land_col) * 256; + land[land_col].blue = 0 * 256; + if (XAllocColor (display, cmap, &land[land_col]) == 0) + printf ("Cant allocate color\n"); + } + + selected_land.flags = DoRed | DoGreen | DoBlue; + selected_land.red = 3 * 256; + selected_land.green = 40 * 256; + selected_land.blue = 13 * 256; + if (XAllocColor (display, cmap, &selected_land) == 0) + printf ("Cant allocate color\n"); + + border.flags = DoRed | DoGreen | DoBlue; + border.red = 0 * 256; + border.green = 0 * 256; + border.blue = 0 * 256; + if (XAllocColor (display, cmap, &border) == 0) + printf ("Cant allocate color\n"); + + selected_border.flags = DoRed | DoGreen | DoBlue; + selected_border.red = 80 * 256; + selected_border.green = 255 * 256; + selected_border.blue = 80 * 256; + if (XAllocColor (display, cmap, &selected_border) == 0) + printf ("Cant allocate color\n"); + + name_colour.flags = DoRed | DoGreen | DoBlue; + name_colour.red = 255 * 256; + name_colour.green = 255 * 256; + name_colour.blue = 0 * 256; + if (XAllocColor (display, cmap, &name_colour) == 0) + printf ("Cant allocate color\n"); + + location_dot.flags = DoRed | DoGreen | DoBlue; + location_dot.red = 255 * 256; + location_dot.green = 55 * 256; + location_dot.blue = 200 * 256; + if (XAllocColor (display, cmap, &location_dot) == 0) + printf ("Cant allocate color\n"); + + // Find LA and make that the selected zone and place. + + for (int zone = 0; zone < NUM_ZONES; zone++) + { + for (int place = 0; place < zone_data[zone].num_places; place++) + { + if (strstr (zone_data[zone].place_info[place].zonename, + arg_zone[0] ? arg_zone : "Los_Angeles")) + { + selected_zone = zone; + select_place (place); + displayed_lat = target_lat; + displayed_lon = target_lon; + } + } + } + + /* ask for exposure event and keyboard events */ + XSelectInput(display, window, KeymapNotify | ExposureMask); + + /* pop this window up on the screen */ + XMapRaised (display, window); + + redraw_map (); + + while (1) + { + if ((displayed_lat != target_lat) || (displayed_lon != target_lon)) + { + next_view (); + redraw_map (); + } + else + { + usleep (1000); + } + + while (strlen (input_keys)) + { + handle_key (input_keys[0]); + memmove (&input_keys[0], &input_keys[1], strlen (input_keys)); + } + + // If there is an event pending, go on to process it. + + if (XCheckIfEvent (display, &xevent, event_predicate, NULL)) + handle_event (&xevent); + } + + return 0; +} |