]> git.itanic.dy.fi Git - maemo-mapper/blob - src/main.c
Added basic APRS support - Can be disabled by removing definition of INCLUDE_APRS
[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
38 #ifdef MAEMO_CHANGES /* probably not the best macro to check for here */
39 #    include <device_symbols.h>
40 #endif
41
42 #ifdef CONIC
43 #    include <conicconnection.h>
44 #    include <conicconnectionevent.h>
45 #endif
46
47 #ifndef LEGACY
48 #    include <hildon/hildon-program.h>
49 #    include <hildon/hildon-banner.h>
50 #else
51 #    include <hildon-widgets/hildon-program.h>
52 #    include <hildon-widgets/hildon-banner.h>
53 #endif
54
55 #include "types.h"
56 #include "data.h"
57 #include "defines.h"
58
59 #include "cmenu.h"
60 #include "dbus-ifc.h"
61 #include "display.h"
62 #include "gps.h"
63 #include "aprs.h"
64 #include "gpx.h"
65 #include "input.h"
66 #include "main.h"
67 #include "maps.h"
68 #include "menu.h"
69 #include "path.h"
70 #include "poi.h"
71 #include "settings.h"
72 #include "util.h"
73
74 static void osso_cb_hw_state(osso_hw_state_t *state, gpointer data);
75
76 static HildonProgram *_program = NULL;
77
78 #ifdef CONIC
79 static ConIcConnection *_conic_conn = NULL;
80 static gboolean _conic_is_connecting = FALSE;
81 static gboolean _conic_conn_failed = FALSE;
82 static GMutex *_conic_connection_mutex = NULL;
83 static GCond *_conic_connection_cond = NULL;
84 #endif
85
86 /* Dynamically-sized in-memory map cache. */
87 static size_t _map_cache_size = (32*1024*1024);
88 static gboolean _map_cache_enabled = TRUE;
89
90 #ifdef CONIC
91 static void
92 conic_conn_event(ConIcConnection *connection, ConIcConnectionEvent *event)
93 {
94     ConIcConnectionStatus status;
95     printf("%s()\n", __PRETTY_FUNCTION__);
96
97     g_mutex_lock(_conic_connection_mutex);
98
99     status = con_ic_connection_event_get_status(event);
100
101     if((_conic_is_connected = (status == CON_IC_STATUS_CONNECTED)))
102     {
103         /* We're connected. */
104         _conic_conn_failed = FALSE;
105         if(_download_banner != NULL)
106             gtk_widget_show(_download_banner);
107     }
108     else
109     {
110         /* We're not connected. */
111         /* Mark as a failed connection, if we had been trying to connect. */
112         _conic_conn_failed = _conic_is_connecting;
113         if(_download_banner != NULL)
114             gtk_widget_hide(_download_banner);
115     }
116
117     _conic_is_connecting = FALSE; /* No longer trying to connect. */
118     g_cond_broadcast(_conic_connection_cond);
119     g_mutex_unlock(_conic_connection_mutex);
120
121     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
122 }
123 #endif
124
125 void
126 conic_recommend_connected()
127 {
128     printf("%s()\n", __PRETTY_FUNCTION__);
129
130 #if defined(__arm__) && defined(CONIC)
131     g_mutex_lock(_conic_connection_mutex);
132     if(!_conic_is_connecting)
133     {
134         /* Fire up a connection request. */
135         con_ic_connection_connect(_conic_conn, CON_IC_CONNECT_FLAG_NONE);
136         _conic_is_connecting = TRUE;
137     }
138     g_mutex_unlock(_conic_connection_mutex);
139 #endif
140
141     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
142 }
143
144 gboolean
145 conic_ensure_connected()
146 {
147     printf("%s()\n", __PRETTY_FUNCTION__);
148
149 #if defined(__arm__) && defined(CONIC)
150     while(_window && !_conic_is_connected)
151     {   
152         g_mutex_lock(_conic_connection_mutex);
153         /* If we're not connected, and if we're not connecting, and if we're
154          * not in the wake of a connection failure, then try to connect. */
155         if(!_conic_is_connected && !_conic_is_connecting &&!_conic_conn_failed)
156         {
157             /* Fire up a connection request. */
158             con_ic_connection_connect(_conic_conn, CON_IC_CONNECT_FLAG_NONE);
159             _conic_is_connecting = TRUE;
160         }
161         g_cond_wait(_conic_connection_cond, _conic_connection_mutex);
162         g_mutex_unlock(_conic_connection_mutex);
163     }
164 #else
165     _conic_is_connected = TRUE;
166 #endif
167
168     vprintf("%s(): return %d\n", __PRETTY_FUNCTION__,
169             _window && _conic_is_connected);
170     return _window && _conic_is_connected;
171 }
172
173 /**
174  * Save state and destroy all non-UI elements created by this program in
175  * preparation for exiting.
176  */
177 static void
178 maemo_mapper_destroy()
179 {
180     printf("%s()\n", __PRETTY_FUNCTION__);
181
182     /* _program and widgets have already been destroyed. */
183     _window = NULL;
184
185     gps_destroy(FALSE);
186
187     path_destroy();
188
189     settings_save();
190
191     poi_destroy();
192
193     g_mutex_lock(_mut_priority_mutex);
194     _mut_priority_tree = g_tree_new((GCompareFunc)mut_priority_comparefunc);
195     g_mutex_unlock(_mut_priority_mutex);
196
197     /* Allow remaining downloads to finish. */
198 #ifdef CONIC
199     g_mutex_lock(_conic_connection_mutex);
200     g_cond_broadcast(_conic_connection_cond);
201     g_mutex_unlock(_conic_connection_mutex);
202 #endif
203     g_thread_pool_free(_mut_thread_pool, TRUE, TRUE);
204
205     if(_curr_repo->db)
206     {
207         RepoData* repo_p;
208 #ifdef MAPDB_SQLITE
209         g_mutex_lock(_mapdb_mutex);
210         sqlite3_close(_curr_repo->db);
211         _curr_repo->db = NULL;
212         g_mutex_unlock(_mapdb_mutex);
213 #else
214         g_mutex_lock(_mapdb_mutex);
215         repo_p = _curr_repo;
216         while (repo_p) {
217             if (repo_p->db) {
218 /*                 /\* perform reorganization for layers which are auto refreshed *\/ */
219 /*                 if (repo_p->layer_level && repo_p->layer_refresh_interval) */
220 /*                     gdbm_reorganize (repo_p->db); */
221                 gdbm_close(repo_p->db);
222             }
223             repo_p->db = NULL;
224             repo_p = repo_p->layers;
225         }
226         g_mutex_unlock(_mapdb_mutex);
227 #endif
228     }
229     map_cache_destroy();
230
231     gps_destroy(TRUE);
232
233     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
234 }
235
236 // Called once per second
237 gboolean timer_callback (gpointer data) {
238         
239 #ifdef INCLUDE_APRS
240         static int inet_beacon_count = 0;
241         static int inet_aprs_filter = 0;
242         static int tty_beacon_count = 0;
243         
244         if(_aprs_enable)
245         {
246                 // Check if we need to resent the filter every 5 minutes
247                 // Note - this should really be dependent on speed and/or range
248                 if(_aprs_inet_enable && inet_aprs_filter > (60*5))
249                 {
250                         // Currently this only needs to be sent on connection
251                         //update_aprs_inet_options(FALSE);
252                         inet_aprs_filter = 0;
253                 }
254                 
255                 if(_aprs_inet_enable && _aprs_enable_inet_tx && _aprs_inet_beacon_interval > 0 && _aprs_inet_state      == RCVR_UP)
256                 {
257                         
258                         
259                         if(inet_beacon_count >= _aprs_inet_beacon_interval)
260                         {
261                                 // Send inet APRS beacon
262                                 aprs_send_beacon(APRS_PORT_INET);
263                                 //g_idle_add((GSourceFunc)aprs_send_beacon, APRS_PORT_INET);
264                                 //fprintf(stderr, "timer %u, %u\n", inet_beacon_count, _aprs_inet_beacon_interval);
265                                 inet_beacon_count = 0;
266                         }
267                         
268                 }
269                 
270                 if(_aprs_tty_enable && _aprs_enable_tty_tx )
271                 {
272                         // Send tty APRS beacon
273                         
274                         if(tty_beacon_count >= _aprs_tty_beacon_interval && _aprs_tty_beacon_interval > 0)
275                         {
276                                 // Send inet APRS beacon
277                                 aprs_send_beacon(APRS_PORT_TTY);
278                                 
279                                 //g_idle_add((GSourceFunc)aprs_send_beacon_inet, NULL);
280                                 
281                                 tty_beacon_count = 0;
282                         }
283
284                 }
285                 
286
287                 inet_aprs_filter++;
288                 inet_beacon_count++;
289                 tty_beacon_count++;
290         }
291 #endif //INCLUDE_APRS
292         
293         return TRUE; // Continue timer
294 }
295
296 // Start a one second timer - this can be used to execute any periodic tasks 
297 void timer_init()
298 {
299         g_timeout_add(1000 , timer_callback, NULL);
300 }
301
302 /**
303  * Initialize everything required in preparation for calling gtk_main().
304  */
305 static void
306 maemo_mapper_init(gint argc, gchar **argv)
307 {
308     GtkWidget *hbox, *label, *vbox;
309     printf("%s()\n", __PRETTY_FUNCTION__);
310
311     /* Set enum-based constants. */
312     UNITS_ENUM_TEXT[UNITS_KM] = _("km");
313     UNITS_ENUM_TEXT[UNITS_MI] = _("mi.");
314     UNITS_ENUM_TEXT[UNITS_NM] = _("n.m.");
315
316     ROTATE_DIR_ENUM_TEXT[ROTATE_DIR_UP] = _("Up");
317     ROTATE_DIR_ENUM_TEXT[ROTATE_DIR_RIGHT] = _("Right");
318     ROTATE_DIR_ENUM_TEXT[ROTATE_DIR_DOWN] = _("Down");
319     ROTATE_DIR_ENUM_TEXT[ROTATE_DIR_LEFT] = _("Left");
320
321     UNBLANK_ENUM_TEXT[UNBLANK_WITH_GPS] = _("When Receiving Any GPS Data");
322     UNBLANK_ENUM_TEXT[UNBLANK_WHEN_MOVING] = _("When Moving");
323     UNBLANK_ENUM_TEXT[UNBLANK_FULLSCREEN] = _("When Moving (Full Screen Only)");
324     UNBLANK_ENUM_TEXT[UNBLANK_WAYPOINT] = _("When Approaching a Waypoint");
325     UNBLANK_ENUM_TEXT[UNBLANK_NEVER] = _("Never");
326
327     INFO_FONT_ENUM_TEXT[INFO_FONT_XXSMALL] = "xx-small";
328     INFO_FONT_ENUM_TEXT[INFO_FONT_XSMALL] = "x-small";
329     INFO_FONT_ENUM_TEXT[INFO_FONT_SMALL] = "small";
330     INFO_FONT_ENUM_TEXT[INFO_FONT_MEDIUM] = "medium";
331     INFO_FONT_ENUM_TEXT[INFO_FONT_LARGE] = "large";
332     INFO_FONT_ENUM_TEXT[INFO_FONT_XLARGE] = "x-large";
333     INFO_FONT_ENUM_TEXT[INFO_FONT_XXLARGE] = "xx-large";
334
335 #ifdef MAEMO_CHANGES /* probably not the best macro to check for here */
336     CUSTOM_KEY_ICON[CUSTOM_KEY_UP] = HWK_BUTTON_UP;
337     CUSTOM_KEY_ICON[CUSTOM_KEY_LEFT] = HWK_BUTTON_LEFT;
338     CUSTOM_KEY_ICON[CUSTOM_KEY_DOWN] = HWK_BUTTON_DOWN;
339     CUSTOM_KEY_ICON[CUSTOM_KEY_RIGHT] = HWK_BUTTON_RIGHT;
340     CUSTOM_KEY_ICON[CUSTOM_KEY_SELECT] = HWK_BUTTON_SELECT;
341     CUSTOM_KEY_ICON[CUSTOM_KEY_INCREASE] = HWK_BUTTON_INCREASE;
342     CUSTOM_KEY_ICON[CUSTOM_KEY_DECREASE] = HWK_BUTTON_DECREASE;
343     CUSTOM_KEY_ICON[CUSTOM_KEY_FULLSCREEN] = HWK_BUTTON_VIEW;
344     CUSTOM_KEY_ICON[CUSTOM_KEY_ESC] = HWK_BUTTON_CANCEL;
345 #else
346     CUSTOM_KEY_ICON[CUSTOM_KEY_UP] = "Up";
347     CUSTOM_KEY_ICON[CUSTOM_KEY_LEFT] = "Left";
348     CUSTOM_KEY_ICON[CUSTOM_KEY_DOWN] = "Down";
349     CUSTOM_KEY_ICON[CUSTOM_KEY_RIGHT] = "Right";
350     CUSTOM_KEY_ICON[CUSTOM_KEY_SELECT] = "Enter";
351     CUSTOM_KEY_ICON[CUSTOM_KEY_INCREASE] = "F7";
352     CUSTOM_KEY_ICON[CUSTOM_KEY_DECREASE] = "F8";
353     CUSTOM_KEY_ICON[CUSTOM_KEY_FULLSCREEN] = "F6";
354     CUSTOM_KEY_ICON[CUSTOM_KEY_ESC] = "Esc";
355 #endif
356
357     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_UP] = CUSTOM_ACTION_RESET_VIEW_ANGLE;
358     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_LEFT] =CUSTOM_ACTION_ROTATE_COUNTERCLOCKWISE;
359     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_DOWN] = CUSTOM_ACTION_TOGGLE_AUTOROTATE;
360     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_RIGHT] = CUSTOM_ACTION_ROTATE_CLOCKWISE;
361     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_SELECT] = CUSTOM_ACTION_TOGGLE_AUTOCENTER;
362     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_INCREASE] = CUSTOM_ACTION_ZOOM_IN;
363     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_DECREASE] = CUSTOM_ACTION_ZOOM_OUT;
364     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_FULLSCREEN]= CUSTOM_ACTION_TOGGLE_FULLSCREEN;
365     CUSTOM_KEY_DEFAULT[CUSTOM_KEY_ESC] = CUSTOM_ACTION_TOGGLE_TRACKS;
366
367     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_PAN_NORTH] = _("Pan North");
368     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_PAN_WEST] = _("Pan West");
369     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_PAN_SOUTH] = _("Pan South");
370     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_PAN_EAST] = _("Pan East");
371     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_PAN_UP] = _("Pan Up");
372     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_PAN_DOWN] = _("Pan Down");
373     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_PAN_LEFT] = _("Pan Left");
374     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_PAN_RIGHT] = _("Pan Right");
375     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_RESET_VIEW_ANGLE]
376         = _("Reset Viewing Angle");
377     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_ROTATE_CLOCKWISE]
378         = _("Rotate View Clockwise");
379     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_ROTATE_COUNTERCLOCKWISE]
380         = _("Rotate View Counter-Clockwise");
381     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_AUTOCENTER]
382         = _("Toggle Auto-Center");
383     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_AUTOROTATE]
384         = _("Toggle Auto-Rotate");
385     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_FULLSCREEN]
386         = _("Toggle Fullscreen");
387     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_ZOOM_IN] = _("Zoom In");
388     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_ZOOM_OUT] = _("Zoom Out");
389     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_TRACKING]
390         = _("Toggle Tracking");
391     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_TRACKS]
392         = _("Toggle Tracks/Routes");
393     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_SCALE] = _("Toggle Scale");
394     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_POI] = _("Toggle POIs");
395     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_CHANGE_REPO]
396         = _("Select Next Repository");
397     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_ROUTE_DISTNEXT]
398         = _("Show Distance to Next Waypoint");
399     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_ROUTE_DISTLAST]
400         = _("Show Distance to End of Route");
401     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TRACK_BREAK]=_("Insert Track Break");
402     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TRACK_CLEAR] = _("Clear Track");
403     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TRACK_DISTLAST]
404         = _("Show Distance from Last Break");
405     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TRACK_DISTFIRST]
406         = _("Show Distance from Beginning");
407     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_GPS] = _("Toggle GPS");
408     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_GPSINFO]=_("Toggle GPS Info");
409     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_SPEEDLIMIT]
410         = _("Toggle Speed Limit");
411     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_RESET_BLUETOOTH]
412         = _("Reset Bluetooth");
413     CUSTOM_ACTION_ENUM_TEXT[CUSTOM_ACTION_TOGGLE_LAYERS] = _("Toggle Layers");
414
415     DEG_FORMAT_ENUM_TEXT[DDPDDDDD].name = "-dd.ddddd°";
416     DEG_FORMAT_ENUM_TEXT[DDPDDDDD].short_field_1 = "Lat";
417     DEG_FORMAT_ENUM_TEXT[DDPDDDDD].long_field_1 = "Latitude";
418     DEG_FORMAT_ENUM_TEXT[DDPDDDDD].short_field_2 = "Lon";
419     DEG_FORMAT_ENUM_TEXT[DDPDDDDD].long_field_2 = "Longitude";
420     DEG_FORMAT_ENUM_TEXT[DDPDDDDD].field_2_in_use = TRUE;
421     
422     DEG_FORMAT_ENUM_TEXT[DD_MMPMMM].name = "-dd°mm.mmm'";
423     DEG_FORMAT_ENUM_TEXT[DD_MMPMMM].short_field_1 = "Lat";
424     DEG_FORMAT_ENUM_TEXT[DD_MMPMMM].long_field_1 = "Latitude";
425     DEG_FORMAT_ENUM_TEXT[DD_MMPMMM].short_field_2 = "Lon";
426     DEG_FORMAT_ENUM_TEXT[DD_MMPMMM].long_field_2 = "Longitude";
427     DEG_FORMAT_ENUM_TEXT[DD_MMPMMM].field_2_in_use = TRUE;
428     
429     DEG_FORMAT_ENUM_TEXT[DD_MM_SSPS].name = "-dd°mm'ss.s\"";
430     DEG_FORMAT_ENUM_TEXT[DD_MM_SSPS].short_field_1 = "Lat";
431     DEG_FORMAT_ENUM_TEXT[DD_MM_SSPS].long_field_1 = "Latitude";
432     DEG_FORMAT_ENUM_TEXT[DD_MM_SSPS].short_field_2 = "Lon";
433     DEG_FORMAT_ENUM_TEXT[DD_MM_SSPS].long_field_2 = "Longitude";
434     DEG_FORMAT_ENUM_TEXT[DD_MM_SSPS].field_2_in_use = TRUE;
435     
436     DEG_FORMAT_ENUM_TEXT[DDPDDDDD_NSEW].name = "dd.ddddd° S";
437     DEG_FORMAT_ENUM_TEXT[DDPDDDDD_NSEW].short_field_1 = "Lat";
438     DEG_FORMAT_ENUM_TEXT[DDPDDDDD_NSEW].long_field_1 = "Latitude";
439     DEG_FORMAT_ENUM_TEXT[DDPDDDDD_NSEW].short_field_2 = "Lon";
440     DEG_FORMAT_ENUM_TEXT[DDPDDDDD_NSEW].long_field_2 = "Longitude";
441     DEG_FORMAT_ENUM_TEXT[DDPDDDDD_NSEW].field_2_in_use = TRUE;
442     
443     DEG_FORMAT_ENUM_TEXT[DD_MMPMMM_NSEW].name = "dd°mm.mmm' S";
444     DEG_FORMAT_ENUM_TEXT[DD_MMPMMM_NSEW].short_field_1 = "Lat";
445     DEG_FORMAT_ENUM_TEXT[DD_MMPMMM_NSEW].long_field_1 = "Latitude";
446     DEG_FORMAT_ENUM_TEXT[DD_MMPMMM_NSEW].short_field_2 = "Lon";
447     DEG_FORMAT_ENUM_TEXT[DD_MMPMMM_NSEW].long_field_2 = "Longitude";
448     DEG_FORMAT_ENUM_TEXT[DD_MMPMMM_NSEW].field_2_in_use = TRUE;
449     
450     DEG_FORMAT_ENUM_TEXT[DD_MM_SSPS_NSEW].name = "dd°mm'ss.s\" S";
451     DEG_FORMAT_ENUM_TEXT[DD_MM_SSPS_NSEW].short_field_1 = "Lat";
452     DEG_FORMAT_ENUM_TEXT[DD_MM_SSPS_NSEW].long_field_1 = "Latitude";
453     DEG_FORMAT_ENUM_TEXT[DD_MM_SSPS_NSEW].short_field_2 = "Lon";
454     DEG_FORMAT_ENUM_TEXT[DD_MM_SSPS_NSEW].long_field_2 = "Longitude";
455     DEG_FORMAT_ENUM_TEXT[DD_MM_SSPS_NSEW].field_2_in_use = TRUE;
456     
457     DEG_FORMAT_ENUM_TEXT[NSEW_DDPDDDDD].name = "S dd.ddddd°";
458     DEG_FORMAT_ENUM_TEXT[NSEW_DDPDDDDD].short_field_1 = "Lat";
459     DEG_FORMAT_ENUM_TEXT[NSEW_DDPDDDDD].long_field_1 = "Latitude";
460     DEG_FORMAT_ENUM_TEXT[NSEW_DDPDDDDD].short_field_2 = "Lon";
461     DEG_FORMAT_ENUM_TEXT[NSEW_DDPDDDDD].long_field_2 = "Longitude";
462     DEG_FORMAT_ENUM_TEXT[NSEW_DDPDDDDD].field_2_in_use = TRUE;
463     
464     DEG_FORMAT_ENUM_TEXT[NSEW_DD_MMPMMM].name = "S dd° mm.mmm'";
465     DEG_FORMAT_ENUM_TEXT[NSEW_DD_MMPMMM].short_field_1 = "Lat";
466     DEG_FORMAT_ENUM_TEXT[NSEW_DD_MMPMMM].long_field_1 = "Latitude";
467     DEG_FORMAT_ENUM_TEXT[NSEW_DD_MMPMMM].short_field_2 = "Lon";
468     DEG_FORMAT_ENUM_TEXT[NSEW_DD_MMPMMM].long_field_2 = "Longitude";
469     DEG_FORMAT_ENUM_TEXT[NSEW_DD_MMPMMM].field_2_in_use = TRUE;
470     
471     DEG_FORMAT_ENUM_TEXT[NSEW_DD_MM_SSPS].name = "S dd° mm' ss.s\"";
472     DEG_FORMAT_ENUM_TEXT[NSEW_DD_MM_SSPS].short_field_1 = "Lat";
473     DEG_FORMAT_ENUM_TEXT[NSEW_DD_MM_SSPS].long_field_1 = "Latitude";
474     DEG_FORMAT_ENUM_TEXT[NSEW_DD_MM_SSPS].short_field_2 = "Lon";
475     DEG_FORMAT_ENUM_TEXT[NSEW_DD_MM_SSPS].long_field_2 = "Longitude";
476     DEG_FORMAT_ENUM_TEXT[NSEW_DD_MM_SSPS].field_2_in_use = TRUE;
477
478     // Used by Radio Amateurs
479     DEG_FORMAT_ENUM_TEXT[IARU_LOC].name = "IARU Locator";
480     DEG_FORMAT_ENUM_TEXT[IARU_LOC].short_field_1 = "Locator";
481     DEG_FORMAT_ENUM_TEXT[IARU_LOC].long_field_1 = "Lacator";
482     DEG_FORMAT_ENUM_TEXT[IARU_LOC].short_field_2 = "";
483     DEG_FORMAT_ENUM_TEXT[IARU_LOC].long_field_2 = "";
484     DEG_FORMAT_ENUM_TEXT[IARU_LOC].field_2_in_use = FALSE;
485
486     
487     DEG_FORMAT_ENUM_TEXT[UK_OSGB].name = "OSGB X,Y Grid";
488     DEG_FORMAT_ENUM_TEXT[UK_OSGB].short_field_1 = "X";
489     DEG_FORMAT_ENUM_TEXT[UK_OSGB].long_field_1 = "OS X";
490     DEG_FORMAT_ENUM_TEXT[UK_OSGB].short_field_2 = "Y";
491     DEG_FORMAT_ENUM_TEXT[UK_OSGB].long_field_2 = "OS Y";
492     DEG_FORMAT_ENUM_TEXT[UK_OSGB].field_2_in_use = TRUE;
493     
494     DEG_FORMAT_ENUM_TEXT[UK_NGR].name = "OSGB Landranger Grid";
495     DEG_FORMAT_ENUM_TEXT[UK_NGR].short_field_1 = "GR";
496     DEG_FORMAT_ENUM_TEXT[UK_NGR].long_field_1 = "OS Grid";
497     DEG_FORMAT_ENUM_TEXT[UK_NGR].short_field_2 = "";
498     DEG_FORMAT_ENUM_TEXT[UK_NGR].long_field_2 = "";
499     DEG_FORMAT_ENUM_TEXT[UK_NGR].field_2_in_use = FALSE;
500     
501     SPEED_LOCATION_ENUM_TEXT[SPEED_LOCATION_TOP_LEFT] = _("Top-Left");
502     SPEED_LOCATION_ENUM_TEXT[SPEED_LOCATION_TOP_RIGHT] = _("Top-Right");
503     SPEED_LOCATION_ENUM_TEXT[SPEED_LOCATION_BOTTOM_RIGHT] = _("Bottom-Right");
504     SPEED_LOCATION_ENUM_TEXT[SPEED_LOCATION_BOTTOM_LEFT] = _("Bottom-Left");
505
506     GPS_RCVR_ENUM_TEXT[GPS_RCVR_BT] = _("Bluetooth");
507     GPS_RCVR_ENUM_TEXT[GPS_RCVR_GPSD] = _("GPSD");
508     GPS_RCVR_ENUM_TEXT[GPS_RCVR_FILE] = _("File");
509
510     /* Set up track array (must be done before config). */
511     memset(&_track, 0, sizeof(_track));
512     memset(&_route, 0, sizeof(_route));
513     /* initialisation of paths is done in path_init() */
514
515     _mapdb_mutex = g_mutex_new();
516     _mut_priority_mutex = g_mutex_new();
517     _mouse_mutex = g_mutex_new();
518
519 #ifdef CONIC
520     _conic_connection_mutex = g_mutex_new();
521     _conic_connection_cond = g_cond_new();
522 #endif
523
524     settings_init();
525     map_cache_init(_map_cache_size);
526
527     /* Initialize _program. */
528     _program = HILDON_PROGRAM(hildon_program_get_instance());
529     g_set_application_name("Maemo Mapper");
530
531     /* Initialize _window. */
532     _window = GTK_WIDGET(hildon_window_new());
533     hildon_program_add_window(_program, HILDON_WINDOW(_window));
534
535     gtk_window_set_default_size(GTK_WINDOW(_window), 800, 480);
536
537     /* Lets go fullscreen if so requested in saved config */
538     if (_fullscreen) {
539       gtk_window_fullscreen(GTK_WINDOW(_window));
540     }
541
542     /* Create and add widgets and supporting data. */
543     hbox = gtk_hbox_new(FALSE, 0);
544     gtk_container_add(GTK_CONTAINER(_window), hbox);
545
546     _gps_widget = gtk_frame_new("GPS Info");
547     gtk_container_add(GTK_CONTAINER(_gps_widget),
548             vbox = gtk_vbox_new(FALSE, 0));
549     gtk_widget_set_size_request(GTK_WIDGET(_gps_widget), 180, 0);
550     gtk_box_pack_start(GTK_BOX(hbox), _gps_widget, FALSE, TRUE, 0);
551
552     label = gtk_label_new(" ");
553     gtk_widget_set_size_request(GTK_WIDGET(label), -1, 10);
554     gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
555
556     _text_lat = gtk_label_new(" --- ");
557     gtk_widget_set_size_request(GTK_WIDGET(_text_lat), -1, 30);
558     gtk_box_pack_start(GTK_BOX(vbox), _text_lat, FALSE, TRUE, 0);
559
560     _text_lon = gtk_label_new(" --- ");
561     gtk_widget_set_size_request(GTK_WIDGET(_text_lon), -1, 30);
562     gtk_box_pack_start(GTK_BOX(vbox), _text_lon, FALSE, TRUE, 0);
563
564     _text_speed = gtk_label_new(" --- ");
565     gtk_widget_set_size_request(GTK_WIDGET(_text_speed), -1, 30);
566     gtk_box_pack_start(GTK_BOX(vbox), _text_speed, FALSE, TRUE, 0);
567
568     _text_alt = gtk_label_new(" --- ");
569     gtk_widget_set_size_request(GTK_WIDGET(_text_alt), -1, 30);
570     gtk_box_pack_start(GTK_BOX(vbox), _text_alt, FALSE, TRUE, 0);
571
572     label = gtk_label_new(" ");
573     gtk_widget_set_size_request(GTK_WIDGET(label), -1, 10);
574     gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
575
576     _sat_panel = gtk_drawing_area_new ();
577     gtk_widget_set_size_request (_sat_panel, -1, 100);
578     gtk_box_pack_start(GTK_BOX(vbox), _sat_panel, TRUE, TRUE, 0);
579
580     label = gtk_label_new(" ");
581     gtk_widget_set_size_request(GTK_WIDGET(label), -1, 10);
582     gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
583
584     _text_time = gtk_label_new("--:--:--");
585     gtk_widget_set_size_request(GTK_WIDGET(_text_time), -1, 30);
586     gtk_box_pack_start(GTK_BOX(vbox), _text_time, FALSE, TRUE, 0);
587
588     _heading_panel = gtk_drawing_area_new ();
589     gtk_widget_set_size_request (_heading_panel, -1, 100);
590     gtk_box_pack_start(GTK_BOX(vbox), _heading_panel, TRUE, TRUE, 0);
591
592     _map_widget = gtk_drawing_area_new();
593
594     gtk_box_pack_start(GTK_BOX(hbox), _map_widget, TRUE, TRUE, 0);
595
596     gtk_widget_show_all(hbox);
597     gps_show_info(); /* hides info, if necessary. */
598
599     gtk_widget_realize(_map_widget);
600
601     /* Tweak the foreground and background colors a little bit... */
602     {
603         GdkColor color;
604         GdkGCValues values;
605         GdkColormap *colormap = gtk_widget_get_colormap(_map_widget);
606
607         gdk_gc_get_values(
608                 _map_widget->style->fg_gc[GTK_STATE_NORMAL],
609                 &values);
610         gdk_colormap_query_color(colormap, values.foreground.pixel, &color);
611         gtk_widget_modify_fg(_map_widget, GTK_STATE_ACTIVE, &color);
612
613         gdk_gc_get_values(
614                 _map_widget->style->bg_gc[GTK_STATE_NORMAL],
615                 &values);
616         gdk_colormap_query_color(colormap, values.foreground.pixel, &color);
617         gtk_widget_modify_bg(_map_widget, GTK_STATE_ACTIVE, &color);
618
619         /* Use a black background for _map_widget, since missing tiles are
620          * also drawn with a black background. */
621         color.red = 0; color.green = 0; color.blue = 0;
622         gtk_widget_modify_bg(_map_widget,
623                 GTK_STATE_NORMAL, &color);
624     }
625
626     _map_pixmap = gdk_pixmap_new(_map_widget->window, 1, 1, -1);
627     /* -1: use bit depth of widget->window. */
628
629     _map_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, 1, 1);
630
631     _mut_exists_table = g_hash_table_new(
632             (GHashFunc)mut_exists_hashfunc, (GEqualFunc)mut_exists_equalfunc);
633     _mut_priority_tree = g_tree_new((GCompareFunc)mut_priority_comparefunc);
634
635     _mut_thread_pool = g_thread_pool_new(
636             (GFunc)thread_proc_mut, NULL, NUM_DOWNLOAD_THREADS, FALSE, NULL);
637     _mrt_thread_pool = g_thread_pool_new(
638             (GFunc)thread_render_map, NULL, 1, FALSE, NULL);
639
640     /* Connect signals. */
641     g_signal_connect(G_OBJECT(_window), "destroy",
642             G_CALLBACK(gtk_main_quit), NULL);
643
644     memset(&_autoroute_data, 0, sizeof(_autoroute_data));
645
646     latlon2unit(_gps.lat, _gps.lon, _pos.unitx, _pos.unity);
647
648     /* Initialize our line styles. */
649     update_gcs();
650
651     menu_init();
652     cmenu_init();
653     path_init();
654     gps_init();
655     input_init();
656     poi_db_connect();
657     display_init();
658     dbus_ifc_init();
659     
660 #ifdef INCLUDE_APRS
661     aprs_init();
662     timer_init();
663 #endif //INCLUDE_APRS
664     
665     /* If present, attempt to load the file specified on the command line. */
666     if(argc > 1)
667     {
668         GnomeVFSResult vfs_result;
669         gint size;
670         gchar *buffer;
671         gchar *file_uri;
672
673         /* Get the selected filename. */
674         file_uri = gnome_vfs_make_uri_from_shell_arg(argv[1]);
675
676         if(GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(
677                         file_uri, &size, &buffer)))
678         {
679             gchar buffer[BUFFER_SIZE];
680             snprintf(buffer, sizeof(buffer),
681                     "%s:\n%s", _("Failed to open file for reading"),
682                     gnome_vfs_result_to_string(vfs_result));
683             popup_error(_window, buffer);
684         }
685         else
686         {
687             if(gpx_path_parse(&_route, buffer, size, 0))
688             {
689                 path_save_route_to_db();
690                 MACRO_BANNER_SHOW_INFO(_window, _("Route Opened"));
691             }
692             else
693                 popup_error(_window, _("Error parsing GPX file."));
694             g_free(buffer);
695         }
696         g_free(file_uri);
697     }
698
699     /* If we have a route, calculate the next point. */
700     route_find_nearest_point();
701
702 #ifdef CONIC
703     _conic_conn = con_ic_connection_new();
704     g_object_set(_conic_conn, "automatic-connection-events", TRUE, NULL);
705     g_signal_connect(G_OBJECT(_conic_conn), "connection-event",
706             G_CALLBACK(conic_conn_event), NULL);
707 #endif
708
709     g_idle_add((GSourceFunc)window_present, NULL);
710
711
712     osso_hw_set_event_cb(_osso, NULL, osso_cb_hw_state, NULL);
713
714     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
715 }
716
717 static gboolean
718 osso_cb_hw_state_idle(osso_hw_state_t *state)
719 {
720     static gboolean _must_save_data = FALSE;
721     printf("%s(inact=%d, save=%d, shut=%d, memlow=%d, state=%d)\n",
722             __PRETTY_FUNCTION__, state->system_inactivity_ind,
723             state->save_unsaved_data_ind, state->shutdown_ind,
724             state->memory_low_ind, state->sig_device_mode_ind);
725
726     if(state->shutdown_ind)
727     {
728         maemo_mapper_destroy();
729         exit(1);
730     }
731
732     if(state->save_unsaved_data_ind)
733     {
734         settings_save();
735         _must_save_data = TRUE;
736     }
737
738     if(state->memory_low_ind)
739     {
740         // Disable the map cache and set the next max cache size to
741         // slightly less than the current cache size.
742         _map_cache_size = map_cache_resize(0) * 0.8;
743         _map_cache_enabled = FALSE;
744     }
745     else
746     {
747         if(!_map_cache_enabled)
748         {
749             // Restore the map cache.
750             map_cache_resize(_map_cache_size);
751             _map_cache_enabled = TRUE;
752         }
753     }
754
755     g_free(state);
756
757     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
758     return FALSE;
759 }
760
761 static void
762 osso_cb_hw_state(osso_hw_state_t *state, gpointer data)
763 {
764     printf("%s()\n", __PRETTY_FUNCTION__);
765     osso_hw_state_t *state_copy = g_new(osso_hw_state_t, 1);
766     memcpy(state_copy, state, sizeof(osso_hw_state_t));
767     g_idle_add((GSourceFunc)osso_cb_hw_state_idle, state_copy);
768     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
769 }
770
771 gint
772 main(gint argc, gchar *argv[])
773 {
774     printf("%s()\n", __PRETTY_FUNCTION__);
775
776     /* Initialize localization. */
777     setlocale(LC_ALL, "");
778     bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
779     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
780     textdomain(GETTEXT_PACKAGE);
781
782     g_thread_init(NULL);
783
784     /* Initialize _osso. */
785     _osso = osso_initialize("com.gnuite.maemo_mapper", VERSION, TRUE, NULL);
786     if(!_osso)
787     {
788         g_printerr("osso_initialize failed.\n");
789         return 1;
790     }
791
792     gtk_init(&argc, &argv);
793
794     /* Init gconf. */
795     g_type_init();
796     gconf_init(argc, argv, NULL);
797
798     /* Init Gnome-VFS. */
799     gnome_vfs_init();
800
801 #ifdef DEBUG
802     /* This is just some helpful DBUS testing code. */
803     if(argc >= 3)
804     {
805         /* Try to set the center to a new lat/lon. */
806         GError *error = NULL;
807         gchar *error_check;
808         gdouble lat, lon;
809         DBusGConnection *bus;
810         DBusGProxy *proxy;
811         
812         bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
813         if(!bus || error)
814         {
815             g_printerr("Error: %s\n", error->message);
816             return -1;
817         }
818
819         proxy = dbus_g_proxy_new_for_name(bus,
820                         MM_DBUS_SERVICE, MM_DBUS_PATH, MM_DBUS_INTERFACE);
821
822         lat = g_ascii_strtod((argv[1]), &error_check);
823         if(error_check == argv[1])
824         {
825             g_printerr("Failed to parse string as float: %s\n", argv[1]);
826             return 1;
827         }
828
829         lon = g_ascii_strtod((argv[2]), &error_check);
830         if(error_check == argv[2])
831         {
832             g_printerr("Failed to parse string as float: %s\n", argv[2]);
833             return 2;
834         }
835
836         error = NULL;
837         if(argc >= 4)
838         {
839             /* We are specifying a zoom. */
840             gint zoom;
841
842             zoom = g_ascii_strtod((argv[3]), &error_check);
843             if(error_check == argv[3])
844             {
845                 g_printerr("Failed to parse string as integer: %s\n", argv[3]);
846                 return 3;
847             }
848             if(!dbus_g_proxy_call(proxy, MM_DBUS_METHOD_SET_VIEW_POSITION,
849                         &error,
850                         G_TYPE_DOUBLE, lat, G_TYPE_DOUBLE, lon,
851                         G_TYPE_INT, zoom, G_TYPE_INVALID,
852                         G_TYPE_INVALID)
853                     || error)
854             {
855                 g_printerr("Error: %s\n", error->message);
856                 return 4;
857             }
858         }
859         else
860         {
861             /* Not specifying a zoom. */
862             if(!dbus_g_proxy_call(proxy, MM_DBUS_METHOD_SET_VIEW_POSITION,
863                         &error,
864                         G_TYPE_DOUBLE, lat, G_TYPE_DOUBLE, lon, G_TYPE_INVALID,
865                         G_TYPE_INVALID)
866                     || error)
867             {
868                 g_printerr("Error: %s\n", error->message);
869                 return -2;
870             }
871         }
872
873         g_object_unref(proxy);
874         dbus_g_connection_unref(bus);
875
876         return 0;
877     }
878 #endif
879
880     maemo_mapper_init(argc, argv);
881
882     gtk_main();
883
884     maemo_mapper_destroy();
885
886     osso_deinitialize(_osso);
887
888     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
889     exit(0);
890 }
891