summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gnome-map/Makefile11
-rw-r--r--gnome-map/gglobe-canvas.c786
-rw-r--r--gnome-map/gnome-canvas-dot.c434
-rw-r--r--gnome-map/gnome-canvas-dot.h60
-rw-r--r--gnome-map/gnome-map.c327
-rw-r--r--gnome-map/gnome-map.h59
-rw-r--r--gnome-map/map480.pngbin0 -> 134252 bytes
-rw-r--r--gnome-map/pygtk.h334
-rwxr-xr-xgnome-map/pytimezone40
-rw-r--r--gnome-map/testtz.c11
-rw-r--r--gnome-map/timezonemapmodule.c824
-rw-r--r--gnome-map/timezones.c178
-rw-r--r--gnome-map/timezones.h40
13 files changed, 3104 insertions, 0 deletions
diff --git a/gnome-map/Makefile b/gnome-map/Makefile
new file mode 100644
index 000000000..7c21a0794
--- /dev/null
+++ b/gnome-map/Makefile
@@ -0,0 +1,11 @@
+all: gglobe-canvas timezonemapmodule.so
+
+CFLAGS=-g -Wall -fPIC `gnome-config --cflags gnomeui` -I/usr/include/python1.5
+LDFLAGS=`gnome-config --libs gnomeui`
+
+gglobe-canvas: gglobe-canvas.c gnome-map.o gnome-canvas-dot.o gglobe-canvas.o gnome-map.h timezones.o timezones.h
+ gcc -O2 -g -o gglobe-canvas gnome-map.o timezones.o gnome-canvas-dot.o gglobe-canvas.o $(LDFLAGS)
+
+
+timezonemapmodule.so: gnome-map.o gnome-canvas-dot.o timezonemapmodule.o gnome-map.h timezones.o timezones.h
+ gcc -o timezonemapmodule.so -shared gnome-map.o gnome-canvas-dot.o timezonemapmodule.o timezones.o $(LDFLAGS)
diff --git a/gnome-map/gglobe-canvas.c b/gnome-map/gglobe-canvas.c
new file mode 100644
index 000000000..68f92682f
--- /dev/null
+++ b/gnome-map/gglobe-canvas.c
@@ -0,0 +1,786 @@
+/* Copyright (C) 1999 Red Hat, Inc. */
+/* Original work by Michael Fulbright <drmike@redhat.com> */
+
+#include <gnome.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+
+#include "gnome-map.h"
+#include "gnome-canvas-dot.h"
+#include "timezones.h"
+
+
+/* Command line options */
+/* image - filename of file to use for map (must be PNG for antialias) */
+/* mapwidth - width to scale image to (also size of canvas widget) */
+/* mapheight - height to scale image to (also size of canvas widget) */
+/* aa - if TRUE use antialiased canvas instead of normal */
+static gchar *image = NULL;
+static int mapwidth = -1;
+static int mapheight = -1;
+static int aa=FALSE;
+
+static const struct poptOption options[] = {
+ {"image", '\0', POPT_ARG_STRING, &image, 0, N_("Map Image to display"), NULL},
+ {"width", '\0', POPT_ARG_INT, &mapwidth, 0, N_("Width of map (in pixels)"), NULL},
+ {"antialias", '\0', POPT_ARG_INT, &aa, 0, N_("Enable antialias"), NULL},
+ { NULL, '\0', 0, NULL, 0}
+};
+
+
+/* time zone data */
+/* This is an array of TimeZoneLocations (see timezone.h). Created */
+/* by a call to loadTZDB */
+GPtrArray *Locations=NULL;
+
+/* index in all Locations GPtrArray of currently selected city */
+gint curselection=-1;
+
+/* toplevel app window */
+GtkWidget *mainwindow;
+
+/* other widgets for the top-level GUI */
+GtkWidget *statusbar;
+
+/* locationlist is the clist on the right side of the GUI showing all the */
+/* currently viewable locations. */
+/* It is created and updated by the create_location_list () function */
+GtkWidget *locationlist;
+
+/* if TRUE we do not want to act on the select_row events to locationlist */
+/* used when we are manually manipulating rows in locationlist and we */
+/* want to ignore the events going to the callback. */
+gboolean ignore_locationlist_selectevents=FALSE;
+
+/* Canvas item circle for selected location */
+GnomeCanvasItem *selmarker=NULL;
+double oldselx, oldsely; /* old location of selection */
+#define SELECTED_COLOR "red"
+
+/* Canvas item circle for hilited location and optionally rubberband */
+/* line pointing from cursor to hilited location */
+GnomeCanvasItem *hilitemarker=NULL;
+GnomeCanvasItem *hiliterubberband=NULL;
+gint hiliteindex=-1; /* index in markers array of */
+ /* currently hilted location */
+double oldhilitex, oldhilitey; /* old location of hilite circle */
+#define HILITED_COLOR "limegreen"
+
+/* set to appropriate value to enable/disable the rubberband */
+#define USE_HILITE_RUBBERBAND TRUE
+
+/* color for normal (non-hilited or -selected locations */
+#define CITY_COLOR "yellow"
+
+/* map and city structures */
+/* See gnome-map.h for more info on the GnomeMap structure */
+/* markers is an array of pointers to GnomeCanvasItems which are the */
+/* indicators for the locations in the Locations array */
+GnomeMap *WorldMap;
+GnomeCanvasItem **markers=NULL;
+
+/* view data */
+/* Views are defined by a range of either longitude or latitude */
+/* as well as the central value for the other axis. */
+typedef enum
+{
+ LONGITUDE_CONSTRAINT,
+ LATITUDE_CONSTRAINT
+} ViewContraintType;
+
+struct _VIEW_DEF {
+ gchar *name;
+ ViewContraintType type;
+ double constraint1, constraint2, constraint3;
+};
+
+typedef struct _VIEW_DEF ViewDefinition;
+
+ViewDefinition Views[] = {
+ { "World", LONGITUDE_CONSTRAINT, -180.0, 180.0, 0.0 },
+ { "North America", LONGITUDE_CONSTRAINT, -171.0, -21.0, 40.0 },
+ { "South America", LATITUDE_CONSTRAINT, 15.0, -70.0, -70.0 },
+ { "Pacific Rim", LATITUDE_CONSTRAINT, -47.0, 47.0, 155.0},
+ { "Europe", LONGITUDE_CONSTRAINT, -25.0, 70.0, 45.0 },
+ { "Africa", LATITUDE_CONSTRAINT, 40.0, -40.0, 15.0},
+ { "Asia", LONGITUDE_CONSTRAINT, 20.0, 165.0, 40.0}
+};
+
+gint numviews = sizeof(Views)/sizeof(ViewDefinition);
+
+
+static gint item_event (GnomeCanvasItem *item, GdkEvent *event, gpointer data);
+static GtkWidget *create_location_list ( GtkWidget **returnlist );
+
+/* give a location name search for match in Locations db */
+/* returns index if found, -1 if not */
+static int
+find_location (gchar *locname)
+{
+ TimeZoneLocation *loc;
+ gint i;
+
+ for (i=0; i < Locations->len; i++) {
+ loc = g_ptr_array_index (Locations, i);
+
+ if (!strcmp (loc->zone, locname))
+ return i;
+ }
+
+ return -1;
+}
+
+
+/* find nearest location to specified map coords - clips to current view */
+/* if no match return -1 */
+static int
+find_nearest ( double longitude, double latitude )
+{
+ double mindist;
+ double dist;
+ double dx, dy;
+ int i, mini;
+ gboolean first=TRUE;
+ TimeZoneLocation *loc;
+
+ mini = -1;
+ for (i=0; i < Locations->len; i++) {
+ loc = g_ptr_array_index (Locations, i);
+
+ if (!gnome_map_is_loc_in_view (WorldMap,
+ loc->longitude, loc->latitude))
+ continue;
+
+ dx = (loc->longitude-longitude);
+ dy = (loc->latitude-latitude);
+ dist = dx*dx + dy*dy;
+
+ if (dist < mindist || first) {
+ mindist = dist;
+ mini = i;
+ first = FALSE;
+ }
+ }
+
+ return mini;
+}
+
+/* attach to signal for canvas items so we can track motion and mouse */
+/* events */
+static void
+setup_item (GnomeCanvasItem *item)
+{
+ gtk_signal_connect (GTK_OBJECT (item), "event",
+ (GtkSignalFunc) item_event,
+ NULL);
+}
+
+/* Moves marker (a circle currently) to the specified location */
+/* and sets it to the specified color. The oldx and oldy */
+/* variables are required because the canvas only allows one */
+/* to do relative moves for items. These are automatically */
+/* set to x and y by this function before it returns. */
+/* */
+/* The first time this function is called for a given marker */
+/* *curmarker should equal NULL. The marker will be created */
+/* automatically. */
+
+static void
+set_flag_marker (GnomeCanvasItem **curmarker, gchar *color,
+ double x, double y, double *oldx, double *oldy)
+{
+ GnomeCanvasGroup *canvas_root;
+ GnomeCanvasItem *group;
+
+ g_return_if_fail ( color != NULL );
+
+ canvas_root = gnome_canvas_root (GNOME_CANVAS(WorldMap->canvas));
+ if (!*curmarker) {
+
+ group = gnome_canvas_item_new ( canvas_root,
+ gnome_canvas_group_get_type(),
+ "x", x,
+ "y", y,
+ NULL);
+
+#define MARKER_RADIUS 3.5
+#define MARKER_WIDTH_PIX 1
+
+ setup_item (gnome_canvas_item_new (GNOME_CANVAS_GROUP (group),
+ gnome_canvas_text_get_type (),
+ "font", "-adobe-helvetica-bold-r-normal--12-*-72-72-p-*-iso8859-1",
+ "anchor", GTK_ANCHOR_CENTER,
+ "fill_color", "red",
+ "text", "X",
+ NULL));
+
+ *curmarker = GNOME_CANVAS_ITEM (group);
+ } else {
+ gnome_canvas_item_move ( *curmarker, x - *oldx, y - *oldy );
+ }
+
+ *oldx = x;
+ *oldy = y;
+}
+
+/* Given a pointer to a GnomeMap and an index into the Locations db */
+/* mark it as the selected location on the canvas */
+static void
+map_mark_location_selected (GnomeMap *map, gint index)
+{
+ TimeZoneLocation *loc;
+ double selx, sely;
+
+ g_return_if_fail ( map != NULL );
+ g_return_if_fail ( index >= 0 );
+
+ loc = g_ptr_array_index (Locations, index);
+
+ gnome_map_xlat_map2screen ( map,
+ loc->longitude, loc->latitude,
+ &selx, &sely );
+ set_flag_marker (&selmarker, SELECTED_COLOR,
+ selx, sely, &oldselx, &oldsely);
+
+ if (curselection >= 0) {
+ gnome_canvas_item_set (markers[curselection],
+ "fill_color", CITY_COLOR, NULL);
+ gnome_canvas_item_show (markers[curselection]);
+ }
+/* gnome_canvas_item_set (markers[index], "fill_color", */
+/* SELECTED_COLOR, NULL); */
+ gnome_canvas_item_hide (markers[index]);
+ gnome_canvas_item_raise_to_top (selmarker);
+}
+
+/* Given a pointer to a GnomeMap and an index into the Locations db */
+/* mark it as the selected location in the clist of locations */
+/* The jumpto gboolean is used to specify if the clist should be */
+/* forced to scroll to the new location. Used because when the */
+/* clist is autoscrolling we do not want to force selection to be */
+/* constantly recentered. */
+static void
+list_mark_location_selected (GnomeMap *map, gint index, gboolean jumpto)
+{
+ gint newrow;
+
+ /* We're messing with list manually, so let callback know to */
+ /* ignore any events till we're done */
+ ignore_locationlist_selectevents = TRUE;
+
+ /* if current selection is visible then select it again, otherwise */
+ /* change clist to not have a current selection */
+ if (index >= 0) {
+ TimeZoneLocation *loc = g_ptr_array_index (Locations, index);
+
+ if (gnome_map_is_loc_in_view (map,loc->longitude,loc->latitude)) {
+ gtk_clist_set_selection_mode (GTK_CLIST (locationlist),
+ GTK_SELECTION_BROWSE);
+ } else {
+ gtk_clist_set_selection_mode (GTK_CLIST (locationlist),
+ GTK_SELECTION_SINGLE);
+ }
+ }
+
+ /* find in list of locations and set as current */
+ newrow = gtk_clist_find_row_from_data( GTK_CLIST (locationlist),
+ GINT_TO_POINTER (index));
+
+ if (newrow >= 0 ) {
+ gtk_clist_select_row (GTK_CLIST(locationlist), newrow, 0);
+ if (jumpto && gtk_clist_row_is_visible (GTK_CLIST (locationlist), newrow) != GTK_VISIBILITY_FULL) {
+ gtk_clist_moveto (GTK_CLIST (locationlist), newrow , 0, 0.5, 0.5 );
+ }
+ }
+
+ /* We're done mucking with clist, ok to listen to events again */
+ ignore_locationlist_selectevents = FALSE;
+
+}
+/* handles all canvas drawing for making the selected location # index */
+/* in the sorted list in the Locations variable */
+static void
+set_selection (gint index, gboolean jumpto)
+{
+ g_return_if_fail ( index >= 0 );
+
+ map_mark_location_selected (WorldMap, index);
+
+ list_mark_location_selected (WorldMap, index, jumpto);
+
+ /* NOTE: curselection is global variable. Only place it gets set */
+ curselection = index;
+}
+
+/* Given an index into the Locations db and a position, draw the hilite */
+/* marker around it to indicate it is city cursor is pointing at */
+static void
+set_hilited (gint index, double item_x, double item_y)
+{
+ TimeZoneLocation *loc;
+ GnomeCanvasPoints *points;
+
+ g_return_if_fail ( index >= 0 );
+
+ loc = g_ptr_array_index (Locations, index);
+
+ points = gnome_canvas_points_new (2);
+ points->coords[0] = item_x;
+ points->coords[1] = item_y;
+ gnome_map_xlat_map2screen ( WorldMap,
+ loc->longitude, loc->latitude,
+ &points->coords[2], &points->coords[3] );
+ if (hiliterubberband) {
+ gnome_canvas_item_set (hiliterubberband, "points", points, NULL);
+ gnome_canvas_item_show (hiliterubberband);
+ } else {
+ GnomeCanvasGroup *canvas_root = gnome_canvas_root (GNOME_CANVAS (WorldMap->canvas));
+
+ hiliterubberband = gnome_canvas_item_new (canvas_root,
+ gnome_canvas_line_get_type (),
+ "points", points,
+ "fill_color", HILITED_COLOR,
+ "width_pixels", 2,
+ "first_arrowhead", FALSE,
+ "last_arrowhead", TRUE,
+ "arrow_shape_a", 4.0,
+ "arrow_shape_b", 8.0,
+ "arrow_shape_c", 4.0,
+ NULL);
+ setup_item (hiliterubberband);
+ }
+
+ /* Set USE_HILITE_RUBBER band define at top of file for desired */
+ /* behavior */
+ if (!USE_HILITE_RUBBERBAND)
+ gnome_canvas_item_hide (hiliterubberband);
+
+ /* if hilited city isn't also currently selected city, draw the */
+ /* hilite marker as well */
+ if (index != curselection) {
+ /*
+ set_flag_marker ( &hilitemarker, HILITED_COLOR,
+ points->coords[2], points->coords[3],
+ &oldhilitex, &oldhilitey );
+ */
+
+/* gnome_canvas_item_set ( markers[index], */
+/* "fill_color", HILITED_COLOR, */
+/* NULL); */
+
+ if (hiliteindex >= 0 && hiliteindex != index) {
+ if (hiliteindex != curselection)
+ gnome_canvas_item_set ( markers[hiliteindex],
+ "fill_color", CITY_COLOR,
+ NULL);
+ else
+ gnome_canvas_item_set ( markers[hiliteindex],
+ "fill_color", SELECTED_COLOR,
+ NULL);
+ }
+ hiliteindex = index;
+
+/* gnome_canvas_item_show (hilitemarker); */
+ } else {
+/* gnome_canvas_item_hide (hilitemarker); */
+ }
+
+ gnome_canvas_points_free (points);
+
+ gtk_statusbar_pop ( GTK_STATUSBAR (statusbar), 1);
+ gtk_statusbar_push ( GTK_STATUSBAR (statusbar), 1, loc->zone );
+}
+
+/* Handles case where cursor leaves the map */
+static int
+canvas_event (GtkWidget *canvas, GdkEvent *event, gpointer data)
+{
+ /* if pointer just left canvas, hide hilite marker(s) */
+ if (event->type == GDK_LEAVE_NOTIFY) {
+/* if (hilitemarker) */
+/* gnome_canvas_item_hide (hilitemarker); */
+ if (hiliterubberband)
+ gnome_canvas_item_hide (hiliterubberband);
+ if (hiliteindex >= 0 && hiliteindex != curselection)
+ gnome_canvas_item_set ( markers[hiliteindex],
+ "fill_color", CITY_COLOR,
+ NULL);
+
+ }
+ return FALSE;
+}
+
+/* Handles as motion and mouse button events in the map */
+static gint
+item_event (GnomeCanvasItem *item, GdkEvent *event, gpointer data)
+{
+ double longitude, latitude;
+ double item_x, item_y;
+ int nearest;
+
+ item_x = event->button.x;
+ item_y = event->button.y;
+ gnome_canvas_item_w2i (WorldMap->image_item, &item_x, &item_y);
+
+ switch (event->type) {
+
+ /* User selected a new location with a left mouse button press */
+ case GDK_BUTTON_PRESS:
+ switch (event->button.button) {
+ case 1:
+
+ gnome_map_xlat_screen2map ( WorldMap, item_x, item_y,
+ &longitude, &latitude );
+
+ nearest = find_nearest( longitude, latitude );
+
+ set_selection (nearest, TRUE);
+
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ /* highlight city which a button press will select */
+ case GDK_MOTION_NOTIFY:
+
+ gnome_map_xlat_screen2map ( WorldMap, item_x, item_y,
+ &longitude, &latitude);
+
+ nearest = find_nearest( longitude, latitude );
+ set_hilited (nearest, item_x, item_y);
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+/* Handles events for the clist of locations */
+static void
+list_select_event ( GtkWidget *clist, gint row, gint column,
+ GdkEventButton *event, gpointer data)
+{
+
+ gchar *text;
+ gint index;
+
+ /* should we do anything? */
+ if (ignore_locationlist_selectevents)
+ return;
+
+ /* msf - always read zero because sometimes col == -1 if they select */
+ /* without a mouse click (ie. keyboard navigation ) */
+ gtk_clist_get_text(GTK_CLIST(clist), row, 0, &text);
+
+ /* Just prints some information about the selected row */
+ g_print("You selected row %d. More specifically you clicked in column %d, and the text in this cell is %s\n\n", row, column, text);
+
+ index = find_location (text);
+ if (index < 0)
+ return;
+
+ set_selection (index, FALSE);
+ return;
+}
+
+
+static GnomeCanvasItem *
+draw_city_marker ( GnomeMap *map, double longitude, double latitude)
+{
+ double x, y;
+ GnomeCanvasItem *item;
+ GnomeCanvasGroup *canvas_root;
+
+ canvas_root = gnome_canvas_root (GNOME_CANVAS (map->canvas));
+
+ gnome_map_xlat_map2screen (map, longitude, latitude, &x, &y);
+
+#define RAD 1
+#ifdef ELLIPSE
+ item = gnome_canvas_item_new (canvas_root,
+ gnome_canvas_ellipse_get_type (),
+ "x1", x-RAD,
+ "y1", y-RAD,
+ "x2", x+RAD,
+ "y2", y+RAD,
+ "fill_color", CITY_COLOR,
+ NULL);
+#else
+ item = gnome_canvas_item_new (canvas_root,
+ gnome_canvas_dot_get_type (),
+ "x", x,
+ "y", y,
+ "diameter_pixels", RAD,
+ "fill_color", CITY_COLOR,
+ NULL);
+#endif
+
+ setup_item ( item );
+ return item;
+}
+
+static void
+draw_cities (GnomeMap *map)
+{
+ gint i;
+
+ if (markers)
+ g_free(markers);
+
+ markers = g_new( GnomeCanvasItem *, Locations->len);
+ for (i=0; i < Locations->len; i++) {
+ TimeZoneLocation *loc = g_ptr_array_index (Locations, i);
+
+ markers[i] = draw_city_marker (map, loc->longitude, loc->latitude);
+ }
+}
+
+static void
+view_menu_activate (GtkWidget *widget, void *data)
+{
+ static gint curitem = -1;
+ gint item = GPOINTER_TO_INT (data);
+
+ double lat1, long1, lat2, long2;
+ double dlat, dlong;
+
+ if ( item == curitem )
+ return;
+
+ curitem = item;
+
+ /* compute aspect correct view and set canvas to it */
+ /* we may have to shift view if it extends outside of map */
+ if (Views[item].type == LONGITUDE_CONSTRAINT) {
+ long1 = Views[item].constraint1;
+ long2 = Views[item].constraint2;
+ dlong = fabs(long2 - long1);
+ dlat = dlong/2.0;
+ lat1 = Views[item].constraint3 - dlat/2.0;
+ lat2 = Views[item].constraint3 + dlat/2.0;
+
+ if (lat1 < -90.0) {
+ lat2 -= (lat1-90.0);
+ lat1 = -90.0;
+ } else if (lat2 > 90.0) {
+ lat1 -= (lat2-90.0);
+ lat2 = 90.0;
+ }
+ } else if (Views[item].type == LATITUDE_CONSTRAINT) {
+ lat1 = Views[item].constraint1;
+ lat2 = Views[item].constraint2;
+ dlat = fabs(lat2 - lat1);
+ dlong = 2.0*dlat;
+ long1 = Views[item].constraint3 - dlong/2.0;
+ long2 = Views[item].constraint3 + dlong/2.0;
+
+ if (long1 < -180.0) {
+ long2 -= (long1-180.0);
+ long1 = -180.0;
+ } else if (long2 > 180.0) {
+ long1 -= (long2-180.0);
+ long2 = 180.0;
+ }
+ } else {
+ g_warning ("Bad contraint type %d in Views structure item # %d.\n",
+ item, Views[item].type);
+ return;
+ }
+
+ gnome_map_set_view (WorldMap, long1, lat1, long2, lat2);
+
+ /* make locationlist clist entries reflect those visible*/
+ create_location_list (&locationlist);
+
+}
+
+GtkWidget *
+create_view_menu ( void )
+{
+ GtkWidget *omenu;
+ GtkWidget *menu;
+ GtkWidget *menu_item;
+ gint i;
+
+ omenu = gtk_option_menu_new ();
+
+ menu = gtk_menu_new ();
+
+ for (i=0; i < numviews; i++) {
+ menu_item = gtk_menu_item_new_with_label (Views[i].name);
+ gtk_menu_append (GTK_MENU (menu), menu_item);
+
+ gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
+ (GtkSignalFunc) view_menu_activate,
+ GINT_TO_POINTER (i));
+
+ gtk_widget_show (menu_item);
+ }
+ gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu);
+ gtk_option_menu_set_history (GTK_OPTION_MENU (omenu), 0);
+
+ gtk_widget_show (omenu);
+ return omenu;
+}
+
+/* returns pointer to the scrolled window containing the clist */
+/* pointer to clist is returned via the passed argument if it doesnt */
+/* already exist. The list is clipped to the current world view */
+static GtkWidget *
+create_location_list ( GtkWidget **returnlist )
+{
+ TimeZoneLocation *loc;
+ GtkWidget *scrolledwin;
+ gchar *titles[] = { "Location", NULL };
+ gchar *row[1];
+ gint i;
+
+ ignore_locationlist_selectevents = TRUE;
+
+ if ( !*returnlist) {
+ scrolledwin = gtk_scrolled_window_new (NULL, NULL);
+
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+
+ gtk_widget_show (scrolledwin);
+
+ *returnlist = gtk_clist_new_with_titles (1, titles);
+ gtk_clist_set_selection_mode (GTK_CLIST(*returnlist),
+ GTK_SELECTION_BROWSE);
+ gtk_clist_column_title_passive (GTK_CLIST(*returnlist), 0);
+ gtk_signal_connect(GTK_OBJECT(*returnlist), "select_row",
+ GTK_SIGNAL_FUNC(list_select_event),
+ NULL);
+
+
+ gtk_container_add (GTK_CONTAINER (scrolledwin), *returnlist);
+ } else {
+ gtk_clist_clear (GTK_CLIST (*returnlist));
+ scrolledwin = NULL;
+ }
+
+ for (i=0; i < Locations->len; i++) {
+ gint newrow;
+
+ loc = g_ptr_array_index (Locations, i);
+ if (!gnome_map_is_loc_in_view (WorldMap,loc->longitude,loc->latitude))
+ continue;
+
+ row[0] = loc->zone;
+ newrow = gtk_clist_append (GTK_CLIST (*returnlist), row);
+ gtk_clist_set_row_data (GTK_CLIST (*returnlist), newrow,
+ GINT_TO_POINTER (i));
+ }
+
+ /* restore selection of location in list now we've recreated it */
+ list_mark_location_selected(WorldMap, curselection, TRUE);
+
+ gtk_widget_show (locationlist);
+
+ ignore_locationlist_selectevents = FALSE;
+ return scrolledwin;
+}
+
+
+int
+main (int argc, char **argv)
+{
+ GtkWidget *frame;
+ GtkWidget *hbox1, *hbox2;
+ GtkWidget *vbox1, *vbox2;
+
+ GtkWidget *viewcombo;
+
+/*
+ tzset ();
+ printf ("tzname[0]=|%s| tzname[1]=|%s|\n",tzname[0], tzname[1]);
+*/
+ gnome_init_with_popt_table("gglobe", "0.1", argc, argv,
+ options, 0, NULL);
+
+ /* load timezone data */
+ Locations = loadTZDB ();
+ if (!Locations) {
+ g_warning (_("Cannot load timezone data"));
+ exit (1);
+ }
+
+ mainwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_position (GTK_WINDOW (mainwindow), GTK_WIN_POS_CENTER);
+ gtk_window_set_title (GTK_WINDOW (mainwindow), _("gglobe-canvas"));
+
+ gtk_signal_connect (GTK_OBJECT (mainwindow), "destroy",
+ GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+
+ /* top-level hbox for packing map/statusbar and view combo/tz list box */
+ hbox1 = gtk_hbox_new (FALSE, 2);
+ gtk_container_add (GTK_CONTAINER (mainwindow), hbox1);
+
+ /* create frame and world map first */
+ vbox1 = gtk_vbox_new (FALSE, 2);
+ gtk_box_pack_start (GTK_BOX (hbox1), vbox1, FALSE, FALSE, 0);
+
+ frame = gtk_frame_new (NULL);
+ gtk_box_pack_start (GTK_BOX (vbox1), frame, FALSE, FALSE, 0);
+
+ WorldMap = gnome_map_new ( image, mapwidth, mapheight, aa );
+ if (!WorldMap) {
+ g_warning ("Could not create map view.");
+ exit (1);
+ }
+
+ setup_item(WorldMap->image_item);
+ gtk_signal_connect (GTK_OBJECT (WorldMap->canvas), "event",
+ (GtkSignalFunc) canvas_event,
+ NULL);
+
+ gtk_container_add (GTK_CONTAINER (frame), WorldMap->canvas);
+
+ statusbar = gtk_statusbar_new ();
+ gtk_box_pack_start (GTK_BOX (vbox1), statusbar, FALSE, FALSE, 0);
+ gtk_statusbar_push (GTK_STATUSBAR (statusbar), 1, "Unselected");
+ gtk_widget_show (statusbar);
+
+ /* add View combo box */
+ frame = gtk_frame_new (NULL);
+ gtk_box_pack_start (GTK_BOX (hbox1), frame, FALSE, FALSE, 2);
+
+ vbox2 = gtk_vbox_new (FALSE, 2);
+ gtk_container_add (GTK_CONTAINER (frame), vbox2);
+
+ hbox2 = gtk_hbox_new (FALSE, 2);
+ gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 2);
+
+ viewcombo = create_view_menu ();
+ gtk_box_pack_start (GTK_BOX (hbox2), gtk_label_new ("View: "),
+ FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox2), viewcombo, FALSE, FALSE, 2);
+
+ /* put cities on the world map */
+ draw_cities (WorldMap);
+
+ /* add list of all timezones */
+ frame = gtk_frame_new (NULL);
+ gtk_box_pack_start (GTK_BOX (vbox2),
+ create_location_list (&locationlist),
+ TRUE, TRUE, 2);
+
+ /* display and wait */
+ gtk_widget_show_all (mainwindow);
+
+ /* pick New York City as default */
+ set_selection (find_location ("America/New_York"), TRUE);
+
+ gtk_main ();
+
+ return 0;
+}
+
diff --git a/gnome-map/gnome-canvas-dot.c b/gnome-map/gnome-canvas-dot.c
new file mode 100644
index 000000000..c69fe030e
--- /dev/null
+++ b/gnome-map/gnome-canvas-dot.c
@@ -0,0 +1,434 @@
+/* Dot item for the GNOME canvas
+ *
+ * Copyright (C) 1999 Red Hat, Inc.
+ *
+ * Author: Federico Mena <federico@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <math.h>
+#include <gtk/gtkgc.h>
+#include "gnome-canvas-dot.h"
+
+
+/* Object argument IDs */
+enum {
+ ARG_0,
+ ARG_X,
+ ARG_Y,
+ ARG_DIAMETER_PIXELS,
+ ARG_FILL_COLOR
+};
+
+
+static void gnome_canvas_dot_class_init (GnomeCanvasDotClass *class);
+static void gnome_canvas_dot_init (GnomeCanvasDot *dot);
+static void gnome_canvas_dot_destroy (GtkObject *object);
+static void gnome_canvas_dot_set_arg (GtkObject *object, GtkArg *arg, guint arg_id);
+static void gnome_canvas_dot_get_arg (GtkObject *object, GtkArg *arg, guint arg_id);
+
+static void gnome_canvas_dot_update (GnomeCanvasItem *item, double *affine,
+ ArtSVP *clip_svp, int flags);
+static void gnome_canvas_dot_unrealize (GnomeCanvasItem *item);
+static void gnome_canvas_dot_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height);
+static double gnome_canvas_dot_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
+ GnomeCanvasItem **actual_item);
+static void gnome_canvas_dot_bounds (GnomeCanvasItem *item,
+ double *x1, double *y1, double *x2, double *y2);
+
+
+static GnomeCanvasItemClass *parent_class;
+
+
+/* Private data of the GnomeCanvasDot structure */
+typedef struct {
+ double x, y;
+ guint diameter;
+
+ guint fill_color;
+
+ GdkGC *gc;
+
+ guint need_shape_update : 1;
+ guint need_color_update : 1;
+} DotPrivate;
+
+
+/**
+ * gnome_canvas_dot_get_type:
+ * @void:
+ *
+ * Registers the &GnomeCanvasDot class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GnomeCanvasDot class.
+ **/
+GtkType
+gnome_canvas_dot_get_type (void)
+{
+ static GtkType dot_type = 0;
+
+ if (!dot_type) {
+ static const GtkTypeInfo dot_info = {
+ "GnomeCanvasDot",
+ sizeof (GnomeCanvasDot),
+ sizeof (GnomeCanvasDotClass),
+ (GtkClassInitFunc) gnome_canvas_dot_class_init,
+ (GtkObjectInitFunc) gnome_canvas_dot_init,
+ NULL, /* reserved_1 */
+ NULL, /* reserved_2 */
+ (GtkClassInitFunc) NULL
+ };
+
+ dot_type = gtk_type_unique (gnome_canvas_item_get_type (), &dot_info);
+ }
+
+ return dot_type;
+}
+
+
+/* Class initialization function for the dot item */
+static void
+gnome_canvas_dot_class_init (GnomeCanvasDotClass *class)
+{
+ GtkObjectClass *object_class;
+ GnomeCanvasItemClass *item_class;
+
+ object_class = (GtkObjectClass *) class;
+ item_class = (GnomeCanvasItemClass *) class;
+
+ parent_class = gtk_type_class (gnome_canvas_item_get_type ());
+
+ gtk_object_add_arg_type ("GnomeCanvasDot::x",
+ GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X);
+ gtk_object_add_arg_type ("GnomeCanvasDot::y",
+ GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y);
+ gtk_object_add_arg_type ("GnomeCanvasDot::diameter_pixels",
+ GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_DIAMETER_PIXELS);
+ gtk_object_add_arg_type ("GnomeCanvasDot::fill_color",
+ GTK_TYPE_STRING, GTK_ARG_WRITABLE, ARG_FILL_COLOR);
+
+ object_class->destroy = gnome_canvas_dot_destroy;
+ object_class->set_arg = gnome_canvas_dot_set_arg;
+ object_class->get_arg = gnome_canvas_dot_get_arg;
+
+ item_class->update = gnome_canvas_dot_update;
+ item_class->unrealize = gnome_canvas_dot_unrealize;
+ item_class->draw = gnome_canvas_dot_draw;
+ item_class->point = gnome_canvas_dot_point;
+ item_class->bounds = gnome_canvas_dot_bounds;
+}
+
+/* Object initialization function for the dot item */
+static void
+gnome_canvas_dot_init (GnomeCanvasDot *dot)
+{
+ DotPrivate *priv;
+
+ priv = g_new0 (DotPrivate, 1);
+ dot->priv = priv;
+
+ priv->x = 0.0;
+ priv->y = 0.0;
+ priv->fill_color = 0x000000ff;
+}
+
+/* Destroy handler for the dot item */
+static void
+gnome_canvas_dot_destroy (GtkObject *object)
+{
+ GnomeCanvasDot *dot;
+ GnomeCanvasItem *item;
+ DotPrivate *priv;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_DOT (object));
+
+ dot = GNOME_CANVAS_DOT (object);
+ item = GNOME_CANVAS_ITEM (object);
+ priv = dot->priv;
+
+ gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2);
+ g_free (priv);
+
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+/* Set_arg handler for the dot item */
+static void
+gnome_canvas_dot_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
+{
+ GnomeCanvasItem *item;
+ GnomeCanvasDot *dot;
+ DotPrivate *priv;
+ char *str;
+ GdkColor color;
+
+ item = GNOME_CANVAS_ITEM (object);
+ dot = GNOME_CANVAS_DOT (object);
+ priv = dot->priv;
+
+ switch (arg_id) {
+ case ARG_X:
+ priv->x = GTK_VALUE_DOUBLE (*arg);
+ priv->need_shape_update = TRUE;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case ARG_Y:
+ priv->y = GTK_VALUE_DOUBLE (*arg);
+ priv->need_shape_update = TRUE;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case ARG_DIAMETER_PIXELS:
+ priv->diameter = GTK_VALUE_UINT (*arg);
+ priv->need_shape_update = TRUE;
+ gnome_canvas_item_request_update (item);
+ break;
+
+ case ARG_FILL_COLOR:
+ str = GTK_VALUE_STRING (*arg);
+ g_return_if_fail (str != NULL);
+
+ if (gdk_color_parse (str, &color)) {
+ priv->fill_color = ((color.red & 0xff00) << 16 |
+ (color.green & 0xff00) << 8 |
+ (color.blue & 0xff00) |
+ 0xff);
+ priv->need_color_update = TRUE;
+ gnome_canvas_item_request_update (item);
+ }
+
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Get_arg handler for the dot item */
+static void
+gnome_canvas_dot_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
+{
+ GnomeCanvasDot *dot;
+ DotPrivate *priv;
+
+ dot = GNOME_CANVAS_DOT (object);
+ priv = dot->priv;
+
+ switch (arg_id) {
+ case ARG_X:
+ GTK_VALUE_DOUBLE (*arg) = priv->x;
+ break;
+
+ case ARG_Y:
+ GTK_VALUE_DOUBLE (*arg) = priv->y;
+ break;
+
+ case ARG_DIAMETER_PIXELS:
+ GTK_VALUE_UINT (*arg) = priv->diameter;
+ break;
+
+ default:
+ arg->type = GTK_TYPE_INVALID;
+ break;
+ }
+}
+
+/* Update handler for the dot item */
+static void
+gnome_canvas_dot_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_svp, int flags)
+{
+ GnomeCanvasDot *dot;
+ DotPrivate *priv;
+
+ dot = GNOME_CANVAS_DOT (item);
+ priv = dot->priv;
+
+ if (parent_class->update)
+ (* parent_class->update) (item, affine, clip_svp, flags);
+
+ /* Redraw old area if necessary */
+
+ if (((flags & GNOME_CANVAS_UPDATE_VISIBILITY)
+ && !(GTK_OBJECT_FLAGS (item) & GNOME_CANVAS_ITEM_VISIBLE))
+ || (flags & GNOME_CANVAS_UPDATE_AFFINE)
+ || priv->need_shape_update)
+ gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2);
+
+ /* Update color if needed */
+ if (priv->need_color_update) {
+ GdkGCValues values;
+ int mask;
+
+ if (priv->gc)
+ gtk_gc_release (priv->gc);
+
+ values.foreground.pixel = gnome_canvas_get_color_pixel (item->canvas,
+ priv->fill_color);
+ mask = GDK_GC_FOREGROUND;
+
+ priv->gc = gtk_gc_get (gtk_widget_get_visual (GTK_WIDGET (item->canvas))->depth,
+ gtk_widget_get_colormap (GTK_WIDGET (item->canvas)),
+ &values,
+ mask);
+
+ priv->need_color_update = FALSE;
+ }
+
+ /* If we need a shape update, or if the item changed visibility
+ * to shown, recompute the bounding box.
+ */
+ if (priv->need_shape_update
+ || ((flags & GNOME_CANVAS_UPDATE_VISIBILITY)
+ && (GTK_OBJECT_FLAGS (item) & GNOME_CANVAS_ITEM_VISIBLE))
+ || (flags & GNOME_CANVAS_UPDATE_AFFINE)) {
+ ArtPoint i1, i2, c1, c2;
+ double d;
+ double i2c[6];
+
+ d = priv->diameter / item->canvas->pixels_per_unit;
+
+ i1.x = priv->x - d / 2;
+ i1.y = priv->y - d / 2;
+ i2.x = priv->x + d / 2;
+ i2.y = priv->y + d / 2;
+
+ gnome_canvas_item_i2c_affine (item, i2c);
+ art_affine_point (&c1, &i1, i2c);
+ art_affine_point (&c2, &i2, i2c);
+
+ item->x1 = c1.x;
+ item->y1 = c1.y;
+ item->x2 = c2.x + 1;
+ item->y2 = c2.y + 1;
+
+ priv->need_shape_update = FALSE;
+ }
+
+ /* If the fill our outline changed, we need to redraw, anyways */
+ gnome_canvas_request_redraw (item->canvas, item->x1, item->y1, item->x2, item->y2);
+}
+
+/* Unrealize handler for the dot item */
+static void
+gnome_canvas_dot_unrealize (GnomeCanvasItem *item)
+{
+ GnomeCanvasDot *dot;
+ DotPrivate *priv;
+
+ dot = GNOME_CANVAS_DOT (item);
+ priv = dot->priv;
+
+ if (priv->gc) {
+ gtk_gc_release (priv->gc);
+ priv->gc = NULL;
+ }
+
+ if (parent_class->unrealize)
+ (* parent_class->unrealize) (item);
+}
+
+/* Draw handler for the dot item */
+static void
+gnome_canvas_dot_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height)
+{
+ GnomeCanvasDot *dot;
+ DotPrivate *priv;
+ double i2c[6];
+ ArtPoint i, c;
+ int x1, y1;
+
+ dot = GNOME_CANVAS_DOT (item);
+ priv = dot->priv;
+
+ i.x = priv->x;
+ i.y = priv->y;
+
+ gnome_canvas_item_i2c_affine (item, i2c);
+ art_affine_point (&c, &i, i2c);
+
+ x1 = floor (c.x - priv->diameter / 2.0 + 0.5) - x;
+ y1 = floor (c.y - priv->diameter / 2.0 + 0.5) - y;
+
+ gdk_draw_arc (drawable,
+ priv->gc,
+ TRUE,
+ x1, y1,
+ priv->diameter,
+ priv->diameter,
+ 0 * 64,
+ 360 * 64);
+
+ gdk_draw_arc (drawable,
+ priv->gc,
+ FALSE,
+ x1, y1,
+ priv->diameter,
+ priv->diameter,
+ 0 * 64,
+ 360 * 64);
+}
+
+/* Point handler for the dot item */
+static double
+gnome_canvas_dot_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
+ GnomeCanvasItem **actual_item)
+{
+ GnomeCanvasDot *dot;
+ DotPrivate *priv;
+ double d;
+ double dx, dy, dist;
+
+ dot = GNOME_CANVAS_DOT (item);
+ priv = dot->priv;
+
+ *actual_item = item;
+
+ d = priv->diameter / item->canvas->pixels_per_unit;
+
+ dx = x - priv->x;
+ dy = y - priv->y;
+ dist = sqrt (dx * dx + dy * dy);
+
+ if (dist <= d / 2.0)
+ return 0.0;
+ else
+ return dist - d / 2.0;
+}
+
+/* Bounds handler for the dot item */
+static void
+gnome_canvas_dot_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
+{
+ GnomeCanvasDot *dot;
+ DotPrivate *priv;
+ double d;
+
+ dot = GNOME_CANVAS_DOT (item);
+ priv = dot->priv;
+
+ d = priv->diameter / item->canvas->pixels_per_unit;
+
+ *x1 = priv->x - d / 2.0;
+ *y1 = priv->y - d / 2.0;
+ *x2 = priv->x + d / 2.0;
+ *y2 = priv->y + d / 2.0;
+}
diff --git a/gnome-map/gnome-canvas-dot.h b/gnome-map/gnome-canvas-dot.h
new file mode 100644
index 000000000..fc748a562
--- /dev/null
+++ b/gnome-map/gnome-canvas-dot.h
@@ -0,0 +1,60 @@
+/* Dot item for the GNOME canvas
+ *
+ * Copyright (C) 1999 Red Hat, Inc.
+ *
+ * Author: Federico Mena <federico@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef GNOME_CANVAS_DOT_H
+#define GNOME_CANVAS_DOT_H
+
+#include <libgnome/gnome-defs.h>
+#include <libgnomeui/gnome-canvas.h>
+
+
+BEGIN_GNOME_DECLS
+
+
+#define GNOME_TYPE_CANVAS_DOT (gnome_canvas_dot_get_type ())
+#define GNOME_CANVAS_DOT(obj) (GTK_CHECK_CAST ((obj), GNOME_TYPE_CANVAS_DOT, \
+ GnomeCanvasDot))
+#define GNOME_CANVAS_DOT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_CANVAS_DOT, \
+ GnomeCanvasDotClass))
+#define GNOME_IS_CANVAS_DOT(obj) (GTK_CHECK_TYPE ((obj), GNOME_TYPE_CANVAS_DOT))
+#define GNOME_IS_CANVAS_DOT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_CANVAS_DOT))
+
+
+typedef struct _GnomeCanvasDot GnomeCanvasDot;
+typedef struct _GnomeCanvasDotClass GnomeCanvasDotClass;
+
+struct _GnomeCanvasDot {
+ GnomeCanvasItem item;
+
+ gpointer priv;
+};
+
+struct _GnomeCanvasDotClass {
+ GnomeCanvasItemClass parent_class;
+};
+
+
+GtkType gnome_canvas_dot_get_type (void);
+
+
+END_GNOME_DECLS
+
+#endif
diff --git a/gnome-map/gnome-map.c b/gnome-map/gnome-map.c
new file mode 100644
index 000000000..31aa0239d
--- /dev/null
+++ b/gnome-map/gnome-map.c
@@ -0,0 +1,327 @@
+/* GNOME canvas based interface to a map using a simple cylindrical proj */
+/* */
+/* Copyright (C) 1999 Red Hat, Incorportated */
+/* Original work by Michael Fulbright <drmike@redhat.com> */
+
+#include <gnome.h>
+#include <math.h>
+#include "gnome-map.h"
+
+/* look in <gdk/gdkcursors.h> for valid values */
+#define MAP_CURSOR GDK_LEFT_PTR
+
+/**
+ * gnome_map_set_image:
+ * @map: Map to apply image to.
+ * @imagefile: Filename of image for map.
+ *
+ * This function sets the image used for the map to @imagefile. It is
+ * assumed that this image is a simple cylindrical projection.
+ *
+ * Return value: 0 on success, -1 if image could not be loaded
+ **/
+static gint
+gnome_map_set_image ( GnomeMap *map, gchar *imagefile )
+{
+
+ g_return_val_if_fail ( map != NULL, -1 );
+ g_return_val_if_fail ( map->image == NULL, -1 );
+
+ /* load map image */
+ if (map->aa)
+ map->image = gnome_canvas_load_alpha (imagefile);
+ else
+ map->image = gdk_imlib_load_image (imagefile);
+
+ if (!map->image)
+ return -1;
+
+ return 0;
+}
+
+
+static void
+canvas_realize_event (GtkWidget *canvas, gpointer *data)
+{
+
+ GdkCursor *ptrcursor;
+
+ ptrcursor = gdk_cursor_new (MAP_CURSOR);
+ if (!ptrcursor) {
+ g_warning ("Unable to load new cursor %d for map\n", MAP_CURSOR);
+ return;
+ }
+
+ gdk_window_set_cursor (canvas->window, ptrcursor);
+
+ gdk_cursor_destroy (ptrcursor);
+}
+
+/**
+ * gnome_map_new:
+ * @imagefile: File to be used map image.
+ * @width: Width of map view in pixels.
+ * @height: Height of map view in pixels.
+ * @antialias: Boolean used to set map to use antialias canvas or not.
+ *
+ * Creates a new map, using anti-aliased or normal canvas based on the
+ * value of @antialias. Of anti-aliased maps the image file must be
+ * in PNG format (this is a gnome-canvas limitation as of gnome-libs 1.0.10).
+ * If @width and @height are both <= 0, then the map image size is used.
+ * If only one of @width or @height is > 0, then the unspecified
+ * dimension is scaled (perserving the aspect of the original image).
+ *
+ * Return value: The newly-created map structure or NULL if image couldn't
+ * be loaded.
+ **/
+GnomeMap *
+gnome_map_new ( gchar *imagefile, gint width, gint height, gboolean aa )
+{
+ GnomeCanvasGroup *canvas_root;
+ GnomeMap *map;
+ gint h, w;
+
+ map = g_new0 ( GnomeMap, 1 );
+ map->aa = aa;
+
+ if ( gnome_map_set_image ( map, imagefile ) < 0 ) {
+ g_free (map);
+ return NULL;
+ }
+
+ /* create a canvas */
+ if (aa) {
+ gtk_widget_push_visual (gdk_rgb_get_visual ());
+ gtk_widget_push_colormap (gdk_rgb_get_cmap ());
+ map->canvas = gnome_canvas_new_aa ();
+ } else {
+ gtk_widget_push_visual (gdk_imlib_get_visual ());
+ gtk_widget_push_colormap (gdk_imlib_get_colormap ());
+ map->canvas = gnome_canvas_new ();
+ }
+
+ /* set map size and scaling */
+ if ( width <= 0 && height <= 0 ) {
+ w = map->image->rgb_width;
+ h = map->image->rgb_height;
+ } else if ( width > 0 && height <= 0 ) {
+ w = width;
+ h = (int)(((float)w/(float)map->image->rgb_width)*map->image->rgb_height);
+ } else if ( width <= 0 && height > 0 ) {
+ h = height;
+ w = (int)(((float)h/(float)map->image->rgb_height)*map->image->rgb_width);
+ } else {
+ w = width;
+ h = height;
+ }
+
+ map->width = w;
+ map->height = h;
+ map->long1 = -180.0;
+ map->lat1 = -90.0;
+ map->long2 = 180.0;
+ map->lat2 = 90.0;
+
+ gtk_widget_set_usize (map->canvas, w, h);
+ gnome_canvas_set_pixels_per_unit (GNOME_CANVAS (map->canvas), 1.0);
+ gnome_canvas_set_scroll_region (GNOME_CANVAS (map->canvas),
+ 0.0, 0.0,
+ (double)w, (double)h);
+
+ gtk_widget_show(map->canvas);
+
+ /* Setup canvas items */
+ canvas_root = gnome_canvas_root (GNOME_CANVAS (map->canvas));
+ map->image_item = gnome_canvas_item_new (canvas_root,
+ gnome_canvas_image_get_type (),
+ "image", map->image,
+ "x", 0.0,
+ "y", 0.0,
+ "width", (double) w,
+ "height", (double) h,
+ "anchor", GTK_ANCHOR_NW,
+ NULL);
+
+ /* grap realize signal so we can set cursor for map */
+ gtk_signal_connect (GTK_OBJECT (map->canvas), "realize",
+ (GtkSignalFunc) canvas_realize_event,
+ NULL);
+
+ /* restore to original */
+ gtk_widget_pop_colormap ();
+ gtk_widget_pop_visual ();
+
+ return map;
+}
+
+
+/**
+ * gnome_map_get_image_size: Get the unscaled image size of map image.
+ * @map: The map which image size is desired for.
+ * @width: Width of map in pixels.
+ * @height: Height of map in pixels.
+ *
+ * Given the GnomeMap @map, this function returns the dimensions of the
+ * original unscaled map image.
+ *
+ * Return value: None.
+ **/
+void
+gnome_map_get_image_size ( GnomeMap *map, gint *width, gint *height )
+{
+ g_return_if_fail ( map != NULL || map->image != NULL);
+ g_return_if_fail ( width != NULL || height != NULL );
+
+ *width = map->image->rgb_width;
+ *height = map->image->rgb_width;
+}
+
+/**
+ * gnome_map_set_size: Set screen dimensions (in pixels) of map view.
+ * @map: Map to apply dimensions to.
+ * @width: Desired width of map view.
+ * @height: Desired height of map view.
+ *
+ * Given a map which has an image associated with it via the
+ * gnome_map_set_image() call, set the onscreen size of the map view widget.
+ *
+ * Return value: None.
+ **/
+void
+gnome_map_set_size ( GnomeMap *map, gint width, gint height )
+{
+ g_return_if_fail ( map != NULL );
+ g_return_if_fail ( map->canvas != NULL );
+ g_return_if_fail ( map->image != NULL );
+ g_return_if_fail ( width > 0 );
+ g_return_if_fail ( height > 0 );
+}
+
+
+
+/**
+ * gnome_map_xlat_map2screen: Convert from map coordinates to screen coordinates.
+ * @map: Map to apply dimensions to.
+ * @longitude: Longitude coordinate to convert (in degrees).
+ * @latitude: Latitude coordinate to convert (in degrees).
+ * @sx: Converted screen coordinate.
+ * @sy: Converted screen coordinate.
+ *
+ * A (longitude, latitude) pair is converted to a (x, y) canvas coordinate.
+ * (An obvious improvement to the gnome-map would be to just let the
+ * canvas do the mapping internally. If this change is made this function
+ * will still work but will be a small stub).
+ *
+ * Return value: None.
+ **/
+void
+gnome_map_xlat_map2screen ( GnomeMap *map,
+ double longitude, double latitude,
+ double *sx, double *sy )
+{
+ g_return_if_fail ( map != NULL );
+
+ *sx = (map->width/2.0 + (map->width/2.0)*longitude/180.0);
+ *sy = (map->height/2.0 - (map->height/2.0)*latitude/90.0);
+}
+
+
+/**
+ * gnome_map_xlat_screen2map: Convert from screen coordinates to map coordinates.
+ * @map: Map to apply dimensions to.
+ * @sx: Screen coordinate to convert.
+ * @sy: Screen coordinate to convert.
+ * @longitude: Converted longitude coordinate (in degrees).
+ * @latitude: Converted latitude coordinate (in degrees).
+ *
+ * A (x, y) canvas coordinate is converted to a (longitude, latitude) pair.
+ * (An obvious improvement to the gnome-map would be to just let the
+ * canvas do the mapping internally. If this change is made this function
+ * will still work but will be a small stub).
+ *
+ * Return value: None.
+ **/
+void
+gnome_map_xlat_screen2map ( GnomeMap *map,
+ double sx, double sy,
+ double *longitude, double *latitude)
+{
+ g_return_if_fail ( map != NULL );
+
+ *longitude = ( sx - (double)map->width/2.0)/((double)map->width/2.0)*180.0;
+ *latitude = ((double)map->height/2.0-sy)/((double)map->height/2.0)*90.0;
+}
+
+/**
+ * gnome_map_set_view: Set view of map in map coordinates.
+ * @map: Map to apply dimensions to.
+ * @longitude1: Longitude of corner 1.
+ * @latitude1: Latitude of corner 1.
+ * @longitude2: Longitude of corner 2.
+ * @latitude2: Latitude of corner 2.
+ *
+ * Sets view of map to a box defined by the two corners given in map
+ * coordinates.
+ *
+ * Return value: None.
+ **/
+void
+gnome_map_set_view ( GnomeMap *map,
+ double longitude1, double latitude1,
+ double longitude2, double latitude2)
+{
+ double x1, y1, x2, y2;
+ double scale;
+
+ g_return_if_fail ( map != NULL );
+ g_return_if_fail ( longitude1 >= -180.0 && longitude1 <= 180.0 );
+ g_return_if_fail ( longitude2 >= -180.0 && longitude2 <= 180.0 );
+ g_return_if_fail ( latitude1 >= -90.0 && latitude1 <= 90.0 );
+ g_return_if_fail ( latitude2 >= -90.0 && latitude2 <= 90.0 );
+
+
+ gnome_map_xlat_map2screen (map, longitude1, latitude1, &x1, &y1);
+ gnome_map_xlat_map2screen (map, longitude2, latitude2, &x2, &y2);
+
+ gnome_canvas_set_scroll_region (GNOME_CANVAS(map->canvas),
+ x1, y1, x2, y2);
+
+ if (longitude1 < longitude2) {
+ map->long1 = longitude1;
+ map->long2 = longitude2;
+ } else {
+ map->long1 = longitude2;
+ map->long2 = longitude1;
+ }
+
+ if (latitude1 < latitude2) {
+ map->lat1 = latitude1;
+ map->lat2 = latitude2;
+ } else {
+ map->lat1 = latitude2;
+ map->lat2 = latitude1;
+ }
+
+ scale = ((double)map->width)/fabs(x1-x2);
+ gnome_canvas_set_pixels_per_unit (GNOME_CANVAS(map->canvas), scale);
+
+}
+
+/**
+ * gnome_map_is_loc_in_view: Test to see if location is on current view
+ * @map: Map to apply dimensions to.
+ * @longitude: Longitude of location to test.
+ * @latitude: Latitude of location to test.
+ *
+ * Tests whether (longitude, latitude) is within current map view.
+ *
+ * Return value: TRUE is visible, FALSE if not.
+ **/
+gboolean
+gnome_map_is_loc_in_view (GnomeMap *map, double longitude, double latitude)
+{
+
+ return !(longitude < map->long1 || longitude > map->long2 ||
+ latitude < map->lat1 || latitude > map->lat2);
+}
+
diff --git a/gnome-map/gnome-map.h b/gnome-map/gnome-map.h
new file mode 100644
index 000000000..a0c2e77ce
--- /dev/null
+++ b/gnome-map/gnome-map.h
@@ -0,0 +1,59 @@
+/* GNOME canvas based interface to a map using a simple cylindrical proj */
+/* */
+/* Copyright (C) 1999 Red Hat, Incorportated */
+/* Original work by Michael Fulbright <drmike@redhat.com> */
+
+#ifndef _GNOME_MAP_H_
+#define _GNOME_MAP_H_
+
+struct _GnomeMapStruct {
+ GtkWidget *canvas; /* canvas object used to display map */
+
+ gboolean aa; /* true if antialiased */
+
+ gint width; /* width of canvas in pixels */
+ gint height; /* height of canvas in pixels */
+ double long1; /* long1, lat1 is lower left corner of view */
+ double lat1;
+ double long2; /* long2, lat2 is upper right corner of view */
+ double lat2;
+
+ GdkImlibImage *image; /* actual image data */
+ GnomeCanvasItem *image_item; /* background image canvas object */
+ void *data; /* extra stuff */
+};
+
+typedef struct _GnomeMapStruct GnomeMap;
+
+
+/* create new map */
+GnomeMap *gnome_map_new ( gchar *imagefile,
+ gint width, gint height,
+ gboolean antialias );
+
+/* set background map image used by map */
+/*gint gnome_map_set_image ( GnomeMap *map, gchar *imagefile ); */
+
+/* get original size of map image */
+/*void gnome_map_get_image_size ( GnomeMap *map, gint *width, gint *height ); */
+
+/* set/get size of view in pixels */
+/*void gnome_map_set_size ( GnomeMap *map, gint width, gint height );*/
+void gnome_map_get_size ( GnomeMap *map, gint *width, gint *height );
+
+/* utility functions to go from screen coords to map coords */
+void gnome_map_xlat_map2screen ( GnomeMap *map,
+ double longitude, double latitude,
+ double *sx, double *sy );
+void gnome_map_xlat_screen2map ( GnomeMap *map,
+ double sx, double sy,
+ double *longitude, double *latitude );
+void gnome_map_set_view (GnomeMap *map,
+ double longitude1, double latitude1,
+ double longitude2, double latitude2);
+
+gboolean gnome_map_is_loc_in_view (GnomeMap *map,
+ double longitude, double latitude);
+#endif
+
+
diff --git a/gnome-map/map480.png b/gnome-map/map480.png
new file mode 100644
index 000000000..e41835b77
--- /dev/null
+++ b/gnome-map/map480.png
Binary files differ
diff --git a/gnome-map/pygtk.h b/gnome-map/pygtk.h
new file mode 100644
index 000000000..f43c30131
--- /dev/null
+++ b/gnome-map/pygtk.h
@@ -0,0 +1,334 @@
+/* -*- Mode: C; c-basic-offset: 4 -*- */
+#ifndef _PYGTK_H_
+#define _PYGTK_H_
+
+#include <Python.h>
+#include <gtk/gtk.h>
+
+struct _PyGtk_FunctionStruct {
+ char *pygtkVersion;
+ gboolean fatalExceptions;
+
+ void (* blockThreads)(void);
+ void (* unblockThreads)(void);
+
+ GtkDestroyNotify destroyNotify;
+ GtkCallbackMarshal callbackMarshal;
+ PyObject *(* argsAsTuple)(int nparams, GtkArg *args);
+ int (* argsFromSequence)(GtkArg *args, int nparams, PyObject *seq);
+ int (* argFromPyObject)(GtkArg *arg, PyObject *obj);
+ PyObject *(* argAsPyObject)(GtkArg *arg);
+ void (* retFromPyObject)(GtkArg *ret, PyObject *obj);
+ PyObject *(* retAsPyObject)(GtkArg *ret);
+ GtkArg *(* dictAsGtkArgs)(PyObject *dict, GtkType type, gint *nargs);
+ void (* registerBoxed)(GtkType boxed_type,
+ PyObject *(*from_func)(gpointer boxed),
+ int (*to_func)(gpointer *boxed, PyObject *obj));
+
+ gint (* enum_get_value)(GtkType enum_type, PyObject *obj, int *val);
+ gint (* flag_get_value)(GtkType enum_type, PyObject *obj, int *val);
+
+ PyTypeObject *gtk_type;
+ PyObject *(* gtk_new)(GtkObject *obj);
+
+ PyTypeObject *gtkAccelGroup_type;
+ PyObject *(*gtkAccelGroup_new)(GtkAccelGroup *ag);
+
+ PyTypeObject *gtkStyle_type;
+ PyObject *(* gtkStyle_new)(GtkStyle *style);
+
+ PyTypeObject *gdkFont_type;
+ PyObject *(* gdkFont_new)(GdkFont *font);
+
+ PyTypeObject *gdkColor_type;
+ PyObject *(* gdkColor_new)(GdkColor *colour);
+
+ PyTypeObject *gdkEvent_type;
+ PyObject *(* gdkEvent_new)(GdkEvent *event);
+
+ PyTypeObject *gdkWindow_type;
+ PyObject *(* gdkWindow_new)(GdkWindow *win);
+
+ PyTypeObject *gdkGC_type;
+ PyObject *(* gdkGC_new)(GdkGC *gc);
+
+ PyTypeObject *gdkColormap_type;
+ PyObject *(* gdkColormap_new)(GdkColormap *colourmap);
+
+ PyTypeObject *gdkDragContext_type;
+ PyObject *(* gdkDragContext_new)(GdkDragContext *ctx);
+
+ PyTypeObject *gtkSelectionData_type;
+ PyObject *(* gtkSelectionData_new)(GtkSelectionData *data);
+
+ PyTypeObject *gdkAtom_type;
+ PyObject *(* gdkAtom_new)(GdkAtom atom);
+
+ PyTypeObject *gdkCursor_type;
+ PyObject *(* gdkCursor_new)(GdkCursor *cursor);
+
+ PyTypeObject *gtkCTreeNode_type;
+ PyObject *(* gtkCTreeNode_new)(GtkCTreeNode *node);
+};
+
+/* structure definitions for the various object types in PyGTK */
+typedef struct {
+ PyObject_HEAD
+ GtkObject *obj;
+} PyGtk_Object;
+
+typedef struct {
+ PyObject_HEAD
+ GtkAccelGroup *obj;
+} PyGtkAccelGroup_Object;
+
+typedef struct {
+ PyObject_HEAD
+ GtkStyle *obj;
+} PyGtkStyle_Object;
+
+typedef struct {
+ PyObject_HEAD
+ GdkFont *obj;
+} PyGdkFont_Object;
+
+typedef struct {
+ PyObject_HEAD
+ GdkColor obj;
+} PyGdkColor_Object;
+
+typedef struct {
+ PyObject_HEAD
+ GdkEvent *obj;
+ PyObject *attrs;
+} PyGdkEvent_Object;
+
+typedef struct {
+ PyObject_HEAD
+ GdkWindow *obj;
+} PyGdkWindow_Object;
+
+typedef struct {
+ PyObject_HEAD
+ GdkGC *obj;
+} PyGdkGC_Object;
+
+typedef struct {
+ PyObject_HEAD
+ GdkColormap *obj;
+} PyGdkColormap_Object;
+
+typedef struct {
+ PyObject_HEAD
+ GdkDragContext *obj;
+} PyGdkDragContext_Object;
+
+typedef struct {
+ PyObject_HEAD
+ GtkSelectionData *obj;
+} PyGtkSelectionData_Object;
+
+typedef struct {
+ PyObject_HEAD
+ gchar *name;
+ GdkAtom atom;
+} PyGdkAtom_Object;
+
+typedef struct {
+ PyObject_HEAD
+ GdkCursor *obj;
+} PyGdkCursor_Object;
+
+typedef struct {
+ PyObject_HEAD
+ GtkCTreeNode *node;
+} PyGtkCTreeNode_Object;
+
+/* routines to get the C object value out of the PyObject wrapper */
+#define PyGtk_Get(v) (((PyGtk_Object *)(v))->obj)
+#define PyGtkAccelGroup_Get(v) (((PyGtkAccelGroup_Object *)(v))->obj)
+#define PyGtkStyle_Get(v) (((PyGtkStyle_Object *)(v))->obj)
+#define PyGdkFont_Get(v) (((PyGdkFont_Object *)(v))->obj)
+#define PyGdkColor_Get(v) (&((PyGdkColor_Object *)(v))->obj)
+#define PyGdkEvent_Get(v) (((PyGdkEvent_Object *)(v))->obj)
+#define PyGdkWindow_Get(v) (((PyGdkWindow_Object *)(v))->obj)
+#define PyGdkGC_Get(v) (((PyGdkGC_Object *)(v))->obj)
+#define PyGdkColormap_Get(v) (((PyGdkColormap_Object *)(v))->obj)
+#define PyGdkDragContext_Get(v) (((PyGdkDragContext_Object *)(v))->obj)
+#define PyGtkSelectionData_Get(v) (((PyGtkSelectionData_Object *)(v))->obj)
+#define PyGdkAtom_Get(v) (((PyGdkAtom_Object *)(v))->atom)
+#define PyGdkCursor_Get(v) (((PyGdkCursor_Object *)(v))->obj)
+#define PyGtkCTreeNode_Get(v) (((PyGtkCTreeNode_Object *)(v))->node)
+
+/* this section is dependent on whether we are being included from gtkmodule.c
+ * or not. A similar source level interface should be provided in both
+ * instances. */
+#ifdef _INSIDE_PYGTK_
+staticforward PyTypeObject PyGtk_Type;
+staticforward PyTypeObject PyGtkAccelGroup_Type;
+staticforward PyTypeObject PyGtkStyle_Type;
+staticforward PyTypeObject PyGdkFont_Type;
+staticforward PyTypeObject PyGdkColor_Type;
+staticforward PyTypeObject PyGdkEvent_Type;
+staticforward PyTypeObject PyGdkWindow_Type;
+staticforward PyTypeObject PyGdkGC_Type;
+staticforward PyTypeObject PyGdkColormap_Type;
+staticforward PyTypeObject PyGdkDragContext_Type;
+staticforward PyTypeObject PyGtkSelectionData_Type;
+staticforward PyTypeObject PyGdkAtom_Type;
+staticforward PyTypeObject PyGdkCursor_Type;
+staticforward PyTypeObject PyGtkCTreeNode_Type;
+
+/* check the type of a PyObject */
+#define PyGtk_Check(v) ((v)->ob_type == &PyGtk_Type)
+#define PyGtkAccelGroup_Check(v) ((v)->ob_type == &PyGtkAccelGroup_Type)
+#define PyGtkStyle_Check(v) ((v)->ob_type == &PyGtkStyle_Type)
+#define PyGdkFont_Check(v) ((v)->ob_type == &PyGdkFont_Type)
+#define PyGdkColor_Check(v) ((v)->ob_type == &PyGdkColor_Type)
+#define PyGdkEvent_Check(v) ((v)->ob_type == &PyGdkEvent_Type)
+#define PyGdkWindow_Check(v) ((v)->ob_type == &PyGdkWindow_Type)
+#define PyGdkGC_Check(v) ((v)->ob_type == &PyGdkGC_Type)
+#define PyGdkColormap_Check(v) ((v)->ob_type == &PyGdkColormap_Type)
+#define PyGdkDragContext_Check(v) ((v)->ob_type == &PyGdkDragContext_Type)
+#define PyGtkSelectionData_Check(v) ((v)->ob_type == &PyGtkSelectionData_Type)
+#define PyGdkAtom_Check(v) ((v)->ob_type == &PyGdkAtom_Type)
+#define PyGdkCursor_Check(v) ((v)->ob_type == &PyGdkCursor_Type)
+#define PyGtkCTreeNode_Check(v) ((v)->ob_type == &PyGtkCTreeNode_Type)
+
+/* constructors for PyObject wrappers ... */
+static PyObject *PyGtk_New(GtkObject *obj);
+static PyObject *PyGtkAccelGroup_New(GtkAccelGroup *obj);
+static PyObject *PyGtkStyle_New(GtkStyle *style);
+static PyObject *PyGdkFont_New(GdkFont *font);
+static PyObject *PyGdkColor_New(GdkColor *colour);
+static PyObject *PyGdkEvent_New(GdkEvent *event);
+static PyObject *PyGdkWindow_New(GdkWindow *window);
+static PyObject *PyGdkGC_New(GdkGC *gc);
+static PyObject *PyGdkColormap_New(GdkColormap *colourmap);
+static PyObject *PyGdkDragContext_New(GdkDragContext *ctx);
+static PyObject *PyGtkSelectionData_New(GtkSelectionData *data);
+static PyObject *PyGdkAtom_New(GdkAtom atom);
+static PyObject *PyGdkCursor_New(GdkCursor *cursor);
+static PyObject *PyGtkCTreeNode_New(GtkCTreeNode *node);
+
+/* miscelaneous functions */
+static void PyGtk_BlockThreads(void);
+static void PyGtk_UnblockThreads(void);
+static void PyGtk_DestroyNotify(gpointer data);
+static void PyGtk_CallbackMarshal(GtkObject *o, gpointer d, guint nargs,
+ GtkArg *args);
+static PyObject *GtkArgs_AsTuple(int nparams, GtkArg *args);
+static int GtkArgs_FromSequence(GtkArg *args, int nparams, PyObject *seq);
+static int GtkArg_FromPyObject(GtkArg *arg, PyObject *obj);
+static PyObject *GtkArg_AsPyObject(GtkArg *arg);
+static void GtkRet_FromPyObject(GtkArg *ret, PyObject *py_ret);
+static PyObject *GtkRet_AsPyObject(GtkArg *arg);
+static GtkArg *PyDict_AsGtkArgs(PyObject *dict, GtkType type, gint *nargs);
+
+static void PyGtk_RegisterBoxed(GtkType boxed_type,
+ PyObject *(*fromarg)(gpointer boxed),
+ int (*toarg)(gpointer *boxed, PyObject *obj));
+gint PyGtkEnum_get_value(GtkType enum_type, PyObject *obj, int *val);
+gint PyGtkFlag_get_value(GtkType enum_type, PyObject *obj, int *val);
+
+static gboolean PyGtk_FatalExceptions = FALSE;
+
+#else
+
+/* for multi file extensions, define one of these in all but the main file
+ * of the module */
+#if defined(NO_IMPORT) || defined(NO_IMPORT_PYGTK)
+extern struct _PyGtk_FunctionStruct *_PyGtk_API;
+#else
+struct _PyGtk_FunctionStruct *_PyGtk_API;
+#endif
+
+/* type objects */
+#define PyGtk_Type *(_PyGtk_API->gtk_type)
+#define PyGtkAccelGroup_Type *(_PyGtk_API->gtkAccelGroup_type)
+#define PyGtkStyle_Type *(_PyGtk_API->gtkStyle_type)
+#define PyGdkFont_Type *(_PyGtk_API->gdkFont_type)
+#define PyGdkColor_Type *(_PyGtk_API->gdkColor_type)
+#define PyGdkEvent_Type *(_PyGtk_API->gdkEvent_type)
+#define PyGdkWindow_Type *(_PyGtk_API->gdkWindow_type)
+#define PyGdkGC_Type *(_PyGtk_API->gdkGC_type)
+#define PyGdkColormap_Type *(_PyGtk_API->gdkColormap_type)
+#define PyGdkDragContext_Type *(_PyGtk_API->gdkDragContext_type)
+#define PyGtkSelectionData_Type *(_PyGtk_API->gtkSelectionData_type)
+#define PyGdkAtom_Type *(_PyGtk_API->gdkAtom_type)
+#define PyGdkCursor_Type *(_PyGtk_API->gdkCursor_type)
+#define PyGtkCTreeNode_Type *(_PyGtk_API->gtkCTreeNode_type)
+
+/* type checking routines */
+#define PyGtk_Check(v) ((v)->ob_type == _PyGtk_API->gtk_type)
+#define PyGtkAccelGroup_Check(v) ((v)->ob_type == _PyGtk_API->gtkAccelGroup_type)
+#define PyGtkStyle_Check(v) ((v)->ob_type == _PyGtk_API->gtkStyle_type)
+#define PyGdkFont_Check(v) ((v)->ob_type == _PyGtk_API->gdkFont_type)
+#define PyGdkColor_Check(v) ((v)->ob_type == _PyGtk_API->gdkColor_type)
+#define PyGdkEvent_Check(v) ((v)->ob_type == _PyGtk_API->gdkEvent_type)
+#define PyGdkWindow_Check(v) ((v)->ob_type == _PyGtk_API->gdkWindow_type)
+#define PyGdkGC_Check(v) ((v)->ob_type == _PyGtk_API->gdkGC_type)
+#define PyGdkColormap_Check(v) ((v)->ob_type == _PyGtk_API->gdkColormap_type)
+#define PyGdkDragContext_Check(v) ((v)->ob_type == _PyGtk_API->gdkDragContext_type)
+#define PyGtkSelectionData_Check(v) ((v)->ob_type == _PyGtk_API->gtkSelectionData_type)
+#define PyGdkAtom_Check(v) ((v)->ob_type == _PyGtk_API->gdkAtom_type)
+#define PyGdkCursor_Check(v) ((v)->ob_type == _PyGtk_API->gdkCursor_type)
+#define PyGtkCTreeNode_Check(v) ((v)->ob_type == _PyGtk_API->GtkCTreeNode_type)
+
+/* type objects */
+#define PyGtk_New (_PyGtk_API->gtk_new)
+#define PyGtkAccelGroup_New (_PyGtk_API->gtkAccelGroup_new)
+#define PyGtkStyle_New (_PyGtk_API->gtkStyle_new)
+#define PyGdkFont_New (_PyGtk_API->gdkFont_new)
+#define PyGdkColor_New (_PyGtk_API->gdkColor_new)
+#define PyGdkEvent_New (_PyGtk_API->gdkEvent_new)
+#define PyGdkWindow_New (_PyGtk_API->gdkWindow_new)
+#define PyGdkGC_New (_PyGtk_API->gdkGC_new)
+#define PyGdkColormap_New (_PyGtk_API->gdkColormap_new)
+#define PyGdkDragContext_New (_PyGtk_API->gdkDragContext_new)
+#define PyGtkSelectionData_New (_PyGtk_API->gtkSelectionData_new)
+#define PyGdkAtom_New (_PyGtk_API->gdkAtom_new)
+#define PyGdkCursor_New (_PyGtk_API->gdkCursor_new)
+#define PyGtkCTreeNode_New (_PyGtk_API->gtkCTreeNode_new)
+
+/* miscelaneous other functions */
+#define PyGtk_BlockThreads (_PyGtk_API->blockThreads)
+#define PyGtk_UnblockThreads (_PyGtk_API->unblockThreads)
+#define PyGtk_DestroyNotify (_PyGtk_API->destroyNotify)
+#define PyGtk_CallbackMarshal (_PyGtk_API->callbackMarshal)
+#define GtkArgs_AsTuple (_PyGtk_API->argsAsTuple)
+#define GtkArgs_FromSequence (_PyGtk_API->argsFromSequence)
+#define GtkArg_FromPyObject (_PyGtk_API->argFromPyObject)
+#define GtkArg_AsPyObject (_PyGtk_API->argAsPyObject)
+#define GtkRet_FromPyObject (_PyGtk_API->retFromPyObject)
+#define GtkRet_AsPyObject (_PyGtk_API->retAsPyObject)
+#define PyDict_AsGtkArgs (_PyGtk_API->dictAsGtkArgs)
+#define PyGtk_RegisterBoxed (_PyGtk_API->registerBoxed)
+#define PyGtkEnum_get_value (_PyGtk_API->enum_get_value)
+#define PyGtkFlag_get_value (_PyGtk_API->flag_get_value)
+
+/* some variables */
+#define PyGtk_FatalExceptions (_PyGtk_API->fatalExceptions)
+#define PYGTK_VERSION (_PyGtk_API->pygtkVersion)
+
+/* a function to initialise the pygtk functions */
+#define init_pygtk() { \
+ PyObject *pygtk = PyImport_ImportModule("_gtk"); \
+ if (pygtk != NULL) { \
+ PyObject *module_dict = PyModule_GetDict(pygtk); \
+ PyObject *cobject = PyDict_GetItemString(module_dict, "_PyGtk_API"); \
+ if (PyCObject_Check(cobject)) \
+ _PyGtk_API = PyCObject_AsVoidPtr(cobject); \
+ else { \
+ Py_FatalError("could not find _PyGtk_API object"); \
+ return; \
+ } \
+ } else { \
+ Py_FatalError("could not import _gtk"); \
+ return; \
+ } \
+}
+
+#endif
+
+#endif /* !_PYGTK_H_ */
diff --git a/gnome-map/pytimezone b/gnome-map/pytimezone
new file mode 100755
index 000000000..dc05e7938
--- /dev/null
+++ b/gnome-map/pytimezone
@@ -0,0 +1,40 @@
+#!/usr/bin/python
+
+import timezonemap
+from gtk import *
+import GdkImlib
+from gnome.ui import *
+
+class Map (GnomeCanvas):
+ def __init__ (self, map):
+ self._o = map
+
+class List (GtkScrolledWindow):
+ def __init__ (self, list):
+ self._o = list
+
+class Status (GtkStatusbar):
+ def __init__ (self, bar):
+ self._o = bar
+
+class Option (GtkOptionMenu):
+ def __init__ (self, option):
+ self._o = option
+
+win = GtkWindow()
+vbox = GtkVBox (FALSE, 10)
+
+tz = timezonemap.new ()
+map = Map (tz.map)
+list = List (tz.citylist)
+option = Option (tz.views)
+status = Status (tz.statusbar)
+vbox.pack_start (option, FALSE)
+vbox.pack_start (map, FALSE)
+vbox.pack_start (status, FALSE)
+vbox.pack_start (list)
+win.add (vbox)
+win.show_all ()
+
+mainloop ()
+
diff --git a/gnome-map/testtz.c b/gnome-map/testtz.c
new file mode 100644
index 000000000..e70cbc193
--- /dev/null
+++ b/gnome-map/testtz.c
@@ -0,0 +1,11 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+
+
+int main()
+{
+
+ tzset ();
+ printf ("%s %s %ld %d\n",tzname[0],tzname[1], timezone, daylight);
+}
diff --git a/gnome-map/timezonemapmodule.c b/gnome-map/timezonemapmodule.c
new file mode 100644
index 000000000..33027c177
--- /dev/null
+++ b/gnome-map/timezonemapmodule.c
@@ -0,0 +1,824 @@
+/* Copyright (C) 1999 Red Hat, Inc. */
+/* Original work by Michael Fulbright <drmike@redhat.com> */
+
+#include <gnome.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+
+#include <Python.h>
+
+#include "pygtk.h"
+#include "gnome-map.h"
+#include "gnome-canvas-dot.h"
+#include "timezones.h"
+
+
+/* Command line options */
+/* image - filename of file to use for map (must be PNG for antialias) */
+/* mapwidth - width to scale image to (also size of canvas widget) */
+/* mapheight - height to scale image to (also size of canvas widget) */
+/* aa - if TRUE use antialiased canvas instead of normal */
+
+typedef struct MapData_t {
+ GnomeMap *map;
+ GtkWidget * locationlist;
+ GtkWidget * citylist;
+ GtkWidget * statusbar;
+ GtkWidget * views;
+ gint curselection;
+ GnomeCanvasItem *selmarker;
+ GnomeCanvasItem *curmarker;
+ GnomeCanvasItem **markers;
+ GPtrArray *Locations;
+ GnomeCanvasItem *hiliterubberband;
+ gint hiliteindex;
+} MapData;
+
+/* if TRUE we do not want to act on the select_row events to locationlist */
+/* used when we are manually manipulating rows in locationlist and we */
+/* want to ignore the events going to the callback. */
+gboolean ignore_locationlist_selectevents=FALSE;
+
+/* Canvas item circle for selected location */
+double oldselx, oldsely; /* old location of selection */
+#define SELECTED_COLOR "red"
+#define HILITED_COLOR "limegreen"
+#define CITY_COLOR "yellow"
+
+GnomeMap *WorldMap;
+
+/* view data */
+/* Views are defined by a range of either longitude or latitude */
+/* as well as the central value for the other axis. */
+typedef enum
+{
+ LONGITUDE_CONSTRAINT,
+ LATITUDE_CONSTRAINT
+} ViewContraintType;
+
+struct _VIEW_DEF {
+ gchar *name;
+ ViewContraintType type;
+ double constraint1, constraint2, constraint3;
+};
+
+typedef struct _VIEW_DEF ViewDefinition;
+
+ViewDefinition Views[] = {
+ { "World", LONGITUDE_CONSTRAINT, -180.0, 180.0, 0.0 },
+ { "North America", LONGITUDE_CONSTRAINT, -171.0, -21.0, 40.0 },
+ { "South America", LATITUDE_CONSTRAINT, 15.0, -70.0, -70.0 },
+ { "Pacific Rim", LATITUDE_CONSTRAINT, -47.0, 47.0, 155.0},
+ { "Europe", LONGITUDE_CONSTRAINT, -25.0, 70.0, 45.0 },
+ { "Africa", LATITUDE_CONSTRAINT, 40.0, -40.0, 15.0},
+ { "Asia", LONGITUDE_CONSTRAINT, 20.0, 165.0, 40.0}
+};
+
+static gint numviews = sizeof(Views)/sizeof(ViewDefinition);
+
+static gint item_event (GnomeCanvasItem *item, GdkEvent *event, gpointer data);
+static GtkWidget * create_location_list (MapData *mapdata);
+
+/* give a location name search for match in Locations db */
+/* returns index if found, -1 if not */
+static int
+find_location (GPtrArray *Locations, gchar *locname)
+{
+ TimeZoneLocation *loc;
+ gint i;
+
+ for (i=0; i < Locations->len; i++) {
+ loc = g_ptr_array_index (Locations, i);
+
+ if (!strcmp (loc->zone, locname))
+ return i;
+ }
+
+ return -1;
+}
+
+
+/* find nearest location to specified map coords - clips to current view */
+/* if no match return -1 */
+static int
+find_nearest (GPtrArray * Locations, double longitude, double latitude )
+{
+ double mindist;
+ double dist;
+ double dx, dy;
+ int i, mini;
+ gboolean first=TRUE;
+ TimeZoneLocation *loc;
+
+ mini = -1;
+ for (i=0; i < Locations->len; i++) {
+ loc = g_ptr_array_index (Locations, i);
+
+ if (!gnome_map_is_loc_in_view (WorldMap,
+ loc->longitude, loc->latitude))
+ continue;
+
+ dx = (loc->longitude-longitude);
+ dy = (loc->latitude-latitude);
+ dist = dx*dx + dy*dy;
+
+ if (dist < mindist || first) {
+ mindist = dist;
+ mini = i;
+ first = FALSE;
+ }
+ }
+
+ return mini;
+}
+
+/* attach to signal for canvas items so we can track motion and mouse */
+/* events */
+static void
+setup_item (GnomeCanvasItem *item, MapData *mapdata)
+{
+ gtk_signal_connect (GTK_OBJECT (item), "event",
+ (GtkSignalFunc) item_event,
+ mapdata);
+}
+
+/* Moves marker (a 'x' currently) to the specified location */
+/* and sets it to the specified color. The oldx and oldy */
+/* variables are required because the canvas only allows one */
+/* to do relative moves for items. These are automatically */
+/* set to x and y by this function before it returns. */
+/* */
+/* The first time this function is called for a given marker */
+/* *curmarker should equal NULL. The marker will be created */
+/* automatically. */
+
+static void
+set_flag_marker (MapData *mapdata, gchar *color,
+ double x, double y, double *oldx, double *oldy)
+{
+ GnomeCanvasGroup *canvas_root;
+ GnomeCanvasItem *group;
+
+ g_return_if_fail ( color != NULL );
+
+ canvas_root = gnome_canvas_root (GNOME_CANVAS(WorldMap->canvas));
+ if (!mapdata->curmarker) {
+ group = gnome_canvas_item_new ( canvas_root,
+ gnome_canvas_group_get_type(),
+ "x", x,
+ "y", y,
+ NULL);
+
+#define MARKER_RADIUS 3.5
+#define MARKER_WIDTH_PIX 1
+
+ setup_item (gnome_canvas_item_new (GNOME_CANVAS_GROUP (group),
+ gnome_canvas_text_get_type (),
+ "font", "-adobe-helvetica-bold-r-normal--12-*-72-72-p-*-iso8859-1",
+ "anchor", GTK_ANCHOR_CENTER,
+ "fill_color", "red",
+ "text", "x",
+ NULL), mapdata);
+
+ mapdata->curmarker = GNOME_CANVAS_ITEM (group);
+ } else {
+ gnome_canvas_item_move (mapdata->curmarker, x - *oldx, y - *oldy);
+ }
+
+ *oldx = x;
+ *oldy = y;
+}
+
+/* Given a pointer to a GnomeMap and an index into the Locations db */
+/* mark it as the selected location on the canvas */
+static void
+map_mark_location_selected (GnomeMap *map, gint index)
+{
+ TimeZoneLocation *loc;
+ double selx, sely;
+ MapData *mapdata = (MapData *) map->data;
+
+ g_return_if_fail ( map != NULL );
+ g_return_if_fail ( index >= 0 );
+
+ loc = g_ptr_array_index (mapdata->Locations, index);
+
+ gnome_map_xlat_map2screen ( map,
+ loc->longitude, loc->latitude,
+ &selx, &sely );
+ set_flag_marker (mapdata, SELECTED_COLOR, selx, sely, &oldselx, &oldsely);
+
+ if (mapdata->curselection >= 0) {
+ gnome_canvas_item_set (mapdata->markers[mapdata->curselection],
+ "fill_color", CITY_COLOR, NULL);
+ gnome_canvas_item_show (mapdata->markers[mapdata->curselection]);
+ }
+
+ gnome_canvas_item_hide (mapdata->markers[index]);
+}
+
+/* Given a pointer to a GnomeMap and an index into the Locations db */
+/* mark it as the selected location in the clist of locations */
+/* The jumpto gboolean is used to specify if the clist should be */
+/* forced to scroll to the new location. Used because when the */
+/* clist is autoscrolling we do not want to force selection to be */
+/* constantly recentered. */
+static void
+list_mark_location_selected (GnomeMap *map, gint index, gboolean jumpto)
+{
+ gint newrow;
+ MapData * mapdata;
+
+ mapdata = (MapData *) map->data;
+
+ /* We're messing with list manually, so let callback know to */
+ /* ignore any events till we're done */
+ ignore_locationlist_selectevents = TRUE;
+
+ /* if current selection is visible then select it again, otherwise */
+ /* change clist to not have a current selection */
+ if (index >= 0) {
+ TimeZoneLocation *loc = g_ptr_array_index (mapdata->Locations, index);
+
+ if (gnome_map_is_loc_in_view (map,loc->longitude,loc->latitude)) {
+ gtk_clist_set_selection_mode (GTK_CLIST (mapdata->locationlist),
+ GTK_SELECTION_BROWSE);
+ } else {
+ gtk_clist_set_selection_mode (GTK_CLIST (mapdata->locationlist),
+ GTK_SELECTION_SINGLE);
+ }
+ }
+
+ /* find in list of locations and set as current */
+ newrow = gtk_clist_find_row_from_data (GTK_CLIST (mapdata->locationlist),
+ GINT_TO_POINTER (index));
+
+ if (newrow >= 0 ) {
+ gtk_clist_select_row (GTK_CLIST(mapdata->locationlist), newrow, 0);
+ if (jumpto && gtk_clist_row_is_visible (GTK_CLIST (mapdata->locationlist), newrow) != GTK_VISIBILITY_FULL) {
+ gtk_clist_moveto (GTK_CLIST (mapdata->locationlist), newrow , 0, 0.5, 0.5 );
+ }
+ }
+
+ /* We're done mucking with clist, ok to listen to events again */
+ ignore_locationlist_selectevents = FALSE;
+
+}
+/* handles all canvas drawing for making the selected location # index */
+/* in the sorted list in the Locations variable */
+static void
+set_selection (MapData *mapdata, gint index, gboolean jumpto)
+{
+ g_return_if_fail ( index >= 0 );
+
+ map_mark_location_selected (WorldMap, index);
+
+ list_mark_location_selected (WorldMap, index, jumpto);
+
+ /* NOTE: curselection is global variable. Only place it gets set */
+ mapdata->curselection = index;
+}
+
+/* Given an index into the Locations db and a position, draw the hilite */
+/* marker around it to indicate it is city cursor is pointing at */
+static void
+set_hilited (MapData *mapdata, gint index, double item_x, double item_y)
+{
+ TimeZoneLocation *loc;
+ GnomeCanvasPoints *points;
+
+ g_return_if_fail ( index >= 0 );
+
+ loc = g_ptr_array_index (mapdata->Locations, index);
+
+ points = gnome_canvas_points_new (2);
+ points->coords[0] = item_x;
+ points->coords[1] = item_y;
+ gnome_map_xlat_map2screen ( WorldMap,
+ loc->longitude, loc->latitude,
+ &points->coords[2], &points->coords[3] );
+ if (mapdata->hiliterubberband) {
+ gnome_canvas_item_set (mapdata->hiliterubberband, "points", points, NULL);
+ gnome_canvas_item_show (mapdata->hiliterubberband);
+ } else {
+ GnomeCanvasGroup *canvas_root = gnome_canvas_root (GNOME_CANVAS (WorldMap->canvas));
+
+ mapdata->hiliterubberband =
+ gnome_canvas_item_new (canvas_root,
+ gnome_canvas_line_get_type (),
+ "points", points,
+ "fill_color", HILITED_COLOR,
+ "width_pixels", 2,
+ "first_arrowhead", FALSE,
+ "last_arrowhead", TRUE,
+ "arrow_shape_a", 4.0,
+ "arrow_shape_b", 8.0,
+ "arrow_shape_c", 4.0,
+ NULL);
+ setup_item (mapdata->hiliterubberband, mapdata);
+ }
+
+ /* if hilited city isn't also currently selected city, draw the */
+ /* hilite marker as well */
+ if (index != mapdata->curselection) {
+
+ if (mapdata->hiliteindex >= 0 && mapdata->hiliteindex != index) {
+ if (mapdata->hiliteindex != mapdata->curselection)
+ gnome_canvas_item_set (mapdata->markers[mapdata->hiliteindex],
+ "fill_color", CITY_COLOR,
+ NULL);
+ else
+ gnome_canvas_item_set (mapdata->markers[mapdata->hiliteindex],
+ "fill_color", SELECTED_COLOR,
+ NULL);
+ }
+ mapdata->hiliteindex = index;
+ gtk_statusbar_pop (GTK_STATUSBAR (mapdata->statusbar), 1);
+ gtk_statusbar_push (GTK_STATUSBAR (mapdata->statusbar), 1, loc->zone );
+ }
+
+ gnome_canvas_points_free (points);
+}
+
+/* Handles case where cursor leaves the map */
+static int
+canvas_event (GtkWidget *canvas, GdkEvent *event, gpointer data)
+{
+ MapData *mapdata = (MapData *) data;
+
+ /* if pointer just left canvas, hide hilite marker(s) */
+ if (event->type == GDK_LEAVE_NOTIFY) {
+ if (mapdata->hiliterubberband)
+ gnome_canvas_item_hide (mapdata->hiliterubberband);
+ if (mapdata->hiliteindex >= 0 &&
+ mapdata->hiliteindex != mapdata->curselection)
+ gnome_canvas_item_set (mapdata->markers[mapdata->hiliteindex],
+ "fill_color", CITY_COLOR,
+ NULL);
+
+ }
+ return FALSE;
+}
+
+/* Handles as motion and mouse button events in the map */
+static gint
+item_event (GnomeCanvasItem *item, GdkEvent *event, gpointer data)
+{
+ double longitude, latitude;
+ double item_x, item_y;
+ int nearest;
+ MapData *mapdata = (MapData *) data;
+
+ item_x = event->button.x;
+ item_y = event->button.y;
+ gnome_canvas_item_w2i (WorldMap->image_item, &item_x, &item_y);
+
+ switch (event->type) {
+
+ /* User selected a new location with a left mouse button press */
+ case GDK_BUTTON_PRESS:
+ switch (event->button.button) {
+ case 1:
+
+ gnome_map_xlat_screen2map (WorldMap, item_x, item_y,
+ &longitude, &latitude);
+
+ nearest = find_nearest(mapdata->Locations, longitude, latitude);
+
+ set_selection (mapdata, nearest, TRUE);
+
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ /* highlight city which a button press will select */
+ case GDK_MOTION_NOTIFY:
+
+ gnome_map_xlat_screen2map ( WorldMap, item_x, item_y,
+ &longitude, &latitude);
+
+ nearest = find_nearest(mapdata->Locations, longitude, latitude);
+ set_hilited (mapdata, nearest, item_x, item_y);
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+/* Handles events for the clist of locations */
+static void
+list_select_event ( GtkWidget *clist, gint row, gint column,
+ GdkEventButton *event, gpointer data)
+{
+ gchar *text;
+ gint index;
+ MapData * mapdata = (MapData *) data;
+
+ /* should we do anything? */
+ if (ignore_locationlist_selectevents)
+ return;
+
+ /* msf - always read zero because sometimes col == -1 if they select */
+ /* without a mouse click (ie. keyboard navigation ) */
+ gtk_clist_get_text(GTK_CLIST(clist), row, 0, &text);
+
+ /* Just prints some information about the selected row */
+ g_print("You selected row %d. More specifically you clicked in column %d, and the text in this cell is %s\n\n", row, column, text);
+
+ index = find_location (mapdata->Locations, text);
+ if (index < 0)
+ return;
+
+ set_selection (mapdata, index, FALSE);
+ return;
+}
+
+
+static GnomeCanvasItem *
+draw_city_marker ( GnomeMap *map, double longitude, double latitude)
+{
+ double x, y;
+ GnomeCanvasItem *item;
+ GnomeCanvasGroup *canvas_root;
+ MapData *mapdata = (MapData *) map->data;
+
+ canvas_root = gnome_canvas_root (GNOME_CANVAS (map->canvas));
+
+ gnome_map_xlat_map2screen (map, longitude, latitude, &x, &y);
+
+#define RAD 1
+#ifdef ELLIPSE
+ item = gnome_canvas_item_new (canvas_root,
+ gnome_canvas_ellipse_get_type (),
+ "x1", x-RAD,
+ "y1", y-RAD,
+ "x2", x+RAD,
+ "y2", y+RAD,
+ "fill_color", CITY_COLOR,
+ NULL);
+#else
+ item = gnome_canvas_item_new (canvas_root,
+ gnome_canvas_dot_get_type (),
+ "x", x,
+ "y", y,
+ "diameter_pixels", RAD,
+ "fill_color", CITY_COLOR,
+ NULL);
+#endif
+
+ setup_item (item, mapdata);
+ return item;
+}
+
+static void
+draw_cities (GnomeMap *map)
+{
+ gint i;
+ MapData * mapdata = (MapData *) map->data;
+
+ if (mapdata->markers)
+ g_free(mapdata->markers);
+
+ mapdata->markers = g_new( GnomeCanvasItem *, mapdata->Locations->len);
+ for (i=0; i < mapdata->Locations->len; i++) {
+ TimeZoneLocation *loc = g_ptr_array_index (mapdata->Locations, i);
+
+ mapdata->markers[i] = draw_city_marker (map, loc->longitude, loc->latitude);
+ }
+}
+
+static void
+view_menu_activate (GtkWidget *widget, void *data)
+{
+ static gint curitem = -1;
+ gint item = GPOINTER_TO_INT (data);
+ MapData *mapdata = gtk_object_get_data (GTK_OBJECT (widget), "mapdata");
+
+ double lat1, long1, lat2, long2;
+ double dlat, dlong;
+
+ if ( item == curitem )
+ return;
+
+ curitem = item;
+
+ /* compute aspect correct view and set canvas to it */
+ /* we may have to shift view if it extends outside of map */
+ if (Views[item].type == LONGITUDE_CONSTRAINT) {
+ long1 = Views[item].constraint1;
+ long2 = Views[item].constraint2;
+ dlong = fabs(long2 - long1);
+ dlat = dlong/2.0;
+ lat1 = Views[item].constraint3 - dlat/2.0;
+ lat2 = Views[item].constraint3 + dlat/2.0;
+
+ if (lat1 < -90.0) {
+ lat2 -= (lat1-90.0);
+ lat1 = -90.0;
+ } else if (lat2 > 90.0) {
+ lat1 -= (lat2-90.0);
+ lat2 = 90.0;
+ }
+ } else if (Views[item].type == LATITUDE_CONSTRAINT) {
+ lat1 = Views[item].constraint1;
+ lat2 = Views[item].constraint2;
+ dlat = fabs(lat2 - lat1);
+ dlong = 2.0*dlat;
+ long1 = Views[item].constraint3 - dlong/2.0;
+ long2 = Views[item].constraint3 + dlong/2.0;
+
+ if (long1 < -180.0) {
+ long2 -= (long1-180.0);
+ long1 = -180.0;
+ } else if (long2 > 180.0) {
+ long1 -= (long2-180.0);
+ long2 = 180.0;
+ }
+ } else {
+ g_warning ("Bad contraint type %d in Views structure item # %d.\n",
+ item, Views[item].type);
+ return;
+ }
+
+ gnome_map_set_view (WorldMap, long1, lat1, long2, lat2);
+
+ /* make locationlist clist entries reflect those visible*/
+ create_location_list (mapdata);
+}
+
+GtkWidget *
+create_view_menu (MapData *mapdata)
+{
+ GtkWidget *omenu;
+ GtkWidget *menu;
+ GtkWidget *menu_item;
+ gint i;
+
+ omenu = gtk_option_menu_new ();
+
+ menu = gtk_menu_new ();
+
+ for (i=0; i < numviews; i++) {
+ menu_item = gtk_menu_item_new_with_label (Views[i].name);
+ gtk_menu_append (GTK_MENU (menu), menu_item);
+
+ gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
+ (GtkSignalFunc) view_menu_activate,
+ GINT_TO_POINTER (i));
+
+ gtk_object_set_data (GTK_OBJECT (menu_item), "mapdata", mapdata);
+
+ gtk_widget_show (menu_item);
+ }
+ gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu);
+ gtk_option_menu_set_history (GTK_OPTION_MENU (omenu), 0);
+
+ gtk_widget_show (omenu);
+
+ return omenu;
+}
+
+/* returns pointer to the scrolled window containing the clist */
+/* pointer to clist is returned via the passed argument if it doesnt */
+/* already exist. The list is clipped to the current world view */
+static GtkWidget *
+create_location_list (MapData *mapdata)
+{
+ TimeZoneLocation *loc;
+ GtkWidget *scrolledwin;
+ gchar *titles[] = { "Location", NULL };
+ gchar *row[1];
+ gint i;
+
+ ignore_locationlist_selectevents = TRUE;
+
+ if (! mapdata->locationlist) {
+ scrolledwin = gtk_scrolled_window_new (NULL, NULL);
+
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+
+ gtk_widget_show (scrolledwin);
+
+ mapdata->locationlist = gtk_clist_new_with_titles (1, titles);
+
+ gtk_clist_set_selection_mode (GTK_CLIST(mapdata->locationlist),
+ GTK_SELECTION_BROWSE);
+ gtk_clist_column_title_passive (GTK_CLIST(mapdata->locationlist), 0);
+ gtk_signal_connect(GTK_OBJECT(mapdata->locationlist), "select_row",
+ GTK_SIGNAL_FUNC(list_select_event),
+ mapdata);
+
+ gtk_container_add (GTK_CONTAINER (scrolledwin), mapdata->locationlist);
+ } else {
+ gtk_clist_clear (GTK_CLIST (mapdata->locationlist));
+ scrolledwin = NULL;
+ }
+
+ for (i=0; i < mapdata->Locations->len; i++) {
+ gint newrow;
+
+ loc = g_ptr_array_index (mapdata->Locations, i);
+ if (!gnome_map_is_loc_in_view (WorldMap, loc->longitude, loc->latitude))
+ continue;
+
+ row[0] = loc->zone;
+ newrow = gtk_clist_append (GTK_CLIST (mapdata->locationlist), row);
+ gtk_clist_set_row_data (GTK_CLIST (mapdata->locationlist), newrow,
+ GINT_TO_POINTER (i));
+ }
+
+ /* restore selection of location in list now we've recreated it */
+ list_mark_location_selected(WorldMap, mapdata->curselection, TRUE);
+
+ ignore_locationlist_selectevents = FALSE;
+ return scrolledwin;
+}
+
+MapData * new_mapdata (void)
+{
+ MapData * mapdata;
+ mapdata = g_new0 (MapData, 1);
+
+ /* make a new map view */
+ WorldMap = gnome_map_new ("map480.png", 390, 180, FALSE);
+ if (!WorldMap) {
+ g_warning ("Could not create map view.");
+ exit (1);
+ }
+ WorldMap->data = mapdata;
+ mapdata->map = WorldMap;
+
+ setup_item (WorldMap->image_item, mapdata);
+ gtk_signal_connect (GTK_OBJECT (WorldMap->canvas), "event",
+ (GtkSignalFunc) canvas_event,
+ mapdata);
+
+ /* load timezone data */
+ mapdata->Locations = loadTZDB ();
+ if (!mapdata->Locations) {
+ g_warning (_("Cannot load timezone data"));
+ exit (1);
+ }
+
+ mapdata->citylist = create_location_list (mapdata);
+ draw_cities (WorldMap);
+
+ mapdata->statusbar = gtk_statusbar_new ();
+ mapdata->views = create_view_menu (mapdata);
+
+ return mapdata;
+}
+
+#if 0
+int
+main (int argc, char **argv)
+{
+ GtkWidget *frame;
+ GtkWidget *hbox1, *hbox2;
+ GtkWidget *vbox1, *vbox2;
+ GtkWidget *viewcombo;
+ GtkWidget *statusbar;
+ GtkWidget *aframe;
+ GtkWidget *mainwindow;
+ MapData *mapdata;
+
+ gnome_init ("gglobe", "0.1", argc, argv);
+
+ mapdata = new_mapdata ();
+
+ mainwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_position (GTK_WINDOW (mainwindow), GTK_WIN_POS_CENTER);
+ gtk_window_set_title (GTK_WINDOW (mainwindow), _("gglobe-canvas"));
+
+ gtk_container_add (GTK_CONTAINER (mainwindow), WorldMap->canvas);
+
+ gtk_widget_show (statusbar);
+
+ /* add View combo box */
+ aframe = gtk_frame_new (NULL);
+ gtk_box_pack_start (GTK_BOX (hbox1), frame, FALSE, FALSE, 2);
+
+ vbox2 = gtk_vbox_new (FALSE, 2);
+ gtk_container_add (GTK_CONTAINER (frame), vbox2);
+
+ hbox2 = gtk_hbox_new (FALSE, 2);
+ gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 2);
+
+ viewcombo = create_view_menu (mapdata);
+ gtk_box_pack_start (GTK_BOX (hbox2), gtk_label_new ("View: "),
+ FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox2), viewcombo, FALSE, FALSE, 2);
+
+ /* put cities on the world map */
+
+ /* add list of all timezones */
+ frame = gtk_frame_new (NULL);
+ gtk_box_pack_start (GTK_BOX (vbox2),
+ create_location_list (mapdata),
+ TRUE, TRUE, 2);
+
+ /* display and wait */
+ gtk_widget_show_all (mainwindow);
+
+ /* pick New York City as default */
+ set_selection (mapdata,
+ find_location (mapdata->Locations, "America/New_York"),
+ TRUE);
+
+ gtk_main ();
+
+ return 0;
+}
+
+#endif
+
+static PyMethodDef tzObjectMethods[] = {
+ { NULL },
+};
+
+typedef struct tzObject_t {
+ PyObject_HEAD;
+ MapData * mapdata;
+} tzObject;
+
+/* typedef struct tzObject_t tzObject; */
+
+static PyObject * tzGetAttr(tzObject * o, char * name);
+static void tzDealloc (tzObject * o);
+
+static PyTypeObject tzType = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0, /* ob_size */
+ "timezonemap", /* tp_name */
+ sizeof(tzObject), /* tp_size */
+ 0, /* tp_itemsize */
+ (destructor) tzDealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ (getattrfunc) tzGetAttr, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+};
+
+static PyObject * tzGetAttr(tzObject * o, char * name) {
+ if (!strncmp (name, "map", 3)) {
+ return PyGtk_New((GtkObject *) o->mapdata->map->canvas);
+ }
+ if (!strncmp (name, "citylist", 8)) {
+ return PyGtk_New((GtkObject *) o->mapdata->citylist);
+ }
+ if (!strncmp (name, "statusbar", 9)) {
+ return PyGtk_New((GtkObject *) o->mapdata->statusbar);
+ }
+ if (!strncmp (name, "views", 5)) {
+ return PyGtk_New((GtkObject *) o->mapdata->views);
+ }
+ return Py_FindMethod(tzObjectMethods, (PyObject *) o, name);
+};
+
+static void tzDealloc (tzObject * o)
+{
+ return;
+}
+
+static tzObject * doNewTZ (PyObject * s, PyObject * args);
+
+static PyMethodDef timezoneMethods[] = {
+ { "new", (PyCFunction) doNewTZ, METH_VARARGS, NULL },
+ { NULL },
+};
+
+static tzObject * doNewTZ (PyObject * s, PyObject * args) {
+ tzObject *o;
+
+ o = (tzObject *) PyObject_NEW(tzObject, &tzType);
+
+ o->mapdata = new_mapdata ();
+
+ if (!WorldMap) {
+ PyErr_SetString(PyExc_TypeError, "Could not create map view.");
+ return NULL;
+ }
+
+ return o;
+}
+
+#include <gdk_imlib.h>
+
+void inittimezonemap (void) {
+ init_pygtk();
+
+ Py_InitModule("timezonemap", timezoneMethods);
+}
diff --git a/gnome-map/timezones.c b/gnome-map/timezones.c
new file mode 100644
index 000000000..28830af5f
--- /dev/null
+++ b/gnome-map/timezones.c
@@ -0,0 +1,178 @@
+/* GNOME canvas based interface to a map using a simple cylindrical proj */
+/* */
+/* Copyright (C) 1999 Red Hat, Incorportated */
+/* Original work by Michael Fulbright <drmike@redhat.com> */
+
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <math.h>
+
+#include "timezones.h"
+
+
+TZZoneInfo *
+tzinfo_get_for_location (TimeZoneLocation *loc)
+{
+ TZZoneInfo *tzinfo;
+ gchar *str;
+
+ g_return_val_if_fail (loc != NULL, NULL);
+ g_return_val_if_fail (loc->zone != NULL, NULL);
+
+ str = g_strdup_printf ("TZ=%s", loc->zone);
+ g_print ("%s %s\n",loc->zone, str);
+ putenv (str);
+ tzset ();
+ g_free (str);
+ tzinfo = g_new0 (TZZoneInfo, 1);
+
+ g_print ("%s %s %ld %d\n",tzname[0], tzname[1], timezone, daylight);
+
+ /* Currently this solution doesnt seem to work - I get that */
+ /* America/Phoenix uses daylight savings, which is wrong */
+ tzinfo->tzname_normal = (tzname[0]) ? g_strdup (tzname[0]) : NULL;
+ tzinfo->tzname_daylight = (tzname[1]) ? g_strdup (tzname[1]) : NULL;
+ tzinfo->utc_offset = timezone;
+ tzinfo->daylight = daylight;
+
+ return tzinfo;
+}
+
+void
+tzinfo_free (TZZoneInfo *tzinfo)
+{
+ g_return_if_fail (tzinfo != NULL);
+
+ if (tzinfo->tzname_normal)
+ g_free (tzinfo->tzname_normal);
+ if (tzinfo->tzname_daylight)
+ g_free (tzinfo->tzname_daylight);
+ g_free (tzinfo);
+}
+
+static float
+convertPos( gchar *pos, int digits )
+{
+ gchar whole[10];
+ gchar *fraction;
+ gint i;
+ float t1, t2;
+
+ if (!pos || strlen(pos) < 4 || digits > 9)
+ return 0.0;
+
+ for (i=0; i < digits+1; i++)
+ whole[i] = pos[i];
+ whole[i] = '\0';
+ fraction = pos+digits+1;
+
+ t1 = g_strtod (whole, NULL);
+ t2 = g_strtod (fraction, NULL);
+
+ /* how do I get sign of a float in a portable fashion? */
+ if (t1 >= 0.0 )
+ return t1 + t2/pow (10.0, strlen(fraction));
+ else
+ return t1 - t2/pow (10.0, strlen(fraction));
+
+}
+
+#if 0
+
+/* Currently not working */
+static void
+free_tzdata( TimeZoneLocation *tz)
+{
+
+ if (tz->country)
+ g_free(tz->country);
+ if (tz->zone)
+ g_free(tz->zone);
+ if (tz->comment)
+ g_free(tz->comment);
+
+ g_free(tz);
+}
+#endif
+
+static int
+compare_country_names (const void * a, const void * b)
+{
+ const TimeZoneLocation *tza = * (TimeZoneLocation **) a;
+ const TimeZoneLocation *tzb = * (TimeZoneLocation **) b;
+
+ return strcmp (tza->zone, tzb->zone);
+}
+
+static void
+sort_locations_by_country (GPtrArray *locations)
+{
+ qsort (locations->pdata, locations->len, sizeof (gpointer),
+ compare_country_names);
+}
+
+
+GPtrArray *
+loadTZDB( void )
+{
+ GPtrArray *tzdb;
+ FILE *tzfile;
+ char buf[4096];
+
+ tzfile = fopen (TZ_DATAFILE, "r");
+ if (!tzfile)
+ return NULL;
+
+ tzdb = g_ptr_array_new ();
+
+ while (fgets (buf, sizeof(buf), tzfile)) {
+ gchar **tmpstrarr;
+ gchar *latstr, *lngstr, *p;
+ TimeZoneLocation *loc;
+
+ if (*buf == '#')
+ continue;
+
+ g_strchomp(buf);
+ tmpstrarr = g_strsplit(buf,"\t", 4);
+
+#ifdef DEBUG_ZONEREAD
+ printf ("country code: %s\nlocaton:%s\ntimezone:%s\ncomment:\%s\n",
+ tmpstrarr[0], tmpstrarr[1], tmpstrarr[2], tmpstrarr[3]);
+#endif
+ latstr = g_strdup (tmpstrarr[1]);
+ p = latstr+1;
+ while (*p != '-' && *p != '+')
+ p++;
+ lngstr = g_strdup (p);
+ *p = '\0';
+
+#ifdef DEBUG_ZONEREAD
+ printf ("lat: %s\nlong: %s\n",latstr, lngstr);
+ printf ("lat: %f\nlong: %f\n\n", convertPos (latstr,2), convertPos (lngstr,3));
+#endif
+ loc = g_new( TimeZoneLocation, 1);
+ loc->country = g_strdup(tmpstrarr[0]);
+ loc->zone = g_strdup(tmpstrarr[2]);
+ loc->comment = (tmpstrarr[3]) ? g_strdup(tmpstrarr[3]) : NULL;
+ loc->latitude = convertPos(latstr,2);
+ loc->longitude = convertPos(lngstr,3);
+
+ g_ptr_array_add (tzdb, (gpointer) loc);
+
+ g_free (latstr);
+ g_free (lngstr);
+ g_strfreev (tmpstrarr);
+ }
+
+ fclose (tzfile);
+
+ /* now sort by country */
+ sort_locations_by_country (tzdb);
+
+ return tzdb;
+}
+
diff --git a/gnome-map/timezones.h b/gnome-map/timezones.h
new file mode 100644
index 000000000..d29cc440e
--- /dev/null
+++ b/gnome-map/timezones.h
@@ -0,0 +1,40 @@
+/* GNOME canvas based interface to a map using a simple cylindrical proj */
+/* */
+/* Copyright (C) 1999 Red Hat, Incorportated */
+/* Original work by Michael Fulbright <drmike@redhat.com> */
+
+#ifndef _GNOME_MAP_TIMEZONES_H
+#define _GNOME_MAP_TIMEZONES_H
+
+
+#define TZ_DATAFILE "/usr/share/zoneinfo/zone.tab"
+
+
+struct _TZ_DATA_LOCATION {
+ char *country;
+ float latitude;
+ float longitude;
+ char *zone;
+ char *comment;
+};
+
+typedef struct _TZ_DATA_LOCATION TimeZoneLocation;
+
+/* see the glibc info page information on time zone information */
+/* tzname_normal is the default name for the timezone */
+/* tzname_daylight is the name of the zone when in daylight savings */
+/* utc_offset is offset in seconds from utc */
+/* daylight if non-zero then location obeys daylight savings */
+struct _TZ_ZONE_INFO {
+ char *tzname_normal;
+ char *tzname_daylight;
+ long int utc_offset;
+ int daylight;
+};
+
+typedef struct _TZ_ZONE_INFO TZZoneInfo;
+
+GPtrArray *loadTZDB ( void );
+TZZoneInfo *tzinfo_get_for_location (TimeZoneLocation *loc);
+void tzinfo_free (TZZoneInfo *tzinfo);
+#endif