]> git.itanic.dy.fi Git - maemo-mapper/blob - src/main.c
93ed9c26ebb08d301b48c9e3e6daf577b3be42f2
[maemo-mapper] / src / main.c
1 /*
2  * Copyright (C) 2006, 2007 John Costigan.
3  *
4  * POI and GPS-Info code originally written by Cezary Jackiewicz.
5  *
6  * Default map data provided by http://www.openstreetmap.org/
7  *
8  * This file is part of Maemo Mapper.
9  *
10  * Maemo Mapper is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * Maemo Mapper is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Maemo Mapper.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #define _GNU_SOURCE
25
26 #ifdef HAVE_CONFIG_H
27 #    include "config.h"
28 #endif
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h>
33 #include <dbus/dbus-glib.h>
34 #include <locale.h>
35
36 #include <gconf/gconf-client.h>
37 #include <device_symbols.h>
38 #include <conicconnection.h>
39 #include <conicconnectionevent.h>
40
41 #ifndef LEGACY
42 #    include <hildon/hildon-program.h>
43 #    include <hildon/hildon-banner.h>
44 #else
45 #    include <hildon-widgets/hildon-program.h>
46 #    include <hildon-widgets/hildon-banner.h>
47 #endif
48
49 #include "types.h"
50 #include "data.h"
51 #include "defines.h"
52
53 #include "cmenu.h"
54 #include "dbus-ifc.h"
55 #include "display.h"
56 #include "gps.h"
57 #include "gpx.h"
58 #include "input.h"
59 #include "main.h"
60 #include "maps.h"
61 #include "menu.h"
62 #include "path.h"
63 #include "poi.h"
64 #include "settings.h"
65 #include "util.h"
66
67 static void osso_cb_hw_state(osso_hw_state_t *state, gpointer data);
68
69 static HildonProgram *_program = NULL;
70
71 static ConIcConnection *_conic_conn = NULL;
72 static gboolean _conic_is_connecting = FALSE;
73 static gboolean _conic_conn_failed = FALSE;
74 static GMutex *_conic_connection_mutex = NULL;
75 static GCond *_conic_connection_cond = NULL;
76
77 static void
78 conic_conn_event(ConIcConnection *connection, ConIcConnectionEvent *event)
79 {
80     ConIcConnectionStatus status;
81     printf("%s()\n", __PRETTY_FUNCTION__);
82
83     g_mutex_lock(_conic_connection_mutex);
84
85     status = con_ic_connection_event_get_status(event);
86
87     if((_conic_is_connected = (status == CON_IC_CONNECTION_ERROR_NONE)))
88     {
89         /* We're connected. */
90         _conic_conn_failed = FALSE;
91         if(_download_banner != NULL)
92             gtk_widget_show(_download_banner);
93     }
94     else
95     {
96         /* We're not connected. */
97         /* Mark as a failed connection, if we had been trying to connect. */
98         _conic_conn_failed = _conic_is_connecting;
99         if(_download_banner != NULL)
100             gtk_widget_hide(_download_banner);
101     }
102
103     _conic_is_connecting = FALSE; /* No longer trying to connect. */
104     g_cond_broadcast(_conic_connection_cond);
105     g_mutex_unlock(_conic_connection_mutex);
106
107     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
108 }
109
110 void
111 conic_recommend_connected()
112 {
113     printf("%s()\n", __PRETTY_FUNCTION__);
114
115 #ifndef DEBUG
116     g_mutex_lock(_conic_connection_mutex);
117     if(!_conic_is_connecting)
118     {
119         /* Fire up a connection request. */
120         con_ic_connection_connect(_conic_conn, CON_IC_CONNECT_FLAG_NONE);
121         _conic_is_connecting = TRUE;
122     }
123     g_mutex_unlock(_conic_connection_mutex);
124 #endif
125
126     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
127 }
128
129 void
130 conic_ensure_connected()
131 {
132     printf("%s()\n", __PRETTY_FUNCTION__);
133
134 #ifndef DEBUG
135     while(!_conic_is_connected)
136     {   
137         g_mutex_lock(_conic_connection_mutex);
138         /* If we're not connected, and if we're not connecting, and if we're
139          * not in the wake of a connection failure, then try to connect. */
140         if(!_conic_is_connected && !_conic_is_connecting &&!_conic_conn_failed)
141         {
142             /* Fire up a connection request. */
143             con_ic_connection_connect(_conic_conn, CON_IC_CONNECT_FLAG_NONE);
144             _conic_is_connecting = TRUE;
145         }
146         g_cond_wait(_conic_connection_cond, _conic_connection_mutex);
147         g_mutex_unlock(_conic_connection_mutex);
148     }
149 #endif
150
151     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
152 }
153
154 /**
155  * Save state and destroy all non-UI elements created by this program in
156  * preparation for exiting.
157  */
158 static void
159 maemo_mapper_destroy()
160 {
161     printf("%s()\n", __PRETTY_FUNCTION__);
162
163     /* _program and widgets have already been destroyed. */
164     _window = NULL;
165
166     gps_destroy(FALSE);
167
168     path_destroy();
169
170     settings_save();
171
172     poi_destroy();
173
174     g_mutex_lock(_mut_priority_mutex);
175     _mut_priority_tree = g_tree_new((GCompareFunc)mut_priority_comparefunc);
176     g_mutex_unlock(_mut_priority_mutex);
177
178     /* Allow remaining downloads to finish. */
179     g_thread_pool_free(_mut_thread_pool, TRUE, TRUE);
180
181     if(_curr_repo->db)
182     {
183 #ifdef MAPDB_SQLITE
184         g_mutex_lock(_mapdb_mutex);
185         sqlite3_close(_curr_repo->db);
186         _curr_repo->db = NULL;
187         g_mutex_unlock(_mapdb_mutex);
188 #else
189         g_mutex_lock(_mapdb_mutex);
190         gdbm_close(_curr_repo->db);
191         _curr_repo->db = NULL;
192         g_mutex_unlock(_mapdb_mutex);
193 #endif
194     }
195
196     gps_destroy(TRUE);
197
198     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
199 }
200
201 /**
202  * Initialize everything required in preparation for calling gtk_main().
203  */
204 static void
205 maemo_mapper_init(gint argc, gchar **argv)
206 {
207     GtkWidget *hbox, *label, *vbox;
208     printf("%s()\n", __PRETTY_FUNCTION__);
209
210     /* Set enum-based constants. */
211     UNITS_ENUM_TEXT[UNITS_KM] = _("km");
212     UNITS_ENUM_TEXT[UNITS_MI] = _("mi.");
213     UNITS_ENUM_TEXT[UNITS_NM] = _("n.m.");
214
215     ROTATE_DIR_ENUM_TEXT[ROTATE_DIR_UP] = _("Up");
216     ROTATE_DIR_ENUM_TEXT[ROTATE_DIR_RIGHT] = _("Right");
217     ROTATE_DIR_ENUM_TEXT[ROTATE_DIR_DOWN] = _("Down");
218     ROTATE_DIR_ENUM_TEXT[ROTATE_DIR_LEFT] = _("Left");
219
220     UNBLANK_ENUM_TEXT[UNBLANK_WITH_GPS] = "When Receiving Any GPS Data";
221     UNBLANK_ENUM_TEXT[UNBLANK_WHEN_MOVING] = "When Moving";
222     UNBLANK_ENUM_TEXT[UNBLANK_FULLSCREEN] = "When Moving (Full Screen Only)";
223     UNBLANK_ENUM_TEXT[UNBLANK_WAYPOINT] = "When Approaching a Waypoint";
224     UNBLANK_ENUM_TEXT[UNBLANK_NEVER] = "Never";
225
226     INFO_FONT_ENUM_TEXT[INFO_FONT_XXSMALL] = "xx-small";
227     INFO_FONT_ENUM_TEXT[INFO_FONT_XSMALL] = "x-small";
228     INFO_FONT_ENUM_TEXT[INFO_FONT_SMALL] = "small";
229     INFO_FONT_ENUM_TEXT[INFO_FONT_MEDIUM] = "medium";
230     INFO_FONT_ENUM_TEXT[INFO_FONT_LARGE] = "large";
231     INFO_FONT_ENUM_TEXT[INFO_FONT_XLARGE] = "x-large";
232     INFO_FONT_ENUM_TEXT[INFO_FONT_XXLARGE] = "xx-large";
233
234     CUSTOM_KEY_GCONF[CUSTOM_KEY_UP] = GCONF_KEY_PREFIX"/key_up";
235     CUSTOM_KEY_GCONF[CUSTOM_KEY_DOWN] = GCONF_KEY_PREFIX"/key_down";
236     CUSTOM_KEY_GCONF[CUSTOM_KEY_LEFT] = GCONF_KEY_PREFIX"/key_left";
237     CUSTOM_KEY_GCONF[CUSTOM_KEY_RIGHT] = GCONF_KEY_PREFIX"/key_right";
238     CUSTOM_KEY_GCONF[CUSTOM_KEY_SELECT] = GCONF_KEY_PREFIX"/key_select";
239     CUSTOM_KEY_GCONF[CUSTOM_KEY_INCREASE] = GCONF_KEY_PREFIX"/key_increase";
240     CUSTOM_KEY_GCONF[CUSTOM_KEY_DECREASE] = GCONF_KEY_PREFIX"/key_decrease";
241     CUSTOM_KEY_GCONF[CUSTOM_KEY_FULLSCREEN]= GCONF_KEY_PREFIX"/key_fullscreen";
242     CUSTOM_KEY_GCONF[CUSTOM_KEY_ESC] = GCONF_KEY_PREFIX"/key_esc";
243
244     CUSTOM_KEY_ICON[CUSTOM_KEY_UP] = HWK_BUTTON_UP;
245     CUSTOM_KEY_ICON[CUSTOM_KEY_LEFT] = HWK_BUTTON_LEFT;
246     CUSTOM_KEY_ICON[CUSTOM_KEY_DOWN] = HWK_BUTTON_DOWN;
247     CUSTOM_KEY_ICON[CUSTOM_KEY_RIGHT] = HWK_BUTTON_RIGHT;
248     CUSTOM_KEY_ICON[CUSTOM_KEY_SELECT] = HWK_BUTTON_SELECT;
249     CUSTOM_KEY_ICON[CUSTOM_KEY_INCREASE] = HWK_BUTTON_INCREASE;
250     CUSTOM_KEY_ICON[CUSTOM_KEY_DECREASE] = HWK_BUTTON_DECREASE;
251     CUSTOM_KEY_ICON[CUSTOM_KEY_FULLSCREEN] = HWK_BUTTON_VIEW;
252     CUSTOM_KEY_ICON[CUSTOM_KEY_ESC] = HWK_BUTTON_CANCEL;
253
254     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_UP] = CUSTOM_ACTION_RESET_VIEW_ANGLE;
255     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_LEFT] =CUSTOM_ACTION_ROTATE_COUNTERCLOCKWISE;
256     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_DOWN] = CUSTOM_ACTION_TOGGLE_AUTOROTATE;
257     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_RIGHT] = CUSTOM_ACTION_ROTATE_CLOCKWISE;
258     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_SELECT] = CUSTOM_ACTION_TOGGLE_AUTOCENTER;
259     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_INCREASE] = CUSTOM_ACTION_ZOOM_IN;
260     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_DECREASE] = CUSTOM_ACTION_ZOOM_OUT;
261     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_FULLSCREEN]= CUSTOM_ACTION_TOGGLE_FULLSCREEN;
262     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_ESC] = CUSTOM_ACTION_TOGGLE_TRACKS;
263
264     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_PAN_NORTH] = _("Pan North");
265     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_PAN_WEST] = _("Pan West");
266     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_PAN_SOUTH] = _("Pan South");
267     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_PAN_EAST] = _("Pan East");
268     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_PAN_UP] = _("Pan Up");
269     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_PAN_DOWN] = _("Pan Down");
270     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_PAN_LEFT] = _("Pan Left");
271     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_PAN_RIGHT] = _("Pan Right");
272     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_RESET_VIEW_ANGLE]
273         = _("Reset Viewing Angle");
274     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_ROTATE_CLOCKWISE]
275         = _("Rotate View Clockwise");
276     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_ROTATE_COUNTERCLOCKWISE]
277         = _("Rotate View Counter-Clockwise");
278     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_AUTOCENTER]
279         = _("Toggle Auto-Center");
280     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_AUTOROTATE]
281         = _("Toggle Auto-Rotate");
282     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_FULLSCREEN]
283         = _("Toggle Fullscreen");
284     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_ZOOM_IN] = _("Zoom In");
285     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_ZOOM_OUT] = _("Zoom Out");
286     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_TRACKS] = _("Toggle Tracks");
287     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_SCALE] = _("Toggle Scale");
288     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_POI] = _("Toggle POIs");
289     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_CHANGE_REPO]
290         = _("Select Next Repository");
291     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_ROUTE_DISTNEXT]
292         = _("Show Distance to Next Waypoint");
293     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_ROUTE_DISTLAST]
294         = _("Show Distance to End of Route");
295     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TRACK_BREAK]=_("Insert Track Break");
296     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TRACK_CLEAR] = _("Clear Track");
297     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TRACK_DISTLAST]
298         = _("Show Distance from Last Break");
299     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TRACK_DISTFIRST]
300         = _("Show Distance from Beginning");
301     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_GPS] = _("Toggle GPS");
302     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_GPSINFO]=_("Toggle GPS Info");
303     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_SPEEDLIMIT]
304         = _("Toggle Speed Limit");
305     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_RESET_BLUETOOTH]
306         = _("Reset Bluetooth");
307
308     COLORABLE_GCONF[COLORABLE_MARK] = GCONF_KEY_PREFIX"/color_mark";
309     COLORABLE_GCONF[COLORABLE_MARK_VELOCITY]
310         = GCONF_KEY_PREFIX"/color_mark_velocity";
311     COLORABLE_GCONF[COLORABLE_MARK_OLD] = GCONF_KEY_PREFIX"/color_mark_old";
312     COLORABLE_GCONF[COLORABLE_TRACK] = GCONF_KEY_PREFIX"/color_track";
313     COLORABLE_GCONF[COLORABLE_TRACK_MARK] =GCONF_KEY_PREFIX"/color_track_mark";
314     COLORABLE_GCONF[COLORABLE_TRACK_BREAK]
315         = GCONF_KEY_PREFIX"/color_track_break";
316     COLORABLE_GCONF[COLORABLE_ROUTE] = GCONF_KEY_PREFIX"/color_route";
317     COLORABLE_GCONF[COLORABLE_ROUTE_WAY] = GCONF_KEY_PREFIX"/color_route_way";
318     COLORABLE_GCONF[COLORABLE_ROUTE_BREAK]
319         = GCONF_KEY_PREFIX"/color_route_break";
320     COLORABLE_GCONF[COLORABLE_POI] = GCONF_KEY_PREFIX"/color_poi";
321
322     DEG_FORMAT_ENUM_TEXT[DDPDDDDD] = "-dd.ddddd°";
323     DEG_FORMAT_ENUM_TEXT[DD_MMPMMM] = "-dd°mm.mmm'";
324     DEG_FORMAT_ENUM_TEXT[DD_MM_SSPS] = "-dd°mm'ss.s\"";
325     DEG_FORMAT_ENUM_TEXT[DDPDDDDD_NSEW] = "dd.ddddd° S";
326     DEG_FORMAT_ENUM_TEXT[DD_MMPMMM_NSEW] = "dd°mm.mmm' S";
327     DEG_FORMAT_ENUM_TEXT[DD_MM_SSPS_NSEW] = "dd°mm'ss.s\" S";
328     DEG_FORMAT_ENUM_TEXT[NSEW_DDPDDDDD] = "S dd.ddddd°";
329     DEG_FORMAT_ENUM_TEXT[NSEW_DD_MMPMMM] = "S dd° mm.mmm'";
330     DEG_FORMAT_ENUM_TEXT[NSEW_DD_MM_SSPS] = "S dd° mm' ss.s\"";
331
332     SPEED_LOCATION_ENUM_TEXT[SPEED_LOCATION_TOP_LEFT] = _("Top-Left");
333     SPEED_LOCATION_ENUM_TEXT[SPEED_LOCATION_TOP_RIGHT] = _("Top-Right");
334     SPEED_LOCATION_ENUM_TEXT[SPEED_LOCATION_BOTTOM_RIGHT] = _("Bottom-Right");
335     SPEED_LOCATION_ENUM_TEXT[SPEED_LOCATION_BOTTOM_LEFT] = _("Bottom-Left");
336
337     GPS_RCVR_ENUM_TEXT[GPS_RCVR_BT] = _("Bluetooth");
338     GPS_RCVR_ENUM_TEXT[GPS_RCVR_GPSD] = _("GPSD");
339     GPS_RCVR_ENUM_TEXT[GPS_RCVR_FILE] = _("File");
340
341     /* Set up track array (must be done before config). */
342     memset(&_track, 0, sizeof(_track));
343     memset(&_route, 0, sizeof(_route));
344     MACRO_PATH_INIT(_track);
345     MACRO_PATH_INIT(_route);
346
347     _mapdb_mutex = g_mutex_new();
348     _mut_priority_mutex = g_mutex_new();
349     _mouse_mutex = g_mutex_new();
350
351     _conic_connection_mutex = g_mutex_new();
352     _conic_connection_cond = g_cond_new();
353
354     settings_init();
355
356     /* Initialize _program. */
357     _program = HILDON_PROGRAM(hildon_program_get_instance());
358     g_set_application_name("Maemo Mapper");
359
360     /* Initialize _window. */
361     _window = GTK_WIDGET(hildon_window_new());
362     hildon_program_add_window(_program, HILDON_WINDOW(_window));
363
364     /* Lets go fullscreen if so requested in saved config */
365     if (_fullscreen) {
366       gtk_window_fullscreen(GTK_WINDOW(_window));
367     }
368
369     /* Create and add widgets and supporting data. */
370     hbox = gtk_hbox_new(FALSE, 0);
371     gtk_container_add(GTK_CONTAINER(_window), hbox);
372
373     _gps_widget = gtk_frame_new("GPS Info");
374     gtk_container_add(GTK_CONTAINER(_gps_widget),
375             vbox = gtk_vbox_new(FALSE, 0));
376     gtk_widget_set_size_request(GTK_WIDGET(_gps_widget), 180, 0);
377     gtk_box_pack_start(GTK_BOX(hbox), _gps_widget, FALSE, TRUE, 0);
378
379     label = gtk_label_new(" ");
380     gtk_widget_set_size_request(GTK_WIDGET(label), -1, 10);
381     gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
382
383     _text_lat = gtk_label_new(" --- ");
384     gtk_widget_set_size_request(GTK_WIDGET(_text_lat), -1, 30);
385     gtk_box_pack_start(GTK_BOX(vbox), _text_lat, FALSE, TRUE, 0);
386
387     _text_lon = gtk_label_new(" --- ");
388     gtk_widget_set_size_request(GTK_WIDGET(_text_lon), -1, 30);
389     gtk_box_pack_start(GTK_BOX(vbox), _text_lon, FALSE, TRUE, 0);
390
391     _text_speed = gtk_label_new(" --- ");
392     gtk_widget_set_size_request(GTK_WIDGET(_text_speed), -1, 30);
393     gtk_box_pack_start(GTK_BOX(vbox), _text_speed, FALSE, TRUE, 0);
394
395     _text_alt = gtk_label_new(" --- ");
396     gtk_widget_set_size_request(GTK_WIDGET(_text_alt), -1, 30);
397     gtk_box_pack_start(GTK_BOX(vbox), _text_alt, FALSE, TRUE, 0);
398
399     label = gtk_label_new(" ");
400     gtk_widget_set_size_request(GTK_WIDGET(label), -1, 10);
401     gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
402
403     _sat_panel = gtk_drawing_area_new ();
404     gtk_widget_set_size_request (_sat_panel, -1, 100);
405     gtk_box_pack_start(GTK_BOX(vbox), _sat_panel, TRUE, TRUE, 0);
406
407     label = gtk_label_new(" ");
408     gtk_widget_set_size_request(GTK_WIDGET(label), -1, 10);
409     gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
410
411     _text_time = gtk_label_new("--:--:--");
412     gtk_widget_set_size_request(GTK_WIDGET(_text_time), -1, 30);
413     gtk_box_pack_start(GTK_BOX(vbox), _text_time, FALSE, TRUE, 0);
414
415     _heading_panel = gtk_drawing_area_new ();
416     gtk_widget_set_size_request (_heading_panel, -1, 100);
417     gtk_box_pack_start(GTK_BOX(vbox), _heading_panel, TRUE, TRUE, 0);
418
419     _map_widget = gtk_drawing_area_new();
420
421     gtk_box_pack_start(GTK_BOX(hbox), _map_widget, TRUE, TRUE, 0);
422
423     gtk_widget_show_all(hbox);
424     gps_show_info(); /* hides info, if necessary. */
425
426     gtk_widget_realize(_map_widget);
427
428     /* Tweak the foreground and background colors a little bit... */
429     {
430         GdkColor color;
431         GdkGCValues values;
432         GdkColormap *colormap = gtk_widget_get_colormap(_map_widget);
433
434         gdk_gc_get_values(
435                 _map_widget->style->fg_gc[GTK_STATE_NORMAL],
436                 &values);
437         gdk_colormap_query_color(colormap, values.foreground.pixel, &color);
438         gtk_widget_modify_fg(_map_widget, GTK_STATE_ACTIVE, &color);
439
440         gdk_gc_get_values(
441                 _map_widget->style->bg_gc[GTK_STATE_NORMAL],
442                 &values);
443         gdk_colormap_query_color(colormap, values.foreground.pixel, &color);
444         gtk_widget_modify_bg(_map_widget, GTK_STATE_ACTIVE, &color);
445
446         /* Use a black background for _map_widget, since missing tiles are
447          * also drawn with a black background. */
448         color.red = 0; color.green = 0; color.blue = 0;
449         gtk_widget_modify_bg(_map_widget,
450                 GTK_STATE_NORMAL, &color);
451     }
452
453     _map_pixmap = gdk_pixmap_new(_map_widget->window, 1, 1, -1);
454     /* -1: use bit depth of widget->window. */
455
456     _map_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, 1, 1);
457
458     _mut_exists_table = g_hash_table_new(
459             (GHashFunc)mut_exists_hashfunc, (GEqualFunc)mut_exists_equalfunc);
460     _mut_priority_tree = g_tree_new((GCompareFunc)mut_priority_comparefunc);
461
462     _mut_thread_pool = g_thread_pool_new(
463             (GFunc)thread_proc_mut, NULL, NUM_DOWNLOAD_THREADS, FALSE, NULL);
464     _mrt_thread_pool = g_thread_pool_new(
465             (GFunc)thread_render_map, NULL, 1, FALSE, NULL);
466
467     /* Connect signals. */
468     g_signal_connect(G_OBJECT(_window), "destroy",
469             G_CALLBACK(gtk_main_quit), NULL);
470
471     memset(&_autoroute_data, 0, sizeof(_autoroute_data));
472
473     latlon2unit(_gps.lat, _gps.lon, _pos.unitx, _pos.unity);
474
475     /* Initialize our line styles. */
476     update_gcs();
477
478     menu_init();
479     cmenu_init();
480     path_init();
481     gps_init();
482     input_init();
483     poi_db_connect();
484     display_init();
485     dbus_ifc_init();
486
487     /* If present, attempt to load the file specified on the command line. */
488     if(argc > 1)
489     {
490         GnomeVFSResult vfs_result;
491         gint size;
492         gchar *buffer;
493         gchar *file_uri;
494
495         /* Get the selected filename. */
496         file_uri = gnome_vfs_make_uri_from_shell_arg(argv[1]);
497
498         if(GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(
499                         file_uri, &size, &buffer)))
500         {
501             gchar buffer[BUFFER_SIZE];
502             snprintf(buffer, sizeof(buffer),
503                     "%s:\n%s", _("Failed to open file for reading"),
504                     gnome_vfs_result_to_string(vfs_result));
505             popup_error(_window, buffer);
506         }
507         else
508         {
509             if(gpx_path_parse(&_route, buffer, size, 0))
510             {
511                 path_save_route_to_db();
512                 MACRO_BANNER_SHOW_INFO(_window, _("Route Opened"));
513             }
514             else
515                 popup_error(_window, _("Error parsing GPX file."));
516             g_free(buffer);
517         }
518         g_free(file_uri);
519     }
520
521     /* If we have a route, calculate the next point. */
522     route_find_nearest_point();
523
524     _conic_conn = con_ic_connection_new();
525     g_object_set(_conic_conn, "automatic-connection-events", TRUE, NULL);
526     g_signal_connect(G_OBJECT(_conic_conn), "connection-event",
527             G_CALLBACK(conic_conn_event), NULL);
528
529     g_idle_add((GSourceFunc)window_present, NULL);
530
531
532     osso_hw_set_event_cb(_osso, NULL, osso_cb_hw_state, NULL);
533
534     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
535 }
536
537 static gboolean
538 osso_cb_hw_state_idle(osso_hw_state_t *state)
539 {
540     static gboolean _must_save_data = FALSE;
541     printf("%s(inact=%d, save=%d, shut=%d, memlow=%d, state=%d)\n",
542             __PRETTY_FUNCTION__, state->system_inactivity_ind,
543             state->save_unsaved_data_ind, state->shutdown_ind,
544             state->memory_low_ind, state->sig_device_mode_ind);
545
546     if(state->save_unsaved_data_ind)
547     {
548         settings_save();
549         _must_save_data = TRUE;
550     }
551     else if(state->shutdown_ind)
552     {
553         maemo_mapper_destroy();
554         exit(1);
555     }
556
557     g_free(state);
558
559     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
560     return FALSE;
561 }
562
563 static void
564 osso_cb_hw_state(osso_hw_state_t *state, gpointer data)
565 {
566     printf("%s()\n", __PRETTY_FUNCTION__);
567     osso_hw_state_t *state_copy = g_new(osso_hw_state_t, 1);
568     memcpy(state_copy, state, sizeof(osso_hw_state_t));
569     g_idle_add((GSourceFunc)osso_cb_hw_state_idle, state_copy);
570     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
571 }
572
573 gint
574 main(gint argc, gchar *argv[])
575 {
576     printf("%s()\n", __PRETTY_FUNCTION__);
577
578     /* Initialize localization. */
579     setlocale(LC_ALL, "");
580     bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
581     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
582     textdomain(GETTEXT_PACKAGE);
583
584     g_thread_init(NULL);
585
586     /* Initialize _osso. */
587     _osso = osso_initialize("com.gnuite.maemo_mapper", VERSION, TRUE, NULL);
588     if(!_osso)
589     {
590         g_printerr("osso_initialize failed.\n");
591         return 1;
592     }
593
594     gtk_init(&argc, &argv);
595
596     /* Init gconf. */
597     g_type_init();
598     gconf_init(argc, argv, NULL);
599
600     /* Init Gnome-VFS. */
601     gnome_vfs_init();
602
603 #ifdef DEBUG
604     /* This is just some helpful DBUS testing code. */
605     if(argc >= 3)
606     {
607         /* Try to set the center to a new lat/lon. */
608         GError *error = NULL;
609         gchar *error_check;
610         gdouble lat, lon;
611         DBusGConnection *bus;
612         DBusGProxy *proxy;
613         
614         bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
615         if(!bus || error)
616         {
617             g_printerr("Error: %s\n", error->message);
618             return -1;
619         }
620
621         proxy = dbus_g_proxy_new_for_name(bus,
622                         MM_DBUS_SERVICE, MM_DBUS_PATH, MM_DBUS_INTERFACE);
623
624         lat = g_ascii_strtod((argv[1]), &error_check);
625         if(error_check == argv[1])
626         {
627             g_printerr("Failed to parse string as float: %s\n", argv[1]);
628             return 1;
629         }
630
631         lon = g_ascii_strtod((argv[2]), &error_check);
632         if(error_check == argv[2])
633         {
634             g_printerr("Failed to parse string as float: %s\n", argv[2]);
635             return 2;
636         }
637
638         error = NULL;
639         if(argc >= 4)
640         {
641             /* We are specifying a zoom. */
642             gint zoom;
643
644             zoom = g_ascii_strtod((argv[3]), &error_check);
645             if(error_check == argv[3])
646             {
647                 g_printerr("Failed to parse string as integer: %s\n", argv[3]);
648                 return 3;
649             }
650             if(!dbus_g_proxy_call(proxy, MM_DBUS_METHOD_SET_VIEW_POSITION,
651                         &error,
652                         G_TYPE_DOUBLE, lat, G_TYPE_DOUBLE, lon,
653                         G_TYPE_INT, zoom, G_TYPE_INVALID,
654                         G_TYPE_INVALID)
655                     || error)
656             {
657                 g_printerr("Error: %s\n", error->message);
658                 return 4;
659             }
660         }
661         else
662         {
663             /* Not specifying a zoom. */
664             if(!dbus_g_proxy_call(proxy, MM_DBUS_METHOD_SET_VIEW_POSITION,
665                         &error,
666                         G_TYPE_DOUBLE, lat, G_TYPE_DOUBLE, lon, G_TYPE_INVALID,
667                         G_TYPE_INVALID)
668                     || error)
669             {
670                 g_printerr("Error: %s\n", error->message);
671                 return -2;
672             }
673         }
674
675         g_object_unref(proxy);
676         dbus_g_connection_unref(bus);
677
678         return 0;
679     }
680 #endif
681
682     maemo_mapper_init(argc, argv);
683
684     gtk_main();
685
686     maemo_mapper_destroy();
687
688     osso_deinitialize(_osso);
689
690     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
691     exit(0);
692 }
693