]> git.itanic.dy.fi Git - maemo-mapper/blob - src/display.c
Added (default) support for SQLite3 in lieu of GDBM.
[maemo-mapper] / src / display.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 #ifdef HAVE_CONFIG_H
25 #    include "config.h"
26 #endif
27
28 #define _GNU_SOURCE
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h>
33 #include "aprs.h"
34 #include "aprs_decode.h"
35 #include "types.h"
36
37 #ifndef LEGACY
38 #    include <hildon/hildon-help.h>
39 #    include <hildon/hildon-note.h>
40 #    include <hildon/hildon-file-chooser-dialog.h>
41 #    include <hildon/hildon-banner.h>
42 #    include <hildon/hildon-sound.h>
43 #else
44 #    include <osso-helplib.h>
45 #    include <hildon-widgets/hildon-note.h>
46 #    include <hildon-widgets/hildon-file-chooser-dialog.h>
47 #    include <hildon-widgets/hildon-banner.h>
48 #    include <hildon-widgets/hildon-system-sound.h>
49 #endif
50
51 #include "types.h"
52 #include "data.h"
53 #include "defines.h"
54
55 #include "dbus-ifc.h"
56 #include "display.h"
57 #include "gdk-pixbuf-rotate.h"
58 #include "gps.h"
59 #include "maps.h"
60 #include "path.h"
61 #include "poi.h"
62 #include "settings.h"
63 #include "util.h"
64
65 #define VELVEC_SIZE_FACTOR (4)
66
67 static GtkWidget *_sat_details_panel = NULL;
68 static GtkWidget *_sdi_lat = NULL;
69 static GtkWidget *_sdi_lon = NULL;
70 static GtkWidget *_sdi_spd = NULL;
71 static GtkWidget *_sdi_alt = NULL;
72 static GtkWidget *_sdi_hea = NULL;
73 static GtkWidget *_sdi_tim = NULL;
74 static GtkWidget *_sdi_vie = NULL;
75 static GtkWidget *_sdi_use = NULL;
76 static GtkWidget *_sdi_fix = NULL;
77 static GtkWidget *_sdi_fqu = NULL;
78 static GtkWidget *_sdi_msp = NULL;
79 static gint _redraw_count = 0;
80
81 static gint _mark_bufx1 = -1;
82 static gint _mark_bufx2 = -1;
83 static gint _mark_bufy1 = -1;
84 static gint _mark_bufy2 = -1;
85 static gint _mark_minx = -1;
86 static gint _mark_miny = -1;
87 static gint _mark_width = -1;
88 static gint _mark_height = -1;
89 static GdkRectangle _scale_rect = { 0, 0, 0, 0};
90 static GdkRectangle _zoom_rect = { 0, 0, 0, 0};
91 static gint _dl_errors = 0;
92
93 static volatile gint _pending_replaces = 0;
94
95 /** Pango stuff. */
96 GdkRectangle _comprose_rect = { 0, 0, 0, 0};
97 PangoLayout *_scale_layout = NULL;
98 PangoLayout *_zoom_layout = NULL;
99 PangoLayout *_comprose_layout = NULL;
100 GdkGC *_speed_limit_gc1 = NULL;
101 GdkGC *_speed_limit_gc2 = NULL;
102 PangoLayout *_speed_limit_layout = NULL;
103 PangoLayout *_sat_panel_layout = NULL;
104 PangoLayout *_heading_panel_layout = NULL;
105 PangoFontDescription *_heading_panel_fontdesc = NULL;
106 GdkGC *_sat_info_gc1 = NULL;
107 GdkGC *_sat_info_gc2 = NULL;
108 PangoLayout *_sat_info_layout = NULL;
109 PangoLayout *_sat_details_layout = NULL;
110 PangoLayout *_sat_details_expose_layout = NULL;
111
112 #ifdef INCLUDE_APRS
113 PangoLayout *_aprs_label_layout = NULL;
114 #endif // INCLUDE_APRS
115
116 #define SCALE_WIDTH (100)
117
118 static gboolean
119 speed_excess(void)
120 {
121     printf("%s()\n", __PRETTY_FUNCTION__);
122     if(!_speed_excess)
123         return FALSE;
124
125     hildon_play_system_sound(
126         "/usr/share/sounds/ui-information_note.wav");
127
128     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
129     return TRUE;
130 }
131
132 #ifdef INCLUDE_APRS
133 //// START OF APRS CODE
134 gint add_aprs_label(gchar *label, gint label_len, gint x, gint y)
135 {
136     gint height = 0;
137     gint width = 0;
138     pango_layout_set_text(_aprs_label_layout, label, label_len);
139
140     pango_layout_get_pixel_size(_aprs_label_layout, &width, &height);
141
142     /* Draw the layout itself. */
143     gdk_draw_layout( _map_pixmap, 
144         _gc[COLORABLE_APRS_STATION],
145         x,
146         y - (gint)((gfloat)height/2.0f),
147         _aprs_label_layout);
148
149     return width;
150 }
151
152 gboolean extract_aprs_symbol(const gchar symbol, const char primary, GdkPixbuf **pixbuf, 
153                 gint *symbol_size, 
154                 gint *symbol_column, 
155                 gint *symbol_row)
156 {
157 //    GdkPixbuf *pixbuf = NULL;
158     GError *error = NULL;
159     gchar filename[100];
160
161
162     const gint startSymbol = ' ';
163     const gint symbols_per_column = 16;
164     const gint symbols_per_row = 6;
165     /*const gint*/ *symbol_size = 96/symbols_per_row;
166
167     gint symbol_number = (gint)symbol - startSymbol;
168
169     if(symbol_number<0 || symbol_number > symbols_per_row * symbols_per_column) symbol_number = 0;
170
171     if(primary == '/') snprintf(filename, sizeof(filename), "/usr/share/icons/hicolor/scalable/hildon/allicons.png");
172     else               snprintf(filename, sizeof(filename), "/usr/share/icons/hicolor/scalable/hildon/allicon2.png");
173     
174     *symbol_column = (gint)(symbol_number/symbols_per_column);
175     *symbol_row    = symbol_number - ((*symbol_column)*symbols_per_column);
176
177
178     *pixbuf = gdk_pixbuf_new_from_file(filename, &error);
179     
180
181     if(error)
182     {
183         return FALSE;
184     }
185
186     if( (*symbol_size)*(*symbol_column) < 0 || (*symbol_size)*(*symbol_row) < 0 ) 
187     {
188         return FALSE;
189     }
190     
191     return TRUE;
192 }
193 //
194 gboolean draw_aprs_symbol(const gchar symbol, const gchar primary, const gint poix, const gint poiy, gint* imageSize)
195 {
196     GdkPixbuf *pixbuf = NULL;
197     
198     gint symbol_column = 0;
199     gint symbol_row    = 0;
200     gint symbol_size = 0;
201
202     if(!extract_aprs_symbol(symbol, primary, &pixbuf, 
203                 &symbol_size, 
204                 &symbol_column, 
205                 &symbol_row))
206         return FALSE;
207     
208     
209     /* We found an icon to draw. */
210     gdk_draw_pixbuf(
211         _map_pixmap,
212         _gc[COLORABLE_POI],
213         pixbuf,
214         symbol_size*symbol_column, symbol_size*symbol_row,
215         poix - symbol_size / 2,
216         poiy - symbol_size / 2,
217         symbol_size, symbol_size,
218         GDK_RGB_DITHER_NONE, 0, 0);
219     g_object_unref(pixbuf);
220
221     *imageSize = symbol_size;
222    
223
224     return TRUE;
225 }
226
227
228 void plot_aprs_station(AprsDataRow *p_station, gboolean single )
229 {
230         if(_poi_zoom <= _zoom) return ;
231         
232     gint image_size = 0;
233     gdouble lat1 = 0;
234     gdouble lon1 = 0;
235     gint poix, poiy;
236     gint unitx, unity;
237     
238     // TODO - if this station has been ploted before, then redraw the map at that position
239     /*
240     if(p_station->newest_trackpoint != NULL)
241     {
242         AprsTrackRow *pPreviousPoint = p_station->newest_trackpoint;
243         
244         lat1 = convert_lat_l2d(pPreviousPoint->trail_lat_pos);
245             lon1 = convert_lon_l2d(pPreviousPoint->trail_long_pos);
246
247         latlon2unit(lat1, lon1, unitx, unity);
248         unit2buf(unitx, unity, poix, poiy);
249         fprintf(stderr, "Removing old pos.\n");
250         
251         poix = poix - 40;
252         poiy = poiy - 25;
253         if(poix<0) poix = 0;
254         if(poiy<0) poiy = 0;
255         
256         if(poix+100 > _view_width_pixels) poix = _view_width_pixels;
257         if(poiy+50 > _view_height_pixels) poiy = _view_height_pixels;
258                 
259         gdk_draw_pixbuf(
260                 _map_pixmap,
261                 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
262                 _map_pixbuf,
263                 poix, poiy,
264                 poix, poiy,
265                 100, 50,
266                 GDK_RGB_DITHER_NONE, 0, 0);
267         
268         // TODO - this will only redraw the background, not any POI´s or other items
269     }
270 */
271     lat1 = convert_lat_l2d(p_station->coord_lat);
272     lon1 = convert_lon_l2d(p_station->coord_lon);
273
274     latlon2unit(lat1, lon1, unitx, unity);
275     unit2buf(unitx, unity, poix, poiy);
276
277     // Ignore this station if it's position is not on the screen
278     if(poix < 0 || poix > _view_width_pixels
279         || poiy < 0 || poiy > _view_height_pixels)
280         return ;
281
282     gchar label[MAX_CALLSIGN+1];
283     snprintf(label, sizeof(label), "%s", p_station->call_sign);
284
285     if(!draw_aprs_symbol(p_station->aprs_symbol.aprs_symbol, p_station->aprs_symbol.aprs_type, poix, poiy, &image_size))
286     {
287         /* No icon for POI or for category or default POI icon file.
288            Draw default purple square. */
289         gdk_draw_rectangle(_map_pixmap, _gc[COLORABLE_APRS_STATION], TRUE,
290             poix - (gint)(1.5f * _draw_width),
291             poiy - (gint)(1.5f * _draw_width),
292             3 * _draw_width,
293             3 * _draw_width);
294
295         image_size = 3 * _draw_width;
296     }
297
298     gint label_width = 0;
299     
300     gint _aprs_label_zoom = _poi_zoom - 1;
301     
302     if(_aprs_label_zoom > _zoom)
303     {
304         label_width = add_aprs_label(label, strlen(label), poix + image_size, poiy);
305     }
306
307     if(single)
308     {
309         gint offset = (gint)((gfloat)image_size/2.0f);
310
311         gtk_widget_queue_draw_area( 
312                 _map_widget, 
313                 poix - offset,
314                 poiy - offset,
315                 (2*image_size) + label_width,
316                 image_size
317             );
318     }
319
320
321 }
322 #endif // INCLUDE_APRS
323
324 //// END OF APRS CODE
325
326 static void
327 speed_limit(void)
328 {
329     GdkGC *gc;
330     gfloat cur_speed;
331     gchar *buffer;
332     static gint x = 0, y = 0, width = 0, height = 0;
333     printf("%s()\n", __PRETTY_FUNCTION__);
334
335     cur_speed = _gps.speed * UNITS_CONVERT[_units];
336
337     if(cur_speed > _speed_limit)
338     {
339         gc = _speed_limit_gc1;
340         if(!_speed_excess)
341         {
342             _speed_excess = TRUE;
343             g_timeout_add_full(G_PRIORITY_HIGH_IDLE,
344                     5000, (GSourceFunc)speed_excess, NULL, NULL);
345         }
346     }
347     else
348     {
349         gc = _speed_limit_gc2;
350         _speed_excess = FALSE;
351     }
352
353     /* remove previous number */
354     if (width != 0 && height != 0) {
355       gtk_widget_queue_draw_area (_map_widget,
356                                  x - 5,
357                                  y - 5,
358                                  width + 10,
359                                  height + 10);
360       gdk_window_process_all_updates();
361     }
362
363     buffer = g_strdup_printf("%0.0f", cur_speed);
364     pango_layout_set_text(_speed_limit_layout, buffer, -1);
365
366
367     pango_layout_get_pixel_size(_speed_limit_layout, &width, &height);
368
369     switch (_speed_location)
370     {
371         case SPEED_LOCATION_TOP_RIGHT:
372             x = _map_widget->allocation.width - 10 - width;
373             y = 5;
374             break;
375         case SPEED_LOCATION_BOTTOM_RIGHT:
376             x = _map_widget->allocation.width - 10 - width;
377             y = _map_widget->allocation.height - 10 - height;
378             break;
379         case SPEED_LOCATION_BOTTOM_LEFT:
380             x = 10;
381             y = _map_widget->allocation.height - 10 - height;
382             break;
383         default:
384             x = 10;
385             y = 10;
386             break;
387     }
388
389     gdk_draw_layout(_map_widget->window,
390         gc,
391         x, y,
392         _speed_limit_layout);
393     g_free(buffer);
394
395     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
396 }
397
398 gboolean
399 gps_display_details(void)
400 {
401     gchar *buffer, litbuf[LL_FMT_LEN], buffer2[LL_FMT_LEN];
402     printf("%s()\n", __PRETTY_FUNCTION__);
403
404     if(_gps.fix < 2)
405     {
406         /* no fix no fun */
407         gtk_label_set_label(GTK_LABEL(_sdi_lat), " --- ");
408         gtk_label_set_label(GTK_LABEL(_sdi_lon), " --- ");
409         gtk_label_set_label(GTK_LABEL(_sdi_spd), " --- ");
410         gtk_label_set_label(GTK_LABEL(_sdi_alt), " --- ");
411         gtk_label_set_label(GTK_LABEL(_sdi_hea), " --- ");
412         gtk_label_set_label(GTK_LABEL(_sdi_tim), " --:--:-- ");
413     }
414     else
415     {
416         gfloat speed = _gps.speed * UNITS_CONVERT[_units];
417
418         format_lat_lon(_gps.lat, _gps.lon, litbuf, buffer2);
419         
420         /* latitude */
421         //lat_format(_gps.lat, litbuf);
422         gtk_label_set_label(GTK_LABEL(_sdi_lat), litbuf);
423
424         /* longitude */
425         //lon_format(_gps.lon, litbuf);
426         //gtk_label_set_label(GTK_LABEL(_sdi_lon), litbuf);
427         if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
428                 gtk_label_set_label(GTK_LABEL(_sdi_lon), buffer2);
429
430         /* speed */
431         switch(_units)
432         {
433             case UNITS_MI:
434                 buffer = g_strdup_printf("%.1f mph", speed);
435                 break;
436             case UNITS_NM:
437                 buffer = g_strdup_printf("%.1f kn", speed);
438                 break;
439             default:
440                 buffer = g_strdup_printf("%.1f km/h", speed);
441                 break;
442         }
443         gtk_label_set_label(GTK_LABEL(_sdi_spd), buffer);
444         g_free(buffer);
445
446         /* altitude */
447         switch(_units)
448         {
449             case UNITS_MI:
450             case UNITS_NM:
451                 buffer = g_strdup_printf("%d ft",
452                         (gint)(_pos.altitude * 3.2808399f));
453                 break;
454             default:
455                 buffer = g_strdup_printf("%d m", _pos.altitude);
456                 break;
457         }
458         gtk_label_set_label(GTK_LABEL(_sdi_alt), buffer);
459         g_free(buffer);
460
461         /* heading */
462         buffer = g_strdup_printf("%0.0f°", _gps.heading);
463         gtk_label_set_label(GTK_LABEL(_sdi_hea), buffer);
464         g_free(buffer);
465
466         /* local time */
467         strftime(litbuf, 15, "%X", localtime(&_pos.time));
468         gtk_label_set_label(GTK_LABEL(_sdi_tim), litbuf);
469     }
470
471     /* Sat in view */
472     buffer = g_strdup_printf("%d", _gps.satinview);
473     gtk_label_set_label(GTK_LABEL(_sdi_vie), buffer);
474     g_free(buffer);
475
476     /* Sat in use */
477     buffer = g_strdup_printf("%d", _gps.satinuse);
478     gtk_label_set_label(GTK_LABEL(_sdi_use), buffer);
479     g_free(buffer);
480
481     /* fix */
482     switch(_gps.fix)
483     {
484         case 2:
485         case 3: buffer = g_strdup_printf("%dD fix", _gps.fix); break;
486         default: buffer = g_strdup_printf("nofix"); break;
487     }
488     gtk_label_set_label(GTK_LABEL(_sdi_fix), buffer);
489     g_free(buffer);
490
491     if(_gps.fix == 1)
492         buffer = g_strdup("none");
493     else
494     {
495         switch (_gps.fixquality)
496         {
497             case 1 : buffer = g_strdup_printf(_("SPS")); break;
498             case 2 : buffer = g_strdup_printf(_("DGPS")); break;
499             case 3 : buffer = g_strdup_printf(_("PPS")); break;
500             case 4 : buffer = g_strdup_printf(_("Real Time Kinematic")); break;
501             case 5 : buffer = g_strdup_printf(_("Float RTK")); break;
502             case 6 : buffer = g_strdup_printf(_("Estimated")); break;
503             case 7 : buffer = g_strdup_printf(_("Manual")); break;
504             case 8 : buffer = g_strdup_printf(_("Simulation")); break;
505             default : buffer = g_strdup_printf(_("none")); break;
506         }
507     }
508     gtk_label_set_label(GTK_LABEL(_sdi_fqu), buffer);
509     g_free(buffer);
510
511     /* max speed */
512     {
513         gfloat maxspeed = _gps.maxspeed * UNITS_CONVERT[_units];
514
515         /* speed */
516         switch(_units)
517         {
518             case UNITS_MI:
519                 buffer = g_strdup_printf("%.1f mph", maxspeed);
520                 break;
521             case UNITS_NM:
522                 buffer = g_strdup_printf("%.1f kn", maxspeed);
523                 break;
524             default:
525                 buffer = g_strdup_printf("%.1f km/h", maxspeed);
526                 break;
527         }
528         gtk_label_set_label(GTK_LABEL(_sdi_msp), buffer);
529         g_free(buffer);
530     }
531
532     /* refresh sat panel */
533     gtk_widget_queue_draw_area(GTK_WIDGET(_sat_details_panel),
534         0, 0,
535         _sat_details_panel->allocation.width,
536         _sat_details_panel->allocation.height);
537
538     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
539     return TRUE;
540 }
541
542 void
543 gps_display_data(void)
544 {
545     gchar *buffer, litbuf[LL_FMT_LEN], buffer2[LL_FMT_LEN];
546     printf("%s()\n", __PRETTY_FUNCTION__);
547
548     if(_gps.fix < 2)
549     {
550         /* no fix no fun */
551         gtk_label_set_label(GTK_LABEL(_text_lat), " --- ");
552         gtk_label_set_label(GTK_LABEL(_text_lon), " --- ");
553         gtk_label_set_label(GTK_LABEL(_text_speed), " --- ");
554         gtk_label_set_label(GTK_LABEL(_text_alt), " --- ");
555         gtk_label_set_label(GTK_LABEL(_text_time), " --:--:-- ");
556     }
557     else
558     {
559         gfloat speed = _gps.speed * UNITS_CONVERT[_units];
560
561         format_lat_lon(_gps.lat, _gps.lon, litbuf, buffer2);
562         
563         /* latitude */
564         //lat_format(_gps.lat, litbuf);
565         gtk_label_set_label(GTK_LABEL(_text_lat), litbuf);
566
567         /* longitude */
568         //lon_format(_gps.lon, litbuf);
569         if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
570                 gtk_label_set_label(GTK_LABEL(_text_lon), buffer2);     
571
572         /* speed */
573         switch(_units)
574         {
575             case UNITS_MI:
576                 buffer = g_strdup_printf("Spd: %.1f mph", speed);
577                 break;
578             case UNITS_NM:
579                 buffer = g_strdup_printf("Spd: %.1f kn", speed);
580                 break;
581             default:
582                 buffer = g_strdup_printf("Spd: %.1f km/h", speed);
583                 break;
584         }
585         gtk_label_set_label(GTK_LABEL(_text_speed), buffer);
586         g_free(buffer);
587
588         /* altitude */
589         switch(_units)
590         {
591             case UNITS_MI:
592             case UNITS_NM:
593                 buffer = g_strdup_printf("Alt: %d ft",
594                         (gint)(_pos.altitude * 3.2808399f));
595                 break;
596             default:
597                 buffer = g_strdup_printf("Alt: %d m", _pos.altitude);
598         }
599         gtk_label_set_label(GTK_LABEL(_text_alt), buffer);
600         g_free(buffer);
601
602         /* local time */
603         strftime(litbuf, 15, "%X", localtime(&_pos.time));
604         gtk_label_set_label(GTK_LABEL(_text_time), litbuf);
605     }
606
607     /* refresh sat panel */
608     gtk_widget_queue_draw_area(GTK_WIDGET(_sat_panel),
609         0, 0,
610         _sat_panel->allocation.width,
611         _sat_panel->allocation.height);
612
613     /* refresh heading panel*/
614     gtk_widget_queue_draw_area(GTK_WIDGET(_heading_panel),
615         0, 0,
616         _heading_panel->allocation.width,
617         _heading_panel->allocation.height);
618
619     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
620     return;
621 }
622
623 void
624 gps_hide_text(void)
625 {
626     printf("%s()\n", __PRETTY_FUNCTION__);
627
628     /* Clear gps data */
629     _gps.fix = 1;
630     _gps.satinuse = 0;
631     _gps.satinview = 0;
632
633     if(_gps_info)
634         gps_display_data();
635
636     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
637 }
638
639 void
640 gps_show_info(void)
641 {
642     printf("%s()\n", __PRETTY_FUNCTION__);
643
644     if(_gps_info && _enable_gps)
645         gtk_widget_show_all(GTK_WIDGET(_gps_widget));
646     else
647     {
648         gps_hide_text();
649         gtk_widget_hide(GTK_WIDGET(_gps_widget));
650     }
651
652     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
653 }
654
655 static void
656 draw_sat_info(GtkWidget *widget, gint x0, gint y0,
657         gint width, gint height, gboolean showsnr)
658 {
659     GdkGC *gc;
660     gint step, i, j, snr_height, bymargin, xoffset, yoffset;
661     gint x, y, x1, y1;
662     gchar *tmp = NULL;
663     printf("%s()\n", __PRETTY_FUNCTION__);
664
665     xoffset = x0;
666     yoffset = y0;
667     /* Bootom margin - 12% */
668     bymargin = height * 0.88f;
669
670     /* Bottom line */
671     gdk_draw_line(widget->window,
672         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
673         xoffset + 5, yoffset + bymargin,
674         xoffset + width - 10 - 2, yoffset + bymargin);
675     gdk_draw_line(widget->window,
676         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
677         xoffset + 5, yoffset + bymargin - 1,
678         xoffset + width - 10 - 2, yoffset + bymargin - 1);
679
680     if(_gps.satinview > 0 )
681     {
682         /* Left margin - 5pix, Right margin - 5pix */
683         step = (width - 10) / _gps.satinview;
684
685         for(i = 0; i < _gps.satinview; i++)
686         {
687             /* Sat used or not */
688             gc = _sat_info_gc1;
689             for(j = 0; j < _gps.satinuse ; j++)
690             {
691                 if(_gps.satforfix[j] == _gps_sat[i].prn)
692                 {
693                     gc = _sat_info_gc2;
694                     break;
695                 }
696             }
697
698             x = 5 + i * step;
699             snr_height = _gps_sat[i].snr * height * 0.78f / 100;
700             y = height * 0.1f + (height * 0.78f - snr_height);
701
702             /* draw sat rectangle... */
703             gdk_draw_rectangle(widget->window,
704                     gc,
705                     TRUE,
706                     xoffset + x,
707                     yoffset + y,
708                     step - 2,
709                     snr_height);
710
711             if(showsnr && _gps_sat[i].snr > 0)
712             {
713                 /* ...snr.. */
714                 tmp = g_strdup_printf("%02d", _gps_sat[i].snr);
715                 pango_layout_set_text(_sat_info_layout, tmp, 2);
716                 pango_layout_get_pixel_size(_sat_info_layout, &x1, &y1);
717                 gdk_draw_layout(widget->window,
718                     widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
719                     xoffset + x + ((step - 2) - x1)/2,
720                     yoffset + y - 15,
721                     _sat_info_layout);
722                 g_free(tmp);
723             }
724
725             /* ...and sat number */
726             tmp = g_strdup_printf("%02d", _gps_sat[i].prn);
727             pango_layout_set_text(_sat_info_layout, tmp, 2);
728             pango_layout_get_pixel_size(_sat_info_layout, &x1, &y1);
729             gdk_draw_layout(widget->window,
730                 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
731                 xoffset + x + ((step - 2) - x1)/2 ,
732                 yoffset + bymargin + 1,
733                 _sat_info_layout);
734             g_free(tmp);
735         }
736     }
737
738     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
739     return;
740 }
741
742 static void
743 draw_sat_details(GtkWidget *widget, gint x0, gint y0,
744         gint width, gint height)
745 {
746     gint i, j, x, y, size, halfsize, xoffset, yoffset;
747     gint x1, y1;
748     gfloat tmp;
749     GdkColor color;
750     GdkGC *gc1, *gc2, *gc3, *gc;
751     gchar *buffer = NULL;
752     printf("%s()\n", __PRETTY_FUNCTION__);
753
754     size = MIN(width, height);
755     halfsize = size/2;
756     if(width > height)
757     {
758         xoffset = x0 + (width - height - 10) / 2;
759         yoffset = y0 + 5;
760     }
761     else
762     {
763         xoffset = x0 + 5;
764         yoffset = y0 + (height - width - 10) / 2;
765     }
766
767     /* 90 */
768     gdk_draw_arc(widget->window,
769             widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
770             FALSE,
771             xoffset + 2, yoffset + 2, size - 4, size - 4,
772             0, 64 * 360);
773
774     /* 60 */
775     gdk_draw_arc(widget->window,
776             widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
777             FALSE,
778             xoffset + size/6, yoffset + size/6,
779             size/6*4, size/6*4,
780             0, 64 * 360);
781
782     /* 30 */
783     gdk_draw_arc(widget->window,
784             widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
785             FALSE,
786             xoffset + size/6*2, yoffset + size/6*2,
787             size/6*2, size/6*2,
788             0, 64 * 360);
789
790     gint line[12] = {0,30,60,90,120,150,180,210,240,270,300,330};
791
792     for(i = 0; i < 6; i++)
793     {
794         /* line */
795         tmp = deg2rad(line[i]);
796         gdk_draw_line(widget->window,
797             widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
798             xoffset + halfsize + (halfsize -2) * sinf(tmp),
799             yoffset + halfsize - (halfsize -2) * cosf(tmp),
800             xoffset + halfsize - (halfsize -2) * sinf(tmp),
801             yoffset + halfsize + (halfsize -2) * cosf(tmp));
802     }
803
804     for(i = 0; i < 12; i++)
805     {
806         tmp = deg2rad(line[i]);
807         /* azimuth */
808         if(line[i] == 0)
809             buffer = g_strdup_printf("N");
810         else
811             buffer = g_strdup_printf("%d°", line[i]);
812         pango_layout_set_text(_sat_details_layout, buffer, -1);
813         pango_layout_get_pixel_size(_sat_details_layout, &x, &y);
814         gdk_draw_layout(widget->window,
815             widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
816             (xoffset + halfsize + (halfsize - size/12) * sinf(tmp)) - x/2,
817             (yoffset + halfsize - (halfsize - size/12) * cosf(tmp)) - y/2,
818             _sat_details_layout);
819         g_free(buffer);
820     }
821
822     /* elevation 30 */
823     tmp = deg2rad(30);
824     buffer = g_strdup_printf("30°");
825     pango_layout_set_text(_sat_details_layout, buffer, -1);
826     pango_layout_get_pixel_size(_sat_details_layout, &x, &y);
827     gdk_draw_layout(widget->window,
828         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
829         (xoffset + halfsize + size/6*2 * sinf(tmp)) - x/2,
830         (yoffset + halfsize - size/6*2 * cosf(tmp)) - y/2,
831         _sat_details_layout);
832     g_free(buffer);
833
834     /* elevation 60 */
835     tmp = deg2rad(30);
836     buffer = g_strdup_printf("60°");
837     pango_layout_set_text(_sat_details_layout, buffer, -1);
838     pango_layout_get_pixel_size(_sat_details_layout, &x, &y);
839     gdk_draw_layout(widget->window,
840         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
841         (xoffset + halfsize + size/6 * sinf(tmp)) - x/2,
842         (yoffset + halfsize - size/6 * cosf(tmp)) - y/2,
843         _sat_details_layout);
844     g_free(buffer);
845
846     color.red = 0;
847     color.green = 0;
848     color.blue = 0;
849     gc1 = gdk_gc_new (widget->window);
850     gdk_gc_set_rgb_fg_color (gc1, &color);
851
852     color.red = 0;
853     color.green = 0;
854     color.blue = 0xffff;
855     gc2 = gdk_gc_new (widget->window);
856     gdk_gc_set_rgb_fg_color (gc2, &color);
857
858     color.red = 0xffff;
859     color.green = 0xffff;
860     color.blue = 0xffff;
861     gc3 = gdk_gc_new (widget->window);
862     gdk_gc_set_rgb_fg_color (gc3, &color);
863
864     for(i = 0; i < _gps.satinview; i++)
865     {
866         /* Sat used or not */
867         gc = gc1;
868         for(j = 0; j < _gps.satinuse ; j++)
869         {
870             if(_gps.satforfix[j] == _gps_sat[i].prn)
871             {
872                 gc = gc2;
873                 break;
874             }
875         }
876
877         tmp = deg2rad(_gps_sat[i].azimuth);
878         x = xoffset + halfsize
879             + (90 - _gps_sat[i].elevation)*halfsize/90 * sinf(tmp);
880         y = yoffset + halfsize
881             - (90 - _gps_sat[i].elevation)*halfsize/90 * cosf(tmp);
882
883         gdk_draw_arc (widget->window,
884             gc, TRUE,
885             x - 10, y - 10, 20, 20,
886             0, 64 * 360);
887
888         buffer = g_strdup_printf("%02d", _gps_sat[i].prn);
889         pango_layout_set_text(_sat_details_layout, buffer, -1);
890         pango_layout_get_pixel_size(_sat_details_layout, &x1, &y1);
891         gdk_draw_layout(widget->window,
892             gc3,
893             x - x1/2,
894             y - y1/2,
895             _sat_details_layout);
896         g_free(buffer);
897     }
898     g_object_unref (gc1);
899     g_object_unref (gc2);
900     g_object_unref (gc3);
901
902     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
903     return;
904 }
905
906
907 static gboolean
908 sat_details_panel_expose(GtkWidget *widget, GdkEventExpose *event)
909 {
910     gint width, height, x, y;
911     gchar *buffer = NULL;
912     printf("%s()\n", __PRETTY_FUNCTION__);
913
914     width = widget->allocation.width;
915     height = widget->allocation.height * 0.9;
916
917     draw_sat_info(widget, 0, 0, width/2, height, TRUE);
918     draw_sat_details(widget, width/2, 0, width/2, height);
919
920     buffer = g_strdup_printf(
921         "%s: %d; %s: %d",
922         _("Satellites in view"), _gps.satinview,
923         _("in use"), _gps.satinuse);
924     pango_layout_set_text(_sat_details_expose_layout, buffer, -1);
925     pango_layout_get_pixel_size(_sat_details_expose_layout, &x, &y);
926     gdk_draw_layout(widget->window,
927         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
928         10,
929         height*0.9 + 10,
930         _sat_details_expose_layout);
931     g_free(buffer);
932
933     buffer = g_strdup_printf("HDOP: %.01f", _gps.hdop);
934     pango_layout_set_text(_sat_details_expose_layout, buffer, -1);
935     pango_layout_get_pixel_size(_sat_details_expose_layout, &x, &y);
936     gdk_draw_layout(widget->window,
937         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
938         (width/8) - x/2,
939         (height/6) - y/2,
940         _sat_details_expose_layout);
941     g_free(buffer);
942     buffer = g_strdup_printf("PDOP: %.01f", _gps.pdop);
943     pango_layout_set_text(_sat_details_expose_layout, buffer, -1);
944     pango_layout_get_pixel_size(_sat_details_expose_layout, &x, &y);
945     gdk_draw_layout(widget->window,
946         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
947         (width/8) - x/2,
948         (height/6) - y/2 + 20,
949         _sat_details_expose_layout);
950     g_free(buffer);
951     buffer = g_strdup_printf("VDOP: %.01f", _gps.vdop);
952     pango_layout_set_text(_sat_details_expose_layout, buffer, -1);
953     pango_layout_get_pixel_size(_sat_details_expose_layout, &x, &y);
954     gdk_draw_layout(widget->window,
955         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
956         (width/8) - x/2,
957         (height/6) - y/2 + 40,
958         _sat_details_expose_layout);
959     g_free(buffer);
960
961     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
962     return TRUE;
963 }
964
965 void
966 gps_details(void)
967 {
968     static GtkWidget *dialog = NULL;
969     static GtkWidget *table = NULL;
970     static GtkWidget *label = NULL;
971     static GtkWidget *notebook = NULL;
972     printf("%s()\n", __PRETTY_FUNCTION__);
973
974     if(dialog == NULL)
975     {
976         dialog = gtk_dialog_new_with_buttons(_("GPS Details"),
977                 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
978                 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
979                 NULL);
980
981         gtk_window_set_default_size(GTK_WINDOW(dialog), 600, 300);
982
983         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
984                 notebook = gtk_notebook_new(), TRUE, TRUE, 0);
985
986         /* textual info */
987         gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
988                 table = gtk_table_new(4, 6, FALSE),
989                 label = gtk_label_new(_("GPS Information")));
990
991         _sat_details_panel = gtk_drawing_area_new ();
992         gtk_widget_set_size_request (_sat_details_panel, 300, 300);
993         /* sat details info */
994         gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
995                 _sat_details_panel,
996                 label = gtk_label_new(_("Satellites details")));
997         g_signal_connect (G_OBJECT (_sat_details_panel), "expose_event",
998                             G_CALLBACK (sat_details_panel_expose), NULL);
999
1000         gtk_table_attach(GTK_TABLE(table),
1001                 label = gtk_label_new(_("Latitude")),
1002                 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, 0, 20, 4);
1003         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1004         gtk_table_attach(GTK_TABLE(table),
1005                 _sdi_lat = gtk_label_new(" --- "),
1006                 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
1007         gtk_misc_set_alignment(GTK_MISC(_sdi_lat), 0.f, 0.5f);
1008
1009         gtk_table_attach(GTK_TABLE(table),
1010                 label = gtk_label_new(_("Longitude")),
1011                 0, 1, 1, 2, GTK_EXPAND | GTK_FILL, 0, 20, 4);
1012         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1013         gtk_table_attach(GTK_TABLE(table),
1014                 _sdi_lon = gtk_label_new(" --- "),
1015                 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
1016         gtk_misc_set_alignment(GTK_MISC(_sdi_lon), 0.f, 0.5f);
1017
1018         gtk_table_attach(GTK_TABLE(table),
1019                 label = gtk_label_new(_("Speed")),
1020                 0, 1, 2, 3, GTK_EXPAND | GTK_FILL, 0, 20, 4);
1021         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1022         gtk_table_attach(GTK_TABLE(table),
1023                 _sdi_spd = gtk_label_new(" --- "),
1024                 1, 2, 2, 3, GTK_EXPAND | GTK_FILL, 0, 2, 4);
1025         gtk_misc_set_alignment(GTK_MISC(_sdi_spd), 0.f, 0.5f);
1026
1027         gtk_table_attach(GTK_TABLE(table),
1028                 label = gtk_label_new(_("Altitude")),
1029                 0, 1, 3, 4, GTK_EXPAND | GTK_FILL, 0, 20, 4);
1030         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1031         gtk_table_attach(GTK_TABLE(table),
1032                 _sdi_alt = gtk_label_new(" --- "),
1033                 1, 2, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 4);
1034         gtk_misc_set_alignment(GTK_MISC(_sdi_alt), 0.f, 0.5f);
1035
1036         gtk_table_attach(GTK_TABLE(table),
1037                 label = gtk_label_new(_("Heading")),
1038                 0, 1, 4, 5, GTK_EXPAND | GTK_FILL, 0, 20, 4);
1039         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1040         gtk_table_attach(GTK_TABLE(table),
1041                 _sdi_hea = gtk_label_new(" --- "),
1042                 1, 2, 4, 5, GTK_EXPAND | GTK_FILL, 0, 2, 4);
1043         gtk_misc_set_alignment(GTK_MISC(_sdi_hea), 0.f, 0.5f);
1044
1045         gtk_table_attach(GTK_TABLE(table),
1046                 label = gtk_label_new(_("Local time")),
1047                 0, 1, 5, 6, GTK_EXPAND | GTK_FILL, 0, 20, 4);
1048         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1049         gtk_table_attach(GTK_TABLE(table),
1050                 _sdi_tim = gtk_label_new(" --:--:-- "),
1051                 1, 2, 5, 6, GTK_EXPAND | GTK_FILL, 0, 2, 4);
1052         gtk_misc_set_alignment(GTK_MISC(_sdi_tim), 0.f, 0.5f);
1053
1054         gtk_table_attach(GTK_TABLE(table),
1055                 label = gtk_label_new(_("Sat in view")),
1056                 2, 3, 0, 1, GTK_EXPAND | GTK_FILL, 0, 20, 4);
1057         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1058         gtk_table_attach(GTK_TABLE(table),
1059                 _sdi_vie = gtk_label_new("0"),
1060                 3, 4, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
1061         gtk_misc_set_alignment(GTK_MISC(_sdi_vie), 0.f, 0.5f);
1062
1063         gtk_table_attach(GTK_TABLE(table),
1064                 label = gtk_label_new(_("Sat in use")),
1065                 2, 3, 1, 2, GTK_EXPAND | GTK_FILL, 0, 20, 4);
1066         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1067         gtk_table_attach(GTK_TABLE(table),
1068                 _sdi_use = gtk_label_new("0"),
1069                 3, 4, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
1070         gtk_misc_set_alignment(GTK_MISC(_sdi_use), 0.f, 0.5f);
1071
1072         gtk_table_attach(GTK_TABLE(table),
1073                 label = gtk_label_new(_("Fix")),
1074                 2, 3, 2, 3, GTK_EXPAND | GTK_FILL, 0, 20, 4);
1075         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1076         gtk_table_attach(GTK_TABLE(table),
1077                 _sdi_fix = gtk_label_new(_("nofix")),
1078                 3, 4, 2, 3, GTK_EXPAND | GTK_FILL, 0, 2, 4);
1079         gtk_misc_set_alignment(GTK_MISC(_sdi_fix), 0.f, 0.5f);
1080
1081         gtk_table_attach(GTK_TABLE(table),
1082                 label = gtk_label_new(_("Fix Quality")),
1083                 2, 3, 3, 4, GTK_EXPAND | GTK_FILL, 0, 20, 4);
1084         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1085         gtk_table_attach(GTK_TABLE(table),
1086                 _sdi_fqu = gtk_label_new(_("none")),
1087                 3, 4, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 4);
1088         gtk_misc_set_alignment(GTK_MISC(_sdi_fqu), 0.f, 0.5f);
1089
1090         gtk_table_attach(GTK_TABLE(table),
1091                 label = gtk_label_new(_("Max speed")),
1092                 2, 3, 5, 6, GTK_EXPAND | GTK_FILL, 0, 20, 4);
1093         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1094         gtk_table_attach(GTK_TABLE(table),
1095                 _sdi_msp = gtk_label_new(" --- "),
1096                 3, 4, 5, 6, GTK_EXPAND | GTK_FILL, 0, 2, 4);
1097         gtk_misc_set_alignment(GTK_MISC(_sdi_msp), 0.f, 0.5f);
1098     }
1099
1100     gtk_widget_show_all(dialog);
1101     _satdetails_on = TRUE;
1102     gps_display_details();
1103     while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1104     {
1105         _satdetails_on = FALSE;
1106         break;
1107     }
1108     gtk_widget_hide(dialog);
1109
1110     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1111 }
1112
1113
1114 /**
1115  * Render a single track line to _map_pixmap.  If either point on the line
1116  * is a break (defined as unity == 0), a circle is drawn at the other point.
1117  * IT IS AN ERROR FOR BOTH POINTS TO INDICATE A BREAK.
1118  */
1119 void
1120 map_render_segment(GdkGC *gc_norm, GdkGC *gc_alt,
1121         gint unitx1, gint unity1, gint unitx2, gint unity2)
1122 {
1123     /* vprintf("%s(%d, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1124             unitx1, unity1, unitx2, unity2); */
1125
1126     if(!unity1)
1127     {
1128         gint x2, y2;
1129         unit2buf(unitx2, unity2, x2, y2);
1130         if(((unsigned)(x2+_draw_width) <= _view_width_pixels+2*_draw_width)
1131          &&((unsigned)(y2+_draw_width) <= _view_height_pixels+2*_draw_width))
1132         {
1133             gdk_draw_arc(_map_pixmap, gc_alt,
1134                     FALSE, /* FALSE: not filled. */
1135                     x2 - _draw_width,
1136                     y2 - _draw_width,
1137                     2 * _draw_width,
1138                     2 * _draw_width,
1139                     0, /* start at 0 degrees. */
1140                     360 * 64);
1141         }
1142     }
1143     else if(!unity2)
1144     {
1145         gint x1, y1;
1146         unit2buf(unitx1, unity1, x1, y1);
1147         if(((unsigned)(x1+_draw_width) <= _view_width_pixels+2*_draw_width)
1148          &&((unsigned)(y1+_draw_width) <= _view_height_pixels+2*_draw_width))
1149         {
1150             gdk_draw_arc(_map_pixmap, gc_alt,
1151                     FALSE, /* FALSE: not filled. */
1152                     x1 - _draw_width,
1153                     y1 - _draw_width,
1154                     2 * _draw_width,
1155                     2 * _draw_width,
1156                     0, /* start at 0 degrees. */
1157                     360 * 64);
1158         }
1159     }
1160     else
1161     {
1162         gint x1, y1, x2, y2;
1163         unit2buf(unitx1, unity1, x1, y1);
1164         unit2buf(unitx2, unity2, x2, y2);
1165         /* Make sure this line could possibly be visible. */
1166         if(!((x1 > _view_width_pixels && x2 > _view_width_pixels)
1167                 || (x1 < 0 && x2 < 0)
1168                 || (y1 > _view_height_pixels && y2 > _view_height_pixels)
1169                 || (y1 < 0 && y2 < 0)))
1170             gdk_draw_line(_map_pixmap, gc_norm, x1, y1, x2, y2);
1171     }
1172
1173     /* vprintf("%s(): return\n", __PRETTY_FUNCTION__); */
1174 }
1175
1176 /**
1177  * Render all track data onto the _map_pixmap.  Note that this does not
1178  * clear the pixmap of previous track data (use map_force_redraw() for
1179  * that), and also note that this method does not queue any redraws, so it
1180  * is up to the caller to decide which part of the track really needs to be
1181  * redrawn.
1182  */
1183 static void
1184 map_render_path(Path *path, GdkGC **gc)
1185 {
1186     Point *curr;
1187     WayPoint *wcurr;
1188     printf("%s()\n", __PRETTY_FUNCTION__);
1189
1190     /* gc is a pointer to the first GC to use (for plain points).  (gc + 1)
1191      * is a pointer to the GC to use for waypoints, and (gc + 2) is a pointer
1192      * to the GC to use for breaks. */
1193
1194     /* else there is a route to draw. */
1195     for(curr = path->head, wcurr = path->whead; curr++ != path->tail; )
1196     {
1197         /* Draw the line from (curr - 1) to (curr). */
1198         map_render_segment(gc[0], gc[2],
1199                 curr[-1].unitx, curr[-1].unity, curr->unitx, curr->unity);
1200
1201         /* Now, check if curr is a waypoint. */
1202         if(wcurr <= path->wtail && wcurr->point == curr)
1203         {
1204             gint x1, y1;
1205             unit2buf(wcurr->point->unitx, wcurr->point->unity, x1, y1);
1206             gdk_draw_arc(_map_pixmap,
1207                     gc[1],
1208                     FALSE, /* FALSE: not filled. */
1209                     x1 - _draw_width,
1210                     y1 - _draw_width,
1211                     2 * _draw_width,
1212                     2 * _draw_width,
1213                     0, /* start at 0 degrees. */
1214                     360 * 64);
1215             wcurr++;
1216         }
1217     }
1218
1219     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1220 }
1221
1222 void
1223 map_render_paths()
1224 {
1225     printf("%s()\n", __PRETTY_FUNCTION__);
1226
1227     if((_show_paths & ROUTES_MASK) && _route.head != _route.tail)
1228     {
1229         WayPoint *next_way;
1230         map_render_path(&_route, _gc + COLORABLE_ROUTE);
1231
1232         next_way = path_get_next_way();
1233
1234         /* Now, draw the next waypoint on top of all other waypoints. */
1235         if(next_way)
1236         {
1237             gint x1, y1;
1238             unit2buf(next_way->point->unitx, next_way->point->unity, x1, y1);
1239             /* Draw the next waypoint as a break. */
1240             gdk_draw_arc(_map_pixmap,
1241                     _gc[COLORABLE_ROUTE_BREAK],
1242                     FALSE, /* FALSE: not filled. */
1243                     x1 - _draw_width,
1244                     y1 - _draw_width,
1245                     2 * _draw_width,
1246                     2 * _draw_width,
1247                     0, /* start at 0 degrees. */
1248                     360 * 64);
1249         }
1250     }
1251     if(_show_paths & TRACKS_MASK)
1252         map_render_path(&_track, _gc + COLORABLE_TRACK);
1253
1254     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1255 }
1256
1257 /**
1258  * Update all GdkGC objects to reflect the current _draw_width.
1259  */
1260 #define UPDATE_GC(gc) \
1261     gdk_gc_set_line_attributes(gc, \
1262             _draw_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
1263 void
1264 update_gcs()
1265 {
1266     gint i;
1267     printf("%s()\n", __PRETTY_FUNCTION__);
1268
1269     for(i = 0; i < COLORABLE_ENUM_COUNT; i++)
1270     {
1271         gdk_color_alloc(gtk_widget_get_colormap(_map_widget), &_color[i]);
1272         if(_gc[i])
1273             g_object_unref(_gc[i]);
1274         _gc[i] = gdk_gc_new(_map_pixmap);
1275         gdk_gc_set_foreground(_gc[i], &_color[i]);
1276         gdk_gc_set_line_attributes(_gc[i],
1277                 _draw_width, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND);
1278     }
1279     
1280     /* Update the _map_widget's gc's. */
1281     gdk_gc_set_line_attributes(
1282             _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
1283             2, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
1284     gdk_gc_set_line_attributes(
1285             _map_widget->style->bg_gc[GTK_STATE_ACTIVE],
1286             2, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
1287
1288     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1289 }
1290
1291 /**
1292  * Call gtk_window_present() on Maemo Mapper.  This also checks the
1293  * configuration and brings up the Settings dialog if the GPS Receiver is
1294  * not set up, the first time it is called.
1295  */
1296 gboolean
1297 window_present()
1298 {
1299     static gint been_here = 0;
1300     static gint done_here = 0;
1301     printf("%s()\n", __PRETTY_FUNCTION__);
1302
1303     if(!been_here++)
1304     {
1305         /* Set connection state first, to avoid going into this if twice. */
1306         if(_is_first_time)
1307         {
1308             GtkWidget *confirm;
1309
1310             gtk_window_present(GTK_WINDOW(_window));
1311
1312             confirm = hildon_note_new_confirmation(GTK_WINDOW(_window),
1313                     _("It looks like this is your first time running"
1314                         " Maemo Mapper.  Press OK to view the the help pages."
1315                         " Otherwise, press Cancel to continue."));
1316
1317             if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
1318             {
1319 #ifndef LEGACY
1320                 hildon_help_show(_osso, HELP_ID_INTRO, 0);
1321 #else
1322                 ossohelp_show(_osso, HELP_ID_INTRO, 0);
1323 #endif
1324             }
1325             gtk_widget_destroy(confirm);
1326
1327             /* Present the settings dialog. */
1328             settings_dialog();
1329             popup_error(_window,
1330                 _("OpenStreetMap.org provides public, free-to-use maps.  "
1331                 "You can also download a sample set of repositories from "
1332                 " the internet by using the \"Download...\" button."));
1333
1334             /* Present the repository dialog. */
1335             repoman_dialog();
1336             confirm = hildon_note_new_confirmation(GTK_WINDOW(_window),
1337                 _("You will now see a blank screen.  You can download"
1338                     " maps using the \"Manage Maps\" menu item in the"
1339                     " \"Maps\" menu.  Or, press OK now to enable"
1340                     " Auto-Download."));
1341             if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
1342             {
1343                 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(
1344                             _menu_maps_auto_download_item), TRUE);
1345             }
1346             gtk_widget_destroy(confirm);
1347         }
1348
1349         /* Connect to receiver. */
1350         if(_enable_gps)
1351             rcvr_connect();
1352
1353         ++done_here; /* Don't ask... */
1354     }
1355     if(done_here)
1356     {
1357         gtk_window_present(GTK_WINDOW(_window));
1358         g_timeout_add_full(G_PRIORITY_HIGH_IDLE,
1359                 250, (GSourceFunc)banner_reset, NULL, NULL);
1360     }
1361
1362     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1363     return FALSE;
1364 }
1365
1366 /**
1367  * "Set" the mark, which translates the current GPS position into on-screen
1368  * units in preparation for drawing the mark with map_draw_mark().
1369  */
1370 static void
1371 map_set_mark()
1372 {
1373     gfloat sqrt_speed, tmp, vel_offset_devx, vel_offset_devy;
1374     printf("%s()\n", __PRETTY_FUNCTION__);
1375
1376     tmp = deg2rad(_gps.heading);
1377     sqrt_speed = VELVEC_SIZE_FACTOR * sqrtf(10 + _gps.speed);
1378     gdk_pixbuf_rotate_vector(&vel_offset_devx, &vel_offset_devy,
1379             _map_rotate_matrix,
1380             sqrt_speed * sinf(tmp), -sqrt_speed * cosf(tmp));
1381
1382     unit2buf(_pos.unitx, _pos.unity, _mark_bufx1, _mark_bufy1);
1383
1384     _mark_bufx2 = _mark_bufx1 + (_show_velvec ? (vel_offset_devx + 0.5f) : 0);
1385     _mark_bufy2 = _mark_bufy1 + (_show_velvec ? (vel_offset_devy + 0.5f) : 0);
1386
1387     _mark_minx = MIN(_mark_bufx1, _mark_bufx2) - (2 * _draw_width);
1388     _mark_miny = MIN(_mark_bufy1, _mark_bufy2) - (2 * _draw_width);
1389     _mark_width = abs(_mark_bufx1 - _mark_bufx2) + (4 * _draw_width);
1390     _mark_height = abs(_mark_bufy1 - _mark_bufy2) + (4 * _draw_width);
1391
1392     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1393 }
1394
1395
1396 /**
1397  * Force a redraw of the entire _map_pixmap, including fetching the
1398  * background maps from disk and redrawing the tracks on top of them.
1399  */
1400 void
1401 map_force_redraw()
1402 {
1403     printf("%s()\n", __PRETTY_FUNCTION__);
1404
1405     gdk_draw_pixbuf(
1406             _map_pixmap,
1407             _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
1408             _map_pixbuf,
1409             0, 0,
1410             0, 0,
1411             _view_width_pixels, _view_height_pixels,
1412             GDK_RGB_DITHER_NONE, 0, 0);
1413
1414     MACRO_MAP_RENDER_DATA();
1415     MACRO_QUEUE_DRAW_AREA();
1416
1417     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1418 }
1419
1420 Point
1421 map_calc_new_center(gint zoom)
1422 {
1423     Point new_center;
1424     printf("%s()\n", __PRETTY_FUNCTION__);
1425
1426     switch(_center_mode)
1427     {
1428         case CENTER_LEAD:
1429         {
1430             gfloat tmp = deg2rad(_gps.heading);
1431             gfloat screen_pixels = _view_width_pixels
1432                 + (((gint)_view_height_pixels
1433                             - (gint)_view_width_pixels)
1434                         * fabsf(cosf(deg2rad(
1435                                 ROTATE_DIR_ENUM_DEGREES[_rotate_dir] -
1436                                 (_center_rotate ? 0
1437                              : (_next_map_rotate_angle
1438                                  - (gint)(_gps.heading)))))));
1439             gfloat lead_pixels = 0.0025f
1440                 * pixel2zunit((gint)screen_pixels, zoom)
1441                 * _lead_ratio
1442                 * VELVEC_SIZE_FACTOR
1443                 * (_lead_is_fixed ? 7 : sqrtf(_gps.speed));
1444
1445             new_center.unitx = _pos.unitx + (gint)(lead_pixels * sinf(tmp));
1446             new_center.unity = _pos.unity - (gint)(lead_pixels * cosf(tmp));
1447             break;
1448         }
1449         case CENTER_LATLON:
1450             new_center.unitx = _pos.unitx;
1451             new_center.unity = _pos.unity;
1452             break;
1453         default:
1454             new_center.unitx = _next_center.unitx;
1455             new_center.unity = _next_center.unity;
1456     }
1457
1458     vprintf("%s(): return (%d, %d)\n", __PRETTY_FUNCTION__,
1459             new_center.unitx, new_center.unity);
1460     return new_center;
1461 }
1462
1463 /**
1464  * Center the view on the given unitx/unity.
1465  */
1466 void
1467 map_center_unit_full(Point new_center,
1468         gint zoom, gint rotate_angle)
1469 {
1470     MapRenderTask *mrt;
1471     printf("%s(%d, %d)\n", __PRETTY_FUNCTION__,
1472             new_center.unitx, new_center.unity);
1473
1474     if(!_mouse_is_down)
1475     {
1476         /* Assure that _center.unitx/y are bounded. */
1477         BOUND(new_center.unitx, 0, WORLD_SIZE_UNITS);
1478         BOUND(new_center.unity, 0, WORLD_SIZE_UNITS);
1479
1480         mrt = g_slice_new(MapRenderTask);
1481         mrt->repo = _curr_repo;
1482         mrt->old_offsetx = _map_offset_devx;
1483         mrt->old_offsety = _map_offset_devy;
1484         mrt->new_center = _next_center = new_center;
1485         mrt->screen_width_pixels = _view_width_pixels;
1486         mrt->screen_height_pixels = _view_height_pixels;
1487         mrt->zoom = _next_zoom = zoom;
1488         mrt->rotate_angle = _next_map_rotate_angle = rotate_angle;
1489
1490
1491         gtk_widget_queue_draw_area(
1492                 _map_widget,
1493                 _redraw_wait_bounds.x,
1494                 _redraw_wait_bounds.y,
1495                 _redraw_wait_bounds.width
1496                     + (_redraw_count * HOURGLASS_SEPARATION),
1497                 _redraw_wait_bounds.height);
1498
1499         ++_redraw_count;
1500
1501         g_thread_pool_push(_mrt_thread_pool, mrt, NULL);
1502     }
1503
1504     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1505 }
1506
1507 void
1508 map_center_unit(Point new_center)
1509 {
1510     map_center_unit_full(new_center, _next_zoom,
1511         _center_mode > 0 && _center_rotate
1512             ? _gps.heading : _next_map_rotate_angle);
1513 }
1514
1515 void
1516 map_rotate(gint rotate_angle)
1517 {
1518     if(_center_mode > 0 && gtk_check_menu_item_get_active(
1519                 GTK_CHECK_MENU_ITEM(_menu_view_rotate_auto_item)))
1520         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(
1521                     _menu_view_rotate_auto_item), FALSE);
1522
1523     map_center_unit_full(map_calc_new_center(_next_zoom), _next_zoom,
1524         (_next_map_rotate_angle + rotate_angle) % 360);
1525 }
1526
1527 void
1528 map_center_zoom(gint zoom)
1529 {
1530     map_center_unit_full(map_calc_new_center(zoom), zoom,
1531         _center_mode > 0 && _center_rotate
1532             ? _gps.heading : _next_map_rotate_angle);
1533 }
1534
1535 /**
1536  * Pan the view by the given number of units in the X and Y directions.
1537  */
1538 void
1539 map_pan(gint delta_unitx, gint delta_unity)
1540 {
1541     Point new_center;
1542     printf("%s(%d, %d)\n", __PRETTY_FUNCTION__, delta_unitx, delta_unity);
1543
1544     if(_center_mode > 0)
1545         gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(
1546                     _menu_view_ac_none_item), TRUE);
1547     new_center.unitx = _center.unitx + delta_unitx;
1548     new_center.unity = _center.unity + delta_unity;
1549     map_center_unit_full(new_center, _next_zoom,
1550             _center_mode > 0 && _center_rotate
1551             ? _gps.heading : _next_map_rotate_angle);
1552
1553     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1554 }
1555
1556 /**
1557  * Initiate a move of the mark from the old location to the current
1558  * location.  This function queues the draw area of the old mark (to force
1559  * drawing of the background map), then updates the mark, then queus the
1560  * draw area of the new mark.
1561  */
1562 void
1563 map_move_mark()
1564 {
1565     printf("%s()\n", __PRETTY_FUNCTION__);
1566
1567     /* Just queue the old and new draw areas. */
1568     gtk_widget_queue_draw_area(_map_widget,
1569             _mark_minx + _map_offset_devx,
1570             _mark_miny + _map_offset_devy,
1571             _mark_width,
1572             _mark_height);
1573     map_set_mark();
1574     gtk_widget_queue_draw_area(_map_widget,
1575             _mark_minx + _map_offset_devx,
1576             _mark_miny + _map_offset_devy,
1577             _mark_width,
1578             _mark_height);
1579
1580     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1581 }
1582
1583 /**
1584  * Make sure the mark is up-to-date.  This function triggers a panning of
1585  * the view if the mark is appropriately close to the edge of the view.
1586  */
1587 void
1588 map_refresh_mark(gboolean force_redraw)
1589 {
1590     printf("%s()\n", __PRETTY_FUNCTION__);
1591
1592     gint new_center_devx, new_center_devy;
1593
1594     Point new_center = map_calc_new_center(_next_zoom);
1595
1596     unit2buf(new_center.unitx, new_center.unity,
1597             new_center_devx, new_center_devy);
1598     if(force_redraw || (_center_mode > 0
1599                 && (UNITS_CONVERT[_units] * _gps.speed) >= _ac_min_speed &&
1600     (((unsigned)(new_center_devx - (_view_width_pixels * _center_ratio / 20))
1601                 > ((10 - _center_ratio) * _view_width_pixels / 10))
1602  || ((unsigned)(new_center_devy - (_view_height_pixels * _center_ratio / 20))
1603                 > ((10 - _center_ratio) * _view_height_pixels / 10))
1604             || (_center_rotate &&
1605               abs(_next_map_rotate_angle - _gps.heading)
1606                   > (4*(10-_rotate_sens))))))
1607     {
1608         map_move_mark();
1609         map_center_unit(new_center);
1610     }
1611     else
1612     {
1613         /* We're not changing the view - just move the mark. */
1614         map_move_mark();
1615     }
1616
1617     /* Draw speed info */
1618     if(_speed_limit_on)
1619         speed_limit();
1620
1621     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1622 }
1623
1624 gboolean
1625 map_download_refresh_idle(MapUpdateTask *mut)
1626 {
1627     vprintf("%s(%p, %d, %d, %d)\n", __PRETTY_FUNCTION__, mut,
1628             mut->zoom, mut->tilex, mut->tiley);
1629
1630     /* Test if download succeeded (only if retries != 0). */
1631     if(mut->pixbuf)
1632     {
1633         gint zoff = mut->zoom - _zoom;
1634         /* Update the UI to reflect the updated map database. */
1635         /* Only refresh at same or "lower" (more detailed) zoom level. */
1636         if(mut->update_type == MAP_UPDATE_AUTO && (unsigned)zoff <= 4)
1637         {
1638             gfloat destx, desty;
1639             gint boundx, boundy, width, height;
1640
1641             pixel2buf(
1642                     tile2pixel(mut->tilex << zoff)
1643                         + ((TILE_SIZE_PIXELS << zoff) >> 1),
1644                     tile2pixel(mut->tiley << zoff)
1645                         + ((TILE_SIZE_PIXELS << zoff) >> 1),
1646                     destx, desty);
1647
1648             /* Multiply the matrix to cause blitting. */
1649             if(zoff)
1650                 gdk_pixbuf_rotate_matrix_mult_number(
1651                         _map_rotate_matrix, 1 << zoff);
1652             gdk_pixbuf_rotate(_map_pixbuf,
1653                         /* Apply Map Correction. */
1654                         destx - unit2pixel(_map_correction_unitx),
1655                         desty - unit2pixel(_map_correction_unity),
1656                         _map_rotate_matrix,
1657                         mut->pixbuf,
1658                         TILE_SIZE_PIXELS / 2,
1659                         TILE_SIZE_PIXELS / 2,
1660                         TILE_SIZE_PIXELS,
1661                         TILE_SIZE_PIXELS,
1662                         &boundx, &boundy, &width, &height);
1663             /* Un-multiply the matrix that we used for blitting.  Good thing
1664              * we're multiplying by powers of two, or this wouldn't work
1665              * consistently... */
1666             if(zoff)
1667                 gdk_pixbuf_rotate_matrix_mult_number(
1668                         _map_rotate_matrix, 1.f / (1 << zoff));
1669
1670             if(width * height)
1671             {
1672                 gdk_draw_pixbuf(
1673                         _map_pixmap,
1674                         _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
1675                         _map_pixbuf,
1676                         boundx, boundy,
1677                         boundx, boundy,
1678                         width, height,
1679                         GDK_RGB_DITHER_NONE, 0, 0);
1680                 MACRO_MAP_RENDER_DATA();
1681                 gtk_widget_queue_draw_area(
1682                     _map_widget, boundx, boundy, width, height);
1683             }
1684         }
1685         g_object_unref(mut->pixbuf);
1686     }
1687     else if(mut->vfs_result != GNOME_VFS_OK)
1688     {
1689         _dl_errors++;
1690     }
1691
1692     if(++_curr_download == _num_downloads)
1693     {
1694         if(_download_banner)
1695         {
1696             gtk_widget_destroy(_download_banner);
1697             _download_banner = NULL;
1698         }
1699         _num_downloads = _curr_download = 0;
1700         g_thread_pool_stop_unused_threads();
1701
1702         if(_curr_repo->gdbm_db && !_curr_repo->is_sqlite)
1703             gdbm_sync(_curr_repo->gdbm_db);
1704
1705         if(_dl_errors)
1706         {
1707             if (mut->repo->layer_level == 0) {
1708                 gchar buffer[BUFFER_SIZE];
1709                 snprintf(buffer, sizeof(buffer), "%d %s", _dl_errors,
1710                          _("maps failed to download."));
1711                 MACRO_BANNER_SHOW_INFO(_window, buffer);
1712             }
1713             _dl_errors = 0;
1714         }
1715
1716         if(mut->update_type != MAP_UPDATE_AUTO || _refresh_map_after_download)
1717         {
1718             /* Update the map. */
1719             map_refresh_mark(TRUE);
1720         }
1721     }
1722     else if(_download_banner)
1723     {
1724         hildon_banner_set_fraction(HILDON_BANNER(_download_banner),
1725                 _curr_download / (double)_num_downloads);
1726     }
1727
1728     g_mutex_lock(_mut_priority_mutex);
1729     g_hash_table_remove(_mut_exists_table, mut);
1730     g_mutex_unlock(_mut_priority_mutex);
1731
1732     g_slice_free(MapUpdateTask, mut);
1733
1734     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1735     return FALSE;
1736 }
1737
1738 /**
1739  * Set the current zoom level.  If the given zoom level is the same as the
1740  * current zoom level, or if the new zoom is invalid
1741  * (not MIN_ZOOM <= new_zoom < MAX_ZOOM), then this method does nothing.
1742  */
1743 void
1744 map_set_zoom(gint new_zoom)
1745 {
1746     printf("%s(%d)\n", __PRETTY_FUNCTION__, _zoom);
1747
1748     /* This if condition also checks for new_zoom >= 0. */
1749     if((unsigned)new_zoom > MAX_ZOOM)
1750         return;
1751
1752     map_center_zoom(new_zoom / _curr_repo->view_zoom_steps
1753                      * _curr_repo->view_zoom_steps);
1754
1755     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1756 }
1757
1758 static gboolean
1759 map_replace_pixbuf_idle(MapRenderTask *mrt)
1760 {
1761     printf("%s()\n", __PRETTY_FUNCTION__);
1762
1763     if(!--_pending_replaces && !_mouse_is_down
1764             && mrt->screen_width_pixels == _view_width_pixels
1765             && mrt->screen_height_pixels == _view_height_pixels)
1766     {
1767         g_object_unref(_map_pixbuf);
1768         _map_pixbuf = mrt->pixbuf;
1769
1770         if(_center.unitx != mrt->new_center.unitx
1771                 || _center.unity != mrt->new_center.unity
1772                 || _zoom != mrt->zoom
1773                 || _map_rotate_angle != mrt->rotate_angle)
1774         {
1775             dbus_ifc_fire_view_position_changed(
1776                     mrt->new_center, mrt->zoom, mrt->rotate_angle);
1777         }
1778
1779         _center = mrt->new_center;
1780         _zoom = mrt->zoom;
1781         _map_rotate_angle = mrt->rotate_angle;
1782
1783         gdk_pixbuf_rotate_matrix_fill_for_rotation(
1784                 _map_rotate_matrix,
1785                 deg2rad(ROTATE_DIR_ENUM_DEGREES[_rotate_dir]
1786                     - _map_rotate_angle));
1787         gdk_pixbuf_rotate_matrix_fill_for_rotation(
1788                 _map_reverse_matrix,
1789                 deg2rad(_map_rotate_angle
1790                     - ROTATE_DIR_ENUM_DEGREES[_rotate_dir]));
1791
1792         --_redraw_count;
1793
1794         _map_offset_devx = 0;
1795         _map_offset_devy = 0;
1796
1797         map_set_mark();
1798         map_force_redraw();
1799     }
1800     else
1801     {
1802         /* Ignore this new pixbuf. We have newer ones coming. */
1803         g_object_unref(mrt->pixbuf);
1804         --_redraw_count;
1805     }
1806
1807     g_slice_free(MapRenderTask, mrt);
1808
1809     vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1810     return FALSE;
1811 }
1812
1813
1814 /* Routine draws one partly-transparent pixbuf on top of the another (base map). For efficiency, we
1815    assume that base map's tile have no transparent pixels (because it should not have them). We also
1816    assume that pixbufs are have the same size. */
1817 static void
1818 combine_tiles (GdkPixbuf *dst_pixbuf, GdkPixbuf *src_pixbuf)
1819 {
1820     gint s_n_channels = gdk_pixbuf_get_n_channels (src_pixbuf);
1821     gint d_n_channels = gdk_pixbuf_get_n_channels (dst_pixbuf);
1822     gint bps = gdk_pixbuf_get_bits_per_sample (dst_pixbuf);
1823     gint width, height, x, y, d_delta, s_delta;
1824     guchar *d_p, *s_p;
1825
1826     if (gdk_pixbuf_get_colorspace (dst_pixbuf) != gdk_pixbuf_get_colorspace (src_pixbuf)) {
1827         printf ("combine return (1)\n");
1828         return;
1829     }
1830     if (gdk_pixbuf_get_colorspace (dst_pixbuf) != GDK_COLORSPACE_RGB) {
1831         printf ("combine return (2)\n");
1832         return;
1833     }
1834
1835     if (bps != gdk_pixbuf_get_bits_per_sample (src_pixbuf)) {
1836         printf ("combine return (5)\n");
1837         return;
1838     }
1839
1840     width = gdk_pixbuf_get_width (dst_pixbuf);
1841     height = gdk_pixbuf_get_height (dst_pixbuf);
1842
1843     if (width != gdk_pixbuf_get_width (src_pixbuf)) {
1844         printf ("combine return (6)\n");
1845         return;
1846     }
1847     if (height != gdk_pixbuf_get_height (src_pixbuf)) {
1848         printf ("combine return (7)\n");
1849         return;
1850     }
1851
1852     s_delta = (bps >> 3) * s_n_channels;
1853     d_delta = (bps >> 3) * d_n_channels;
1854     d_p = gdk_pixbuf_get_pixels (dst_pixbuf);
1855     s_p = gdk_pixbuf_get_pixels (src_pixbuf);
1856
1857     /* ok, we're ready to combine */
1858     for (y = 0; y < height; y++) {
1859         for (x = 0; x < width; x++, d_p += d_delta, s_p += s_delta) {
1860             /* TODO: alpha blending? */
1861             if (s_n_channels == 3 || s_p[3]) {
1862                 d_p[0] = s_p[0];
1863                 d_p[1] = s_p[1];
1864                 d_p[2] = s_p[2];
1865             }
1866         }
1867     }
1868 }
1869
1870
1871 gboolean
1872 thread_render_map(MapRenderTask *mrt)
1873 {
1874     gfloat matrix[4];
1875     gint start_tilex, start_tiley, stop_tilex, stop_tiley;
1876     gint x = 0, y, num_tilex, num_tiley;
1877     gint diag_halflength_units;
1878     gfloat angle_rad;
1879     gint tile_rothalf_pixels;
1880     gint curr_tile_to_draw, num_tiles_to_draw;
1881     gfloat *tile_dev;
1882     ThreadLatch *refresh_latch = NULL;
1883     gint cache_amount;
1884     static gint8 auto_download_batch_id = INT8_MIN;
1885     printf("%s(%d, %d, %d, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1886             mrt->screen_width_pixels, mrt->screen_height_pixels,
1887             mrt->new_center.unitx, mrt->new_center.unity, mrt->zoom,
1888             mrt->rotate_angle);
1889
1890     /* If there are more render tasks in the queue, skip this one. */
1891     if(g_thread_pool_unprocessed(_mrt_thread_pool))
1892     {
1893         g_slice_free(MapRenderTask, mrt);
1894         --_redraw_count;
1895         vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1896         return FALSE;
1897     }
1898
1899     angle_rad = deg2rad(ROTATE_DIR_ENUM_DEGREES[_rotate_dir]
1900             - mrt->rotate_angle);
1901
1902     gdk_pixbuf_rotate_matrix_fill_for_rotation(matrix, angle_rad);
1903
1904     /* Determine (roughly) the tiles we might have to process.
1905      * Basically, we take the center unit and subtract the maximum dimension
1906      * of the screen plus the maximum additional pixels of a rotated tile.
1907      */
1908     tile_rothalf_pixels = MAX(
1909             fabsf(TILE_HALFDIAG_PIXELS * sinf((PI / 4) - angle_rad)),
1910             fabsf(TILE_HALFDIAG_PIXELS * cosf((PI / 4) - angle_rad)));
1911
1912     mrt->zoom = _next_zoom;
1913
1914     if(mrt->repo->type != REPOTYPE_NONE && MAPDB_EXISTS(mrt->repo))
1915         cache_amount = _auto_download_precache;
1916     else
1917         cache_amount = 1; /* No cache. */
1918
1919     diag_halflength_units = pixel2zunit(TILE_HALFDIAG_PIXELS
1920         + MAX(mrt->screen_width_pixels, mrt->screen_height_pixels) / 2,
1921         mrt->zoom);
1922     start_tilex = unit2ztile(
1923             mrt->new_center.unitx - diag_halflength_units
1924             + _map_correction_unitx, mrt->zoom);
1925     start_tilex = MAX(start_tilex - (cache_amount - 1), 0);
1926     start_tiley = unit2ztile(
1927             mrt->new_center.unity - diag_halflength_units
1928             + _map_correction_unity, mrt->zoom);
1929     start_tiley = MAX(start_tiley - (cache_amount - 1), 0);
1930     stop_tilex = unit2ztile(mrt->new_center.unitx + diag_halflength_units
1931             + _map_correction_unitx, mrt->zoom);
1932     stop_tilex = MIN(stop_tilex + (cache_amount - 1),
1933             unit2ztile(WORLD_SIZE_UNITS, mrt->zoom));
1934     stop_tiley = unit2ztile(mrt->new_center.unity + diag_halflength_units
1935             + _map_correction_unity, mrt->zoom);
1936     stop_tiley = MIN(stop_tiley + (cache_amount - 1),
1937             unit2ztile(WORLD_SIZE_UNITS, mrt->zoom));
1938
1939     num_tilex = (stop_tilex - start_tilex + 1);
1940     num_tiley = (stop_tiley - start_tiley + 1);
1941     tile_dev = g_new0(gfloat, num_tilex * num_tiley * 2);
1942
1943     ++auto_download_batch_id;
1944
1945     /* Iterate through the tiles and mark which ones need retrieval. */
1946     num_tiles_to_draw = 0;
1947     for(y = 0; y < num_tiley; ++y)
1948     {
1949         for(x = 0; x < num_tilex; ++x)
1950         {
1951             gfloat devx, devy;
1952
1953             /* Find the device location of this tile's center. */
1954             pixel2buf_full(
1955                     tile2pixel(x + start_tilex) + (TILE_SIZE_PIXELS >> 1),
1956                     tile2pixel(y + start_tiley) + (TILE_SIZE_PIXELS >> 1),
1957                     devx, devy,
1958                     mrt->new_center, mrt->zoom, matrix);
1959
1960             /* Apply Map Correction. */
1961             devx -= unit2zpixel(_map_correction_unitx, mrt->zoom);
1962             devy -= unit2zpixel(_map_correction_unity, mrt->zoom);
1963
1964             /* Skip this tile under the following conditions:
1965              * devx < -tile_rothalf_pixels
1966              * devx > _view_width_pixels + tile_rothalf_pixels
1967              * devy < -tile_rothalf_pixels
1968              * devy > _view_height_pixels + tile_rothalf_pixels
1969              */
1970             if(((unsigned)(devx + tile_rothalf_pixels))
1971                     < (_view_width_pixels + (2 * tile_rothalf_pixels))
1972                 && ((unsigned)(devy + tile_rothalf_pixels))
1973                     < (_view_height_pixels + (2 * tile_rothalf_pixels)))
1974             {
1975                 tile_dev[2 * (y * num_tilex + x)] = devx;
1976                 tile_dev[2 * (y * num_tilex + x) + 1] = devy;
1977                 ++num_tiles_to_draw;
1978             }
1979             else
1980             {
1981                 tile_dev[2 * (y * num_tilex + x)] = FLT_MAX;
1982             }
1983         }
1984     }
1985
1986     mrt->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
1987             mrt->screen_width_pixels, mrt->screen_height_pixels);
1988     _refresh_map_after_download = FALSE;
1989
1990     /* Iterate through the tiles, get them (or queue a download if they're
1991      * not in the cache), and rotate them into the pixbuf. */
1992     for(y = curr_tile_to_draw = 0; y < num_tiley; ++y)
1993     {
1994         gint tiley = y + start_tiley;
1995         for(x = 0; x < num_tilex; ++x)
1996         {
1997             GdkPixbuf *tile_pixbuf = NULL, *layer_pixbuf = NULL;
1998             gboolean started_download = FALSE;
1999             gint zoff, zoff_base;
2000             gint tilex;
2001             RepoData* repo_p = mrt->repo;
2002
2003             tilex = x + start_tilex;
2004             zoff_base = mrt->repo->double_size ? 1 : 0;
2005
2006             /* iterating over tile and all it's layers */
2007             while (repo_p)
2008             {
2009                 started_download = FALSE;
2010
2011                 /* for layers we must use resolution of underlying map */
2012                 zoff = zoff_base;
2013
2014                 /* if this is not a bottom layer and layer not enabled, skip it */
2015                 if (repo_p != mrt->repo && !repo_p->layer_enabled)
2016                 {
2017                     repo_p = repo_p->layers;
2018                     continue;
2019                 }
2020
2021                 /* Iteratively try to retrieve a map to draw the tile. */
2022                 while((mrt->zoom + zoff) <= MAX_ZOOM && zoff < 4)
2023                 {
2024                     /* Check if we're actually going to draw this map. */
2025                     if(tile_dev[2 * (y*num_tilex + x)] != FLT_MAX)
2026                     {
2027                         if(NULL != (layer_pixbuf = mapdb_get(
2028                                         repo_p, mrt->zoom + zoff,
2029                                         tilex >> zoff,
2030                                         tiley >> zoff)))
2031                         {
2032                             /* Found a map. Check for it's age. */
2033                             gint age = get_tile_age (layer_pixbuf);
2034                             printf ("Tile age (%d)\n", age);
2035
2036                             /* throw away tile only if we can download something */
2037                             if (!repo_p->layer_refresh_interval ||
2038                                 age < repo_p->layer_refresh_interval * 60 ||
2039                                 !_auto_download)
2040                             {
2041                                 /* if this is a layer's tile, join with main tile */
2042                                 if (repo_p != mrt->repo)
2043                                 {
2044                                     /* but only if main layer is exists */
2045                                     if (tile_pixbuf)
2046                                         combine_tiles (tile_pixbuf, layer_pixbuf);
2047                                     g_object_unref (layer_pixbuf);
2048                                 }
2049                                 else {
2050                                     tile_pixbuf = layer_pixbuf;
2051                                     zoff_base = zoff;
2052                                 }
2053                                 break;
2054                             }
2055                             else
2056                                 g_object_unref (layer_pixbuf);
2057                         }
2058                         else
2059                             if (repo_p->layers)
2060                                 _refresh_map_after_download = TRUE;
2061                     }
2062                     /* Else we're not going to be drawing this map, so just check
2063                      * if it's in the database. */
2064                     else if(mapdb_exists(
2065                                         repo_p, mrt->zoom + zoff,
2066                                         tilex >> zoff,
2067                                         tiley >> zoff))
2068                     {
2069                         zoff_base = zoff;
2070                         break;
2071                     }
2072
2073                     /* No map; download, if we should. */
2074                     if(!started_download && _auto_download
2075                        && mrt->repo->type != REPOTYPE_NONE
2076                        /* Make sure this map is within dl zoom limits. */
2077                        && ((unsigned)(mrt->zoom + zoff - mrt->repo->min_zoom)
2078                            <= (mrt->repo->max_zoom - mrt->repo->min_zoom))
2079                        /* Make sure this map matches the dl_zoom_steps,
2080                         * or that there currently is no cache. */
2081                        && (!MAPDB_EXISTS(repo_p) || !((mrt->zoom + zoff
2082                                              - (mrt->repo->double_size ? 1 : 0))
2083                                             % mrt->repo->dl_zoom_steps))
2084                        /* Make sure this tile is even possible. */
2085                        && ((unsigned)(tilex >> zoff)
2086                            < unit2ztile(WORLD_SIZE_UNITS, mrt->zoom + zoff)
2087                            && (unsigned)(tiley >> zoff)
2088                            < unit2ztile(WORLD_SIZE_UNITS, mrt->zoom + zoff)))
2089                     {
2090                         started_download = TRUE;
2091
2092                         if(!refresh_latch)
2093                         {
2094                             refresh_latch = g_slice_new(ThreadLatch);
2095                             refresh_latch->is_open = FALSE;
2096                             refresh_latch->is_done_adding_tasks = FALSE;
2097                             refresh_latch->num_tasks = 1;
2098                             refresh_latch->num_done = 0;
2099                             refresh_latch->mutex = g_mutex_new();
2100                             refresh_latch->cond = g_cond_new();
2101                         }
2102                         else
2103                             ++refresh_latch->num_tasks;
2104
2105                         mapdb_initiate_update(
2106                                 repo_p,
2107                                 mrt->zoom + zoff,
2108                                 tilex >> zoff,
2109                                 tiley >> zoff,
2110                                 MAP_UPDATE_AUTO,
2111                                 auto_download_batch_id,
2112                                 (abs((tilex >> zoff) - unit2ztile(
2113                                      mrt->new_center.unitx, mrt->zoom + zoff))
2114                                  + abs((tiley >> zoff) - unit2ztile(
2115                                      mrt->new_center.unity, mrt->zoom + zoff))),
2116                                 refresh_latch);
2117                     }
2118
2119                     /* Try again at a coarser resolution. Only for underlying map.*/
2120                     if (repo_p == mrt->repo && MAPDB_EXISTS(repo_p))
2121                         ++zoff;
2122                     else
2123                         break;
2124                 }
2125
2126                 repo_p = repo_p->layers;
2127             }
2128
2129             /* use zoom of the base map */
2130             zoff = zoff_base;
2131
2132             if(tile_pixbuf)
2133             {
2134                 gint boundx, boundy, width, height;
2135
2136                 if(zoff)
2137                     gdk_pixbuf_rotate_matrix_mult_number(matrix, 1 << zoff);
2138                 gdk_pixbuf_rotate(mrt->pixbuf,
2139                         tile_dev[2 * (y * num_tilex + x)],
2140                         tile_dev[2 * (y * num_tilex + x) + 1],
2141                         matrix,
2142                         tile_pixbuf,
2143                         ((tilex - ((tilex >> zoff) << zoff))
2144                             << (TILE_SIZE_P2 - zoff))
2145                             + (TILE_SIZE_PIXELS >> (1 + zoff)),
2146                         ((tiley - ((tiley>>zoff) << zoff))
2147                             << (TILE_SIZE_P2 - zoff))
2148                             + (TILE_SIZE_PIXELS >> (1 + zoff)),
2149                         TILE_SIZE_PIXELS >> zoff,
2150                         TILE_SIZE_PIXELS >> zoff,
2151                         &boundx, &boundy, &width, &height);
2152                 g_object_unref(tile_pixbuf);
2153                 /* Un-multiply the matrix that we used for blitting.  Good
2154                  * thing we're multiplying by powers of two, or this wouldn't
2155                  * work consistently... */
2156                 if(zoff)
2157                     gdk_pixbuf_rotate_matrix_mult_number(
2158                             matrix, 1.f / (1 << zoff));
2159             }
2160             /* usleep(10000); DEBUG */
2161         }
2162     }
2163
2164     /* Don't replace the pixbuf unless/until the mouse is released. */
2165     g_mutex_lock(_mouse_mutex);
2166     ++_pending_replaces;
2167     g_idle_add_full(G_PRIORITY_HIGH_IDLE + 20,
2168             (GSourceFunc)map_replace_pixbuf_idle, mrt, NULL);
2169     g_mutex_unlock(_mouse_mutex);
2170
2171     /* Release the view-change lock. */
2172     if(refresh_latch)
2173     {
2174         g_mutex_lock(refresh_latch->mutex);
2175         if(refresh_latch->num_tasks == refresh_latch->num_done)
2176         {
2177             /* Fast little workers, aren't they? */
2178             g_mutex_unlock(refresh_latch->mutex);
2179             g_cond_free(refresh_latch->cond);
2180             g_mutex_free(refresh_latch->mutex);
2181             g_slice_free(ThreadLatch, refresh_latch);
2182         }
2183         else
2184         {
2185             refresh_latch->is_done_adding_tasks = TRUE;
2186             refresh_latch->is_open = TRUE;
2187             g_cond_signal(refresh_latch->cond);
2188             g_mutex_unlock(refresh_latch->mutex);
2189         }
2190     }
2191
2192     g_free(tile_dev);
2193
2194     vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2195     return FALSE;
2196 }
2197
2198 gboolean
2199 map_cb_configure(GtkWidget *widget, GdkEventConfigure *event)
2200 {
2201     gint old_view_width_pixels, old_view_height_pixels;
2202     GdkPixbuf *old_map_pixbuf;
2203     printf("%s(%d, %d)\n", __PRETTY_FUNCTION__,
2204             _map_widget->allocation.width, _map_widget->allocation.height);
2205
2206     if(_map_widget->allocation.width == 1
2207             && _map_widget->allocation.height == 1)
2208         /* Special case - first allocation - not persistent. */
2209         return TRUE;
2210
2211     old_view_width_pixels = _view_width_pixels;
2212     old_view_height_pixels = _view_height_pixels;
2213     _view_width_pixels = _map_widget->allocation.width;
2214     _view_height_pixels = _map_widget->allocation.height;
2215     _view_halfwidth_pixels = _view_width_pixels / 2;
2216     _view_halfheight_pixels = _view_height_pixels / 2;
2217
2218     g_object_unref(_map_pixmap);
2219     _map_pixmap = gdk_pixmap_new(
2220                 _map_widget->window,
2221                 _view_width_pixels, _view_height_pixels,
2222                 -1); /* -1: use bit depth of widget->window. */
2223
2224     old_map_pixbuf = _map_pixbuf;
2225     _map_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
2226             _view_width_pixels, _view_height_pixels);
2227
2228     {
2229         gint oldnew_diffx = (gint)(_view_width_pixels
2230                 - old_view_width_pixels) / 2;
2231         gint oldnew_diffy = (gint)(_view_height_pixels
2232                 - old_view_height_pixels) / 2;
2233         gdk_pixbuf_copy_area(old_map_pixbuf,
2234                 MAX(0, -oldnew_diffx), MAX(0, -oldnew_diffy),
2235                 MIN(_view_width_pixels, old_view_width_pixels),
2236                 MIN(_view_height_pixels, old_view_height_pixels),
2237                 _map_pixbuf,
2238                 MAX(0, oldnew_diffx), MAX(0, oldnew_diffy));
2239     }
2240
2241     g_object_unref(old_map_pixbuf);
2242
2243     /* Set _scale_rect. */
2244     _scale_rect.x = (_view_width_pixels - SCALE_WIDTH) / 2;
2245     _scale_rect.width = SCALE_WIDTH;
2246     pango_layout_set_text(_scale_layout, "0", -1);
2247     pango_layout_get_pixel_size(_scale_layout, NULL, &_scale_rect.height);
2248     _scale_rect.y = _view_height_pixels - _scale_rect.height - 1;
2249
2250     /* Set _zoom rect. */
2251     pango_layout_set_text(_zoom_layout, "00", -1);
2252     pango_layout_get_pixel_size(_zoom_layout, &_zoom_rect.width,
2253             &_zoom_rect.height);
2254     _zoom_rect.width *= 1.25;
2255     pango_layout_set_width(_zoom_layout, _zoom_rect.width);
2256     pango_layout_context_changed(_zoom_layout);
2257     _zoom_rect.x = _scale_rect.x - _zoom_rect.width;
2258     _zoom_rect.y = _view_height_pixels - _zoom_rect.height - 1;
2259
2260     /* Set _comprose_rect. */
2261     _comprose_rect.x = _view_width_pixels - 25 - _comprose_rect.width;
2262     _comprose_rect.y = _view_height_pixels - 25 - _comprose_rect.height;
2263
2264     map_set_mark();
2265     map_force_redraw();
2266
2267     /* Fire the screen_dimensions_changed DBUS signal. */
2268     dbus_ifc_fire_view_dimensions_changed(
2269             _view_width_pixels, _view_height_pixels);
2270
2271     /* If Auto-Center is set to Lead, then recalc center. */
2272     if(_center_mode == CENTER_LEAD)
2273         map_center_unit(map_calc_new_center(_next_zoom));
2274     else
2275         map_center_unit(_next_center);
2276
2277     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2278     return TRUE;
2279 }
2280
2281 gboolean
2282 sat_panel_expose(GtkWidget *widget, GdkEventExpose *event)
2283 {
2284     gchar *tmp = NULL;
2285     gint x, y;
2286     printf("%s()\n", __PRETTY_FUNCTION__);
2287
2288     draw_sat_info(widget,
2289         0, 0,
2290         widget->allocation.width,
2291         widget->allocation.height,
2292         FALSE);
2293
2294     /* Sat View/In Use */
2295     tmp = g_strdup_printf("%d/%d", _gps.satinuse, _gps.satinview);
2296     pango_layout_set_text(_sat_panel_layout, tmp, -1);
2297     pango_layout_set_alignment(_sat_panel_layout, PANGO_ALIGN_LEFT);
2298     gdk_draw_layout(widget->window,
2299         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2300         20, 2,
2301         _sat_panel_layout);
2302     g_free(tmp);
2303
2304     switch(_gps.fix)
2305     {
2306         case 2:
2307         case 3: tmp = g_strdup_printf("%dD fix", _gps.fix); break;
2308         default: tmp = g_strdup_printf("nofix"); break;
2309     }
2310     pango_layout_set_text(_sat_panel_layout, tmp, -1);
2311     pango_layout_set_alignment(_sat_panel_layout, PANGO_ALIGN_RIGHT);
2312     pango_layout_get_pixel_size(_sat_panel_layout, &x, &y);
2313     gdk_draw_layout(widget->window,
2314         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2315         widget->allocation.width - 20 - x, 2,
2316         _sat_panel_layout);
2317     g_free(tmp);
2318
2319     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
2320     return TRUE;
2321 }
2322
2323 gboolean
2324 heading_panel_expose(GtkWidget *widget, GdkEventExpose *event)
2325 {
2326     gint size, xoffset, yoffset, i, x, y;
2327     gint dir;
2328     gfloat tmp;
2329     gchar *text;
2330     printf("%s()\n", __PRETTY_FUNCTION__);
2331
2332     size = MIN(widget->allocation.width, widget->allocation.height);
2333     if(widget->allocation.width > widget->allocation.height)
2334     {
2335         xoffset = (widget->allocation.width - widget->allocation.height) / 2;
2336         yoffset = 0;
2337     }
2338     else
2339     {
2340         xoffset = 0;
2341         yoffset = (widget->allocation.height - widget->allocation.width) / 2;
2342     }
2343     pango_font_description_set_size(_heading_panel_fontdesc,12*PANGO_SCALE);
2344     pango_layout_set_font_description(_heading_panel_layout,
2345             _heading_panel_fontdesc);
2346     pango_layout_set_alignment(_heading_panel_layout, PANGO_ALIGN_CENTER);
2347
2348     text = g_strdup_printf("%3.0f°", _gps.heading);
2349     pango_layout_set_text(_heading_panel_layout, text, -1);
2350     pango_layout_get_pixel_size(_heading_panel_layout, &x, &y);
2351
2352     gdk_draw_layout(widget->window,
2353         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2354         xoffset + size/2 - x/2,
2355         yoffset + size - y - 2, _heading_panel_layout);
2356     g_free(text);
2357
2358     gdk_draw_arc (widget->window,
2359         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2360         FALSE,
2361         xoffset, yoffset + size/2,
2362         size, size,
2363         0, 64 * 180);
2364
2365     /* Simple arrow for heading*/
2366     gdk_draw_line(widget->window,
2367         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2368         xoffset + size/2 + 3,
2369         yoffset + size - y - 5,
2370         xoffset + size/2,
2371         yoffset + size/2 + 5);
2372
2373     gdk_draw_line(widget->window,
2374         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2375         xoffset + size/2 - 3,
2376         yoffset + size - y - 5,
2377         xoffset + size/2,
2378         yoffset + size/2 + 5);
2379
2380     gdk_draw_line(widget->window,
2381         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2382         xoffset + size/2 - 3,
2383         yoffset + size - y - 5,
2384         xoffset + size/2,
2385         yoffset + size - y - 8);
2386
2387     gdk_draw_line(widget->window,
2388         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2389         xoffset + size/2 + 3,
2390         yoffset + size - y - 5,
2391         xoffset + size/2,
2392         yoffset + size - y - 8);
2393
2394     gint angle[5] = {-90,-45,0,45,90};
2395     gint fsize[5] = {0,4,10,4,0};
2396     for(i = 0; i < 5; i++)
2397     {
2398         dir = (gint)(_gps.heading/45)*45 + angle[i];
2399
2400         switch(dir)
2401         {
2402             case   0:
2403             case 360: text = g_strdup("N"); break;
2404             case  45:
2405             case 405:
2406                 text = g_strdup("NE"); break;
2407             case  90:
2408                 text = g_strdup("E"); break;
2409             case 135:
2410                 text = g_strdup("SE"); break;
2411             case 180:
2412                 text = g_strdup("S"); break;
2413             case 225:
2414                 text = g_strdup("SW"); break;
2415             case 270:
2416             case -90:
2417                 text = g_strdup("W"); break;
2418             case 315:
2419             case -45:
2420                 text = g_strdup("NW"); break;
2421             default :
2422                 text = g_strdup("??");
2423                 break;
2424         }
2425
2426         tmp = deg2rad(dir - _gps.heading);
2427         gdk_draw_line(widget->window,
2428             widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2429             xoffset + size/2 + ((size/2 - 5) * sinf(tmp)),
2430             yoffset + size - ((size/2 - 5) * cosf(tmp)),
2431             xoffset + size/2 + ((size/2 + 5) * sinf(tmp)),
2432             yoffset + size - ((size/2 + 5) * cosf(tmp)));
2433
2434         x = fsize[i];
2435         if(abs((gint)(_gps.heading/45)*45 - _gps.heading)
2436                 > abs((gint)(_gps.heading/45)*45 + 45 - _gps.heading)
2437                 && (i > 0))
2438             x = fsize[i - 1];
2439
2440         pango_font_description_set_size(_heading_panel_fontdesc,
2441                 (10 + x)*PANGO_SCALE);
2442         pango_layout_set_font_description(_heading_panel_layout,
2443                 _heading_panel_fontdesc);
2444         pango_layout_set_text(_heading_panel_layout, text, -1);
2445         pango_layout_get_pixel_size(_heading_panel_layout, &x, &y);
2446         x = xoffset + size/2 + ((size/2 + 15) * sinf(tmp)) - x/2,
2447         y = yoffset + size - ((size/2 + 15) * cosf(tmp)) - y/2,
2448
2449         gdk_draw_layout(widget->window,
2450             widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2451             x, y, _heading_panel_layout);
2452         g_free(text);
2453     }
2454
2455     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
2456     return TRUE;
2457 }
2458
2459 gboolean
2460 map_cb_expose(GtkWidget *widget, GdkEventExpose *event)
2461 {
2462     gint i;
2463     printf("%s(%d, %d, %d, %d)\n", __PRETTY_FUNCTION__,
2464             event->area.x, event->area.y,
2465             event->area.width, event->area.height);
2466
2467     gdk_draw_drawable(
2468             _map_widget->window,
2469             _gc[COLORABLE_MARK],
2470             _map_pixmap,
2471             event->area.x - _map_offset_devx, event->area.y - _map_offset_devy,
2472             event->area.x, event->area.y,
2473             event->area.width, event->area.height);
2474
2475     /* Draw the mark. */
2476     if((((unsigned)(_mark_bufx1 + _draw_width)
2477                 <= _view_width_pixels+2*_draw_width)
2478              &&((unsigned)(_mark_bufy1 + _draw_width)
2479                  <= _view_height_pixels+2*_draw_width))
2480         || (((unsigned)(_mark_bufx2 + _draw_width)
2481                  <= _view_width_pixels+2*_draw_width)
2482              &&((unsigned)(_mark_bufy2 + _draw_width)
2483                  <= _view_height_pixels+2*_draw_width)))
2484     {
2485         gdk_draw_arc(
2486                 _map_widget->window,
2487                 _gps_state == RCVR_FIXED
2488                     ? _gc[COLORABLE_MARK] : _gc[COLORABLE_MARK_OLD],
2489                 FALSE, /* not filled. */
2490                 _mark_bufx1 - _draw_width + _map_offset_devx,
2491                 _mark_bufy1 - _draw_width + _map_offset_devy,
2492                 2 * _draw_width, 2 * _draw_width,
2493                 0, 360 * 64);
2494         gdk_draw_line(
2495                 _map_widget->window,
2496                 _gps_state == RCVR_FIXED
2497                     ? (_show_velvec
2498                         ? _gc[COLORABLE_MARK_VELOCITY] : _gc[COLORABLE_MARK])
2499                     : _gc[COLORABLE_MARK_OLD],
2500                 _mark_bufx1 + _map_offset_devx,
2501                 _mark_bufy1 + _map_offset_devy,
2502                 _mark_bufx2 + _map_offset_devx,
2503                 _mark_bufy2 + _map_offset_devy);
2504     }
2505
2506     /* draw zoom box if so wanted */
2507     if(_show_zoomlevel) {
2508         gchar *buffer = g_strdup_printf("%d", _zoom);
2509         gdk_draw_rectangle(_map_widget->window,
2510                 _map_widget->style->bg_gc[GTK_STATE_ACTIVE],
2511                 TRUE,
2512                 _zoom_rect.x, _zoom_rect.y,
2513                 _zoom_rect.width, _zoom_rect.height);
2514         gdk_draw_rectangle(_map_widget->window,
2515                 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2516                 FALSE,
2517                 _zoom_rect.x, _zoom_rect.y,
2518                 _zoom_rect.width, _zoom_rect.height);
2519         pango_layout_set_text(_zoom_layout, buffer, -1);
2520         gdk_draw_layout(_map_widget->window,
2521                 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2522                 _zoom_rect.x + _zoom_rect.width / 2,
2523                 _zoom_rect.y, _zoom_layout);
2524     }
2525
2526     /* Draw scale, if necessary. */
2527     if(_show_scale)
2528     {
2529         gdk_rectangle_intersect(&event->area, &_scale_rect, &event->area);
2530         if(event->area.width && event->area.height)
2531         {
2532             gdk_draw_rectangle(_map_widget->window,
2533                     _map_widget->style->bg_gc[GTK_STATE_ACTIVE],
2534                     TRUE,
2535                     _scale_rect.x, _scale_rect.y,
2536                     _scale_rect.width, _scale_rect.height);
2537             gdk_draw_rectangle(_map_widget->window,
2538                     _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2539                     FALSE,
2540                     _scale_rect.x, _scale_rect.y,
2541                     _scale_rect.width, _scale_rect.height);
2542
2543             /* Now calculate and draw the distance. */
2544             {
2545                 gchar buffer[16];
2546                 gfloat distance;
2547                 gdouble lat1, lon1, lat2, lon2;
2548                 gint width;
2549
2550                 unit2latlon(_center.unitx - pixel2unit(SCALE_WIDTH / 2 - 4),
2551                         _center.unity, lat1, lon1);
2552                 unit2latlon(_center.unitx + pixel2unit(SCALE_WIDTH / 2 - 4),
2553                         _center.unity, lat2, lon2);
2554                 distance = calculate_distance(lat1, lon1, lat2, lon2)
2555                     * UNITS_CONVERT[_units];
2556
2557                 if(distance < 1.f)
2558                     snprintf(buffer, sizeof(buffer), "%0.2f %s", distance,
2559                             UNITS_ENUM_TEXT[_units]);
2560                 else if(distance < 10.f)
2561                     snprintf(buffer, sizeof(buffer), "%0.1f %s", distance,
2562                             UNITS_ENUM_TEXT[_units]);
2563                 else
2564                     snprintf(buffer, sizeof(buffer), "%0.f %s", distance,
2565                             UNITS_ENUM_TEXT[_units]);
2566                 pango_layout_set_text(_scale_layout, buffer, -1);
2567
2568                 pango_layout_get_pixel_size(_scale_layout, &width, NULL);
2569
2570                 /* Draw the layout itself. */
2571                 gdk_draw_layout(_map_widget->window,
2572                     _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2573                     _scale_rect.x + (_scale_rect.width - width) / 2,
2574                     _scale_rect.y, _scale_layout);
2575
2576                 /* Draw little hashes on the ends. */
2577                 gdk_draw_line(_map_widget->window,
2578                     _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2579                     _scale_rect.x + 4,
2580                     _scale_rect.y + _scale_rect.height / 2 - 4,
2581                     _scale_rect.x + 4,
2582                     _scale_rect.y + _scale_rect.height / 2 + 4);
2583                 gdk_draw_line(_map_widget->window,
2584                     _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2585                     _scale_rect.x + 4,
2586                     _scale_rect.y + _scale_rect.height / 2,
2587                     _scale_rect.x + (_scale_rect.width - width) / 2 - 4,
2588                     _scale_rect.y + _scale_rect.height / 2);
2589                 gdk_draw_line(_map_widget->window,
2590                     _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2591                     _scale_rect.x + _scale_rect.width - 4,
2592                     _scale_rect.y + _scale_rect.height / 2 - 4,
2593                     _scale_rect.x + _scale_rect.width - 4,
2594                     _scale_rect.y + _scale_rect.height / 2 + 4);
2595                 gdk_draw_line(_map_widget->window,
2596                     _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2597                     _scale_rect.x + _scale_rect.width - 4,
2598                     _scale_rect.y + _scale_rect.height / 2,
2599                     _scale_rect.x + (_scale_rect.width + width) / 2 + 4,
2600                     _scale_rect.y + _scale_rect.height / 2);
2601             }
2602         }
2603     }
2604
2605     /* Draw the compass rose, if necessary. */
2606     if(_show_comprose)
2607     {
2608         GdkPoint points[3];
2609         gint offsetx, offsety;
2610         gfloat x, y;
2611
2612         offsetx = _comprose_rect.x;
2613         offsety = _comprose_rect.y;
2614
2615         gdk_pixbuf_rotate_vector(&x, &y, _map_rotate_matrix, 0, 12);
2616         points[0].x = offsetx + x + 0.5f; points[0].y = offsety + y + 0.5f;
2617         gdk_pixbuf_rotate_vector(&x, &y, _map_rotate_matrix, 20, 30);
2618         points[1].x = offsetx + x + 0.5f; points[1].y = offsety + y + 0.5f;
2619         gdk_pixbuf_rotate_vector(&x, &y, _map_rotate_matrix, 0, -45);
2620         points[2].x = offsetx + x + 0.5f; points[2].y = offsety + y + 0.5f;
2621         gdk_pixbuf_rotate_vector(&x, &y, _map_rotate_matrix, -20, 30);
2622         points[3].x = offsetx + x + 0.5f; points[3].y = offsety + y + 0.5f;
2623
2624         gdk_draw_polygon(_map_widget->window,
2625                 _map_widget->style->bg_gc[GTK_STATE_ACTIVE],
2626                 TRUE, /* FILLED */
2627                 points, 4);
2628         gdk_draw_polygon(_map_widget->window,
2629                 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2630                 FALSE, /* NOT FILLED */
2631                 points, 4);
2632
2633         gdk_draw_layout(_map_widget->window,
2634                 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2635                 _comprose_rect.x - _comprose_rect.width / 2 + 1,
2636                 _comprose_rect.y - _comprose_rect.height / 2 - 4,
2637                 _comprose_layout);
2638     }
2639
2640     /* Draw a stopwatch if we're redrawing the map. */
2641     for(i = _redraw_count - 1; i >= 0; i--)
2642     {
2643         gdk_draw_pixbuf(
2644                 _map_widget->window,
2645                 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2646                 _redraw_wait_icon,
2647                 0, 0,
2648                 _redraw_wait_bounds.x + i
2649                         * HOURGLASS_SEPARATION,
2650                 _redraw_wait_bounds.y,
2651                 _redraw_wait_bounds.width,
2652                 _redraw_wait_bounds.height,
2653                 GDK_RGB_DITHER_NONE, 0, 0);
2654     }
2655
2656     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2657     return TRUE;
2658 }
2659
2660 static void
2661 latlon_cb_copy_clicked(GtkWidget *widget, LatlonDialog *lld) {
2662     gchar buffer[42];
2663
2664     snprintf(buffer, sizeof(buffer),
2665             "%s %s",
2666             gtk_label_get_text(GTK_LABEL(lld->lat)),
2667             gtk_label_get_text(GTK_LABEL(lld->lon)));
2668
2669     gtk_clipboard_set_text(
2670             gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), buffer, -1);
2671 }
2672
2673 static void
2674 latlon_cb_fmt_changed(GtkWidget *widget, LatlonDialog *lld) {
2675   DegFormat fmt;
2676
2677   fmt = gtk_combo_box_get_active(GTK_COMBO_BOX(lld->fmt_combo));
2678
2679   {
2680     gint old = _degformat; /* augh... */
2681     gchar buffer[LL_FMT_LEN];
2682     gchar buffer2[LL_FMT_LEN];
2683
2684     _degformat = fmt;
2685     
2686     format_lat_lon(lld->glat, lld->glon, buffer, buffer2);
2687     
2688     //lat_format(lld->glat, buffer);
2689     gtk_label_set_label(GTK_LABEL(lld->lat), buffer);
2690     //lon_format(lld->glon, buffer);
2691     
2692     if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
2693         gtk_label_set_label(GTK_LABEL(lld->lon), buffer2);
2694     else
2695         gtk_label_set_label(GTK_LABEL(lld->lon), g_strdup(""));
2696     
2697     
2698     // And set the titles
2699     gtk_label_set_label(GTK_LABEL(lld->lat_title), 
2700                 DEG_FORMAT_ENUM_TEXT[_degformat].short_field_1 );
2701     
2702     if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
2703         gtk_label_set_label(GTK_LABEL(lld->lon_title), 
2704                         DEG_FORMAT_ENUM_TEXT[_degformat].short_field_2 );
2705     else
2706         gtk_label_set_label(GTK_LABEL(lld->lon_title), g_strdup(""));
2707     
2708     
2709     _degformat = old;
2710   }
2711 }
2712
2713 gboolean
2714 latlon_dialog(gdouble lat, gdouble lon)
2715 {
2716     LatlonDialog lld;
2717     GtkWidget *dialog;
2718     GtkWidget *table;
2719     GtkWidget *label;
2720     GtkWidget *lbl_lon_title;
2721     GtkWidget *lbl_lat_title;
2722     GtkWidget *txt_lat;
2723     GtkWidget *txt_lon;
2724     GtkWidget *cmb_format;
2725     GtkWidget *btn_copy = NULL;
2726     gint prev_degformat = _degformat;
2727     gint fallback_deg_format = _degformat;
2728     
2729     printf("%s()\n", __PRETTY_FUNCTION__);
2730
2731     // Check that the current coord system supports the select position
2732     if(!coord_system_check_lat_lon (lat, lon, &fallback_deg_format))
2733     {
2734         _degformat = fallback_deg_format;
2735     }
2736      
2737     
2738     dialog = gtk_dialog_new_with_buttons(_("Show Position"),
2739             GTK_WINDOW(_window), GTK_DIALOG_MODAL,
2740             GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2741             NULL);
2742
2743     /* Set the lat/lon strings. */
2744     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2745             table = gtk_table_new(5, 2, FALSE), TRUE, TRUE, 0);
2746
2747     gtk_table_attach(GTK_TABLE(table),
2748                 lbl_lat_title = gtk_label_new(/*_("Lat")*/ DEG_FORMAT_ENUM_TEXT[_degformat].short_field_1 ),
2749             0, 1, 0, 1, GTK_FILL, 0, 2, 4);
2750     gtk_misc_set_alignment(GTK_MISC(lbl_lat_title), 1.f, 0.5f);
2751     gtk_table_attach(GTK_TABLE(table),
2752             txt_lat = gtk_label_new(""),
2753             1, 2, 0, 1, GTK_FILL, 0, 2, 4);
2754     gtk_misc_set_alignment(GTK_MISC(txt_lat), 1.f, 0.5f);
2755
2756     
2757     gtk_table_attach(GTK_TABLE(table),
2758             lbl_lon_title = gtk_label_new(/*_("Lon")*/ DEG_FORMAT_ENUM_TEXT[_degformat].short_field_2 ),
2759             0, 1, 1, 2, GTK_FILL, 0, 2, 4);
2760     gtk_misc_set_alignment(GTK_MISC(lbl_lon_title), 1.f, 0.5f);
2761     
2762     gtk_table_attach(GTK_TABLE(table),
2763             txt_lon = gtk_label_new(""),
2764             1, 2, 1, 2, GTK_FILL, 0, 2, 4);
2765     gtk_misc_set_alignment(GTK_MISC(txt_lon), 1.f, 0.5f);
2766
2767     
2768     gtk_table_attach(GTK_TABLE(table),
2769             label = gtk_label_new(_("Format")),
2770             0, 1, 2, 3, GTK_FILL, 0, 2, 4);
2771     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2772     gtk_table_attach(GTK_TABLE(table),
2773             label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
2774             1, 2, 2, 3, GTK_FILL, 0, 2, 4);
2775     gtk_container_add(GTK_CONTAINER(label),
2776             cmb_format = gtk_combo_box_new_text());
2777     gtk_table_attach(GTK_TABLE(table),
2778             btn_copy = gtk_button_new_with_label(_("Copy")),
2779             0, 2, 3, 4, GTK_FILL, 0, 2, 4);
2780
2781     /* Lat/Lon */
2782     {
2783       gchar buffer[LL_FMT_LEN];
2784       gchar buffer2[LL_FMT_LEN];
2785
2786       format_lat_lon(lat, lon, buffer, buffer2);
2787       
2788       //lat_format(lat, buffer);
2789       gtk_label_set_label(GTK_LABEL(txt_lat), buffer);
2790       //lat_format(lon, buffer);
2791       if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
2792           gtk_label_set_label(GTK_LABEL(txt_lon), buffer2);
2793       else
2794           gtk_label_set_label(GTK_LABEL(txt_lon), g_strdup(""));
2795     }
2796
2797     /* Fill in formats */
2798     {
2799       int i;
2800
2801       for(i = 0; i < DEG_FORMAT_ENUM_COUNT; i++) {
2802           gtk_combo_box_append_text(GTK_COMBO_BOX(cmb_format),
2803                   DEG_FORMAT_ENUM_TEXT[i].name);
2804       }
2805       gtk_combo_box_set_active(GTK_COMBO_BOX(cmb_format), _degformat);
2806     }
2807
2808
2809     /* setup cb context */
2810     lld.fmt_combo = cmb_format;
2811     lld.glat = lat;
2812     lld.glon = lon;
2813     lld.lat = txt_lat;
2814     lld.lon = txt_lon;
2815
2816     lld.lat_title = lbl_lat_title;
2817     lld.lon_title = lbl_lon_title;
2818     
2819     /* Connect Signals */
2820     g_signal_connect(G_OBJECT(cmb_format), "changed",
2821                     G_CALLBACK(latlon_cb_fmt_changed), &lld);
2822     g_signal_connect(G_OBJECT(btn_copy), "clicked",
2823                     G_CALLBACK(latlon_cb_copy_clicked), &lld);
2824
2825     gtk_widget_show_all(dialog);
2826
2827     gtk_dialog_run(GTK_DIALOG(dialog));
2828     
2829     _degformat = prev_degformat; // Put back incase it had to be auto changed
2830     
2831     gtk_widget_hide(dialog);
2832
2833     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2834     return TRUE;
2835 }
2836
2837
2838 /**
2839  * This is a multi-purpose function for allowing the user to select a file
2840  * for either reading or writing.  If chooser_action is
2841  * GTK_FILE_CHOOSER_ACTION_OPEN, then bytes_out and size_out must be
2842  * non-NULL.  If chooser_action is GTK_FILE_CHOOSER_ACTION_SAVE, then
2843  * handle_out must be non-NULL.  Either dir or file (or both) can be NULL.
2844  * This function returns TRUE if a file was successfully opened.
2845  */
2846 gboolean
2847 display_open_file(GtkWindow *parent, gchar **bytes_out,
2848         GnomeVFSHandle **handle_out, gint *size_out,
2849         gchar **dir, gchar **file, GtkFileChooserAction chooser_action)
2850 {
2851     GtkWidget *dialog;
2852     gboolean success = FALSE;
2853     printf("%s()\n", __PRETTY_FUNCTION__);
2854
2855     dialog = hildon_file_chooser_dialog_new(parent, chooser_action);
2856
2857     if(dir && *dir)
2858         gtk_file_chooser_set_current_folder_uri(
2859                 GTK_FILE_CHOOSER(dialog), *dir);
2860     if(file && *file)
2861     {
2862         gtk_file_chooser_set_uri(
2863                 GTK_FILE_CHOOSER(dialog), *file);
2864         if(chooser_action == GTK_FILE_CHOOSER_ACTION_SAVE)
2865         {
2866             /* Work around a bug in HildonFileChooserDialog. */
2867             gchar *basename = g_path_get_basename(*file);
2868             g_object_set(G_OBJECT(dialog), "autonaming", FALSE, NULL);
2869             gtk_file_chooser_set_current_name(
2870                     GTK_FILE_CHOOSER(dialog), basename);
2871             g_free(basename);
2872         }
2873     }
2874
2875     gtk_widget_show_all(dialog);
2876
2877     while(!success && gtk_dialog_run(GTK_DIALOG(dialog))==GTK_RESPONSE_OK)
2878     {
2879         gchar *file_uri_str;
2880         GnomeVFSResult vfs_result;
2881
2882         /* Get the selected filename. */
2883         file_uri_str = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog));
2884
2885         if((chooser_action == GTK_FILE_CHOOSER_ACTION_OPEN
2886                 && (GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(
2887                         file_uri_str, size_out, bytes_out))))
2888                 || (chooser_action == GTK_FILE_CHOOSER_ACTION_SAVE
2889                     && GNOME_VFS_OK != (vfs_result = gnome_vfs_create(
2890                             handle_out, file_uri_str,
2891                             GNOME_VFS_OPEN_WRITE, FALSE, 0664))))
2892         {
2893             gchar buffer[BUFFER_SIZE];
2894             snprintf(buffer, sizeof(buffer),
2895                     "%s:\n%s", chooser_action == GTK_FILE_CHOOSER_ACTION_OPEN
2896                                 ? _("Failed to open file for reading")
2897                                 : _("Failed to open file for writing"),
2898                     gnome_vfs_result_to_string(vfs_result));
2899             popup_error(dialog, buffer);
2900         }
2901         else
2902             success = TRUE;
2903
2904         g_free(file_uri_str);
2905     }
2906
2907     if(success)
2908     {
2909         /* Success!. */
2910         if(dir)
2911         {
2912             g_free(*dir);
2913             *dir = gtk_file_chooser_get_current_folder_uri(
2914                     GTK_FILE_CHOOSER(dialog));
2915         }
2916
2917         /* If desired, save the file for later. */
2918         if(file)
2919         {
2920             g_free(*file);
2921             *file = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog));
2922         }
2923     }
2924
2925     gtk_widget_destroy(dialog);
2926
2927     vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
2928     return success;
2929 }
2930
2931 void
2932 display_init()
2933 {
2934     PangoContext *pango_context;
2935     PangoFontDescription *pango_font;
2936     GdkColor color;
2937     printf("%s()\n", __PRETTY_FUNCTION__);
2938
2939     /* Cache some pango and GCs for drawing. */
2940     pango_context = gtk_widget_get_pango_context(_map_widget);
2941     _scale_layout = pango_layout_new(pango_context);
2942     pango_font = pango_font_description_new();
2943     pango_font_description_set_size(pango_font, 12 * PANGO_SCALE);
2944     pango_layout_set_font_description(_scale_layout, pango_font);
2945     
2946 #ifdef INCLUDE_APRS
2947     /* APRS Labels */
2948     pango_context = gtk_widget_get_pango_context(_map_widget);
2949     _aprs_label_layout = pango_layout_new(pango_context);
2950     pango_font = pango_font_description_new();
2951     pango_font_description_set_size(pango_font, 10 * PANGO_SCALE);
2952     pango_font_description_set_family(pango_font,"Sans Serif");
2953     pango_layout_set_font_description(_aprs_label_layout, pango_font);
2954 #endif // INCLUDE_APRS
2955
2956     /* zoom box */
2957     pango_context = gtk_widget_get_pango_context(_map_widget);
2958     _zoom_layout = pango_layout_new(pango_context);
2959     pango_font = pango_font_description_new();
2960     pango_font_description_set_size(pango_font, 12 * PANGO_SCALE);
2961     pango_layout_set_font_description(_zoom_layout, pango_font);
2962     pango_layout_set_alignment(_zoom_layout, PANGO_ALIGN_CENTER);
2963
2964     /* compose rose */
2965     pango_context = gtk_widget_get_pango_context(_map_widget);
2966     _comprose_layout = pango_layout_new(pango_context);
2967     pango_font = pango_font_description_new();
2968     pango_font_description_set_size(pango_font, 16 * PANGO_SCALE);
2969     pango_font_description_set_weight(pango_font, PANGO_WEIGHT_BOLD);
2970     pango_layout_set_font_description(_comprose_layout, pango_font);
2971     pango_layout_set_alignment(_comprose_layout, PANGO_ALIGN_CENTER);
2972     pango_layout_set_text(_comprose_layout, "N", -1);
2973     {
2974         PangoRectangle rect;
2975         pango_layout_get_pixel_extents(_comprose_layout, &rect, NULL);
2976         _comprose_rect.width = rect.width + 3;
2977         _comprose_rect.height = rect.height + 3;
2978     }
2979
2980     /* speed limit */
2981     _speed_limit_gc1 = gdk_gc_new (_map_widget->window);
2982     color.red = 0xffff;
2983     color.green = 0;
2984     color.blue = 0;
2985     gdk_gc_set_rgb_fg_color(_speed_limit_gc1, &color);
2986     color.red = 0;
2987     color.green = 0;
2988     color.blue = 0;
2989     _speed_limit_gc2 = gdk_gc_new(_map_widget->window);
2990     gdk_gc_set_rgb_fg_color(_speed_limit_gc2, &color);
2991     pango_context = gtk_widget_get_pango_context(_map_widget);
2992     _speed_limit_layout = pango_layout_new(pango_context);
2993     pango_font = pango_font_description_new();
2994     pango_font_description_set_size(pango_font, 64 * PANGO_SCALE);
2995     pango_layout_set_font_description(_speed_limit_layout,
2996             pango_font);
2997     pango_layout_set_alignment(_speed_limit_layout, PANGO_ALIGN_CENTER);
2998
2999     /* draw_sat_info() */
3000     _sat_info_gc1 = gdk_gc_new(_map_widget->window);
3001     color.red = 0;
3002     color.green = 0;
3003     color.blue = 0;
3004     gdk_gc_set_rgb_fg_color(_sat_info_gc1, &color);
3005     color.red = 0;
3006     color.green = 0;
3007     color.blue = 0xffff;
3008     _sat_info_gc2 = gdk_gc_new(_map_widget->window);
3009     gdk_gc_set_rgb_fg_color(_sat_info_gc2, &color);
3010     pango_context = gtk_widget_get_pango_context(_map_widget);
3011     _sat_info_layout = pango_layout_new(pango_context);
3012     pango_font = pango_font_description_new();
3013     pango_font_description_set_family(pango_font,"Sans Serif");
3014     pango_font_description_set_size(pango_font, 8*PANGO_SCALE);
3015     pango_layout_set_font_description(_sat_info_layout, pango_font);
3016     pango_layout_set_alignment(_sat_info_layout, PANGO_ALIGN_CENTER);
3017
3018     /* sat_panel_expose() */
3019     pango_context = gtk_widget_get_pango_context(_map_widget);
3020     _sat_panel_layout = pango_layout_new(pango_context);
3021     pango_font = pango_font_description_new();
3022     pango_font_description_set_family(pango_font,"Sans Serif");
3023     pango_font_description_set_size(pango_font, 14*PANGO_SCALE);
3024     pango_layout_set_font_description (_sat_panel_layout, pango_font);
3025
3026     /* heading_panel_expose() */
3027     pango_context = gtk_widget_get_pango_context(_map_widget);
3028     _heading_panel_layout = pango_layout_new(pango_context);
3029     _heading_panel_fontdesc =  pango_font_description_new();
3030     pango_font_description_set_family(_heading_panel_fontdesc, "Sans Serif");
3031
3032     /* draw_sat_details() */
3033     pango_context = gtk_widget_get_pango_context(_map_widget);
3034     _sat_details_layout = pango_layout_new(pango_context);
3035     pango_font = pango_font_description_new();
3036     pango_font_description_set_family(pango_font,"Sans Serif");
3037     pango_font_description_set_size(pango_font, 10*PANGO_SCALE);
3038     pango_layout_set_font_description(_sat_details_layout,
3039             pango_font);
3040     pango_layout_set_alignment(_sat_details_layout, PANGO_ALIGN_CENTER);
3041
3042     /* sat_details_panel_expose() */
3043     pango_context = gtk_widget_get_pango_context(_map_widget);
3044     _sat_details_expose_layout = pango_layout_new(pango_context);
3045     pango_font = pango_font_description_new();
3046     pango_font_description_set_family(
3047             pango_font,"Sans Serif");
3048     pango_layout_set_alignment(_sat_details_expose_layout,
3049             PANGO_ALIGN_CENTER);
3050     pango_font_description_set_size(pango_font,
3051             14*PANGO_SCALE);
3052     pango_layout_set_font_description(_sat_details_expose_layout,
3053             pango_font);
3054
3055     /* Load the _redraw_wait_icon. */
3056     {
3057         GError *error = NULL;
3058         gchar *icon_path = "/usr/share/icons/hicolor/scalable/hildon"
3059                            "/maemo-mapper-wait.png";
3060         _redraw_wait_bounds.x = 0;
3061         _redraw_wait_bounds.y = 0;
3062         _redraw_wait_icon = gdk_pixbuf_new_from_file(icon_path, &error);
3063         if(!_redraw_wait_icon || error)
3064         {
3065             g_printerr("Error parsing pixbuf: %s\n",
3066                     error ? error->message : icon_path);
3067             _redraw_wait_bounds.width = 0;
3068             _redraw_wait_bounds.height = 0;
3069             _redraw_wait_icon = NULL;
3070         }
3071         else
3072         {
3073             _redraw_wait_bounds.width
3074                 = gdk_pixbuf_get_width(_redraw_wait_icon);
3075             _redraw_wait_bounds.height
3076                 = gdk_pixbuf_get_height(_redraw_wait_icon);
3077         }
3078     }
3079
3080     g_signal_connect(G_OBJECT(_map_widget), "configure_event",
3081             G_CALLBACK(map_cb_configure), NULL);
3082
3083     g_signal_connect(G_OBJECT(_map_widget), "expose_event",
3084             G_CALLBACK(map_cb_expose), NULL);
3085     g_signal_connect(G_OBJECT(_sat_panel), "expose_event",
3086             G_CALLBACK(sat_panel_expose), NULL);
3087     g_signal_connect(G_OBJECT(_heading_panel), "expose_event",
3088             G_CALLBACK(heading_panel_expose), NULL);
3089
3090     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
3091 }