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