summaryrefslogtreecommitdiffstats
path: root/abs/core/LinHES-timezone/linhes_timezone.c
diff options
context:
space:
mode:
Diffstat (limited to 'abs/core/LinHES-timezone/linhes_timezone.c')
-rw-r--r--abs/core/LinHES-timezone/linhes_timezone.c1120
1 files changed, 1120 insertions, 0 deletions
diff --git a/abs/core/LinHES-timezone/linhes_timezone.c b/abs/core/LinHES-timezone/linhes_timezone.c
new file mode 100644
index 0000000..d7a56d2
--- /dev/null
+++ b/abs/core/LinHES-timezone/linhes_timezone.c
@@ -0,0 +1,1120 @@
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#define _GNU_SOURCE
+#include <string.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 aspect_correction = 1;
+
+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 guessing_timezone = FALSE;
+time_t guess_timeout = 0;
+int guess_failed = FALSE;
+time_t guess_failed_timeout = 0;
+int show_information = FALSE;
+int info_displayed = FALSE;
+
+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;
+}
+
+void default_zone (char *arg_zone)
+{
+ int found_zone = FALSE;
+
+ 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);
+ found_zone = TRUE;
+ }
+ }
+ }
+
+ if (!found_zone)
+ {
+ default_zone ("");
+ }
+}
+
+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)) * aspect_correction;
+ p->y = height/2 - radius * cos (atan2 (v3.y,v3.z));
+ }
+ else
+ {
+ p->x = width /2 + lrint (v3.y) * aspect_correction;
+ 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, const 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 * aspect_correction, height / 2 - radius,
+ radius * 2 * aspect_correction, 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);
+
+ if (show_information)
+ {
+ info_displayed = TRUE;
+ char *s[4] = {"Left/Right: Change Offset",
+ "Up/Down: Change Location",
+ "Enter: Select Location",
+ "Esc: Abort"};
+ int num = XtNumber(s);
+ for (int i = 0; i < num; i++)
+ {
+ int text_width = XTextWidth (font, s[i], strlen (s[i]));
+ draw_string (width/2 - text_width/2,
+ height/2 + (-2 + i) * (font->ascent + font->descent),
+ s[i], name_colour.pixel);
+ }
+ }
+ else if (guessing_timezone || (info_displayed = FALSE))
+ {
+ char *s = "Guessing Timezone";
+ int text_width = XTextWidth (font, s, strlen (s));
+ draw_string (width/2 - text_width/2, height/2, s, name_colour.pixel);
+ }
+ else if (guess_failed)
+ {
+ char *s = "Unable to Guess Timezone";
+ char *s2 = "Please Select Timezone Manually";
+ int text_width = XTextWidth (font, s, strlen (s));
+ draw_string (width/2 - text_width/2, height/2, s, name_colour.pixel);
+ text_width = XTextWidth (font, s2, strlen (s2));
+ draw_string (width/2 - text_width/2,
+ height/2 + font->ascent + font->descent,
+ s2, name_colour.pixel);
+ }
+ else
+ {
+ 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) && (!guessing_timezone))
+ {
+ 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, "UTC+88", strlen ("UTC+88"))) +
+ ((width / 2) + radius / sqrt (2))) / 2,
+ ((lrint (height * 0.05) + font->ascent) +
+ (height / 2 - radius / sqrt (2))) / 2,
+ zone_offset, name_colour.pixel);
+ }
+ }
+
+ if (!guessing_timezone && !guess_failed)
+ {
+ const char *title = "Select Your Time Zone";
+ const char *help = "Help = i";
+
+ draw_string (width / 2 - XTextWidth (font, title, strlen (title)) / 2,
+ ((lrint (height * 0.05) + font->ascent) +
+ (height / 2 - radius / sqrt (2))) / 2,
+ title, WhitePixel (display,screen));
+
+ draw_string (width * 0.05, height * 0.95 - font->descent - font->ascent,
+ help, name_colour.pixel);
+ }
+
+ XCopyArea (display, pixmap, window, gc, 0, 0, width, height, 0, 0);
+}
+
+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;
+
+ if (show_information)
+ {
+ show_information = FALSE;
+ return;
+ }
+
+ 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 'I':
+ show_information = !show_information;
+ 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;
+
+ case XK_I:
+ case XK_i:
+ handle_key ('I');
+ 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;
+
+ if (guessing_timezone)
+ {
+ displayed_lon += 1 / 180.0 * M_PI;
+ }
+ else
+ {
+ 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 get_value (FILE *input, char*output, int out_len)
+{
+ const char *value_pattern = "value=\"";
+ char *value;
+
+ output[0] = 0;
+ fgets (output, out_len, input);
+
+ if (value = strcasestr (output, value_pattern))
+ {
+ memmove (output, value + strlen (value_pattern),
+ strlen (value + strlen (value_pattern)) + 1);
+ }
+
+ if (value = strchr (output, '"'))
+ value[0] = 0;
+}
+
+void *timezone_guess (void *unused)
+{
+ const double invalid = 99999;
+ FILE *guess_data;
+ char line_in[1000];
+ double guess_latitude = invalid;
+ double guess_longitude = invalid;
+ char guess_zone[1000] = {0};
+ char *timezone_info_command;
+
+ if (getenv ("FAKE_GEOBYTES"))
+ {
+ timezone_info_command =
+ "sleep 2 ; "
+ "echo Latitude ; "
+ "echo \" <td value=\\\"-34.993\\\"\" ;"
+ "echo Longitude ; "
+ "echo \" <td value=\\\"138.6\\\"\" ;"
+ "echo TimeZone ; "
+ "echo \" <td value=\\\"+09:30\\\"\"";
+ }
+ else
+ {
+ timezone_info_command =
+ "wget http://www.geobytes.com/IpLocator.htm -O - 2> /dev/null |"
+ "grep \"^ <td \" |"
+ "grep -i -E -A1 \"Latitude|Longitude|TimeZone\" | grep -v \"^--$\"";
+ }
+
+ guess_data = popen (timezone_info_command, "r");
+
+ if (!guess_data)
+ {
+ fprintf (stderr, "error parsing web page for timezone guess\n");
+ if (guessing_timezone)
+ {
+ guessing_timezone = FALSE;
+ guess_failed = TRUE;
+ guess_failed_timeout = time (NULL) + 3;
+ }
+ return NULL;
+ }
+
+ while (fgets (line_in, sizeof (line_in), guess_data))
+ {
+ // Look for the entries in the guess data and then the next line
+ // will hold the value.
+
+ if (strcasestr (line_in, "latitude"))
+ {
+ get_value (guess_data, line_in, sizeof (line_in));
+ sscanf (line_in, "%lf", &guess_latitude);
+ }
+ else if (strcasestr (line_in, "longitude"))
+ {
+ get_value (guess_data, line_in, sizeof (line_in));
+ sscanf (line_in, "%lf", &guess_longitude);
+ }
+ else if (strcasestr (line_in, "timezone"))
+ {
+ get_value (guess_data, line_in, sizeof (line_in));
+
+ // The geobytes timezone data is of the form "+09:30" whereas the
+ // map timezone data is of the form "+6" or "+9.5". Convert
+ // to the map timezone data format so we can find the timezone.
+
+ if (strcmp (&line_in[3], ":30") == 0)
+ sprintf (&line_in[3], ".5");
+ else
+ line_in[3] = 0;
+
+ if (line_in[1] == '0')
+ memmove (&line_in[1], &line_in[2], strlen (&line_in[2]) + 1);
+
+ strncpy (guess_zone, line_in, sizeof (guess_zone));
+ }
+ }
+
+ pclose (guess_data);
+
+ if ((guess_latitude != invalid) &&
+ (guess_longitude != invalid) &&
+ guess_zone[0] != 0)
+ {
+ int zone;
+
+ fprintf (stderr, "guessed lat lon %f %f %s\n",
+ guess_latitude, guess_longitude, guess_zone);
+
+ // Look for the guessed zone in the zone_data structure.
+ for (zone = 0; zone < NUM_ZONES; zone++)
+ {
+ if (strcmp (guess_zone, zone_data[zone].offset) == 0)
+ break;
+ }
+
+ if (zone == NUM_ZONES)
+ {
+ fprintf (stderr, "couldnt find zone %s\n", guess_zone);
+ if (guessing_timezone)
+ {
+ guessing_timezone = FALSE;
+ guess_failed = TRUE;
+ guess_failed_timeout = time (NULL) + 3;
+ }
+ }
+ else
+ {
+ double x,y,z;
+ double min_dist_squared;
+ int closest_place;
+
+ // Look for the location in the zone nearest to the guess lat/lon.
+
+ // Convert the guessed lat/lon to x,y,z.
+
+ guess_latitude *= M_PI / 180.0;
+ guess_longitude *= M_PI / 180.0;
+
+ x = cos (guess_longitude) * cos (guess_latitude);
+ y = sin (guess_longitude) * cos (guess_latitude);
+ z = sin (guess_latitude);
+
+ min_dist_squared =
+ pow (x - zone_data[zone].place_info[0].v.x, 2) +
+ pow (y - zone_data[zone].place_info[0].v.y, 2) +
+ pow (z - zone_data[zone].place_info[0].v.z, 2);
+ closest_place = 0;
+
+ for (int place = 1; place < zone_data[zone].num_places; place++)
+ {
+ double dist_squared;
+
+ dist_squared =
+ pow (x - zone_data[zone].place_info[place].v.x, 2) +
+ pow (y - zone_data[zone].place_info[place].v.y, 2) +
+ pow (z - zone_data[zone].place_info[place].v.z, 2);
+
+ if (dist_squared < min_dist_squared)
+ {
+ closest_place = place;
+ min_dist_squared = dist_squared;
+ }
+ }
+
+ fprintf (stderr, "Guess=%s %s\n",
+ zone_data[zone].place_info[closest_place].zonename,
+ zone_data[zone].offset);
+
+ selected_zone = zone;
+ select_place (closest_place);
+ }
+ }
+ else
+ {
+ if (guessing_timezone)
+ {
+ guessing_timezone = FALSE;
+ guess_failed = TRUE;
+ guess_failed_timeout = time (NULL) + 3;
+ }
+ }
+
+ guessing_timezone = FALSE;
+ return 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);
+}
+
+void set_window_position (int x, int y)
+{
+ XSizeHints hints;
+
+ hints.flags = USPosition | PPosition;
+ hints.x = x;
+ hints.y = y;
+
+ XSetWMNormalHints(display, window, &hints);
+}
+
+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);
+
+ if (strcasecmp (arg_zone, "guess") == 0)
+ {
+ guessing_timezone = TRUE;
+ arg_zone[0]=0;
+ }
+
+ 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"
+ "specify a timezone of 'guess' to determine the initial "
+ "timezone from\n"
+ "your ip address using geocache.\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;
+
+ if ((screen_height == 0) ||
+ (XWidthMMOfScreen (DefaultScreenOfDisplay (display)) == 0))
+ aspect_correction = 1;
+ else
+ aspect_correction =
+ sqrt (screen_width *
+ XHeightMMOfScreen (DefaultScreenOfDisplay (display)) * 1.0 /
+ screen_height /
+ XWidthMMOfScreen (DefaultScreenOfDisplay (display)));
+
+ // Protect against very wierd aspect corrections from bogus
+ // screen dimensions.
+ if ((aspect_correction < 0.5) || (aspect_correction > 2))
+ aspect_correction = 1;
+
+ window = XCreateSimpleWindow (display,
+ DefaultRootWindow(display), x, y, width, height, 0,
+ land[0].pixel, ocean.pixel);
+
+ remove_titlebar_and_borders ();
+ set_window_position (x, y);
+
+ 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 the selected timezone (or LA if a timezone was not selected) and
+ // make that the selected zone and place.
+
+ default_zone (arg_zone);
+
+ if (guessing_timezone)
+ {
+ pthread_create (&tid, NULL, timezone_guess, NULL);
+ guess_timeout = time (NULL) + 10;
+ displayed_lat = M_PI/2;
+ displayed_lon = 0;
+ }
+ else
+ {
+ 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 (guessing_timezone && (time (NULL) > guess_timeout))
+ {
+ guessing_timezone = FALSE;
+ guess_failed_timeout = time (NULL) + 3;
+ guess_failed = TRUE;
+ }
+
+ if ((displayed_lat != target_lat) || (displayed_lon != target_lon) ||
+ guessing_timezone || guess_failed ||
+ (info_displayed ^ show_information))
+ {
+ if (guess_failed && (time (NULL) > guess_failed_timeout))
+ {
+ guess_failed = FALSE;
+ }
+
+ 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;
+}