]> git.itanic.dy.fi Git - maemo-mapper/blob - src/display.c
Administrative changes in preparation for release of Maemo Mapper v2.6.2.
[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     printf("combine_tiles()\n");
1826
1827     if (gdk_pixbuf_get_colorspace (dst_pixbuf) != gdk_pixbuf_get_colorspace (src_pixbuf)) {
1828         printf ("combine return (1)\n");
1829         return;
1830     }
1831     if (gdk_pixbuf_get_colorspace (dst_pixbuf) != GDK_COLORSPACE_RGB) {
1832         printf ("combine return (2)\n");
1833         return;
1834     }
1835
1836     if (bps != gdk_pixbuf_get_bits_per_sample (src_pixbuf)) {
1837         printf ("combine return (5)\n");
1838         return;
1839     }
1840
1841     width = gdk_pixbuf_get_width (dst_pixbuf);
1842     height = gdk_pixbuf_get_height (dst_pixbuf);
1843
1844     if (width != gdk_pixbuf_get_width (src_pixbuf)) {
1845         printf ("combine return (6)\n");
1846         return;
1847     }
1848     if (height != gdk_pixbuf_get_height (src_pixbuf)) {
1849         printf ("combine return (7)\n");
1850         return;
1851     }
1852
1853     s_delta = (bps >> 3) * s_n_channels;
1854     d_delta = (bps >> 3) * d_n_channels;
1855     d_p = gdk_pixbuf_get_pixels (dst_pixbuf);
1856     s_p = gdk_pixbuf_get_pixels (src_pixbuf);
1857
1858     /* ok, we're ready to combine */
1859     for (y = 0; y < height; y++) {
1860         for (x = 0; x < width; x++, d_p += d_delta, s_p += s_delta) {
1861             /* TODO: alpha blending? */
1862             if (s_n_channels == 3 || s_p[3]) {
1863                 d_p[0] = s_p[0];
1864                 d_p[1] = s_p[1];
1865                 d_p[2] = s_p[2];
1866             }
1867         }
1868     }
1869 }
1870
1871
1872 gboolean
1873 thread_render_map(MapRenderTask *mrt)
1874 {
1875     gfloat matrix[4];
1876     gint start_tilex, start_tiley, stop_tilex, stop_tiley;
1877     gint x = 0, y, num_tilex, num_tiley;
1878     gint diag_halflength_units;
1879     gfloat angle_rad;
1880     gint tile_rothalf_pixels;
1881     gint curr_tile_to_draw, num_tiles_to_draw;
1882     gfloat *tile_dev;
1883     ThreadLatch *refresh_latch = NULL;
1884     gint cache_amount;
1885     static gint8 auto_download_batch_id = INT8_MIN;
1886     printf("%s(%d, %d, %d, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1887             mrt->screen_width_pixels, mrt->screen_height_pixels,
1888             mrt->new_center.unitx, mrt->new_center.unity, mrt->zoom,
1889             mrt->rotate_angle);
1890
1891     /* If there are more render tasks in the queue, skip this one. */
1892     if(g_thread_pool_unprocessed(_mrt_thread_pool))
1893     {
1894         g_slice_free(MapRenderTask, mrt);
1895         --_redraw_count;
1896         vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1897         return FALSE;
1898     }
1899
1900     angle_rad = deg2rad(ROTATE_DIR_ENUM_DEGREES[_rotate_dir]
1901             - mrt->rotate_angle);
1902
1903     gdk_pixbuf_rotate_matrix_fill_for_rotation(matrix, angle_rad);
1904
1905     /* Determine (roughly) the tiles we might have to process.
1906      * Basically, we take the center unit and subtract the maximum dimension
1907      * of the screen plus the maximum additional pixels of a rotated tile.
1908      */
1909     tile_rothalf_pixels = MAX(
1910             fabsf(TILE_HALFDIAG_PIXELS * sinf((PI / 4) - angle_rad)),
1911             fabsf(TILE_HALFDIAG_PIXELS * cosf((PI / 4) - angle_rad)));
1912
1913     mrt->zoom = _next_zoom;
1914
1915     if(mrt->repo->type != REPOTYPE_NONE && MAPDB_EXISTS(mrt->repo))
1916         cache_amount = _auto_download_precache;
1917     else
1918         cache_amount = 1; /* No cache. */
1919
1920     diag_halflength_units = pixel2zunit(TILE_HALFDIAG_PIXELS
1921         + MAX(mrt->screen_width_pixels, mrt->screen_height_pixels) / 2,
1922         mrt->zoom);
1923     start_tilex = unit2ztile(
1924             mrt->new_center.unitx - diag_halflength_units
1925             + _map_correction_unitx, mrt->zoom);
1926     start_tilex = MAX(start_tilex - (cache_amount - 1), 0);
1927     start_tiley = unit2ztile(
1928             mrt->new_center.unity - diag_halflength_units
1929             + _map_correction_unity, mrt->zoom);
1930     start_tiley = MAX(start_tiley - (cache_amount - 1), 0);
1931     stop_tilex = unit2ztile(mrt->new_center.unitx + diag_halflength_units
1932             + _map_correction_unitx, mrt->zoom);
1933     stop_tilex = MIN(stop_tilex + (cache_amount - 1),
1934             unit2ztile(WORLD_SIZE_UNITS, mrt->zoom));
1935     stop_tiley = unit2ztile(mrt->new_center.unity + diag_halflength_units
1936             + _map_correction_unity, mrt->zoom);
1937     stop_tiley = MIN(stop_tiley + (cache_amount - 1),
1938             unit2ztile(WORLD_SIZE_UNITS, mrt->zoom));
1939
1940     num_tilex = (stop_tilex - start_tilex + 1);
1941     num_tiley = (stop_tiley - start_tiley + 1);
1942     tile_dev = g_new0(gfloat, num_tilex * num_tiley * 2);
1943
1944     ++auto_download_batch_id;
1945
1946     /* Iterate through the tiles and mark which ones need retrieval. */
1947     num_tiles_to_draw = 0;
1948     for(y = 0; y < num_tiley; ++y)
1949     {
1950         for(x = 0; x < num_tilex; ++x)
1951         {
1952             gfloat devx, devy;
1953
1954             /* Find the device location of this tile's center. */
1955             pixel2buf_full(
1956                     tile2pixel(x + start_tilex) + (TILE_SIZE_PIXELS >> 1),
1957                     tile2pixel(y + start_tiley) + (TILE_SIZE_PIXELS >> 1),
1958                     devx, devy,
1959                     mrt->new_center, mrt->zoom, matrix);
1960
1961             /* Apply Map Correction. */
1962             devx -= unit2zpixel(_map_correction_unitx, mrt->zoom);
1963             devy -= unit2zpixel(_map_correction_unity, mrt->zoom);
1964
1965             /* Skip this tile under the following conditions:
1966              * devx < -tile_rothalf_pixels
1967              * devx > _view_width_pixels + tile_rothalf_pixels
1968              * devy < -tile_rothalf_pixels
1969              * devy > _view_height_pixels + tile_rothalf_pixels
1970              */
1971             if(((unsigned)(devx + tile_rothalf_pixels))
1972                     < (_view_width_pixels + (2 * tile_rothalf_pixels))
1973                 && ((unsigned)(devy + tile_rothalf_pixels))
1974                     < (_view_height_pixels + (2 * tile_rothalf_pixels)))
1975             {
1976                 tile_dev[2 * (y * num_tilex + x)] = devx;
1977                 tile_dev[2 * (y * num_tilex + x) + 1] = devy;
1978                 ++num_tiles_to_draw;
1979             }
1980             else
1981             {
1982                 tile_dev[2 * (y * num_tilex + x)] = FLT_MAX;
1983             }
1984         }
1985     }
1986
1987     mrt->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
1988             mrt->screen_width_pixels, mrt->screen_height_pixels);
1989     _refresh_map_after_download = FALSE;
1990
1991     /* Iterate through the tiles, get them (or queue a download if they're
1992      * not in the cache), and rotate them into the pixbuf. */
1993     for(y = curr_tile_to_draw = 0; y < num_tiley; ++y)
1994     {
1995         gint tiley = y + start_tiley;
1996         for(x = 0; x < num_tilex; ++x)
1997         {
1998             GdkPixbuf *tile_pixbuf = NULL, *layer_pixbuf = NULL;
1999             gboolean started_download = FALSE;
2000             gint zoff, zoff_base;
2001             gint tilex;
2002             RepoData* repo_p = mrt->repo;
2003
2004             tilex = x + start_tilex;
2005             zoff_base = mrt->repo->double_size ? 1 : 0;
2006
2007             /* iterating over tile and all it's layers */
2008             while (repo_p)
2009             {
2010                 started_download = FALSE;
2011
2012                 /* for layers we must use resolution of underlying map */
2013                 zoff = zoff_base;
2014
2015                 /* if this is not a bottom layer and layer not enabled, skip it */
2016                 if (repo_p != mrt->repo && !repo_p->layer_enabled)
2017                 {
2018                     repo_p = repo_p->layers;
2019                     continue;
2020                 }
2021
2022                 /* Iteratively try to retrieve a map to draw the tile. */
2023                 while((mrt->zoom + zoff) <= MAX_ZOOM && zoff < 4)
2024                 {
2025                     /* Check if we're actually going to draw this map. */
2026                     if(tile_dev[2 * (y*num_tilex + x)] != FLT_MAX)
2027                     {
2028                         if(NULL != (layer_pixbuf = mapdb_get(
2029                                         repo_p, mrt->zoom + zoff,
2030                                         tilex >> zoff,
2031                                         tiley >> zoff)))
2032                         {
2033                             /* if this is a layer's tile, join with main tile */
2034                             if (repo_p != mrt->repo)
2035                             {
2036                                 /* but only if main layer is exists */
2037                                 if (tile_pixbuf)
2038                                     combine_tiles (tile_pixbuf, layer_pixbuf);
2039                                 g_object_unref (layer_pixbuf);
2040                             }
2041                             else {
2042                                 tile_pixbuf = layer_pixbuf;
2043                                 zoff_base = zoff;
2044                             }
2045                             break;
2046                         }
2047                         else if (repo_p->layers)
2048                             _refresh_map_after_download = TRUE;
2049                     }
2050                     /* Else we're not going to be drawing this map, so just check
2051                      * if it's in the database. */
2052                     else if(mapdb_exists(
2053                                         repo_p, mrt->zoom + zoff,
2054                                         tilex >> zoff,
2055                                         tiley >> zoff))
2056                     {
2057                         zoff_base = zoff;
2058                         break;
2059                     }
2060
2061                     /* No map; download, if we should. */
2062                     if(!started_download && _auto_download
2063                        && mrt->repo->type != REPOTYPE_NONE
2064                        /* Make sure this map is within dl zoom limits. */
2065                        && ((unsigned)(mrt->zoom + zoff - mrt->repo->min_zoom)
2066                            <= (mrt->repo->max_zoom - mrt->repo->min_zoom))
2067                        /* Make sure this map matches the dl_zoom_steps,
2068                         * or that there currently is no cache. */
2069                        && (!MAPDB_EXISTS(repo_p) || !((mrt->zoom + zoff
2070                                              - (mrt->repo->double_size ? 1 : 0))
2071                                             % mrt->repo->dl_zoom_steps))
2072                        /* Make sure this tile is even possible. */
2073                        && ((unsigned)(tilex >> zoff)
2074                            < unit2ztile(WORLD_SIZE_UNITS, mrt->zoom + zoff)
2075                            && (unsigned)(tiley >> zoff)
2076                            < unit2ztile(WORLD_SIZE_UNITS, mrt->zoom + zoff)))
2077                     {
2078                         started_download = TRUE;
2079
2080                         if(!refresh_latch)
2081                         {
2082                             refresh_latch = g_slice_new(ThreadLatch);
2083                             refresh_latch->is_open = FALSE;
2084                             refresh_latch->is_done_adding_tasks = FALSE;
2085                             refresh_latch->num_tasks = 1;
2086                             refresh_latch->num_done = 0;
2087                             refresh_latch->mutex = g_mutex_new();
2088                             refresh_latch->cond = g_cond_new();
2089                         }
2090                         else
2091                             ++refresh_latch->num_tasks;
2092
2093                         mapdb_initiate_update(
2094                                 repo_p,
2095                                 mrt->zoom + zoff,
2096                                 tilex >> zoff,
2097                                 tiley >> zoff,
2098                                 MAP_UPDATE_AUTO,
2099                                 auto_download_batch_id,
2100                                 (abs((tilex >> zoff) - unit2ztile(
2101                                      mrt->new_center.unitx, mrt->zoom + zoff))
2102                                  + abs((tiley >> zoff) - unit2ztile(
2103                                      mrt->new_center.unity, mrt->zoom + zoff))),
2104                                 refresh_latch);
2105                     }
2106
2107                     /* Try again at a coarser resolution. Only for underlying map.*/
2108                     if (repo_p == mrt->repo && MAPDB_EXISTS(repo_p))
2109                         ++zoff;
2110                     else
2111                         break;
2112                 }
2113
2114                 repo_p = repo_p->layers;
2115             }
2116
2117             /* use zoom of the base map */
2118             zoff = zoff_base;
2119
2120             if(tile_pixbuf)
2121             {
2122                 gint boundx, boundy, width, height;
2123
2124                 if(zoff)
2125                     gdk_pixbuf_rotate_matrix_mult_number(matrix, 1 << zoff);
2126                 gdk_pixbuf_rotate(mrt->pixbuf,
2127                         tile_dev[2 * (y * num_tilex + x)],
2128                         tile_dev[2 * (y * num_tilex + x) + 1],
2129                         matrix,
2130                         tile_pixbuf,
2131                         ((tilex - ((tilex >> zoff) << zoff))
2132                             << (TILE_SIZE_P2 - zoff))
2133                             + (TILE_SIZE_PIXELS >> (1 + zoff)),
2134                         ((tiley - ((tiley>>zoff) << zoff))
2135                             << (TILE_SIZE_P2 - zoff))
2136                             + (TILE_SIZE_PIXELS >> (1 + zoff)),
2137                         TILE_SIZE_PIXELS >> zoff,
2138                         TILE_SIZE_PIXELS >> zoff,
2139                         &boundx, &boundy, &width, &height);
2140                 g_object_unref(tile_pixbuf);
2141                 /* Un-multiply the matrix that we used for blitting.  Good
2142                  * thing we're multiplying by powers of two, or this wouldn't
2143                  * work consistently... */
2144                 if(zoff)
2145                     gdk_pixbuf_rotate_matrix_mult_number(
2146                             matrix, 1.f / (1 << zoff));
2147             }
2148             /* usleep(10000); DEBUG */
2149         }
2150     }
2151
2152     /* Don't replace the pixbuf unless/until the mouse is released. */
2153     g_mutex_lock(_mouse_mutex);
2154     ++_pending_replaces;
2155     g_idle_add_full(G_PRIORITY_HIGH_IDLE + 20,
2156             (GSourceFunc)map_replace_pixbuf_idle, mrt, NULL);
2157     g_mutex_unlock(_mouse_mutex);
2158
2159     /* Release the view-change lock. */
2160     if(refresh_latch)
2161     {
2162         g_mutex_lock(refresh_latch->mutex);
2163         if(refresh_latch->num_tasks == refresh_latch->num_done)
2164         {
2165             /* Fast little workers, aren't they? */
2166             g_mutex_unlock(refresh_latch->mutex);
2167             g_cond_free(refresh_latch->cond);
2168             g_mutex_free(refresh_latch->mutex);
2169             g_slice_free(ThreadLatch, refresh_latch);
2170         }
2171         else
2172         {
2173             refresh_latch->is_done_adding_tasks = TRUE;
2174             refresh_latch->is_open = TRUE;
2175             g_cond_signal(refresh_latch->cond);
2176             g_mutex_unlock(refresh_latch->mutex);
2177         }
2178     }
2179
2180     g_free(tile_dev);
2181
2182     vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2183     return FALSE;
2184 }
2185
2186 gboolean
2187 map_cb_configure(GtkWidget *widget, GdkEventConfigure *event)
2188 {
2189     gint old_view_width_pixels, old_view_height_pixels;
2190     GdkPixbuf *old_map_pixbuf;
2191     printf("%s(%d, %d)\n", __PRETTY_FUNCTION__,
2192             _map_widget->allocation.width, _map_widget->allocation.height);
2193
2194     if(_map_widget->allocation.width == 1
2195             && _map_widget->allocation.height == 1)
2196         /* Special case - first allocation - not persistent. */
2197         return TRUE;
2198
2199     old_view_width_pixels = _view_width_pixels;
2200     old_view_height_pixels = _view_height_pixels;
2201     _view_width_pixels = _map_widget->allocation.width;
2202     _view_height_pixels = _map_widget->allocation.height;
2203     _view_halfwidth_pixels = _view_width_pixels / 2;
2204     _view_halfheight_pixels = _view_height_pixels / 2;
2205
2206     g_object_unref(_map_pixmap);
2207     _map_pixmap = gdk_pixmap_new(
2208                 _map_widget->window,
2209                 _view_width_pixels, _view_height_pixels,
2210                 -1); /* -1: use bit depth of widget->window. */
2211
2212     old_map_pixbuf = _map_pixbuf;
2213     _map_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
2214             _view_width_pixels, _view_height_pixels);
2215
2216     {
2217         gint oldnew_diffx = (gint)(_view_width_pixels
2218                 - old_view_width_pixels) / 2;
2219         gint oldnew_diffy = (gint)(_view_height_pixels
2220                 - old_view_height_pixels) / 2;
2221         gdk_pixbuf_copy_area(old_map_pixbuf,
2222                 MAX(0, -oldnew_diffx), MAX(0, -oldnew_diffy),
2223                 MIN(_view_width_pixels, old_view_width_pixels),
2224                 MIN(_view_height_pixels, old_view_height_pixels),
2225                 _map_pixbuf,
2226                 MAX(0, oldnew_diffx), MAX(0, oldnew_diffy));
2227     }
2228
2229     g_object_unref(old_map_pixbuf);
2230
2231     /* Set _scale_rect. */
2232     _scale_rect.x = (_view_width_pixels - SCALE_WIDTH) / 2;
2233     _scale_rect.width = SCALE_WIDTH;
2234     pango_layout_set_text(_scale_layout, "0", -1);
2235     pango_layout_get_pixel_size(_scale_layout, NULL, &_scale_rect.height);
2236     _scale_rect.y = _view_height_pixels - _scale_rect.height - 1;
2237
2238     /* Set _zoom rect. */
2239     pango_layout_set_text(_zoom_layout, "00", -1);
2240     pango_layout_get_pixel_size(_zoom_layout, &_zoom_rect.width,
2241             &_zoom_rect.height);
2242     _zoom_rect.width *= 1.25;
2243     pango_layout_set_width(_zoom_layout, _zoom_rect.width);
2244     pango_layout_context_changed(_zoom_layout);
2245     _zoom_rect.x = _scale_rect.x - _zoom_rect.width;
2246     _zoom_rect.y = _view_height_pixels - _zoom_rect.height - 1;
2247
2248     /* Set _comprose_rect. */
2249     _comprose_rect.x = _view_width_pixels - 25 - _comprose_rect.width;
2250     _comprose_rect.y = _view_height_pixels - 25 - _comprose_rect.height;
2251
2252     map_set_mark();
2253     map_force_redraw();
2254
2255     /* Fire the screen_dimensions_changed DBUS signal. */
2256     dbus_ifc_fire_view_dimensions_changed(
2257             _view_width_pixels, _view_height_pixels);
2258
2259     /* If Auto-Center is set to Lead, then recalc center. */
2260     if(_center_mode == CENTER_LEAD)
2261         map_center_unit(map_calc_new_center(_next_zoom));
2262     else
2263         map_center_unit(_next_center);
2264
2265     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2266     return TRUE;
2267 }
2268
2269 gboolean
2270 sat_panel_expose(GtkWidget *widget, GdkEventExpose *event)
2271 {
2272     gchar *tmp = NULL;
2273     gint x, y;
2274     printf("%s()\n", __PRETTY_FUNCTION__);
2275
2276     draw_sat_info(widget,
2277         0, 0,
2278         widget->allocation.width,
2279         widget->allocation.height,
2280         FALSE);
2281
2282     /* Sat View/In Use */
2283     tmp = g_strdup_printf("%d/%d", _gps.satinuse, _gps.satinview);
2284     pango_layout_set_text(_sat_panel_layout, tmp, -1);
2285     pango_layout_set_alignment(_sat_panel_layout, PANGO_ALIGN_LEFT);
2286     gdk_draw_layout(widget->window,
2287         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2288         20, 2,
2289         _sat_panel_layout);
2290     g_free(tmp);
2291
2292     switch(_gps.fix)
2293     {
2294         case 2:
2295         case 3: tmp = g_strdup_printf("%dD fix", _gps.fix); break;
2296         default: tmp = g_strdup_printf("nofix"); break;
2297     }
2298     pango_layout_set_text(_sat_panel_layout, tmp, -1);
2299     pango_layout_set_alignment(_sat_panel_layout, PANGO_ALIGN_RIGHT);
2300     pango_layout_get_pixel_size(_sat_panel_layout, &x, &y);
2301     gdk_draw_layout(widget->window,
2302         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2303         widget->allocation.width - 20 - x, 2,
2304         _sat_panel_layout);
2305     g_free(tmp);
2306
2307     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
2308     return TRUE;
2309 }
2310
2311 gboolean
2312 heading_panel_expose(GtkWidget *widget, GdkEventExpose *event)
2313 {
2314     gint size, xoffset, yoffset, i, x, y;
2315     gint dir;
2316     gfloat tmp;
2317     gchar *text;
2318     printf("%s()\n", __PRETTY_FUNCTION__);
2319
2320     size = MIN(widget->allocation.width, widget->allocation.height);
2321     if(widget->allocation.width > widget->allocation.height)
2322     {
2323         xoffset = (widget->allocation.width - widget->allocation.height) / 2;
2324         yoffset = 0;
2325     }
2326     else
2327     {
2328         xoffset = 0;
2329         yoffset = (widget->allocation.height - widget->allocation.width) / 2;
2330     }
2331     pango_font_description_set_size(_heading_panel_fontdesc,12*PANGO_SCALE);
2332     pango_layout_set_font_description(_heading_panel_layout,
2333             _heading_panel_fontdesc);
2334     pango_layout_set_alignment(_heading_panel_layout, PANGO_ALIGN_CENTER);
2335
2336     text = g_strdup_printf("%3.0f°", _gps.heading);
2337     pango_layout_set_text(_heading_panel_layout, text, -1);
2338     pango_layout_get_pixel_size(_heading_panel_layout, &x, &y);
2339
2340     gdk_draw_layout(widget->window,
2341         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2342         xoffset + size/2 - x/2,
2343         yoffset + size - y - 2, _heading_panel_layout);
2344     g_free(text);
2345
2346     gdk_draw_arc (widget->window,
2347         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2348         FALSE,
2349         xoffset, yoffset + size/2,
2350         size, size,
2351         0, 64 * 180);
2352
2353     /* Simple arrow for heading*/
2354     gdk_draw_line(widget->window,
2355         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2356         xoffset + size/2 + 3,
2357         yoffset + size - y - 5,
2358         xoffset + size/2,
2359         yoffset + size/2 + 5);
2360
2361     gdk_draw_line(widget->window,
2362         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2363         xoffset + size/2 - 3,
2364         yoffset + size - y - 5,
2365         xoffset + size/2,
2366         yoffset + size/2 + 5);
2367
2368     gdk_draw_line(widget->window,
2369         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2370         xoffset + size/2 - 3,
2371         yoffset + size - y - 5,
2372         xoffset + size/2,
2373         yoffset + size - y - 8);
2374
2375     gdk_draw_line(widget->window,
2376         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2377         xoffset + size/2 + 3,
2378         yoffset + size - y - 5,
2379         xoffset + size/2,
2380         yoffset + size - y - 8);
2381
2382     gint angle[5] = {-90,-45,0,45,90};
2383     gint fsize[5] = {0,4,10,4,0};
2384     for(i = 0; i < 5; i++)
2385     {
2386         dir = (gint)(_gps.heading/45)*45 + angle[i];
2387
2388         switch(dir)
2389         {
2390             case   0:
2391             case 360: text = g_strdup("N"); break;
2392             case  45:
2393             case 405:
2394                 text = g_strdup("NE"); break;
2395             case  90:
2396                 text = g_strdup("E"); break;
2397             case 135:
2398                 text = g_strdup("SE"); break;
2399             case 180:
2400                 text = g_strdup("S"); break;
2401             case 225:
2402                 text = g_strdup("SW"); break;
2403             case 270:
2404             case -90:
2405                 text = g_strdup("W"); break;
2406             case 315:
2407             case -45:
2408                 text = g_strdup("NW"); break;
2409             default :
2410                 text = g_strdup("??");
2411                 break;
2412         }
2413
2414         tmp = deg2rad(dir - _gps.heading);
2415         gdk_draw_line(widget->window,
2416             widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2417             xoffset + size/2 + ((size/2 - 5) * sinf(tmp)),
2418             yoffset + size - ((size/2 - 5) * cosf(tmp)),
2419             xoffset + size/2 + ((size/2 + 5) * sinf(tmp)),
2420             yoffset + size - ((size/2 + 5) * cosf(tmp)));
2421
2422         x = fsize[i];
2423         if(abs((gint)(_gps.heading/45)*45 - _gps.heading)
2424                 > abs((gint)(_gps.heading/45)*45 + 45 - _gps.heading)
2425                 && (i > 0))
2426             x = fsize[i - 1];
2427
2428         pango_font_description_set_size(_heading_panel_fontdesc,
2429                 (10 + x)*PANGO_SCALE);
2430         pango_layout_set_font_description(_heading_panel_layout,
2431                 _heading_panel_fontdesc);
2432         pango_layout_set_text(_heading_panel_layout, text, -1);
2433         pango_layout_get_pixel_size(_heading_panel_layout, &x, &y);
2434         x = xoffset + size/2 + ((size/2 + 15) * sinf(tmp)) - x/2,
2435         y = yoffset + size - ((size/2 + 15) * cosf(tmp)) - y/2,
2436
2437         gdk_draw_layout(widget->window,
2438             widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
2439             x, y, _heading_panel_layout);
2440         g_free(text);
2441     }
2442
2443     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
2444     return TRUE;
2445 }
2446
2447 gboolean
2448 map_cb_expose(GtkWidget *widget, GdkEventExpose *event)
2449 {
2450     gint i;
2451     printf("%s(%d, %d, %d, %d)\n", __PRETTY_FUNCTION__,
2452             event->area.x, event->area.y,
2453             event->area.width, event->area.height);
2454
2455     gdk_draw_drawable(
2456             _map_widget->window,
2457             _gc[COLORABLE_MARK],
2458             _map_pixmap,
2459             event->area.x - _map_offset_devx, event->area.y - _map_offset_devy,
2460             event->area.x, event->area.y,
2461             event->area.width, event->area.height);
2462
2463     /* Draw the mark. */
2464     if((((unsigned)(_mark_bufx1 + _draw_width)
2465                 <= _view_width_pixels+2*_draw_width)
2466              &&((unsigned)(_mark_bufy1 + _draw_width)
2467                  <= _view_height_pixels+2*_draw_width))
2468         || (((unsigned)(_mark_bufx2 + _draw_width)
2469                  <= _view_width_pixels+2*_draw_width)
2470              &&((unsigned)(_mark_bufy2 + _draw_width)
2471                  <= _view_height_pixels+2*_draw_width)))
2472     {
2473         gdk_draw_arc(
2474                 _map_widget->window,
2475                 _gps_state == RCVR_FIXED
2476                     ? _gc[COLORABLE_MARK] : _gc[COLORABLE_MARK_OLD],
2477                 FALSE, /* not filled. */
2478                 _mark_bufx1 - _draw_width + _map_offset_devx,
2479                 _mark_bufy1 - _draw_width + _map_offset_devy,
2480                 2 * _draw_width, 2 * _draw_width,
2481                 0, 360 * 64);
2482         gdk_draw_line(
2483                 _map_widget->window,
2484                 _gps_state == RCVR_FIXED
2485                     ? (_show_velvec
2486                         ? _gc[COLORABLE_MARK_VELOCITY] : _gc[COLORABLE_MARK])
2487                     : _gc[COLORABLE_MARK_OLD],
2488                 _mark_bufx1 + _map_offset_devx,
2489                 _mark_bufy1 + _map_offset_devy,
2490                 _mark_bufx2 + _map_offset_devx,
2491                 _mark_bufy2 + _map_offset_devy);
2492     }
2493
2494     /* draw zoom box if so wanted */
2495     if(_show_zoomlevel) {
2496         gchar *buffer = g_strdup_printf("%d", _zoom);
2497         gdk_draw_rectangle(_map_widget->window,
2498                 _map_widget->style->bg_gc[GTK_STATE_ACTIVE],
2499                 TRUE,
2500                 _zoom_rect.x, _zoom_rect.y,
2501                 _zoom_rect.width, _zoom_rect.height);
2502         gdk_draw_rectangle(_map_widget->window,
2503                 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2504                 FALSE,
2505                 _zoom_rect.x, _zoom_rect.y,
2506                 _zoom_rect.width, _zoom_rect.height);
2507         pango_layout_set_text(_zoom_layout, buffer, -1);
2508         gdk_draw_layout(_map_widget->window,
2509                 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2510                 _zoom_rect.x + _zoom_rect.width / 2,
2511                 _zoom_rect.y, _zoom_layout);
2512     }
2513
2514     /* Draw scale, if necessary. */
2515     if(_show_scale)
2516     {
2517         gdk_rectangle_intersect(&event->area, &_scale_rect, &event->area);
2518         if(event->area.width && event->area.height)
2519         {
2520             gdk_draw_rectangle(_map_widget->window,
2521                     _map_widget->style->bg_gc[GTK_STATE_ACTIVE],
2522                     TRUE,
2523                     _scale_rect.x, _scale_rect.y,
2524                     _scale_rect.width, _scale_rect.height);
2525             gdk_draw_rectangle(_map_widget->window,
2526                     _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2527                     FALSE,
2528                     _scale_rect.x, _scale_rect.y,
2529                     _scale_rect.width, _scale_rect.height);
2530
2531             /* Now calculate and draw the distance. */
2532             {
2533                 gchar buffer[16];
2534                 gfloat distance;
2535                 gdouble lat1, lon1, lat2, lon2;
2536                 gint width;
2537
2538                 unit2latlon(_center.unitx - pixel2unit(SCALE_WIDTH / 2 - 4),
2539                         _center.unity, lat1, lon1);
2540                 unit2latlon(_center.unitx + pixel2unit(SCALE_WIDTH / 2 - 4),
2541                         _center.unity, lat2, lon2);
2542                 distance = calculate_distance(lat1, lon1, lat2, lon2)
2543                     * UNITS_CONVERT[_units];
2544
2545                 if(distance < 1.f)
2546                     snprintf(buffer, sizeof(buffer), "%0.2f %s", distance,
2547                             UNITS_ENUM_TEXT[_units]);
2548                 else if(distance < 10.f)
2549                     snprintf(buffer, sizeof(buffer), "%0.1f %s", distance,
2550                             UNITS_ENUM_TEXT[_units]);
2551                 else
2552                     snprintf(buffer, sizeof(buffer), "%0.f %s", distance,
2553                             UNITS_ENUM_TEXT[_units]);
2554                 pango_layout_set_text(_scale_layout, buffer, -1);
2555
2556                 pango_layout_get_pixel_size(_scale_layout, &width, NULL);
2557
2558                 /* Draw the layout itself. */
2559                 gdk_draw_layout(_map_widget->window,
2560                     _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2561                     _scale_rect.x + (_scale_rect.width - width) / 2,
2562                     _scale_rect.y, _scale_layout);
2563
2564                 /* Draw little hashes on the ends. */
2565                 gdk_draw_line(_map_widget->window,
2566                     _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2567                     _scale_rect.x + 4,
2568                     _scale_rect.y + _scale_rect.height / 2 - 4,
2569                     _scale_rect.x + 4,
2570                     _scale_rect.y + _scale_rect.height / 2 + 4);
2571                 gdk_draw_line(_map_widget->window,
2572                     _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2573                     _scale_rect.x + 4,
2574                     _scale_rect.y + _scale_rect.height / 2,
2575                     _scale_rect.x + (_scale_rect.width - width) / 2 - 4,
2576                     _scale_rect.y + _scale_rect.height / 2);
2577                 gdk_draw_line(_map_widget->window,
2578                     _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2579                     _scale_rect.x + _scale_rect.width - 4,
2580                     _scale_rect.y + _scale_rect.height / 2 - 4,
2581                     _scale_rect.x + _scale_rect.width - 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 + _scale_rect.width - 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             }
2590         }
2591     }
2592
2593     /* Draw the compass rose, if necessary. */
2594     if(_show_comprose)
2595     {
2596         GdkPoint points[3];
2597         gint offsetx, offsety;
2598         gfloat x, y;
2599
2600         offsetx = _comprose_rect.x;
2601         offsety = _comprose_rect.y;
2602
2603         gdk_pixbuf_rotate_vector(&x, &y, _map_rotate_matrix, 0, 12);
2604         points[0].x = offsetx + x + 0.5f; points[0].y = offsety + y + 0.5f;
2605         gdk_pixbuf_rotate_vector(&x, &y, _map_rotate_matrix, 20, 30);
2606         points[1].x = offsetx + x + 0.5f; points[1].y = offsety + y + 0.5f;
2607         gdk_pixbuf_rotate_vector(&x, &y, _map_rotate_matrix, 0, -45);
2608         points[2].x = offsetx + x + 0.5f; points[2].y = offsety + y + 0.5f;
2609         gdk_pixbuf_rotate_vector(&x, &y, _map_rotate_matrix, -20, 30);
2610         points[3].x = offsetx + x + 0.5f; points[3].y = offsety + y + 0.5f;
2611
2612         gdk_draw_polygon(_map_widget->window,
2613                 _map_widget->style->bg_gc[GTK_STATE_ACTIVE],
2614                 TRUE, /* FILLED */
2615                 points, 4);
2616         gdk_draw_polygon(_map_widget->window,
2617                 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2618                 FALSE, /* NOT FILLED */
2619                 points, 4);
2620
2621         gdk_draw_layout(_map_widget->window,
2622                 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2623                 _comprose_rect.x - _comprose_rect.width / 2 + 1,
2624                 _comprose_rect.y - _comprose_rect.height / 2 - 4,
2625                 _comprose_layout);
2626     }
2627
2628     /* Draw a stopwatch if we're redrawing the map. */
2629     for(i = _redraw_count - 1; i >= 0; i--)
2630     {
2631         gdk_draw_pixbuf(
2632                 _map_widget->window,
2633                 _map_widget->style->fg_gc[GTK_STATE_ACTIVE],
2634                 _redraw_wait_icon,
2635                 0, 0,
2636                 _redraw_wait_bounds.x + i
2637                         * HOURGLASS_SEPARATION,
2638                 _redraw_wait_bounds.y,
2639                 _redraw_wait_bounds.width,
2640                 _redraw_wait_bounds.height,
2641                 GDK_RGB_DITHER_NONE, 0, 0);
2642     }
2643
2644     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2645     return TRUE;
2646 }
2647
2648 static void
2649 latlon_cb_copy_clicked(GtkWidget *widget, LatlonDialog *lld) {
2650     gchar buffer[42];
2651
2652     snprintf(buffer, sizeof(buffer),
2653             "%s %s",
2654             gtk_label_get_text(GTK_LABEL(lld->lat)),
2655             gtk_label_get_text(GTK_LABEL(lld->lon)));
2656
2657     gtk_clipboard_set_text(
2658             gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), buffer, -1);
2659 }
2660
2661 static void
2662 latlon_cb_fmt_changed(GtkWidget *widget, LatlonDialog *lld) {
2663   DegFormat fmt;
2664
2665   fmt = gtk_combo_box_get_active(GTK_COMBO_BOX(lld->fmt_combo));
2666
2667   {
2668     gint old = _degformat; /* augh... */
2669     gchar buffer[LL_FMT_LEN];
2670     gchar buffer2[LL_FMT_LEN];
2671
2672     _degformat = fmt;
2673     
2674     format_lat_lon(lld->glat, lld->glon, buffer, buffer2);
2675     
2676     //lat_format(lld->glat, buffer);
2677     gtk_label_set_label(GTK_LABEL(lld->lat), buffer);
2678     //lon_format(lld->glon, buffer);
2679     
2680     if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
2681         gtk_label_set_label(GTK_LABEL(lld->lon), buffer2);
2682     else
2683         gtk_label_set_label(GTK_LABEL(lld->lon), g_strdup(""));
2684     
2685     
2686     // And set the titles
2687     gtk_label_set_label(GTK_LABEL(lld->lat_title), 
2688                 DEG_FORMAT_ENUM_TEXT[_degformat].short_field_1 );
2689     
2690     if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
2691         gtk_label_set_label(GTK_LABEL(lld->lon_title), 
2692                         DEG_FORMAT_ENUM_TEXT[_degformat].short_field_2 );
2693     else
2694         gtk_label_set_label(GTK_LABEL(lld->lon_title), g_strdup(""));
2695     
2696     
2697     _degformat = old;
2698   }
2699 }
2700
2701 gboolean
2702 latlon_dialog(gdouble lat, gdouble lon)
2703 {
2704     LatlonDialog lld;
2705     GtkWidget *dialog;
2706     GtkWidget *table;
2707     GtkWidget *label;
2708     GtkWidget *lbl_lon_title;
2709     GtkWidget *lbl_lat_title;
2710     GtkWidget *txt_lat;
2711     GtkWidget *txt_lon;
2712     GtkWidget *cmb_format;
2713     GtkWidget *btn_copy = NULL;
2714     gint prev_degformat = _degformat;
2715     gint fallback_deg_format = _degformat;
2716     
2717     printf("%s()\n", __PRETTY_FUNCTION__);
2718
2719     // Check that the current coord system supports the select position
2720     if(!coord_system_check_lat_lon (lat, lon, &fallback_deg_format))
2721     {
2722         _degformat = fallback_deg_format;
2723     }
2724      
2725     
2726     dialog = gtk_dialog_new_with_buttons(_("Show Position"),
2727             GTK_WINDOW(_window), GTK_DIALOG_MODAL,
2728             GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2729             NULL);
2730
2731     /* Set the lat/lon strings. */
2732     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2733             table = gtk_table_new(5, 2, FALSE), TRUE, TRUE, 0);
2734
2735     gtk_table_attach(GTK_TABLE(table),
2736                 lbl_lat_title = gtk_label_new(/*_("Lat")*/ DEG_FORMAT_ENUM_TEXT[_degformat].short_field_1 ),
2737             0, 1, 0, 1, GTK_FILL, 0, 2, 4);
2738     gtk_misc_set_alignment(GTK_MISC(lbl_lat_title), 1.f, 0.5f);
2739     gtk_table_attach(GTK_TABLE(table),
2740             txt_lat = gtk_label_new(""),
2741             1, 2, 0, 1, GTK_FILL, 0, 2, 4);
2742     gtk_misc_set_alignment(GTK_MISC(txt_lat), 1.f, 0.5f);
2743
2744     
2745     gtk_table_attach(GTK_TABLE(table),
2746             lbl_lon_title = gtk_label_new(/*_("Lon")*/ DEG_FORMAT_ENUM_TEXT[_degformat].short_field_2 ),
2747             0, 1, 1, 2, GTK_FILL, 0, 2, 4);
2748     gtk_misc_set_alignment(GTK_MISC(lbl_lon_title), 1.f, 0.5f);
2749     
2750     gtk_table_attach(GTK_TABLE(table),
2751             txt_lon = gtk_label_new(""),
2752             1, 2, 1, 2, GTK_FILL, 0, 2, 4);
2753     gtk_misc_set_alignment(GTK_MISC(txt_lon), 1.f, 0.5f);
2754
2755     
2756     gtk_table_attach(GTK_TABLE(table),
2757             label = gtk_label_new(_("Format")),
2758             0, 1, 2, 3, GTK_FILL, 0, 2, 4);
2759     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2760     gtk_table_attach(GTK_TABLE(table),
2761             label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
2762             1, 2, 2, 3, GTK_FILL, 0, 2, 4);
2763     gtk_container_add(GTK_CONTAINER(label),
2764             cmb_format = gtk_combo_box_new_text());
2765     gtk_table_attach(GTK_TABLE(table),
2766             btn_copy = gtk_button_new_with_label(_("Copy")),
2767             0, 2, 3, 4, GTK_FILL, 0, 2, 4);
2768
2769     /* Lat/Lon */
2770     {
2771       gchar buffer[LL_FMT_LEN];
2772       gchar buffer2[LL_FMT_LEN];
2773
2774       format_lat_lon(lat, lon, buffer, buffer2);
2775       
2776       //lat_format(lat, buffer);
2777       gtk_label_set_label(GTK_LABEL(txt_lat), buffer);
2778       //lat_format(lon, buffer);
2779       if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
2780           gtk_label_set_label(GTK_LABEL(txt_lon), buffer2);
2781       else
2782           gtk_label_set_label(GTK_LABEL(txt_lon), g_strdup(""));
2783     }
2784
2785     /* Fill in formats */
2786     {
2787       int i;
2788
2789       for(i = 0; i < DEG_FORMAT_ENUM_COUNT; i++) {
2790           gtk_combo_box_append_text(GTK_COMBO_BOX(cmb_format),
2791                   DEG_FORMAT_ENUM_TEXT[i].name);
2792       }
2793       gtk_combo_box_set_active(GTK_COMBO_BOX(cmb_format), _degformat);
2794     }
2795
2796
2797     /* setup cb context */
2798     lld.fmt_combo = cmb_format;
2799     lld.glat = lat;
2800     lld.glon = lon;
2801     lld.lat = txt_lat;
2802     lld.lon = txt_lon;
2803
2804     lld.lat_title = lbl_lat_title;
2805     lld.lon_title = lbl_lon_title;
2806     
2807     /* Connect Signals */
2808     g_signal_connect(G_OBJECT(cmb_format), "changed",
2809                     G_CALLBACK(latlon_cb_fmt_changed), &lld);
2810     g_signal_connect(G_OBJECT(btn_copy), "clicked",
2811                     G_CALLBACK(latlon_cb_copy_clicked), &lld);
2812
2813     gtk_widget_show_all(dialog);
2814
2815     gtk_dialog_run(GTK_DIALOG(dialog));
2816     
2817     _degformat = prev_degformat; // Put back incase it had to be auto changed
2818     
2819     gtk_widget_hide(dialog);
2820
2821     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2822     return TRUE;
2823 }
2824
2825
2826 /**
2827  * This is a multi-purpose function for allowing the user to select a file
2828  * for either reading or writing.  If chooser_action is
2829  * GTK_FILE_CHOOSER_ACTION_OPEN, then bytes_out and size_out must be
2830  * non-NULL.  If chooser_action is GTK_FILE_CHOOSER_ACTION_SAVE, then
2831  * handle_out must be non-NULL.  Either dir or file (or both) can be NULL.
2832  * This function returns TRUE if a file was successfully opened.
2833  */
2834 gboolean
2835 display_open_file(GtkWindow *parent, gchar **bytes_out,
2836         GnomeVFSHandle **handle_out, gint *size_out,
2837         gchar **dir, gchar **file, GtkFileChooserAction chooser_action)
2838 {
2839     GtkWidget *dialog;
2840     gboolean success = FALSE;
2841     printf("%s()\n", __PRETTY_FUNCTION__);
2842
2843     dialog = hildon_file_chooser_dialog_new(parent, chooser_action);
2844
2845     if(dir && *dir)
2846         gtk_file_chooser_set_current_folder_uri(
2847                 GTK_FILE_CHOOSER(dialog), *dir);
2848     if(file && *file)
2849     {
2850         gtk_file_chooser_set_uri(
2851                 GTK_FILE_CHOOSER(dialog), *file);
2852         if(chooser_action == GTK_FILE_CHOOSER_ACTION_SAVE)
2853         {
2854             /* Work around a bug in HildonFileChooserDialog. */
2855             gchar *basename = g_path_get_basename(*file);
2856             g_object_set(G_OBJECT(dialog), "autonaming", FALSE, NULL);
2857             gtk_file_chooser_set_current_name(
2858                     GTK_FILE_CHOOSER(dialog), basename);
2859             g_free(basename);
2860         }
2861     }
2862
2863     gtk_widget_show_all(dialog);
2864
2865     while(!success && gtk_dialog_run(GTK_DIALOG(dialog))==GTK_RESPONSE_OK)
2866     {
2867         gchar *file_uri_str;
2868         GnomeVFSResult vfs_result;
2869
2870         /* Get the selected filename. */
2871         file_uri_str = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog));
2872
2873         if((chooser_action == GTK_FILE_CHOOSER_ACTION_OPEN
2874                 && (GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(
2875                         file_uri_str, size_out, bytes_out))))
2876                 || (chooser_action == GTK_FILE_CHOOSER_ACTION_SAVE
2877                     && GNOME_VFS_OK != (vfs_result = gnome_vfs_create(
2878                             handle_out, file_uri_str,
2879                             GNOME_VFS_OPEN_WRITE, FALSE, 0664))))
2880         {
2881             gchar buffer[BUFFER_SIZE];
2882             snprintf(buffer, sizeof(buffer),
2883                     "%s:\n%s", chooser_action == GTK_FILE_CHOOSER_ACTION_OPEN
2884                                 ? _("Failed to open file for reading")
2885                                 : _("Failed to open file for writing"),
2886                     gnome_vfs_result_to_string(vfs_result));
2887             popup_error(dialog, buffer);
2888         }
2889         else
2890             success = TRUE;
2891
2892         g_free(file_uri_str);
2893     }
2894
2895     if(success)
2896     {
2897         /* Success!. */
2898         if(dir)
2899         {
2900             g_free(*dir);
2901             *dir = gtk_file_chooser_get_current_folder_uri(
2902                     GTK_FILE_CHOOSER(dialog));
2903         }
2904
2905         /* If desired, save the file for later. */
2906         if(file)
2907         {
2908             g_free(*file);
2909             *file = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog));
2910         }
2911     }
2912
2913     gtk_widget_destroy(dialog);
2914
2915     vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
2916     return success;
2917 }
2918
2919 void
2920 display_init()
2921 {
2922     PangoContext *pango_context;
2923     PangoFontDescription *pango_font;
2924     GdkColor color;
2925     printf("%s()\n", __PRETTY_FUNCTION__);
2926
2927     /* Cache some pango and GCs for drawing. */
2928     pango_context = gtk_widget_get_pango_context(_map_widget);
2929     _scale_layout = pango_layout_new(pango_context);
2930     pango_font = pango_font_description_new();
2931     pango_font_description_set_size(pango_font, 12 * PANGO_SCALE);
2932     pango_layout_set_font_description(_scale_layout, pango_font);
2933     
2934 #ifdef INCLUDE_APRS
2935     /* APRS Labels */
2936     pango_context = gtk_widget_get_pango_context(_map_widget);
2937     _aprs_label_layout = pango_layout_new(pango_context);
2938     pango_font = pango_font_description_new();
2939     pango_font_description_set_size(pango_font, 10 * PANGO_SCALE);
2940     pango_font_description_set_family(pango_font,"Sans Serif");
2941     pango_layout_set_font_description(_aprs_label_layout, pango_font);
2942 #endif // INCLUDE_APRS
2943
2944     /* zoom box */
2945     pango_context = gtk_widget_get_pango_context(_map_widget);
2946     _zoom_layout = pango_layout_new(pango_context);
2947     pango_font = pango_font_description_new();
2948     pango_font_description_set_size(pango_font, 12 * PANGO_SCALE);
2949     pango_layout_set_font_description(_zoom_layout, pango_font);
2950     pango_layout_set_alignment(_zoom_layout, PANGO_ALIGN_CENTER);
2951
2952     /* compose rose */
2953     pango_context = gtk_widget_get_pango_context(_map_widget);
2954     _comprose_layout = pango_layout_new(pango_context);
2955     pango_font = pango_font_description_new();
2956     pango_font_description_set_size(pango_font, 16 * PANGO_SCALE);
2957     pango_font_description_set_weight(pango_font, PANGO_WEIGHT_BOLD);
2958     pango_layout_set_font_description(_comprose_layout, pango_font);
2959     pango_layout_set_alignment(_comprose_layout, PANGO_ALIGN_CENTER);
2960     pango_layout_set_text(_comprose_layout, "N", -1);
2961     {
2962         PangoRectangle rect;
2963         pango_layout_get_pixel_extents(_comprose_layout, &rect, NULL);
2964         _comprose_rect.width = rect.width + 3;
2965         _comprose_rect.height = rect.height + 3;
2966     }
2967
2968     /* speed limit */
2969     _speed_limit_gc1 = gdk_gc_new (_map_widget->window);
2970     color.red = 0xffff;
2971     color.green = 0;
2972     color.blue = 0;
2973     gdk_gc_set_rgb_fg_color(_speed_limit_gc1, &color);
2974     color.red = 0;
2975     color.green = 0;
2976     color.blue = 0;
2977     _speed_limit_gc2 = gdk_gc_new(_map_widget->window);
2978     gdk_gc_set_rgb_fg_color(_speed_limit_gc2, &color);
2979     pango_context = gtk_widget_get_pango_context(_map_widget);
2980     _speed_limit_layout = pango_layout_new(pango_context);
2981     pango_font = pango_font_description_new();
2982     pango_font_description_set_size(pango_font, 64 * PANGO_SCALE);
2983     pango_layout_set_font_description(_speed_limit_layout,
2984             pango_font);
2985     pango_layout_set_alignment(_speed_limit_layout, PANGO_ALIGN_CENTER);
2986
2987     /* draw_sat_info() */
2988     _sat_info_gc1 = gdk_gc_new(_map_widget->window);
2989     color.red = 0;
2990     color.green = 0;
2991     color.blue = 0;
2992     gdk_gc_set_rgb_fg_color(_sat_info_gc1, &color);
2993     color.red = 0;
2994     color.green = 0;
2995     color.blue = 0xffff;
2996     _sat_info_gc2 = gdk_gc_new(_map_widget->window);
2997     gdk_gc_set_rgb_fg_color(_sat_info_gc2, &color);
2998     pango_context = gtk_widget_get_pango_context(_map_widget);
2999     _sat_info_layout = pango_layout_new(pango_context);
3000     pango_font = pango_font_description_new();
3001     pango_font_description_set_family(pango_font,"Sans Serif");
3002     pango_font_description_set_size(pango_font, 8*PANGO_SCALE);
3003     pango_layout_set_font_description(_sat_info_layout, pango_font);
3004     pango_layout_set_alignment(_sat_info_layout, PANGO_ALIGN_CENTER);
3005
3006     /* sat_panel_expose() */
3007     pango_context = gtk_widget_get_pango_context(_map_widget);
3008     _sat_panel_layout = pango_layout_new(pango_context);
3009     pango_font = pango_font_description_new();
3010     pango_font_description_set_family(pango_font,"Sans Serif");
3011     pango_font_description_set_size(pango_font, 14*PANGO_SCALE);
3012     pango_layout_set_font_description (_sat_panel_layout, pango_font);
3013
3014     /* heading_panel_expose() */
3015     pango_context = gtk_widget_get_pango_context(_map_widget);
3016     _heading_panel_layout = pango_layout_new(pango_context);
3017     _heading_panel_fontdesc =  pango_font_description_new();
3018     pango_font_description_set_family(_heading_panel_fontdesc, "Sans Serif");
3019
3020     /* draw_sat_details() */
3021     pango_context = gtk_widget_get_pango_context(_map_widget);
3022     _sat_details_layout = pango_layout_new(pango_context);
3023     pango_font = pango_font_description_new();
3024     pango_font_description_set_family(pango_font,"Sans Serif");
3025     pango_font_description_set_size(pango_font, 10*PANGO_SCALE);
3026     pango_layout_set_font_description(_sat_details_layout,
3027             pango_font);
3028     pango_layout_set_alignment(_sat_details_layout, PANGO_ALIGN_CENTER);
3029
3030     /* sat_details_panel_expose() */
3031     pango_context = gtk_widget_get_pango_context(_map_widget);
3032     _sat_details_expose_layout = pango_layout_new(pango_context);
3033     pango_font = pango_font_description_new();
3034     pango_font_description_set_family(
3035             pango_font,"Sans Serif");
3036     pango_layout_set_alignment(_sat_details_expose_layout,
3037             PANGO_ALIGN_CENTER);
3038     pango_font_description_set_size(pango_font,
3039             14*PANGO_SCALE);
3040     pango_layout_set_font_description(_sat_details_expose_layout,
3041             pango_font);
3042
3043     /* Load the _redraw_wait_icon. */
3044     {
3045         GError *error = NULL;
3046         gchar *icon_path = "/usr/share/icons/hicolor/scalable/hildon"
3047                            "/maemo-mapper-wait.png";
3048         _redraw_wait_bounds.x = 0;
3049         _redraw_wait_bounds.y = 0;
3050         _redraw_wait_icon = gdk_pixbuf_new_from_file(icon_path, &error);
3051         if(!_redraw_wait_icon || error)
3052         {
3053             g_printerr("Error parsing pixbuf: %s\n",
3054                     error ? error->message : icon_path);
3055             _redraw_wait_bounds.width = 0;
3056             _redraw_wait_bounds.height = 0;
3057             _redraw_wait_icon = NULL;
3058         }
3059         else
3060         {
3061             _redraw_wait_bounds.width
3062                 = gdk_pixbuf_get_width(_redraw_wait_icon);
3063             _redraw_wait_bounds.height
3064                 = gdk_pixbuf_get_height(_redraw_wait_icon);
3065         }
3066     }
3067
3068     g_signal_connect(G_OBJECT(_map_widget), "configure_event",
3069             G_CALLBACK(map_cb_configure), NULL);
3070
3071     g_signal_connect(G_OBJECT(_map_widget), "expose_event",
3072             G_CALLBACK(map_cb_expose), NULL);
3073     g_signal_connect(G_OBJECT(_sat_panel), "expose_event",
3074             G_CALLBACK(sat_panel_expose), NULL);
3075     g_signal_connect(G_OBJECT(_heading_panel), "expose_event",
3076             G_CALLBACK(heading_panel_expose), NULL);
3077
3078     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
3079 }