"Fossies" - the Fresh Open Source Software Archive

Member "navit-0.5.6/navit/navit.c" (6 Mar 2021, 129343 Bytes) of package /linux/privat/navit-0.5.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "navit.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.5.5_vs_0.5.6.

    1 /**
    2  * Navit, a modular navigation system.
    3  * Copyright (C) 2005-2009 Navit Team
    4  *
    5  * This program is free software; you can redistribute it and/or
    6  * modify it under the terms of the GNU General Public License
    7  * version 2 as published by the Free Software Foundation.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public License
   15  * along with this program; if not, write to the
   16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   17  * Boston, MA  02110-1301, USA.
   18  */
   19 
   20 #define _USE_MATH_DEFINES 1
   21 #include "config.h"
   22 #ifdef HAVE_UNISTD_H
   23 #include <unistd.h>
   24 #endif
   25 #include <stdio.h>
   26 #include <errno.h>
   27 #include <stdlib.h>
   28 #include <signal.h>
   29 #include <string.h>
   30 #include <fcntl.h>
   31 #include <glib.h>
   32 #include <math.h>
   33 #include <time.h>
   34 #include "debug.h"
   35 #include "navit.h"
   36 #include "callback.h"
   37 #include "gui.h"
   38 #include "item.h"
   39 #include "xmlconfig.h"
   40 #include "projection.h"
   41 #include "map.h"
   42 #include "mapset.h"
   43 #include "main.h"
   44 #include "coord.h"
   45 #include "point.h"
   46 #include "transform.h"
   47 #include "traffic.h"
   48 #include "param.h"
   49 #include "menu.h"
   50 #include "graphics.h"
   51 #include "popup.h"
   52 #include "data_window.h"
   53 #include "route.h"
   54 #include "navigation.h"
   55 #include "speech.h"
   56 #include "track.h"
   57 #include "vehicle.h"
   58 #include "layout.h"
   59 #include "log.h"
   60 #include "attr.h"
   61 #include "event.h"
   62 #include "file.h"
   63 #include "profile.h"
   64 #include "command.h"
   65 #include "navit_nls.h"
   66 #include "map.h"
   67 #include "util.h"
   68 #include "messages.h"
   69 #include "vehicleprofile.h"
   70 #include "sunriset.h"
   71 #include "bookmarks.h"
   72 #ifdef HAVE_API_WIN32_BASE
   73 #include <windows.h>
   74 #include "util.h"
   75 #endif
   76 #ifdef HAVE_API_WIN32_CE
   77 #include "libc.h"
   78 #endif
   79 
   80 /* define string for bookmark handling */
   81 #define TEXTFILE_COMMENT_NAVI_STOPPED "# navigation stopped\n"
   82 
   83 /**
   84  * @defgroup navit The navit core instance
   85  * @brief navit is the object containing most global data structures.
   86  *
   87  * Among others:
   88  * - a set of maps
   89  * - one or more vehicles
   90  * - a graphics object for rendering the map
   91  * - a gui object for displaying the user interface
   92  * - a route object
   93  * - a navigation object
   94  * @{
   95  */
   96 
   97 //! The vehicle used for navigation.
   98 struct navit_vehicle {
   99     int follow;
  100     /*! Limit of the follow counter. See navit_add_vehicle */
  101     int follow_curr;
  102     /*! Deprecated : follow counter itself. When it reaches 'update' counts, map is recentered*/
  103     struct coord coord;
  104     int dir;
  105     int speed;
  106     struct coord last; /*< Position of the last update of this vehicle */
  107     struct vehicle *vehicle;
  108     struct attr callback;
  109     int animate_cursor;
  110 };
  111 
  112 struct navit {
  113     NAVIT_OBJECT
  114     struct attr self;
  115     GList *mapsets;
  116     GList *layouts;
  117     struct gui *gui;
  118     char *default_layout_name;  /*!< The default layout indicated by the config file (if any) */
  119     struct layout *layout_current;  /*!< The current layout theme used to display the map */
  120     struct graphics *gra;
  121     struct action *action;
  122     struct transformation *trans, *trans_cursor;
  123     struct compass *compass;
  124     struct route *route;
  125     struct navigation *navigation;
  126     struct speech *speech;
  127     struct tracking *tracking;
  128     int ready;
  129     struct window *win;
  130     struct displaylist *displaylist;
  131     int tracking_flag;
  132     int orientation;
  133     int recentdest_count;
  134     int osd_configuration;
  135     GList *vehicles;
  136     GList *windows_items;
  137     struct navit_vehicle *vehicle;
  138     struct callback_list *attr_cbl;
  139     struct callback *nav_speech_cb, *roadbook_callback, *popup_callback, *route_cb, *progress_cb;
  140     struct datawindow *roadbook_window;
  141     struct map *former_destination;
  142     struct point pressed, last, current;
  143     int button_pressed,moved,popped,zoomed;
  144     int center_timeout;
  145     int autozoom_secs;
  146     int autozoom_min;
  147     int autozoom_max;
  148     int autozoom_active;
  149     int autozoom_paused;
  150     struct event_timeout *button_timeout, *motion_timeout;
  151     struct callback *motion_timeout_callback;
  152     int ignore_button;
  153     int ignore_graphics_events;
  154     struct log *textfile_debug_log;
  155     struct pcoord destination;
  156     int destination_valid;
  157     int blocked;    /**< Whether draw operations are currently blocked. This can be a combination of the
  158                          following flags:
  159                          1: draw operations are blocked
  160                          2: draw operations are pending, requiring a redraw once draw operations are unblocked */
  161     int w,h;
  162     int drag_bitmap;
  163     int use_mousewheel;
  164     struct messagelist *messages;
  165     struct callback *resize_callback,*button_callback,*motion_callback,*predraw_callback;
  166     struct vehicleprofile *vehicleprofile;
  167     GList *vehicleprofiles;
  168     int pitch;
  169     int follow_cursor;
  170     int prevTs;
  171     int graphics_flags;
  172     int zoom_min, zoom_max;
  173     int radius;
  174     struct bookmarks *bookmarks;
  175     int flags;
  176     /* 1=No graphics ok */
  177     /* 2=No gui ok */
  178     int border;
  179     int imperial;
  180     int waypoints_flag;
  181     struct coord_geo center;
  182     int auto_switch; /*auto switching between day/night layout enabled ?*/
  183 };
  184 
  185 struct gui *main_loop_gui;
  186 
  187 struct attr_iter {
  188     void *iter;
  189     union {
  190         GList *list;
  191         struct mapset_handle *mapset_handle;
  192     } u;
  193 };
  194 
  195 static void navit_vehicle_update_position(struct navit *this_, struct navit_vehicle *nv);
  196 static void navit_vehicle_draw(struct navit *this_, struct navit_vehicle *nv, struct point *pnt);
  197 static int navit_add_vehicle(struct navit *this_, struct vehicle *v);
  198 static int navit_set_attr_do(struct navit *this_, struct attr *attr, int init);
  199 static int navit_get_cursor_pnt(struct navit *this_, struct point *p, int keep_orientation, int *dir);
  200 static void navit_set_cursors(struct navit *this_);
  201 static int navit_cmd_zoom_to_route(struct navit *this, char *function, struct attr **in, struct attr ***out);
  202 static int navit_cmd_set_center_cursor(struct navit *this_, char *function, struct attr **in, struct attr ***out);
  203 static int navit_cmd_announcer_toggle(struct navit *this_, char *function, struct attr **in, struct attr ***out);
  204 static void navit_set_vehicle(struct navit *this_, struct navit_vehicle *nv);
  205 static int navit_set_vehicleprofile(struct navit *this_, struct vehicleprofile *vp);
  206 static int navit_cmd_switch_layout_day_night(struct navit *this_, char *function, struct attr **in, struct attr ***out);
  207 struct object_func navit_func;
  208 
  209 struct navit *global_navit;
  210 
  211 void navit_add_mapset(struct navit *this_, struct mapset *ms) {
  212     this_->mapsets = g_list_append(this_->mapsets, ms);
  213 }
  214 
  215 /**
  216  * @brief Get the current mapset
  217  *
  218  * @param this_ The navit instance
  219  *
  220  * @return A pointer to the current mapset
  221  */
  222 struct mapset *
  223 navit_get_mapset(struct navit *this_) {
  224     if(this_->mapsets) {
  225         return this_->mapsets->data;
  226     } else {
  227         dbg(lvl_error,"No mapsets enabled! Is it on purpose? Navit can't draw a map. Please check your navit.xml");
  228     }
  229     return NULL;
  230 }
  231 
  232 /**
  233  * @brief Get the search result map (and create it if it does not exist)
  234  *
  235  * @param this_ The navit instance
  236  *
  237  * @return A pointer to the map named "search_results" or NULL if there wasa failure
  238  */
  239 struct map *navit_get_search_results_map(struct navit *this_) {
  240 
  241     struct mapset *ms;
  242     struct map *map;
  243 
  244     ms=navit_get_mapset(this_);
  245 
  246     if(!ms)
  247         return NULL;
  248 
  249     map=mapset_get_map_by_name(ms, "search_results");
  250     if(!map) {
  251         struct attr *attrs[10], attrmap;
  252         enum attr_type types[]= {attr_position_longitude,attr_position_latitude,attr_label,attr_none};
  253         int i;
  254 
  255         attrs[0]=g_new0(struct attr,1);
  256         attrs[0]->type=attr_type;
  257         attrs[0]->u.str="csv";
  258 
  259         attrs[1]=g_new0(struct attr,1);
  260         attrs[1]->type=attr_name;
  261         attrs[1]->u.str="search_results";
  262 
  263         attrs[2]=g_new0(struct attr,1);
  264         attrs[2]->type=attr_charset;
  265         attrs[2]->u.str="utf-8";
  266 
  267         attrs[3]=g_new0(struct attr,1);
  268         attrs[3]->type=attr_item_type;
  269         attrs[3]->u.num=type_found_item;
  270 
  271         attrs[4]=g_new0(struct attr,1);
  272         attrs[4]->type=attr_attr_types;
  273         attrs[4]->u.attr_types=types;
  274         attrs[5]=NULL;
  275 
  276         attrmap.type=attr_map;
  277         map=attrmap.u.map=map_new(NULL,attrs);
  278         if(map)
  279             mapset_add_attr(ms,&attrmap);
  280 
  281         for(i=0; attrs[i]; i++)
  282             g_free(attrs[i]);
  283     }
  284     return map;
  285 }
  286 
  287 /**
  288  * @brief Populate a map containing one or more search result points
  289  *
  290  * These search results will be displayed as an overlay on the top of the geographic map.
  291  *
  292  * @warning Each call to this function will replace currently displayed results, it will not add to them
  293  *
  294  * @param this_ The navit instance
  295  * @param search_results A GList storing {@code struct lcoord} elements to display on the result map
  296  *                       If this argument in NULL, all existing results will be removed from the map
  297  * @param[in,out] coord_rect An optional rectangular zone that will be extended to contain all result points
  298  *                           or NULL if no zone needs to be computed
  299  * @return The number of results actually added to the map
  300  */
  301 int navit_populate_search_results_map(struct navit *this_, GList *search_results, struct coord_rect *r) {
  302     struct map *map;
  303     struct map_rect *mr;
  304     struct item *item;
  305     GList *curr_result = search_results;
  306     int count;
  307     char *name_label;
  308 
  309     map = navit_get_search_results_map(this_);
  310     if(!map)
  311         return 0;
  312 
  313     mr = map_rect_new(map, NULL);
  314 
  315     if(!mr)
  316         return 0;
  317 
  318     /* Clean the map */
  319     while((item = map_rect_get_item(mr))!=NULL) {
  320         item_type_set(item,type_none);
  321     }
  322 
  323     if(!search_results) {
  324         map_rect_destroy(mr);
  325         dbg(lvl_warning,"NULL result table - only map clean up is done.");
  326         return 0;
  327     }
  328 
  329     /* Populate the map with search results*/
  330     for(curr_result = search_results, count=0; curr_result; curr_result=g_list_next(curr_result)) {
  331         struct lcoord *point = curr_result->data;
  332         struct item* it;
  333         if(point->label==NULL)
  334             continue;
  335         dbg(lvl_info,"%s",point->label);
  336         it=map_rect_create_item(mr,type_found_item);
  337         if(it) {
  338             struct attr a;
  339             item_coord_set(it, &(point->c), 1, change_mode_modify);
  340             a.type=attr_label;
  341             name_label = g_strdup(point->label);
  342             square_shape_str(name_label);
  343             a.u.str=name_label;
  344             item_attr_set(it, &a, change_mode_modify);
  345             if (r) {
  346                 if(!count++)
  347                     r->lu=r->rl=point->c;
  348                 else
  349                     coord_rect_extend(r,&(point->c));
  350             }
  351         }
  352     }
  353     map_rect_destroy(mr);
  354     return count;
  355 }
  356 
  357 struct tracking *
  358 navit_get_tracking(struct navit *this_) {
  359     return this_->tracking;
  360 }
  361 
  362 /**
  363  * @brief   Get the user data directory.
  364  * @param[in]    create - create the directory if it does not exist
  365  *
  366  * @return  char * to the data directory string.
  367  *
  368  * returns the directory used to store user data files (center.txt,
  369  * destination.txt, bookmark.txt, ...)
  370  *
  371  */
  372 char* navit_get_user_data_directory(int create) {
  373     char *dir;
  374     dir = getenv("NAVIT_USER_DATADIR");
  375     if (create && !file_exists(dir)) {
  376         dbg(lvl_debug,"creating dir %s", dir);
  377         if (file_mkdir(dir,0)) {
  378             dbg(lvl_error,"failed creating dir %s", dir);
  379             return NULL;
  380         }
  381     }
  382     return dir;
  383 }
  384 
  385 
  386 void navit_draw_async(struct navit *this_, int async) {
  387 
  388     if (this_->blocked) {
  389         this_->blocked |= 2;
  390         return;
  391     }
  392     transform_setup_source_rect(this_->trans);
  393     graphics_draw(this_->gra, this_->displaylist, this_->mapsets->data, this_->trans, this_->layout_current, async, NULL,
  394                   this_->graphics_flags|1);
  395 }
  396 
  397 void navit_draw(struct navit *this_) {
  398     if (this_->ready == 3)
  399         navit_draw_async(this_, 0);
  400 }
  401 
  402 int navit_get_ready(struct navit *this_) {
  403     return this_->ready;
  404 }
  405 
  406 
  407 
  408 void navit_draw_displaylist(struct navit *this_) {
  409     if (this_->ready == 3)
  410         graphics_displaylist_draw(this_->gra, this_->displaylist, this_->trans, this_->layout_current, this_->graphics_flags|1);
  411 }
  412 
  413 static void navit_map_progress(struct navit *this_) {
  414     struct map *map;
  415     struct mapset *ms;
  416     struct mapset_handle *msh;
  417     struct attr attr;
  418     struct point p;
  419     if (this_->ready != 3)
  420         return;
  421     p.x=10;
  422     p.y=32;
  423 
  424     ms=this_->mapsets->data;
  425     msh=mapset_open(ms);
  426     while (msh && (map=mapset_next(msh, 0))) {
  427         if (map_get_attr(map, attr_progress, &attr, NULL)) {
  428             char *str=g_strdup_printf("%s           ",attr.u.str);
  429             graphics_draw_mode(this_->gra, draw_mode_begin);
  430             graphics_draw_text_std(this_->gra, 16, str, &p);
  431             g_free(str);
  432             p.y+=32;
  433             graphics_draw_mode(this_->gra, draw_mode_end);
  434         }
  435     }
  436     mapset_close(msh);
  437 }
  438 
  439 static void navit_redraw_route(struct navit *this_, struct route *route, struct attr *attr) {
  440     int updated;
  441     if (attr->type != attr_route_status)
  442         return;
  443     updated=attr->u.num;
  444     if (this_->ready != 3)
  445         return;
  446     if (updated != route_status_path_done_new)
  447         return;
  448     if (this_->vehicle) {
  449         if (this_->vehicle->follow_curr == 1)
  450             return;
  451         if (this_->vehicle->follow_curr <= this_->vehicle->follow)
  452             this_->vehicle->follow_curr=this_->vehicle->follow;
  453     }
  454     navit_draw(this_);
  455 }
  456 
  457 void navit_handle_resize(struct navit *this_, int w, int h) {
  458     struct map_selection sel;
  459     int callback=(this_->ready == 1);
  460     this_->ready |= 2;
  461     memset(&sel, 0, sizeof(sel));
  462     this_->w=w;
  463     this_->h=h;
  464     sel.u.p_rect.rl.x=w;
  465     sel.u.p_rect.rl.y=h;
  466     transform_set_screen_selection(this_->trans, &sel);
  467     graphics_init(this_->gra);
  468     graphics_set_rect(this_->gra, &sel.u.p_rect);
  469     if (callback)
  470         callback_list_call_attr_1(this_->attr_cbl, attr_graphics_ready, this_);
  471     if (this_->ready == 3)
  472         navit_draw_async(this_, 1);
  473 }
  474 
  475 static void navit_resize(void *data, int w, int h) {
  476     struct navit *this=data;
  477     if (!this->ignore_graphics_events)
  478         navit_handle_resize(this, w, h);
  479 }
  480 
  481 int navit_get_width(struct navit *this_) {
  482     return this_->w;
  483 }
  484 
  485 
  486 int navit_get_height(struct navit *this_) {
  487     return this_->h;
  488 }
  489 
  490 static void navit_popup(void *data) {
  491     struct navit *this_=data;
  492     popup(this_, 1, &this_->pressed);
  493     this_->button_timeout=NULL;
  494     this_->popped=1;
  495 }
  496 
  497 
  498 /**
  499  * @brief Sets a flag indicating that the current button event should be ignored by subsequent handlers.
  500  *
  501  * Calling this function will set the {@code ignore_button} member to {@code true} and return its previous state.
  502  * The default handler, {@link navit_handle_button(navit *, int, int, point *, callback *)} calls this function
  503  * just before the actual event handling core and aborts if the result is {@code true}. In order to prevent
  504  * multiple handlers from firing on a single event, custom button click handlers should implement the same logic
  505  * for events they wish to handle.
  506  *
  507  * If a handler wishes to pass down an event to other handlers, it must abort without calling this function.
  508  *
  509  * @param this_ The navit instance
  510  * @return {@code true} if the caller should ignore the button event, {@code false} if it should handle it
  511  */
  512 int navit_ignore_button(struct navit *this_) {
  513     if (this_->ignore_button)
  514         return 1;
  515     this_->ignore_button=1;
  516     return 0;
  517 }
  518 
  519 void navit_ignore_graphics_events(struct navit *this_, int ignore) {
  520     this_->ignore_graphics_events=ignore;
  521 }
  522 
  523 static int navit_restrict_to_range(int value, int min, int max) {
  524     if (value>max) {
  525         value = max;
  526     }
  527     if (value<min) {
  528         value = min;
  529     }
  530     return value;
  531 }
  532 
  533 static void navit_restrict_map_center_to_world_boundingbox(struct transformation *tr, struct coord *new_center) {
  534     new_center->x = navit_restrict_to_range(new_center->x, WORLD_BOUNDINGBOX_MIN_X, WORLD_BOUNDINGBOX_MAX_X);
  535     new_center->y = navit_restrict_to_range(new_center->y, WORLD_BOUNDINGBOX_MIN_Y, WORLD_BOUNDINGBOX_MAX_Y);
  536 }
  537 
  538 /**
  539  * @brief Change map center position by translating from "old" to "new".
  540  */
  541 static void update_transformation(struct transformation *tr, struct point *old, struct point *new) {
  542     /* Code for rotation was removed in rev. 5252; see Trac #1078. */
  543     struct coord coord_old,coord_new;
  544     struct coord center_new,*center_old;
  545     if (!transform_reverse(tr, old, &coord_old))
  546         return;
  547     if (!transform_reverse(tr, new, &coord_new))
  548         return;
  549     center_old=transform_get_center(tr);
  550     center_new.x=center_old->x+coord_old.x-coord_new.x;
  551     center_new.y=center_old->y+coord_old.y-coord_new.y;
  552     navit_restrict_map_center_to_world_boundingbox(tr, &center_new);
  553     dbg(lvl_debug,"change center from 0x%x,0x%x to 0x%x,0x%x", center_old->x, center_old->y, center_new.x, center_new.y);
  554     transform_set_center(tr, &center_new);
  555 }
  556 
  557 void navit_set_timeout(struct navit *this_) {
  558     struct attr follow;
  559     follow.type=attr_follow;
  560     follow.u.num=this_->center_timeout;
  561     navit_set_attr(this_, &follow);
  562 }
  563 
  564 int navit_handle_button(struct navit *this_, int pressed, int button, struct point *p,
  565                         struct callback *popup_callback) {
  566     int border=16;
  567 
  568     dbg(lvl_debug,"button %d %s (ignore: %d)",button,pressed?"pressed":"released",this_->ignore_button);
  569     callback_list_call_attr_4(this_->attr_cbl, attr_button, this_, GINT_TO_POINTER(pressed), GINT_TO_POINTER(button), p);
  570     if (this_->ignore_button) {
  571         this_->ignore_button=0;
  572         return 0;
  573     }
  574     if (pressed) {
  575         this_->pressed=*p;
  576         this_->last=*p;
  577         this_->zoomed=0;
  578         if (button == 1) {
  579             this_->button_pressed=1;
  580             this_->moved=0;
  581             this_->popped=0;
  582             if (popup_callback)
  583                 this_->button_timeout=event_add_timeout(500, 0, popup_callback);
  584         }
  585         if (button == 2)
  586             navit_set_center_screen(this_, p, 1);
  587         if (button == 3)
  588             popup(this_, button, p);
  589         if (button == 4 && this_->use_mousewheel) {
  590             this_->zoomed = 1;
  591             navit_zoom_in(this_, 2, p);
  592         }
  593         if (button == 5 && this_->use_mousewheel) {
  594             this_->zoomed = 1;
  595             navit_zoom_out(this_, 2, p);
  596         }
  597     } else {
  598 
  599         this_->button_pressed=0;
  600         if (this_->button_timeout) {
  601             event_remove_timeout(this_->button_timeout);
  602             this_->button_timeout=NULL;
  603             if (! this_->moved && ! transform_within_border(this_->trans, p, border)) {
  604                 navit_set_center_screen(this_, p, !this_->zoomed);
  605             }
  606         }
  607         if (this_->motion_timeout) {
  608             event_remove_timeout(this_->motion_timeout);
  609             this_->motion_timeout=NULL;
  610         }
  611         if (this_->moved) {
  612             dbg(lvl_debug, "mouse drag (%d, %d)->(%d, %d)", this_->pressed.x, this_->pressed.y, p->x, p->y);
  613             update_transformation(this_->trans, &this_->pressed, p);
  614             graphics_draw_drag(this_->gra, NULL);
  615             transform_copy(this_->trans, this_->trans_cursor);
  616             graphics_overlay_disable(this_->gra, 0);
  617             if (!this_->zoomed)
  618                 navit_set_timeout(this_);
  619             navit_draw(this_);
  620         } else
  621             return 1;
  622     }
  623     return 0;
  624 }
  625 
  626 static void navit_button(void *data, int pressed, int button, struct point *p) {
  627     struct navit *this=data;
  628     dbg(lvl_debug,"enter %d %d ignore %d",pressed,button,this->ignore_graphics_events);
  629     if (!this->ignore_graphics_events) {
  630         if (! this->popup_callback)
  631             this->popup_callback=callback_new_1(callback_cast(navit_popup), this);
  632         navit_handle_button(this, pressed, button, p, this->popup_callback);
  633     }
  634 }
  635 
  636 
  637 static void navit_motion_timeout(struct navit *this_) {
  638     int dx, dy;
  639 
  640     if (this_->drag_bitmap) {
  641         struct point point;
  642         point.x=(this_->current.x-this_->pressed.x);
  643         point.y=(this_->current.y-this_->pressed.y);
  644         if (graphics_draw_drag(this_->gra, &point)) {
  645             graphics_overlay_disable(this_->gra, 1);
  646             graphics_draw_mode(this_->gra, draw_mode_end);
  647             this_->moved=1;
  648             this_->motion_timeout=NULL;
  649             return;
  650         }
  651     }
  652     dx=(this_->current.x-this_->last.x);
  653     dy=(this_->current.y-this_->last.y);
  654     if (dx || dy) {
  655         struct transformation *tr;
  656         this_->last=this_->current;
  657         graphics_overlay_disable(this_->gra, 1);
  658         tr=transform_dup(this_->trans);
  659         update_transformation(tr, &this_->pressed, &this_->current);
  660         graphics_draw_cancel(this_->gra, this_->displaylist);
  661         graphics_displaylist_draw(this_->gra, this_->displaylist, tr, this_->layout_current, this_->graphics_flags|512);
  662         transform_destroy(tr);
  663         this_->moved=1;
  664     }
  665     this_->motion_timeout=NULL;
  666     return;
  667 }
  668 
  669 void navit_handle_motion(struct navit *this_, struct point *p) {
  670     int dx, dy;
  671 
  672     if (this_->button_pressed && !this_->popped) {
  673         dx=(p->x-this_->pressed.x);
  674         dy=(p->y-this_->pressed.y);
  675         if (dx < -8 || dx > 8 || dy < -8 || dy > 8) {
  676             this_->moved=1;
  677             if (this_->button_timeout) {
  678                 event_remove_timeout(this_->button_timeout);
  679                 this_->button_timeout=NULL;
  680             }
  681             this_->current=*p;
  682             if (! this_->motion_timeout_callback)
  683                 this_->motion_timeout_callback=callback_new_1(callback_cast(navit_motion_timeout), this_);
  684             if (! this_->motion_timeout)
  685                 this_->motion_timeout=event_add_timeout(this_->drag_bitmap?10:100, 0, this_->motion_timeout_callback);
  686         }
  687     }
  688 }
  689 
  690 static void navit_motion(void *data, struct point *p) {
  691     struct navit *this=data;
  692     if (!this->ignore_graphics_events)
  693         navit_handle_motion(this, p);
  694 }
  695 
  696 static void navit_predraw(struct navit *this_) {
  697     GList *l;
  698     struct navit_vehicle *nv;
  699     transform_copy(this_->trans, this_->trans_cursor);
  700     l=this_->vehicles;
  701     while (l) {
  702         nv=l->data;
  703         navit_vehicle_draw(this_, nv, NULL);
  704         l=g_list_next(l);
  705     }
  706 }
  707 
  708 static void navit_scale(struct navit *this_, long scale, struct point *p, int draw) {
  709     struct coord c1, c2, *center;
  710     if (scale < this_->zoom_min)
  711         scale=this_->zoom_min;
  712     if (scale > this_->zoom_max)
  713         scale=this_->zoom_max;
  714     if (p)
  715         transform_reverse(this_->trans, p, &c1);
  716     transform_set_scale(this_->trans, scale);
  717     if (p) {
  718         transform_reverse(this_->trans, p, &c2);
  719         center = transform_center(this_->trans);
  720         center->x += c1.x - c2.x;
  721         center->y += c1.y - c2.y;
  722     }
  723     if (draw)
  724         navit_draw(this_);
  725 }
  726 
  727 /**
  728  * @brief Automatically adjusts zoom level
  729  *
  730  * This function automatically adjusts the current
  731  * zoom level according to the current speed.
  732  *
  733  * @param this_ The navit struct
  734  * @param center The "immovable" point - i.e. the vehicles position if we're centering on the vehicle
  735  * @param speed The vehicles speed in meters per second
  736  * @param dir The direction into which the vehicle moves
  737  */
  738 static void navit_autozoom(struct navit *this_, struct coord *center, int speed, int draw) {
  739     struct point pc;
  740     int distance,w,h;
  741     double new_scale;
  742     long scale;
  743 
  744     if (! this_->autozoom_active) {
  745         return;
  746     }
  747 
  748     if(this_->autozoom_paused) {
  749         this_->autozoom_paused--;
  750         return;
  751     }
  752 
  753     distance = speed * this_->autozoom_secs;
  754 
  755     transform_get_size(this_->trans, &w, &h);
  756     transform(this_->trans, transform_get_projection(this_->trans), center, &pc, 1, 0, 0, NULL);
  757     scale = transform_get_scale(this_->trans);
  758 
  759     /* We make sure that the point we want to see is within a certain range
  760      * around the vehicle. The radius of this circle is the size of the
  761      * screen. This doesn't necessarily mean the point is visible because of
  762      * perspective etc. Quite rough, but should be enough. */
  763 
  764     if (w > h) {
  765         new_scale = (double)distance / h * 16;
  766     } else {
  767         new_scale = (double)distance / w * 16;
  768     }
  769 
  770     if (abs((int)new_scale - (int)scale) < 2) {
  771         return; // Smoothing
  772     }
  773     if (new_scale > this_->autozoom_max)
  774         new_scale=this_->autozoom_max;
  775     if (new_scale < this_->autozoom_min)
  776         new_scale=this_->autozoom_min;
  777     if (new_scale != scale)
  778         navit_scale(this_, (long)new_scale, &pc, 0);
  779 }
  780 
  781 /**
  782  * Change the current zoom level, zooming closer to the ground
  783  *
  784  * @param navit The navit instance
  785  * @param factor The zoom factor, usually 2
  786  * @param p The invariant point (if set to NULL, default to center)
  787  * @returns nothing
  788  */
  789 void navit_zoom_in(struct navit *this_, int factor, struct point *p) {
  790     long scale=transform_get_scale(this_->trans)/factor;
  791     if(this_->autozoom_active) {
  792         this_->autozoom_paused = 10;
  793     }
  794     if (scale < 1)
  795         scale=1;
  796     navit_scale(this_, scale, p, 1);
  797 }
  798 
  799 /**
  800  * Change the current zoom level
  801  *
  802  * @param navit The navit instance
  803  * @param factor The zoom factor, usually 2
  804  * @param p The invariant point (if set to NULL, default to center)
  805  * @returns nothing
  806  */
  807 void navit_zoom_out(struct navit *this_, int factor, struct point *p) {
  808     long scale=transform_get_scale(this_->trans)*factor;
  809     if(this_->autozoom_active) {
  810         this_->autozoom_paused = 10;
  811     }
  812     navit_scale(this_, scale, p, 1);
  813 }
  814 
  815 void navit_zoom_in_cursor(struct navit *this_, int factor) {
  816     struct point p;
  817     if (this_->vehicle && this_->vehicle->follow_curr <= 1 && navit_get_cursor_pnt(this_, &p, 0, NULL)) {
  818         navit_zoom_in(this_, factor, &p);
  819         this_->vehicle->follow_curr=this_->vehicle->follow;
  820     } else
  821         navit_zoom_in(this_, factor, NULL);
  822 }
  823 
  824 void navit_zoom_out_cursor(struct navit *this_, int factor) {
  825     struct point p;
  826     if (this_->vehicle && this_->vehicle->follow_curr <= 1 && navit_get_cursor_pnt(this_, &p, 0, NULL)) {
  827         navit_zoom_out(this_, 2, &p);
  828         this_->vehicle->follow_curr=this_->vehicle->follow;
  829     } else
  830         navit_zoom_out(this_, 2, NULL);
  831 }
  832 static int navit_cmd_zoom_in(struct navit *this_, char *cmd, struct attr **in, struct attr ***out) {
  833 
  834     navit_zoom_in_cursor(this_, 2);
  835     return 0;
  836 }
  837 
  838 static int navit_cmd_zoom_out(struct navit *this_, char *cmd, struct attr **in, struct attr ***out) {
  839     navit_zoom_out_cursor(this_, 2);
  840     return 0;
  841 }
  842 
  843 
  844 static int navit_cmd_say(struct navit *this, char *function, struct attr **in, struct attr ***out) {
  845     if (in && in[0] && ATTR_IS_STRING(in[0]->type) && in[0]->u.str)
  846         navit_say(this, in[0]->u.str);
  847     return 0;
  848 }
  849 
  850 static GHashTable *cmd_int_var_hash = NULL;
  851 static GHashTable *cmd_attr_var_hash = NULL;
  852 
  853 /**
  854  * Store key value pair for the  command system (for int typed values)
  855  *
  856  * @param navit The navit instance
  857  * @param function unused (needed to match command function signature)
  858  * @param in input attributes in[0] is the key string, in[1] is the integer value to store
  859  * @param out output attributes, unused
  860  * @returns 0
  861  */
  862 static int navit_cmd_set_int_var(struct navit *this, char *function, struct attr **in, struct attr ***out) {
  863     char*key;
  864     struct attr*val;
  865     if(!cmd_int_var_hash) {
  866         cmd_int_var_hash = g_hash_table_new(g_str_hash, g_str_equal);
  867     }
  868 
  869     if ( (in && in[0] && ATTR_IS_STRING(in[0]->type) && in[0]->u.str) &&
  870             (in && in[1] && ATTR_IS_NUMERIC(in[1]->type))) {
  871         val = g_new(struct attr,1);
  872         attr_dup_content(in[1],val);
  873         key = g_strdup(in[0]->u.str);
  874         g_hash_table_insert(cmd_int_var_hash, key, val);
  875     }
  876     return 0;
  877 }
  878 
  879 
  880 /**
  881  * Store key value pair for the  command system (for attr typed values, can be used as opaque handles)
  882  *
  883  * @param navit The navit instance
  884  * @param function unused (needed to match command function signature)
  885  * @param in input attributes in[0] is the key string, in[1] is the attr* value to store
  886  * @param out output attributes, unused
  887  * @returns 0
  888  */
  889 static int navit_cmd_set_attr_var(struct navit *this, char *function, struct attr **in, struct attr ***out) {
  890     char*key;
  891     struct attr*val;
  892     if(!cmd_attr_var_hash) {
  893         cmd_attr_var_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)attr_free);
  894     }
  895 
  896     if ( (in && in[0] && ATTR_IS_STRING(in[0]->type) && in[0]->u.str) &&
  897             (in && in[1] )) {
  898         val = attr_dup(in[1]);
  899         key = g_strdup(in[0]->u.str);
  900         g_hash_table_insert(cmd_attr_var_hash, key, val);
  901     } else {
  902         dbg(lvl_warning, "Wrong parameters for set_attr_var() command function");
  903     }
  904     return 0;
  905 }
  906 
  907 
  908 
  909 /**
  910  * command to toggle the active state of a named layer of the current layout
  911  *
  912  * @param navit The navit instance
  913  * @param function unused (needed to match command function signature)
  914  * @param in input attribute in[0] is the name of the layer
  915  * @param out output unused
  916  * @param valid unused
  917  * @returns 0
  918  */
  919 static int navit_cmd_toggle_layer(struct navit *this, char *function, struct attr **in, struct attr ***out) {
  920     if (in && in[0] && ATTR_IS_STRING(in[0]->type) && in[0]->u.str) {
  921         if(this->layout_current && this->layout_current->layers) {
  922             GList* layers = this->layout_current->layers;
  923             while (layers) {
  924                 struct layer*l=layers->data;
  925                 if(l && !strcmp(l->name,in[0]->u.str) ) {
  926                     l->active ^= 1;
  927                     navit_draw(this);
  928                     return 0;
  929                 }
  930                 layers=g_list_next(layers);
  931             }
  932         }
  933     }
  934     return 0;
  935 }
  936 
  937 /**
  938  * adds an item with the current coordinate of the vehicle to a named map
  939  *
  940  * @param navit The navit instance
  941  * @param function unused (needed to match command function signature)
  942  * @param in input attribute in[0] is the name of the map
  943  * @param out output attribute, 0 on error or the id of the created item on success
  944  * @returns 0
  945  */
  946 static int navit_cmd_map_add_curr_pos(struct navit *this, char *function, struct attr **in, struct attr ***out) {
  947     struct attr **list = g_new0(struct attr *,2);
  948     struct attr*val = g_new0(struct attr,1);
  949     struct mapset* ms;
  950     struct map_selection sel;
  951     const int selection_range = 10;
  952     enum item_type item_type;
  953     struct item *it;
  954     struct map* curr_map = NULL;
  955     struct coord curr_coord;
  956     struct map_rect *mr;
  957 
  958     //return invalid item on error
  959     val->type   = attr_none;
  960     val->u.item  = NULL;
  961     list[0]     = val;
  962     list[1]     = NULL;
  963     *out = list;
  964     if (
  965         in && in[0] && ATTR_IS_STRING(in[0]->type) && in[0]->u.str && //map name
  966         in[1] && ATTR_IS_STRING(in[1]->type) && in[1]->u.str    //item type
  967     ) {
  968 
  969         if(!(ms=navit_get_mapset(this))) {
  970             dbg(lvl_error, "Command function map_add_curr_pos(): there is no active mapset");
  971             return 0;
  972         }
  973 
  974         if((item_type = item_from_name(in[1]->u.str))==type_none) {
  975             dbg(lvl_error, "Command function map_add_curr_pos(): unknown item type");
  976             return 0;
  977         }
  978 
  979         curr_map = mapset_get_map_by_name(ms, in[0]->u.str);
  980 
  981         //no map with the given name found
  982         if( ! curr_map) {
  983             dbg(lvl_error, "Command function map_add_curr_pos(): map not found");
  984             return 0;
  985         }
  986 
  987         if(this->vehicle && this->vehicle->vehicle ) {
  988             struct attr pos_attr;
  989             if(vehicle_get_attr(this->vehicle->vehicle,attr_position_coord_geo,&pos_attr,NULL)) {
  990                 transform_from_geo(projection_mg, pos_attr.u.coord_geo, &curr_coord);
  991             } else {
  992                 dbg(lvl_error, "Command function map_add_curr_pos(): vehicle position is not accessible");
  993                 return 0;
  994             }
  995         } else {
  996             dbg(lvl_error, "Command function map_add_curr_pos(): no vehicle");
  997             return 0;
  998         }
  999 
 1000         sel.next=NULL;
 1001         sel.order=18;
 1002         sel.range.min=type_none;
 1003         sel.range.max=type_tec_common;
 1004         sel.u.c_rect.lu.x=curr_coord.x-selection_range;
 1005         sel.u.c_rect.lu.y=curr_coord.y+selection_range;
 1006         sel.u.c_rect.rl.x=curr_coord.x+selection_range;
 1007         sel.u.c_rect.rl.y=curr_coord.y-selection_range;
 1008 
 1009         mr = map_rect_new(curr_map, &sel);
 1010         if(mr) {
 1011 
 1012             it = map_rect_create_item( mr, item_type);
 1013             if (it) {
 1014                 struct attr attr;
 1015                 attr.type=attr_type_item_begin;
 1016                 attr.u.item=it;
 1017                 attr_dup_content(&attr,val);
 1018                 item_coord_set(it,&curr_coord, 1, change_mode_modify);
 1019             }
 1020         }
 1021         map_rect_destroy(mr);
 1022     }
 1023     return 0;
 1024 }
 1025 
 1026 /**
 1027  * sets an attribute (name value pair) of a map item specified by map name and item id
 1028  *
 1029  * @param navit The navit instance
 1030  * @param function unused (needed to match command function signature)
 1031  * @param in input attribute in[0] - name of the map  ; in[1] - item  ; in[2] - attr name ; in[3] - attr value
 1032  * @param out output attribute, 0 on error, 1 on success
 1033  * @returns 0
 1034  */
 1035 static int navit_cmd_map_item_set_attr(struct navit *this, char *function, struct attr **in, struct attr ***out) {
 1036     if (
 1037         in && in[0] && ATTR_IS_STRING(in[0]->type) && in[0]->u.str  &&//map name
 1038         in[1] && ATTR_IS_ITEM(in[1]->type)   && in[2]->u.item &&//item
 1039         in[2] && ATTR_IS_STRING(in[2]->type) && in[2]->u.str && //attr_type str
 1040         in[3] && ATTR_IS_STRING(in[3]->type) && in[3]->u.str    //attr_value str
 1041     ) {
 1042         struct attr attr_to_set;
 1043         struct map* curr_map = NULL;
 1044         struct mapset *ms;
 1045         struct item *it;
 1046         struct map_rect *mr;
 1047 
 1048         if(ATTR_IS_STRING(attr_from_name(in[2]->u.str))) {
 1049             attr_to_set.u.str = in[3]->u.str;
 1050             attr_to_set.type = attr_from_name(in[2]->u.str);
 1051         } else if(ATTR_IS_INT(attr_from_name(in[2]->u.str))) {
 1052             attr_to_set.u.num = atoi(in[3]->u.str);
 1053             attr_to_set.type = attr_from_name(in[2]->u.str);
 1054         } else if(ATTR_IS_DOUBLE(attr_from_name(in[2]->u.str))) {
 1055             double* val = g_new0(double,1);
 1056             *val = atof(in[3]->u.str);
 1057             attr_to_set.u.numd = val;
 1058             attr_to_set.type = attr_from_name(in[2]->u.str);
 1059         }
 1060 
 1061         ms = navit_get_mapset(this);
 1062 
 1063         curr_map = mapset_get_map_by_name(ms, in[0]->u.str);
 1064 
 1065         if( ! curr_map) {
 1066             return 0;
 1067         }
 1068 
 1069         mr=map_rect_new(curr_map,NULL);
 1070         it=in[1]->u.item;
 1071         it=map_rect_get_item_byid(mr,it->id_hi,it->id_lo);
 1072 
 1073         if(it) {
 1074             item_attr_set(it, &attr_to_set, change_mode_modify);
 1075         }
 1076         map_rect_destroy(mr);
 1077     } else {
 1078         dbg(lvl_debug,"Error in command function item_set_attr()");
 1079         dbg(lvl_debug,"Command function item_set_attr(): map cond:       %d",(in[0] && ATTR_IS_STRING(in[0]->type)
 1080                 && in[0]->u.str)?1:0);
 1081         dbg(lvl_debug,"Command function item_set_attr(): item cond:      %d",(in[1] && ATTR_IS_ITEM(in[1]->type))?1:0);
 1082         dbg(lvl_debug,"Command function item_set_attr(): attr type cond: %d",(in[2] && ATTR_IS_STRING(in[2]->type)
 1083                 && in[2]->u.str)?1:0);
 1084         dbg(lvl_debug,"Command function item_set_attr(): attr val cond:  %d",(in[3] && ATTR_IS_STRING(in[3]->type)
 1085                 && in[3]->u.str)?1:0);
 1086     }
 1087     return 0;
 1088 }
 1089 
 1090 /**
 1091  * Get attr variable given a key string for the command system (for opaque usage)
 1092  *
 1093  * @param navit The navit instance
 1094  * @param function unused (needed to match command function signature)
 1095  * @param in input attribute in[0] is the key string
 1096  * @param out output attribute, the attr for the given key string if exists or NULL
 1097  * @returns 0
 1098  */
 1099 static int navit_cmd_get_attr_var(struct navit *this, char *function, struct attr **in, struct attr ***out) {
 1100     struct attr **list = g_new0(struct attr *,2);
 1101     list[1] = NULL;
 1102     *out = list;
 1103     if(!cmd_attr_var_hash) {
 1104         struct attr*val = g_new0(struct attr,1);
 1105         val->type   = attr_type_item_begin;
 1106         val->u.item = NULL;
 1107         list[0]     = val;
 1108         return 0;
 1109     }
 1110     if (in && in[0] && ATTR_IS_STRING(in[0]->type) && in[0]->u.str) {
 1111         struct attr*ret = g_hash_table_lookup(cmd_attr_var_hash, in[0]->u.str);
 1112         if(ret) {
 1113             list[0] = attr_dup(ret);
 1114         } else {
 1115             struct attr*val = g_new0(struct attr,1);
 1116             val->type   = attr_type_int_begin;
 1117             val->u.item = NULL;
 1118             list[0]   = val;
 1119         }
 1120     }
 1121     return 0;
 1122 }
 1123 
 1124 
 1125 /**
 1126  * Get value given a key string for the command system
 1127  *
 1128  * @param navit The navit instance
 1129  * @param function unused (needed to match command function signature)
 1130  * @param in input attribute in[0] is the key string
 1131  * @param out output attribute, the value for the given key string if exists or 0
 1132  * @returns 0
 1133  */
 1134 static int navit_cmd_get_int_var(struct navit *this, char *function, struct attr **in, struct attr ***out) {
 1135     struct attr **list = g_new0(struct attr *,2);
 1136     list[1] = NULL;
 1137     *out = list;
 1138     if(!cmd_int_var_hash) {
 1139         struct attr*val = g_new0(struct attr,1);
 1140         val->type   = attr_type_int_begin;
 1141         val->u.num  = 0;
 1142         list[0]     = val;
 1143         return 0;
 1144     }
 1145     if (in && in[0] && ATTR_IS_STRING(in[0]->type) && in[0]->u.str) {
 1146         struct attr*ret = g_hash_table_lookup(cmd_int_var_hash, in[0]->u.str);
 1147         if(ret) {
 1148             list[0] = attr_dup(ret);
 1149         } else {
 1150             struct attr*val = g_new0(struct attr,1);
 1151             val->type   = attr_type_int_begin;
 1152             val->u.num  = 0;
 1153             list[0]   = val;
 1154         }
 1155     }
 1156     return 0;
 1157 }
 1158 
 1159 GList *cmd_int_var_stack = NULL;
 1160 
 1161 /**
 1162  * Push an integer to the stack for the command system
 1163  *
 1164  * @param navit The navit instance
 1165  * @param function unused (needed to match command function signature)
 1166  * @param in input attribute in[0] is the integer attibute to push
 1167  * @param out output attributes, unused
 1168  * @returns 0
 1169  */
 1170 static int navit_cmd_push_int(struct navit *this, char *function, struct attr **in, struct attr ***out) {
 1171     if (in && in[0] && ATTR_IS_NUMERIC(in[0]->type)) {
 1172         struct attr*val = g_new(struct attr,1);
 1173         attr_dup_content(in[0],val);
 1174         cmd_int_var_stack = g_list_prepend(cmd_int_var_stack, val);
 1175     }
 1176     return 0;
 1177 }
 1178 
 1179 /**
 1180  * Pop an integer from the command system's integer stack
 1181  *
 1182  * @param navit The navit instance
 1183  * @param function unused (needed to match command function signature)
 1184  * @param in input attributes unused
 1185  * @param out output attribute, the value popped if stack isn't empty or 0
 1186  * @returns 0
 1187  */
 1188 static int navit_cmd_pop_int(struct navit *this, char *function, struct attr **in, struct attr ***out) {
 1189     struct attr **list = g_new0(struct attr *,2);
 1190     if(!cmd_int_var_stack) {
 1191         struct attr*val = g_new0(struct attr,1);
 1192         val->type = attr_type_int_begin;
 1193         val->u.num  = 0;
 1194         list[0]   = val;
 1195     } else {
 1196         list[0] = cmd_int_var_stack->data;
 1197         cmd_int_var_stack = g_list_remove_link(cmd_int_var_stack,cmd_int_var_stack);
 1198     }
 1199     list[1] = NULL;
 1200     *out = list;
 1201     return 0;
 1202 }
 1203 
 1204 /**
 1205  * Get current size of command system's integer stack
 1206  *
 1207  * @param navit The navit instance
 1208  * @param function unused (needed to match command function signature)
 1209  * @param in input attributes unused
 1210  * @param out output attribute, the size of stack
 1211  * @returns 0
 1212  */
 1213 static int navit_cmd_int_stack_size(struct navit *this, char *function, struct attr **in, struct attr ***out) {
 1214     struct attr **list;
 1215     struct attr *attr  = g_new0(struct attr,1);
 1216     attr->type  = attr_type_int_begin;
 1217     if(!cmd_int_var_stack) {
 1218         attr->u.num = 0;
 1219     } else {
 1220         attr->u.num = g_list_length(cmd_int_var_stack);
 1221     }
 1222     list = g_new0(struct attr *,2);
 1223     list[0] = attr;
 1224     list[1] = NULL;
 1225     *out = list;
 1226     cmd_int_var_stack = g_list_remove_link(cmd_int_var_stack,cmd_int_var_stack);
 1227     return 0;
 1228 }
 1229 
 1230 static struct attr ** navit_get_coord(struct navit *this, struct attr **in, struct pcoord *pc) {
 1231     if (!in)
 1232         return NULL;
 1233     if (!in[0])
 1234         return NULL;
 1235     pc->pro = transform_get_projection(this->trans);
 1236     if (ATTR_IS_STRING(in[0]->type)) {
 1237         struct coord c;
 1238         coord_parse(in[0]->u.str, pc->pro, &c);
 1239         pc->x=c.x;
 1240         pc->y=c.y;
 1241         in++;
 1242     } else if (ATTR_IS_COORD(in[0]->type)) {
 1243         pc->x=in[0]->u.coord->x;
 1244         pc->y=in[0]->u.coord->y;
 1245         in++;
 1246     } else if (ATTR_IS_PCOORD(in[0]->type)) {
 1247         *pc=*in[0]->u.pcoord;
 1248         in++;
 1249     } else if (in[1] && in[2] && ATTR_IS_INT(in[0]->type) && ATTR_IS_INT(in[1]->type) && ATTR_IS_INT(in[2]->type)) {
 1250         pc->pro=in[0]->u.num;
 1251         pc->x=in[1]->u.num;
 1252         pc->y=in[2]->u.num;
 1253         in+=3;
 1254     } else if (in[1] && ATTR_IS_INT(in[0]->type) && ATTR_IS_INT(in[1]->type)) {
 1255         pc->x=in[0]->u.num;
 1256         pc->y=in[1]->u.num;
 1257         in+=2;
 1258     } else
 1259         return NULL;
 1260     return in;
 1261 }
 1262 
 1263 static int navit_cmd_set_destination(struct navit *this, char *function, struct attr **in, struct attr ***out) {
 1264     struct pcoord pc;
 1265     char *description=NULL;
 1266     in=navit_get_coord(this, in, &pc);
 1267     if (!in)
 1268         return 0;
 1269     if (in[0] && ATTR_IS_STRING(in[0]->type))
 1270         description=in[0]->u.str;
 1271     navit_set_destination(this, &pc, description, 1);
 1272     return 0;
 1273 }
 1274 
 1275 
 1276 static int navit_cmd_route_remove_next_waypoint(struct navit *this, char *function, struct attr **in,
 1277         struct attr ***out) {
 1278     navit_remove_waypoint(this);
 1279     return 0;
 1280 }
 1281 
 1282 
 1283 static int navit_cmd_route_remove_last_waypoint(struct navit *this, char *function, struct attr **in,
 1284         struct attr ***out) {
 1285     navit_remove_nth_waypoint(this, navit_get_destination_count(this)-1);
 1286     return 0;
 1287 }
 1288 
 1289 
 1290 static int navit_cmd_set_center(struct navit *this, char *function, struct attr **in, struct attr ***out) {
 1291     struct pcoord pc;
 1292     int set_timeout=0;
 1293     in=navit_get_coord(this, in, &pc);
 1294     if (!in)
 1295         return 0;
 1296     if(in[0] && ATTR_IS_INT(in[0]->type))
 1297         set_timeout=in[0]->u.num!=0;
 1298     navit_set_center(this, &pc, set_timeout);
 1299     return 0;
 1300 }
 1301 
 1302 
 1303 static int navit_cmd_set_position(struct navit *this, char *function, struct attr **in, struct attr ***out) {
 1304     struct pcoord pc;
 1305     in=navit_get_coord(this, in, &pc);
 1306     if (!in)
 1307         return 0;
 1308     navit_set_position(this, &pc);
 1309     return 0;
 1310 }
 1311 
 1312 
 1313 static int navit_cmd_fmt_coordinates(struct navit *this, char *function, struct attr **in, struct attr ***out) {
 1314     struct attr attr;
 1315     attr.type=attr_type_string_begin;
 1316     attr.u.str="Fix me";
 1317     if (out) {
 1318         *out=attr_generic_add_attr(*out, &attr);
 1319     }
 1320     return 0;
 1321 }
 1322 
 1323 /**
 1324  * Join several string attributes into one
 1325  *
 1326  * @param navit The navit instance
 1327  * @param function unused (needed to match command function signature)
 1328  * @param in input attributes in[0] - separator, in[1..] - attributes to join
 1329  * @param out output attribute joined attribute as string
 1330  * @returns 0
 1331  */
 1332 static int navit_cmd_strjoin(struct navit *this, char *function, struct attr **in, struct attr ***out) {
 1333     struct attr attr;
 1334     gchar *ret, *sep;
 1335     int i;
 1336     attr.type=attr_type_string_begin;
 1337     attr.u.str=NULL;
 1338     if(in[0] && in[1]) {
 1339         sep=attr_to_text(in[0],NULL,1);
 1340         ret=attr_to_text(in[1],NULL,1);
 1341         for(i=2; in[i]; i++) {
 1342             gchar *in_i=attr_to_text(in[i],NULL,1);
 1343             gchar *r=g_strjoin(sep,ret,in_i,NULL);
 1344             g_free(in_i);
 1345             g_free(ret);
 1346             ret=r;
 1347         }
 1348         g_free(sep);
 1349         attr.u.str=ret;
 1350         if(out) {
 1351             *out=attr_generic_add_attr(*out, &attr);
 1352         }
 1353         g_free(ret);
 1354     }
 1355     return 0;
 1356 }
 1357 
 1358 /**
 1359  * Call external program
 1360  *
 1361  * @param navit The navit instance
 1362  * @param function unused (needed to match command function signature)
 1363  * @param in input attributes in[0] - name of executable, in[1..] - parameters
 1364  * @param out output attribute unused
 1365  * @returns 0
 1366  */
 1367 static int navit_cmd_spawn(struct navit *this, char *function, struct attr **in, struct attr ***out) {
 1368     int i,j, nparms, nvalid;
 1369     char ** argv=NULL;
 1370     struct spawn_process_info *pi;
 1371 
 1372     nparms=0;
 1373     nvalid=0;
 1374     if(in) {
 1375         while(in[nparms]) {
 1376             if (in[nparms]->type!=attr_none)
 1377                 nvalid++;
 1378             nparms++;
 1379         }
 1380     }
 1381 
 1382     if(nvalid>0) {
 1383         argv=g_new(char*,nvalid+1);
 1384         for(i=0,j=0; in[i]; i++) {
 1385             if(in[i]->type!=attr_none ) {
 1386                 argv[j++]=attr_to_text(in[i],NULL,1);
 1387             } else {
 1388                 dbg(lvl_debug,"Parameter #%i is attr_none - skipping",i);
 1389             }
 1390         }
 1391         argv[j]=NULL;
 1392         pi=spawn_process(argv);
 1393 
 1394         // spawn_process() testing suite - uncomment following code to test.
 1395         //sleep(3);
 1396         // example of non-blocking wait
 1397         //int st=spawn_process_check_status(pi,0);dbg(lvl_debug,"status %i",st);
 1398         // example of blocking wait
 1399         //st=spawn_process_check_status(pi,1);dbg(lvl_debug,"status %i",st);
 1400         // example of wait after process is finished and status is
 1401         // already tested
 1402         //st=spawn_process_check_status(pi,1);dbg(lvl_debug,"status %i",st);
 1403         // example of wait after process is finished and status is
 1404         // already tested - unblocked
 1405         //st=spawn_process_check_status(pi,0);dbg(lvl_debug,"status %i",st);
 1406 
 1407         // End testing suite
 1408         spawn_process_info_free(pi);
 1409         for(i=0; argv[i]; i++)
 1410             g_free(argv[i]);
 1411         g_free(argv);
 1412     }
 1413     return 0;
 1414 }
 1415 
 1416 
 1417 static struct command_table commands[] = {
 1418     {"zoom_in",command_cast(navit_cmd_zoom_in)},
 1419     {"zoom_out",command_cast(navit_cmd_zoom_out)},
 1420     {"zoom_to_route",command_cast(navit_cmd_zoom_to_route)},
 1421     {"say",command_cast(navit_cmd_say)},
 1422     {"set_center",command_cast(navit_cmd_set_center)},
 1423     {"set_center_cursor",command_cast(navit_cmd_set_center_cursor)},
 1424     {"set_destination",command_cast(navit_cmd_set_destination)},
 1425     {"set_position",command_cast(navit_cmd_set_position)},
 1426     {"route_remove_next_waypoint",command_cast(navit_cmd_route_remove_next_waypoint)},
 1427     {"route_remove_last_waypoint",command_cast(navit_cmd_route_remove_last_waypoint)},
 1428     {"set_position",command_cast(navit_cmd_set_position)},
 1429     {"announcer_toggle",command_cast(navit_cmd_announcer_toggle)},
 1430     {"fmt_coordinates",command_cast(navit_cmd_fmt_coordinates)},
 1431     {"set_int_var",command_cast(navit_cmd_set_int_var)},
 1432     {"get_int_var",command_cast(navit_cmd_get_int_var)},
 1433     {"push_int",command_cast(navit_cmd_push_int)},
 1434     {"pop_int",command_cast(navit_cmd_pop_int)},
 1435     {"int_stack_size",command_cast(navit_cmd_int_stack_size)},
 1436     {"toggle_layer",command_cast(navit_cmd_toggle_layer)},
 1437     {"strjoin",command_cast(navit_cmd_strjoin)},
 1438     {"spawn",command_cast(navit_cmd_spawn)},
 1439     {"map_add_curr_pos",command_cast(navit_cmd_map_add_curr_pos)},
 1440     {"map_item_set_attr",command_cast(navit_cmd_map_item_set_attr)},
 1441     {"set_attr_var",command_cast(navit_cmd_set_attr_var)},
 1442     {"get_attr_var",command_cast(navit_cmd_get_attr_var)},
 1443     {"switch_layout_day_night",command_cast(navit_cmd_switch_layout_day_night)},
 1444 };
 1445 
 1446 void navit_command_add_table(struct navit*this_, struct command_table *commands, int count) {
 1447     command_add_table(this_->attr_cbl, commands, count, this_);
 1448 }
 1449 
 1450 struct navit *
 1451 navit_new(struct attr *parent, struct attr **attrs) {
 1452     struct navit *this_=g_new0(struct navit, 1);
 1453     struct pcoord center;
 1454     struct coord co;
 1455     struct coord_geo g;
 1456     enum projection pro=projection_mg;
 1457     int zoom = 256;
 1458     g.lat=53.13;
 1459     g.lng=11.70;
 1460 
 1461     this_->func=&navit_func;
 1462     navit_object_ref((struct navit_object *)this_);
 1463     this_->attrs=attr_list_dup(attrs);
 1464     this_->self.type=attr_navit;
 1465     this_->self.u.navit=this_;
 1466     this_->attr_cbl=callback_list_new();
 1467 
 1468     this_->orientation=-1;
 1469     this_->tracking_flag=1;
 1470     this_->recentdest_count=10;
 1471     this_->osd_configuration=-1;
 1472     this_->default_layout_name=NULL;
 1473 
 1474     this_->center_timeout = 10;
 1475     this_->use_mousewheel = 1;
 1476     this_->autozoom_secs = 10;
 1477     this_->autozoom_min = 7;
 1478     this_->autozoom_active = 0;
 1479     this_->autozoom_paused = 0;
 1480     this_->zoom_min = 1;
 1481     this_->zoom_max = 2097152;
 1482     this_->autozoom_max = this_->zoom_max;
 1483     this_->follow_cursor = 1;
 1484     this_->radius = 30;
 1485     this_->border = 16;
 1486     this_->auto_switch = TRUE;
 1487 
 1488     transform_from_geo(pro, &g, &co);
 1489     center.x=co.x;
 1490     center.y=co.y;
 1491     center.pro = pro;
 1492     this_->trans = transform_new(&center, zoom, (this_->orientation != -1) ? this_->orientation : 0);
 1493     this_->trans_cursor = transform_new(&center, zoom, (this_->orientation != -1) ? this_->orientation : 0);
 1494 
 1495     this_->bookmarks=bookmarks_new(&this_->self, NULL, this_->trans);
 1496 
 1497     this_->prevTs=0;
 1498 
 1499     for (; *attrs; attrs++) {
 1500         navit_set_attr_do(this_, *attrs, 1);
 1501     }
 1502     this_->displaylist=graphics_displaylist_new();
 1503     command_add_table(this_->attr_cbl, commands, sizeof(commands)/sizeof(struct command_table), this_);
 1504 
 1505     this_->messages = messagelist_new(attrs);
 1506 
 1507     dbg(lvl_debug,"return %p",this_);
 1508 
 1509     return this_;
 1510 }
 1511 
 1512 static int navit_set_gui(struct navit *this_, struct gui *gui) {
 1513     if (this_->gui)
 1514         return 0;
 1515     this_->gui=gui;
 1516     if (gui_has_main_loop(this_->gui)) {
 1517         if (! main_loop_gui) {
 1518             main_loop_gui=this_->gui;
 1519         } else {
 1520             dbg(lvl_error,"gui with main loop already active, ignoring this instance");
 1521             return 0;
 1522         }
 1523     }
 1524     return 1;
 1525 }
 1526 
 1527 void navit_add_message(struct navit *this_, const char *message) {
 1528     message_new(this_->messages, message);
 1529 }
 1530 
 1531 struct message
 1532 *navit_get_messages(struct navit *this_) {
 1533     return message_get(this_->messages);
 1534 }
 1535 
 1536 static int navit_set_graphics(struct navit *this_, struct graphics *gra) {
 1537     if (this_->gra)
 1538         return 0;
 1539     this_->gra=gra;
 1540     this_->resize_callback=callback_new_attr_1(callback_cast(navit_resize), attr_resize, this_);
 1541     graphics_add_callback(gra, this_->resize_callback);
 1542     this_->button_callback=callback_new_attr_1(callback_cast(navit_button), attr_button, this_);
 1543     graphics_add_callback(gra, this_->button_callback);
 1544     this_->motion_callback=callback_new_attr_1(callback_cast(navit_motion), attr_motion, this_);
 1545     graphics_add_callback(gra, this_->motion_callback);
 1546     this_->predraw_callback=callback_new_attr_1(callback_cast(navit_predraw), attr_predraw, this_);
 1547     graphics_add_callback(gra, this_->predraw_callback);
 1548     return 1;
 1549 }
 1550 
 1551 struct graphics *
 1552 navit_get_graphics(struct navit *this_) {
 1553     return this_->gra;
 1554 }
 1555 
 1556 struct vehicleprofile *
 1557 navit_get_vehicleprofile(struct navit *this_) {
 1558     return this_->vehicleprofile;
 1559 }
 1560 
 1561 GList *navit_get_vehicleprofiles(struct navit *this_) {
 1562     return this_->vehicleprofiles;
 1563 }
 1564 
 1565 static void navit_projection_set(struct navit *this_, enum projection pro, int draw) {
 1566     struct coord_geo g;
 1567     struct coord *c;
 1568 
 1569     c=transform_center(this_->trans);
 1570     transform_to_geo(transform_get_projection(this_->trans), c, &g);
 1571     transform_set_projection(this_->trans, pro);
 1572     transform_from_geo(pro, &g, c);
 1573     if (draw)
 1574         navit_draw(this_);
 1575 }
 1576 
 1577 static void navit_mark_navigation_stopped(char *former_destination_file) {
 1578     FILE *f;
 1579     f=fopen(former_destination_file, "a");
 1580     if (f) {
 1581         fprintf(f,"%s", TEXTFILE_COMMENT_NAVI_STOPPED);
 1582         fclose(f);
 1583     } else {
 1584         dbg(lvl_error, "Error setting mark in destination file %s: %s", former_destination_file, strerror(errno));
 1585     }
 1586 }
 1587 
 1588 
 1589 /**
 1590  * Start or add a given set of coordinates for route computing
 1591  *
 1592  * @param navit The navit instance
 1593  * @param c The coordinate to start routing to
 1594  * @param description A label which allows the user to later identify this destination in the former destinations selection
 1595  * @param async Set to 1 to do route calculation asynchronously
 1596  * @return nothing
 1597  */
 1598 void navit_set_destination(struct navit *this_, struct pcoord *c, const char *description, int async) {
 1599     char *destination_file;
 1600     destination_file = bookmarks_get_destination_file(TRUE);
 1601     if (c) {
 1602         this_->destination=*c;
 1603         this_->destination_valid=1;
 1604 
 1605         dbg(lvl_debug, "c=(%i,%i)", c->x,c->y);
 1606         bookmarks_append_destinations(this_->former_destination, destination_file, c, 1, type_former_destination, description,
 1607                                       this_->recentdest_count);
 1608     } else {
 1609         this_->destination_valid=0;
 1610         bookmarks_append_destinations(this_->former_destination, destination_file, NULL, 0, type_former_destination, NULL,
 1611                                       this_->recentdest_count);
 1612         navit_mark_navigation_stopped(destination_file);
 1613     }
 1614     g_free(destination_file);
 1615 
 1616     if (this_->route) {
 1617         struct attr attr;
 1618         int dstcount;
 1619         struct pcoord *pc;
 1620 
 1621         navit_get_attr(this_, attr_waypoints_flag, &attr, NULL);
 1622         if (this_->waypoints_flag==0 || route_get_destination_count(this_->route)==0) {
 1623             route_set_destination(this_->route, c, async);
 1624         } else {
 1625             route_append_destination(this_->route, c, async);
 1626         }
 1627 
 1628         dstcount=route_get_destination_count(this_->route);
 1629         if(dstcount>0) {
 1630             destination_file = bookmarks_get_destination_file(TRUE);
 1631             pc=g_new(struct pcoord,dstcount);
 1632             route_get_destinations(this_->route,pc,dstcount);
 1633             bookmarks_append_destinations(this_->former_destination, destination_file, pc, dstcount, type_former_itinerary,
 1634                                           description, this_->recentdest_count);
 1635             g_free(pc);
 1636             g_free(destination_file);
 1637         }
 1638     }
 1639 
 1640     callback_list_call_attr_0(this_->attr_cbl, attr_destination);
 1641 
 1642     if (this_->route && this_->ready == 3 && !(this_->flags & 4))
 1643         navit_draw(this_);
 1644 }
 1645 
 1646 /**
 1647  * Add destination description to the recent dest file. Doesn't start routing.
 1648  *
 1649  * @param navit The navit instance
 1650  * @param c The coordinate to start routing to
 1651  * @param description A label which allows the user to later identify this destination in the former destinations selection
 1652  * @returns nothing
 1653  */
 1654 void navit_add_destination_description(struct navit *this_, struct pcoord *c, const char *description) {
 1655     char *destination_file;
 1656     if (c) {
 1657         destination_file = bookmarks_get_destination_file(TRUE);
 1658         bookmarks_append_destinations(this_->former_destination, destination_file, c, 1, type_former_destination, description,
 1659                                       this_->recentdest_count);
 1660         g_free(destination_file);
 1661     }
 1662 }
 1663 
 1664 
 1665 /**
 1666  * Start the route computing to a given set of coordinates including waypoints
 1667  *
 1668  * @param this_ The navit instance
 1669  * @param c The coordinate to start routing to
 1670  * @param description A label which allows the user to later identify this destination in the former destinations selection
 1671  * @param async If routing should be done asynchronously
 1672  * @returns nothing
 1673  */
 1674 void navit_set_destinations(struct navit *this_, struct pcoord *c, int count, const char *description, int async) {
 1675     char *destination_file;
 1676     if (c && count) {
 1677         this_->destination=c[count-1];
 1678         this_->destination_valid=1;
 1679 
 1680         destination_file = bookmarks_get_destination_file(TRUE);
 1681         bookmarks_append_destinations(this_->former_destination, destination_file, c, count, type_former_itinerary, description,
 1682                                       this_->recentdest_count);
 1683         g_free(destination_file);
 1684     } else
 1685         this_->destination_valid=0;
 1686     if (this_->route)
 1687         route_set_destinations(this_->route, c, count, async);
 1688 
 1689     callback_list_call_attr_0(this_->attr_cbl, attr_destination);
 1690     if (this_->route && this_->ready == 3)
 1691         navit_draw(this_);
 1692 }
 1693 
 1694 /**
 1695  * @brief Retrieves destinations from the route
 1696  *
 1697  * Prior to calling this method, you may want to retrieve the number of destinations by calling
 1698  * {@link navit_get_destination_count(struct navit *)} and assigning a buffer of sufficient capacity.
 1699  *
 1700  * If the return value equals `count`, the buffer was either just large enough or too small to hold the
 1701  * entire list of destinations; there is no way to tell from the result which is the case.
 1702  *
 1703  * If the Navit instance does not have a route, the result is 0.
 1704  *
 1705  * @param this_ The Navit instance
 1706  * @param pc Pointer to an array of projected coordinates which will receive the destination coordinates
 1707  * @param count Capacity of `pc`
 1708  * @return The number of destinations stored in `pc`, never greater than `count`
 1709  */
 1710 int navit_get_destinations(struct navit *this_, struct pcoord *pc, int count) {
 1711     if(!this_->route)
 1712         return 0;
 1713     return route_get_destinations(this_->route, pc, count);
 1714 
 1715 }
 1716 
 1717 /**
 1718  * @brief Get the destinations count for the route
 1719  *
 1720  * @param this The Navit instance
 1721  * @return destination count for the route, or 0 if the Navit instance has no route
 1722  */
 1723 int navit_get_destination_count(struct navit *this_) {
 1724     if(!this_->route)
 1725         return 0;
 1726     return route_get_destination_count(this_->route);
 1727 }
 1728 
 1729 char* navit_get_destination_description(struct navit *this_, int n) {
 1730     if(!this_->route)
 1731         return NULL;
 1732     return route_get_destination_description(this_->route, n);
 1733 }
 1734 
 1735 void navit_remove_nth_waypoint(struct navit *this_, int n) {
 1736     if(!this_->route)
 1737         return;
 1738     if (route_get_destination_count(this_->route)>1) {
 1739         route_remove_nth_waypoint(this_->route, n);
 1740     } else {
 1741         navit_set_destination(this_, NULL, NULL, 0);
 1742     }
 1743 }
 1744 
 1745 void navit_remove_waypoint(struct navit *this_) {
 1746     if(!this_->route)
 1747         return;
 1748     if (route_get_destination_count(this_->route)>1) {
 1749         route_remove_waypoint(this_->route);
 1750     } else {
 1751         navit_set_destination(this_, NULL, NULL, 0);
 1752     }
 1753 }
 1754 
 1755 /**
 1756  * @brief Checks if a route is calculated
 1757  *
 1758  * This function checks if a route is calculated.
 1759  *
 1760  * @param this_ The navit struct whose route should be checked.
 1761  * @return True if the route is set, false otherwise.
 1762  */
 1763 int navit_check_route(struct navit *this_) {
 1764     if (this_->route) {
 1765         return route_get_path_set(this_->route);
 1766     }
 1767 
 1768     return 0;
 1769 }
 1770 
 1771 static int navit_former_destinations_active(struct navit *this_) {
 1772     char *destination_file_name = bookmarks_get_destination_file(FALSE);
 1773     FILE *destination_file;
 1774     int active=0;
 1775     char lastline[100];
 1776     destination_file=fopen(destination_file_name,"r");
 1777     if (destination_file) {
 1778         while(fgets(lastline, sizeof(lastline), destination_file));
 1779         fclose(destination_file);
 1780         if ((lastline != NULL) && (strcmp(lastline, TEXTFILE_COMMENT_NAVI_STOPPED))) {
 1781             active=1;
 1782         }
 1783     }
 1784     g_free(destination_file_name);
 1785     return active;
 1786 }
 1787 
 1788 
 1789 struct map* read_former_destinations_from_file() {
 1790     struct attr type, data, no_warn, flags, *attrs[5];
 1791     char *destination_file = bookmarks_get_destination_file(FALSE);
 1792     struct map *m;
 1793 
 1794     type.type=attr_type;
 1795     type.u.str="textfile";
 1796 
 1797     data.type=attr_data;
 1798     data.u.str=destination_file;
 1799 
 1800     no_warn.type=attr_no_warning_if_map_file_missing;
 1801     no_warn.u.num=1;
 1802 
 1803     flags.type=attr_flags;
 1804     flags.u.num=1;
 1805 
 1806     attrs[0]=&type;
 1807     attrs[1]=&data;
 1808     attrs[2]=&flags;
 1809     attrs[3]=&no_warn;
 1810     attrs[4]=NULL;
 1811 
 1812     m=map_new(NULL, attrs);
 1813     g_free(destination_file);
 1814     return m;
 1815 }
 1816 
 1817 static void navit_add_former_destinations_from_file(struct navit *this_) {
 1818     struct item *item;
 1819     int i,valid=0,count=0,maxcount=1;
 1820     struct coord *c=g_new(struct coord, maxcount);
 1821     struct pcoord *pc;
 1822     struct map_rect *mr;
 1823 
 1824     this_->former_destination=read_former_destinations_from_file();
 1825     if (!this_->route || !navit_former_destinations_active(this_) || !this_->vehicle)
 1826         return;
 1827     mr=map_rect_new(this_->former_destination, NULL);
 1828     while ((item=map_rect_get_item(mr))) {
 1829         if (item->type == type_former_itinerary || item->type == type_former_itinerary_part) {
 1830             count=item_coord_get(item, c, maxcount);
 1831             while(count==maxcount) {
 1832                 maxcount*=2;
 1833                 c=g_realloc(c, sizeof(struct coord)*maxcount);
 1834                 count+=item_coord_get(item, &c[count], maxcount-count);
 1835             }
 1836             if(count)
 1837                 valid=1;
 1838         }
 1839     }
 1840     map_rect_destroy(mr);
 1841     if (valid && count > 0) {
 1842         pc=g_new(struct pcoord, count);
 1843         for (i = 0 ; i < count ; i++) {
 1844             pc[i].pro=map_projection(this_->former_destination);
 1845             pc[i].x=c[i].x;
 1846             pc[i].y=c[i].y;
 1847         }
 1848         if (count == 1)
 1849             route_set_destination(this_->route, &pc[0], 1);
 1850         else
 1851             route_set_destinations(this_->route, pc, count, 1);
 1852         this_->destination=pc[count-1];
 1853         this_->destination_valid=1;
 1854         g_free(pc);
 1855     }
 1856     g_free(c);
 1857 }
 1858 
 1859 
 1860 void navit_textfile_debug_log(struct navit *this_, const char *fmt, ...) {
 1861     va_list ap;
 1862     char *str1,*str2;
 1863     va_start(ap, fmt);
 1864     if (this_->textfile_debug_log && this_->vehicle) {
 1865         str1=g_strdup_vprintf(fmt, ap);
 1866         str2=g_strdup_printf("0x%x 0x%x%s%s\n", this_->vehicle->coord.x, this_->vehicle->coord.y, strlen(str1) ? " " : "",
 1867                              str1);
 1868         log_write(this_->textfile_debug_log, str2, strlen(str2), 0);
 1869         g_free(str2);
 1870         g_free(str1);
 1871     }
 1872     va_end(ap);
 1873 }
 1874 
 1875 void navit_textfile_debug_log_at(struct navit *this_, struct pcoord *pc, const char *fmt, ...) {
 1876     va_list ap;
 1877     char *str1,*str2;
 1878     va_start(ap, fmt);
 1879     if (this_->textfile_debug_log && this_->vehicle) {
 1880         str1=g_strdup_vprintf(fmt, ap);
 1881         str2=g_strdup_printf("0x%x 0x%x%s%s\n", pc->x, pc->y, strlen(str1) ? " " : "", str1);
 1882         log_write(this_->textfile_debug_log, str2, strlen(str2), 0);
 1883         g_free(str2);
 1884         g_free(str1);
 1885     }
 1886     va_end(ap);
 1887 }
 1888 
 1889 void navit_say(struct navit *this_, const char *text) {
 1890     struct attr attr;
 1891     if(this_->speech) {
 1892         if (!speech_get_attr(this_->speech, attr_active, &attr, NULL))
 1893             attr.u.num = 1;
 1894         dbg(lvl_debug, "this_.speech->active %ld", attr.u.num);
 1895         if(attr.u.num)
 1896             speech_say(this_->speech, text);
 1897     }
 1898 }
 1899 
 1900 /**
 1901  * @brief Toggles the navigation announcer for navit
 1902  * @param this_ The navit object
 1903  */
 1904 static int navit_cmd_announcer_toggle(struct navit *this_, char *function, struct attr **in, struct attr ***out) {
 1905     struct attr attr, speechattr;
 1906 
 1907     // search for the speech attribute
 1908     if(!navit_get_attr(this_, attr_speech, &speechattr, NULL))
 1909         return 0;
 1910     // find out if the corresponding attribute attr_active has been set
 1911     if(speech_get_attr(speechattr.u.speech, attr_active, &attr, NULL)) {
 1912         // flip it then...
 1913         attr.u.num = !attr.u.num;
 1914     } else {
 1915         // otherwise disable it because voice is enabled by default
 1916         attr.type = attr_active;
 1917         attr.u.num = 0;
 1918     }
 1919 
 1920     // apply the new state
 1921     if(!speech_set_attr(speechattr.u.speech, &attr))
 1922         return 0;
 1923 
 1924     // announce that the speech attribute has changed
 1925     callback_list_call_attr_1(this_->attr_cbl, attr_speech, this_);
 1926     return 0;
 1927 }
 1928 
 1929 void navit_speak(struct navit *this_) {
 1930     struct navigation *nav=this_->navigation;
 1931     struct map *map=NULL;
 1932     struct map_rect *mr=NULL;
 1933     struct item *item;
 1934     struct attr attr;
 1935 
 1936     if (!speech_get_attr(this_->speech, attr_active, &attr, NULL))
 1937         attr.u.num = 1;
 1938     dbg(lvl_debug, "this_.speech->active %ld", attr.u.num);
 1939     if(!attr.u.num)
 1940         return;
 1941 
 1942     if (nav)
 1943         map=navigation_get_map(nav);
 1944     if (map)
 1945         mr=map_rect_new(map, NULL);
 1946     if (mr) {
 1947         while ((item=map_rect_get_item(mr)) && (item->type == type_nav_position || item->type == type_nav_none));
 1948         if (item && item_attr_get(item, attr_navigation_speech, &attr)) {
 1949             if (*attr.u.str != '\0') {
 1950                 speech_say(this_->speech, attr.u.str);
 1951                 navit_add_message(this_, attr.u.str);
 1952             }
 1953             navit_textfile_debug_log(this_, "type=announcement label=\"%s\"", attr.u.str);
 1954         }
 1955         map_rect_destroy(mr);
 1956     }
 1957 }
 1958 
 1959 static void navit_window_roadbook_update(struct navit *this_) {
 1960     struct navigation *nav=this_->navigation;
 1961     struct map *map=NULL;
 1962     struct map_rect *mr=NULL;
 1963     struct item *item;
 1964     struct attr attr;
 1965     struct param_list param[5];
 1966     int secs;
 1967 
 1968     /* Respect the Imperial attribute as we enlighten the user. */
 1969     int imperial = FALSE;  /* default to using metric measures. */
 1970     if (navit_get_attr(this_, attr_imperial, &attr, NULL))
 1971         imperial=attr.u.num;
 1972 
 1973     dbg(lvl_debug,"enter");
 1974     datawindow_mode(this_->roadbook_window, 1);
 1975     if (nav)
 1976         map=navigation_get_map(nav);
 1977     if (map)
 1978         mr=map_rect_new(map, NULL);
 1979     dbg(lvl_debug,"nav=%p map=%p mr=%p", nav, map, mr);
 1980     if (mr) {
 1981         dbg(lvl_debug,"while loop");
 1982         while ((item=map_rect_get_item(mr))) {
 1983             dbg(lvl_debug,"item=%p", item);
 1984             attr.u.str=NULL;
 1985             if (item->type != type_nav_position) {
 1986                 item_attr_get(item, attr_navigation_long, &attr);
 1987                 if (attr.u.str == NULL) {
 1988                     continue;
 1989                 }
 1990                 dbg(lvl_info, "Command='%s'", attr.u.str);
 1991                 param[0].value=g_strdup(attr.u.str);
 1992             } else
 1993                 param[0].value=_("Position");
 1994             param[0].name=_("Command");
 1995 
 1996             /* Distance to the next maneuver. */
 1997             item_attr_get(item, attr_length, &attr);
 1998             dbg(lvl_info, "Length=%ld in meters", attr.u.num);
 1999             param[1].name=_("Length");
 2000 
 2001             if ( attr.u.num >= 2000 ) {
 2002                 param[1].value=g_strdup_printf("%5.1f %s",
 2003                                                imperial == TRUE ? (float)attr.u.num * METERS_TO_MILES : (float)attr.u.num / 1000,
 2004                                                imperial == TRUE ? _("mi") : _("km")
 2005                                               );
 2006             } else {
 2007                 param[1].value=g_strdup_printf("%7.0f %s",
 2008                                                imperial == TRUE ? (attr.u.num * FEET_PER_METER) : attr.u.num,
 2009                                                imperial == TRUE ? _("feet") : _("m")
 2010                                               );
 2011             }
 2012 
 2013             /* Time to next maneuver. */
 2014             item_attr_get(item, attr_time, &attr);
 2015             dbg(lvl_info, "Time=%ld", attr.u.num);
 2016             secs=attr.u.num/10;
 2017             param[2].name=_("Time");
 2018             if ( secs >= 3600 ) {
 2019                 param[2].value=g_strdup_printf("%d:%02d:%02d",secs / 60, ( secs / 60 ) % 60, secs % 60);
 2020             } else {
 2021                 param[2].value=g_strdup_printf("%d:%02d",secs / 60, secs % 60);
 2022             }
 2023 
 2024             /* Distance from next maneuver to destination. */
 2025             item_attr_get(item, attr_destination_length, &attr);
 2026             dbg(lvl_info, "Destlength=%ld in meters.", attr.u.num);
 2027             param[3].name=_("Destination Length");
 2028             if ( attr.u.num >= 2000 ) {
 2029                 param[3].value=g_strdup_printf("%5.1f %s",
 2030                                                imperial == TRUE ? (float)attr.u.num * METERS_TO_MILES : (float)attr.u.num / 1000,
 2031                                                imperial == TRUE ? _("mi") : _("km")
 2032                                               );
 2033             } else {
 2034                 param[3].value=g_strdup_printf("%7.0f %s",
 2035                                                imperial == TRUE ? (attr.u.num * FEET_PER_METER) : attr.u.num,
 2036                                                imperial == TRUE ? _("feet") : _("m")
 2037                                               );
 2038             }
 2039 
 2040             /* Time from next maneuver to destination. */
 2041             item_attr_get(item, attr_destination_time, &attr);
 2042             dbg(lvl_info, "Desttime=%ld", attr.u.num);
 2043             secs=attr.u.num/10;
 2044             param[4].name=_("Destination Time");
 2045             if ( secs >= 3600 ) {
 2046                 param[4].value=g_strdup_printf("%d:%02d:%02d",secs / 3600, (secs / 60 ) % 60, secs % 60);
 2047             } else {
 2048                 param[4].value=g_strdup_printf("%d:%02d",secs / 60, secs % 60);
 2049             }
 2050             datawindow_add(this_->roadbook_window, param, 5);
 2051         }
 2052         map_rect_destroy(mr);
 2053     }
 2054     datawindow_mode(this_->roadbook_window, 0);
 2055 }
 2056 
 2057 void navit_window_roadbook_destroy(struct navit *this_) {
 2058     dbg(lvl_debug, "enter");
 2059     navigation_unregister_callback(this_->navigation, attr_navigation_long, this_->roadbook_callback);
 2060     callback_destroy(this_->roadbook_callback);
 2061     this_->roadbook_window=NULL;
 2062     this_->roadbook_callback=NULL;
 2063 }
 2064 void navit_window_roadbook_new(struct navit *this_) {
 2065     if (!this_->gui || this_->roadbook_callback || this_->roadbook_window) {
 2066         return;
 2067     }
 2068 
 2069     this_->roadbook_callback=callback_new_1(callback_cast(navit_window_roadbook_update), this_);
 2070     navigation_register_callback(this_->navigation, attr_navigation_long, this_->roadbook_callback);
 2071     this_->roadbook_window=gui_datawindow_new(this_->gui, _("Roadbook"), NULL,
 2072                            callback_new_1(callback_cast(navit_window_roadbook_destroy), this_));
 2073     navit_window_roadbook_update(this_);
 2074 }
 2075 
 2076 int navit_init(struct navit *this_) {
 2077     struct mapset *ms;
 2078     struct map *map;
 2079     int callback;
 2080     char *center_file;
 2081     struct attr_iter *iter;
 2082     struct attr *attr;
 2083     struct traffic * traffic;
 2084 
 2085     dbg(lvl_info,"enter gui %p graphics %p",this_->gui,this_->gra);
 2086 
 2087     if (!this_->gui && !(this_->flags & 2)) {
 2088         dbg(lvl_error,"FATAL: No GUI available.");
 2089         exit(1);
 2090     }
 2091     if (!this_->gra && !(this_->flags & 1)) {
 2092         dbg(lvl_error,"FATAL: No graphics subsystem available.");
 2093         exit(1);
 2094     }
 2095     dbg(lvl_info,"Connecting gui to graphics");
 2096     if (this_->gui && this_->gra && gui_set_graphics(this_->gui, this_->gra)) {
 2097         struct attr attr_type_gui, attr_type_graphics;
 2098         gui_get_attr(this_->gui, attr_type, &attr_type_gui, NULL);
 2099         graphics_get_attr(this_->gra, attr_type, &attr_type_graphics, NULL);
 2100         dbg(lvl_error,"FATAL: Failed to connect graphics '%s' to gui '%s'", attr_type_graphics.u.str, attr_type_gui.u.str);
 2101         dbg(lvl_error,"Please see http://wiki.navit-project.org/index.php/Failed_to_connect_graphics_to_gui "
 2102             "for explanations and solutions\n");
 2103         exit(1);
 2104     }
 2105     if (this_->speech && this_->navigation) {
 2106         struct attr speech;
 2107         speech.type=attr_speech;
 2108         speech.u.speech=this_->speech;
 2109         navigation_set_attr(this_->navigation, &speech);
 2110     }
 2111     dbg(lvl_info,"Initializing graphics");
 2112     dbg(lvl_info,"Setting Vehicle");
 2113     navit_set_vehicle(this_, this_->vehicle);
 2114     dbg(lvl_info,"Adding dynamic maps to mapset %p",this_->mapsets);
 2115     if (this_->mapsets) {
 2116         struct mapset_handle *msh;
 2117         ms=this_->mapsets->data;
 2118         this_->progress_cb=callback_new_attr_1(callback_cast(navit_map_progress), attr_progress, this_);
 2119         msh=mapset_open(ms);
 2120         while (msh && (map=mapset_next(msh, 0))) {
 2121             //pass new callback instance for each map in the mapset to make map callback list destruction work correctly
 2122             struct callback *pcb = callback_new_attr_1(callback_cast(navit_map_progress), attr_progress, this_);
 2123             map_add_callback(map, pcb);
 2124         }
 2125         mapset_close(msh);
 2126 
 2127         if (this_->route) {
 2128             if ((map=route_get_map(this_->route))) {
 2129                 struct attr map_a;
 2130                 map_a.type=attr_map;
 2131                 map_a.u.map=map;
 2132                 mapset_add_attr(ms, &map_a);
 2133             }
 2134             if ((map=route_get_graph_map(this_->route))) {
 2135                 struct attr map_a,active;
 2136                 map_a.type=attr_map;
 2137                 map_a.u.map=map;
 2138                 active.type=attr_active;
 2139                 active.u.num=0;
 2140                 mapset_add_attr(ms, &map_a);
 2141                 map_set_attr(map, &active);
 2142             }
 2143             route_set_mapset(this_->route, ms);
 2144             route_set_projection(this_->route, transform_get_projection(this_->trans));
 2145         }
 2146         if (this_->tracking) {
 2147             tracking_set_mapset(this_->tracking, ms);
 2148             if (this_->route)
 2149                 tracking_set_route(this_->tracking, this_->route);
 2150         }
 2151 
 2152         attr = g_new0(struct attr, 1);
 2153         iter = navit_attr_iter_new(NULL);
 2154         map = NULL;
 2155         while (navit_get_attr(this_, attr_traffic, attr, iter)) {
 2156             traffic = (struct traffic *) attr->u.navit_object;
 2157             traffic_set_mapset(traffic, ms);
 2158             if (this_->route)
 2159                 traffic_set_route(traffic, this_->route);
 2160             /* add the first map found */
 2161             if (!map && (map = traffic_get_map(traffic))) {
 2162                 struct attr map_a;
 2163                 map_a.type = attr_map;
 2164                 map_a.u.map = map;
 2165                 mapset_add_attr(ms, &map_a);
 2166             }
 2167         }
 2168         navit_attr_iter_destroy(iter);
 2169         g_free(attr);
 2170 
 2171         if (this_->navigation) {
 2172             if ((map=navigation_get_map(this_->navigation))) {
 2173                 struct attr map_a,active;
 2174                 map_a.type=attr_map;
 2175                 map_a.u.map=map;
 2176                 active.type=attr_active;
 2177                 active.u.num=0;
 2178                 mapset_add_attr(ms, &map_a);
 2179                 map_set_attr(map, &active);
 2180             }
 2181         }
 2182         if (this_->tracking) {
 2183             if ((map=tracking_get_map(this_->tracking))) {
 2184                 struct attr map_a,active;
 2185                 map_a.type=attr_map;
 2186                 map_a.u.map=map;
 2187                 active.type=attr_active;
 2188                 active.u.num=0;
 2189                 mapset_add_attr(ms, &map_a);
 2190                 map_set_attr(map, &active);
 2191             }
 2192         }
 2193         navit_add_former_destinations_from_file(this_);
 2194     } else {
 2195         dbg(lvl_error, "FATAL: No mapset available. Please add a (valid) mapset to your configuration.");
 2196         exit(1);
 2197     }
 2198     if (this_->route) {
 2199         struct attr callback;
 2200         this_->route_cb=callback_new_attr_1(callback_cast(navit_redraw_route), attr_route_status, this_);
 2201         callback.type=attr_callback;
 2202         callback.u.callback=this_->route_cb;
 2203         route_add_attr(this_->route, &callback);
 2204     }
 2205     if (this_->navigation) {
 2206         if (this_->speech) {
 2207             this_->nav_speech_cb=callback_new_1(callback_cast(navit_speak), this_);
 2208             navigation_register_callback(this_->navigation, attr_navigation_speech, this_->nav_speech_cb);
 2209         }
 2210         if (this_->route)
 2211             navigation_set_route(this_->navigation, this_->route);
 2212     }
 2213     dbg(lvl_info,"Setting Center");
 2214     center_file = bookmarks_get_center_file(FALSE);
 2215     bookmarks_set_center_from_file(this_->bookmarks, center_file);
 2216     g_free(center_file);
 2217     global_navit=this_;
 2218 
 2219     messagelist_init(this_->messages);
 2220 
 2221     navit_set_cursors(this_);
 2222 
 2223     callback_list_call_attr_1(this_->attr_cbl, attr_navit, this_);
 2224     callback=(this_->ready == 2);
 2225     this_->ready|=1;
 2226     dbg(lvl_info,"ready=%d",this_->ready);
 2227     if (this_->ready == 3)
 2228         navit_draw_async(this_, 1);
 2229     if (callback)
 2230         callback_list_call_attr_1(this_->attr_cbl, attr_graphics_ready, this_);
 2231     return 0;
 2232 }
 2233 
 2234 void navit_zoom_to_rect(struct navit *this_, struct coord_rect *r) {
 2235     struct coord c;
 2236     int w,h,scale=16;
 2237 
 2238     c.x=(r->rl.x+r->lu.x)/2;
 2239     c.y=(r->rl.y+r->lu.y)/2;
 2240     transform_set_center(this_->trans, &c);
 2241     transform_get_size(this_->trans, &w, &h);
 2242     dbg(lvl_debug,"center 0x%x,0x%x w %d h %d",c.x,c.y,w,h);
 2243     dbg(lvl_debug,"%x,%x-%x,%x", r->lu.x,r->lu.y,r->rl.x,r->rl.y);
 2244     while (scale < 1<<20) {
 2245         struct point p1,p2;
 2246         transform_set_scale(this_->trans, scale);
 2247         transform_setup_source_rect(this_->trans);
 2248         transform(this_->trans, transform_get_projection(this_->trans), &r->lu, &p1, 1, 0, 0, NULL);
 2249         transform(this_->trans, transform_get_projection(this_->trans), &r->rl, &p2, 1, 0, 0, NULL);
 2250         dbg(lvl_debug,"%d,%d-%d,%d",p1.x,p1.y,p2.x,p2.y);
 2251         if (p1.x < 0 || p2.x < 0 || p1.x > w || p2.x > w ||
 2252                 p1.y < 0 || p2.y < 0 || p1.y > h || p2.y > h)
 2253             scale*=2;
 2254         else
 2255             break;
 2256 
 2257     }
 2258     dbg(lvl_debug,"scale=%d (0x%x) of %d (0x%x)",scale,scale,1<<20,1<<20);
 2259     if (this_->ready == 3)
 2260         navit_draw_async(this_,0);
 2261 }
 2262 
 2263 void navit_zoom_to_route(struct navit *this_, int orientation) {
 2264     struct map *map;
 2265     struct map_rect *mr=NULL;
 2266     struct item *item;
 2267     struct coord c;
 2268     struct coord_rect r;
 2269     int count=0;
 2270     if (! this_->route)
 2271         return;
 2272     dbg(lvl_debug,"enter");
 2273     map=route_get_map(this_->route);
 2274     dbg(lvl_debug,"map=%p",map);
 2275     if (map)
 2276         mr=map_rect_new(map, NULL);
 2277     dbg(lvl_debug,"mr=%p",mr);
 2278     if (mr) {
 2279         while ((item=map_rect_get_item(mr))) {
 2280             dbg(lvl_debug,"item=%s", item_to_name(item->type));
 2281             while (item_coord_get(item, &c, 1)) {
 2282                 dbg(lvl_debug,"coord");
 2283                 if (!count)
 2284                     r.lu=r.rl=c;
 2285                 else
 2286                     coord_rect_extend(&r, &c);
 2287                 count++;
 2288             }
 2289         }
 2290         map_rect_destroy(mr);
 2291     }
 2292     if (! count)
 2293         return;
 2294     if (orientation != -1)
 2295         transform_set_yaw(this_->trans, orientation);
 2296     navit_zoom_to_rect(this_, &r);
 2297 }
 2298 
 2299 static int navit_cmd_zoom_to_route(struct navit *this, char *function, struct attr **in, struct attr ***out) {
 2300     navit_zoom_to_route(this, 0);
 2301     return 0;
 2302 }
 2303 
 2304 
 2305 /**
 2306  * Change the current zoom level
 2307  *
 2308  * @param navit The navit instance
 2309  * @param center The point where to center the map, including its projection
 2310  * @returns nothing
 2311  */
 2312 void navit_set_center(struct navit *this_, struct pcoord *center, int set_timeout) {
 2313     struct coord *c=transform_center(this_->trans);
 2314     struct coord c1,c2;
 2315     enum projection pro = transform_get_projection(this_->trans);
 2316     if (pro != center->pro) {
 2317         c1.x = center->x;
 2318         c1.y = center->y;
 2319         transform_from_to(&c1, center->pro, &c2, pro);
 2320     } else {
 2321         c2.x = center->x;
 2322         c2.y = center->y;
 2323     }
 2324     *c=c2;
 2325     if (set_timeout)
 2326         navit_set_timeout(this_);
 2327     if (this_->ready == 3)
 2328         navit_draw(this_);
 2329 }
 2330 
 2331 static void navit_set_center_coord_screen(struct navit *this_, struct coord *c, struct point *p, int set_timeout) {
 2332     int width, height;
 2333     struct point po;
 2334     transform_set_center(this_->trans, c);
 2335     transform_get_size(this_->trans, &width, &height);
 2336     po.x=width/2;
 2337     po.y=height/2;
 2338     update_transformation(this_->trans, &po, p);
 2339     if (set_timeout)
 2340         navit_set_timeout(this_);
 2341 }
 2342 
 2343 /**
 2344  * Links all vehicles to a cursor depending on the current profile.
 2345  *
 2346  * @param this_ A navit instance
 2347  * @author Ralph Sennhauser (10/2009)
 2348  */
 2349 static void navit_set_cursors(struct navit *this_) {
 2350     struct attr name;
 2351     struct navit_vehicle *nv;
 2352     struct cursor *c;
 2353     GList *v;
 2354 
 2355     v=g_list_first(this_->vehicles); // GList of navit_vehicles
 2356     while (v) {
 2357         nv=v->data;
 2358         if (vehicle_get_attr(nv->vehicle, attr_cursorname, &name, NULL)) {
 2359             if (!strcmp(name.u.str,"none"))
 2360                 c=NULL;
 2361             else
 2362                 c=layout_get_cursor(this_->layout_current, name.u.str);
 2363         } else
 2364             c=layout_get_cursor(this_->layout_current, "default");
 2365         vehicle_set_cursor(nv->vehicle, c, 0);
 2366         v=g_list_next(v);
 2367     }
 2368     return;
 2369 }
 2370 
 2371 
 2372 /**
 2373  * @brief Calculates the position of the cursor on the screen.
 2374  *
 2375  * This method considers padding if supported by the graphics plugin. In that case, the inner rectangle
 2376  * (i.e. screen size minus padding) will be used to center the cursor and to determine cursor offset (as
 2377  * specified in `this_->radius`).
 2378  *
 2379  * @param this_ The navit object
 2380  * @param p Receives the screen coordinates for the cursor
 2381  * @param keep_orientation Whether to maintain the current map orientation. If false, the map will be
 2382  * rotated so that the bearing of the vehicle is up.
 2383  * @param dir Receives the new map orientation as requested by `screen_orientation` (can be `NULL`)
 2384  *
 2385  * @return Always 1
 2386  */
 2387 static int navit_get_cursor_pnt(struct navit *this_, struct point *p, int keep_orientation, int *dir) {
 2388     int width, height;
 2389     struct navit_vehicle *nv=this_->vehicle;
 2390     struct padding *padding = NULL;
 2391 
 2392     float offset=this_->radius;      // Cursor offset from the center of the screen (percent).
 2393 #if 0 /* Better improve track.c to get that issue resolved or make it configurable with being off the default, the jumping back to the center is a bit annoying */
 2394     float min_offset = 0.;      // Percent offset at min_offset_speed.
 2395     float max_offset = 30.;     // Percent offset at max_offset_speed.
 2396     int min_offset_speed = 2;   // Speed in km/h
 2397     int max_offset_speed = 50;  // Speed in km/h
 2398     // Calculate cursor offset from the center of the screen, upon speed.
 2399     if (nv->speed <= min_offset_speed) {
 2400         offset = min_offset;
 2401     } else if (nv->speed > max_offset_speed) {
 2402         offset = max_offset;
 2403     } else {
 2404         offset = (max_offset - min_offset) / (max_offset_speed - min_offset_speed) * (nv->speed - min_offset_speed);
 2405     }
 2406 #endif
 2407 
 2408     if (this_->gra) {
 2409         padding = graphics_get_data(this_->gra, "padding");
 2410     } else
 2411         dbg(lvl_warning, "cannot get padding: this->gra is NULL");
 2412 
 2413     transform_get_size(this_->trans, &width, &height);
 2414     dbg(lvl_debug, "width=%d height=%d", width, height);
 2415 
 2416     if (padding) {
 2417         width -= (padding->left + padding->right);
 2418         height -= (padding->top + padding->bottom);
 2419         dbg(lvl_debug, "corrected for padding: width=%d height=%d", width, height);
 2420     }
 2421 
 2422     if (this_->orientation == -1 || keep_orientation) {
 2423         p->x=50*width/100;
 2424         p->y=(50 + offset)*height/100;
 2425         if (dir)
 2426             *dir=keep_orientation?this_->orientation:nv->dir;
 2427     } else {
 2428         int mdir;
 2429         if (this_->tracking && this_->tracking_flag) {
 2430             mdir = tracking_get_angle(this_->tracking) - this_->orientation;
 2431         } else {
 2432             mdir=nv->dir-this_->orientation;
 2433         }
 2434 
 2435         p->x=(50 - offset*sin(M_PI*mdir/180.))*width/100;
 2436         p->y=(50 + offset*cos(M_PI*mdir/180.))*height/100;
 2437         if (dir)
 2438             *dir=this_->orientation;
 2439     }
 2440 
 2441     if (padding) {
 2442         p->x += padding->left;
 2443         p->y += padding->top;
 2444     }
 2445 
 2446     dbg(lvl_debug, "x=%d y=%d, offset=%f", p->x, p->y, offset);
 2447 
 2448     return 1;
 2449 }
 2450 
 2451 /**
 2452  * @brief Recalculates the map view so that the vehicle cursor is visible
 2453  *
 2454  * This function recalculates the parameters which control the visible map area, zoom and orientation. The
 2455  * caller is responsible for redrawing the map after the function returns.
 2456  *
 2457  * If the vehicle supplies a {@code position_valid} attribute and it is {@code attr_position_valid_invalid},
 2458  * the map position is not changed.
 2459  *
 2460  * @param this_ The navit object
 2461  * @param autozoom Whether to set zoom based on current speed. If false, current zoom will be maintained.
 2462  * @param keep_orientation Whether to maintain the current map orientation. If false, the map will be rotated
 2463  * so that the bearing of the vehicle is up.
 2464  */
 2465 void navit_set_center_cursor(struct navit *this_, int autozoom, int keep_orientation) {
 2466     int dir;
 2467     struct point pn;
 2468     struct navit_vehicle *nv=this_->vehicle;
 2469     struct attr attr;
 2470     if (!nv || !nv->vehicle) {
 2471         return;
 2472     }
 2473     if (vehicle_get_attr(nv->vehicle, attr_position_valid, &attr, NULL) && (attr.u.num == attr_position_valid_invalid))
 2474         return;
 2475     navit_get_cursor_pnt(this_, &pn, keep_orientation, &dir);
 2476     transform_set_yaw(this_->trans, dir);
 2477     navit_set_center_coord_screen(this_, &nv->coord, &pn, 0);
 2478     if (autozoom)
 2479         navit_autozoom(this_, &nv->coord, nv->speed, 0);
 2480 }
 2481 
 2482 /**
 2483  * @brief Recenters the map so that the vehicle cursor is visible
 2484  *
 2485  * This function first calls {@code navit_set_center_cursor()} to recalculate the map display, then
 2486  * triggers a redraw of the map.
 2487  *
 2488  *@param this_ The navit object
 2489  */
 2490 static void navit_set_center_cursor_draw(struct navit *this_) {
 2491     navit_set_center_cursor(this_,1,0);
 2492     if (this_->ready == 3)
 2493         navit_draw_async(this_, 1);
 2494 }
 2495 
 2496 /**
 2497  * @brief Recenters the map so that the vehicle cursor is visible
 2498  *
 2499  * This is the callback function for the {@code set_center_cursor()} command. It is just a wrapper around
 2500  * {@code navit_set_center_cursor_draw()}.
 2501  *
 2502  *@param this_ The navit object
 2503  */
 2504 static int navit_cmd_set_center_cursor(struct navit *this_, char *function, struct attr **in, struct attr ***out) {
 2505     navit_set_center_cursor_draw(this_);
 2506     return 0;
 2507 }
 2508 
 2509 void navit_set_center_screen(struct navit *this_, struct point *p, int set_timeout) {
 2510     struct coord c;
 2511     struct pcoord pc;
 2512     transform_reverse(this_->trans, p, &c);
 2513     pc.x = c.x;
 2514     pc.y = c.y;
 2515     pc.pro = transform_get_projection(this_->trans);
 2516     navit_set_center(this_, &pc, set_timeout);
 2517 }
 2518 
 2519 static int navit_set_attr_do(struct navit *this_, struct attr *attr, int init) {
 2520     int dir=0, orient_old=0, attr_updated=0;
 2521     struct coord co;
 2522     long zoom;
 2523     GList *l;
 2524     struct navit_vehicle *nv;
 2525     struct layout *lay;
 2526     struct attr active;
 2527     active.type=attr_active;
 2528     active.u.num=0;
 2529 
 2530     dbg(lvl_debug, "enter, this_=%p, attr=%p (%s), init=%d", this_, attr, attr_to_name(attr->type), init);
 2531 
 2532     switch (attr->type) {
 2533     case attr_autozoom:
 2534         attr_updated=(this_->autozoom_secs != attr->u.num);
 2535         this_->autozoom_secs = attr->u.num;
 2536         break;
 2537     case attr_autozoom_active:
 2538         attr_updated=(this_->autozoom_active != attr->u.num);
 2539         this_->autozoom_active = attr->u.num;
 2540         break;
 2541     case attr_center:
 2542         transform_from_geo(transform_get_projection(this_->trans), attr->u.coord_geo, &co);
 2543         dbg(lvl_debug,"0x%x,0x%x",co.x,co.y);
 2544         transform_set_center(this_->trans, &co);
 2545         break;
 2546     case attr_drag_bitmap:
 2547         attr_updated=(this_->drag_bitmap != !!attr->u.num);
 2548         this_->drag_bitmap=!!attr->u.num;
 2549         break;
 2550     case attr_flags:
 2551         attr_updated=(this_->flags != attr->u.num);
 2552         this_->flags=attr->u.num;
 2553         break;
 2554     case attr_flags_graphics:
 2555         attr_updated=(this_->graphics_flags != attr->u.num);
 2556         this_->graphics_flags=attr->u.num;
 2557         break;
 2558     case attr_follow:
 2559         if (!this_->vehicle)
 2560             return 0;
 2561         attr_updated=(this_->vehicle->follow_curr != attr->u.num);
 2562         this_->vehicle->follow_curr = attr->u.num;
 2563         break;
 2564     case attr_default_layout:
 2565         if(!attr->u.str)
 2566             return 0;
 2567         if(this_->default_layout_name)  /* There is already a default layout, ignore this new value */
 2568             g_free(this_->default_layout_name); /* Drop the previous layout name, use the this one instead */
 2569         this_->default_layout_name=g_strdup(attr->u.str);
 2570         attr_updated=1;
 2571         break;
 2572     case attr_layout:
 2573         if(!attr->u.layout)
 2574             return 0;
 2575         dbg(lvl_debug,"setting attr_layout to %s", attr->u.layout->name);
 2576         if(this_->layout_current!=attr->u.layout) {
 2577             navit_update_current_layout(this_, attr->u.layout);
 2578             graphics_font_destroy_all(this_->gra);
 2579             navit_set_cursors(this_);
 2580             if (this_->ready == 3)
 2581                 navit_draw(this_);
 2582             attr_updated=1;
 2583         }
 2584         break;
 2585     case attr_layout_name:
 2586         if(!attr->u.str)
 2587             return 0;
 2588         dbg(lvl_debug,"setting attr_layout_name to %s", attr->u.str);
 2589         l=this_->layouts;
 2590         while (l) {
 2591             lay=l->data;
 2592             if (!strcmp(lay->name,attr->u.str)) {
 2593                 struct attr attr;
 2594                 attr.type=attr_layout;
 2595                 attr.u.layout=lay;
 2596                 return navit_set_attr_do(this_, &attr, init);
 2597             }
 2598             l=g_list_next(l);
 2599         }
 2600         return 0;
 2601     case attr_map_border:
 2602         if (this_->border != attr->u.num) {
 2603             this_->border=attr->u.num;
 2604             attr_updated=1;
 2605         }
 2606         break;
 2607     case attr_orientation:
 2608         orient_old=this_->orientation;
 2609         this_->orientation=attr->u.num;
 2610         if (!init) {
 2611             if (this_->orientation != -1) {
 2612                 dir = this_->orientation;
 2613             } else {
 2614                 if (this_->vehicle) {
 2615                     dir = this_->vehicle->dir;
 2616                 }
 2617             }
 2618             transform_set_yaw(this_->trans, dir);
 2619             if (orient_old != this_->orientation) {
 2620 #if 0
 2621                 if (this_->ready == 3)
 2622                     navit_draw(this_);
 2623 #endif
 2624                 attr_updated=1;
 2625             }
 2626         }
 2627         break;
 2628     case attr_osd_configuration:
 2629         dbg(lvl_debug,"setting osd_configuration to %ld (was %d)", attr->u.num, this_->osd_configuration);
 2630         attr_updated=(this_->osd_configuration != attr->u.num);
 2631         this_->osd_configuration=attr->u.num;
 2632         break;
 2633     case attr_pitch:
 2634         attr_updated=(this_->pitch != attr->u.num);
 2635         this_->pitch=attr->u.num;
 2636         transform_set_pitch(this_->trans, round(this_->pitch*sqrt(240*320)/sqrt(
 2637                 this_->w*this_->h))); // Pitch corrected for window resolution
 2638         if (!init && attr_updated && this_->ready == 3)
 2639             navit_draw(this_);
 2640         break;
 2641     case attr_projection:
 2642         if(this_->trans && transform_get_projection(this_->trans) != attr->u.projection) {
 2643             navit_projection_set(this_, attr->u.projection, !init);
 2644             attr_updated=1;
 2645         }
 2646         break;
 2647     case attr_radius:
 2648         attr_updated=(this_->radius != attr->u.num);
 2649         this_->radius=attr->u.num;
 2650         break;
 2651     case attr_recent_dest:
 2652         attr_updated=(this_->recentdest_count != attr->u.num);
 2653         this_->recentdest_count=attr->u.num;
 2654         break;
 2655     case attr_speech:
 2656         if(this_->speech && this_->speech != attr->u.speech) {
 2657             attr_updated=1;
 2658             this_->speech = attr->u.speech;
 2659         }
 2660         break;
 2661     case attr_timeout:
 2662         attr_updated=(this_->center_timeout != attr->u.num);
 2663         this_->center_timeout = attr->u.num;
 2664         break;
 2665     case attr_tracking:
 2666         attr_updated=(this_->tracking_flag != !!attr->u.num);
 2667         this_->tracking_flag=!!attr->u.num;
 2668         break;
 2669     case attr_transformation:
 2670         this_->trans=attr->u.transformation;
 2671         break;
 2672     case attr_use_mousewheel:
 2673         attr_updated=(this_->use_mousewheel != !!attr->u.num);
 2674         this_->use_mousewheel=!!attr->u.num;
 2675         break;
 2676     case attr_vehicle:
 2677         if (!attr->u.vehicle) {
 2678             if (this_->vehicle) {
 2679                 vehicle_set_attr(this_->vehicle->vehicle, &active);
 2680                 navit_set_vehicle(this_, NULL);
 2681                 attr_updated=1;
 2682             }
 2683             break;
 2684         }
 2685         l=this_->vehicles;
 2686         while(l) {
 2687             nv=l->data;
 2688             if (nv->vehicle == attr->u.vehicle) {
 2689                 if (!this_->vehicle || this_->vehicle->vehicle != attr->u.vehicle) {
 2690                     if (this_->vehicle)
 2691                         vehicle_set_attr(this_->vehicle->vehicle, &active);
 2692                     active.u.num=1;
 2693                     vehicle_set_attr(nv->vehicle, &active);
 2694                     attr_updated=1;
 2695                 }
 2696                 navit_set_vehicle(this_, nv);
 2697             }
 2698             l=g_list_next(l);
 2699         }
 2700         break;
 2701     case attr_vehicleprofile:
 2702         attr_updated=navit_set_vehicleprofile(this_, attr->u.vehicleprofile);
 2703         break;
 2704     case attr_zoom:
 2705         zoom=transform_get_scale(this_->trans);
 2706         attr_updated=(zoom != attr->u.num);
 2707         transform_set_scale(this_->trans, attr->u.num);
 2708         if (attr_updated && !init)
 2709             navit_draw(this_);
 2710         break;
 2711     case attr_zoom_min:
 2712         attr_updated=(attr->u.num != this_->zoom_min);
 2713         this_->zoom_min=attr->u.num;
 2714         break;
 2715     case attr_zoom_max:
 2716         attr_updated=(attr->u.num != this_->zoom_max);
 2717         this_->zoom_max=attr->u.num;
 2718         break;
 2719     case attr_message:
 2720         navit_add_message(this_, attr->u.str);
 2721         break;
 2722     case attr_follow_cursor:
 2723         attr_updated=(this_->follow_cursor != !!attr->u.num);
 2724         this_->follow_cursor=!!attr->u.num;
 2725         break;
 2726     case attr_imperial:
 2727         attr_updated=(this_->imperial != attr->u.num);
 2728         this_->imperial=attr->u.num;
 2729         break;
 2730     case attr_waypoints_flag:
 2731         attr_updated=(this_->waypoints_flag != !!attr->u.num);
 2732         this_->waypoints_flag=!!attr->u.num;
 2733         break;
 2734     default:
 2735         dbg(lvl_debug, "calling generic setter method for attribute type %s", attr_to_name(attr->type))
 2736         return navit_object_set_attr((struct navit_object *) this_, attr);
 2737     }
 2738     if (attr_updated && !init) {
 2739         callback_list_call_attr_2(this_->attr_cbl, attr->type, this_, attr);
 2740         if (attr->type == attr_osd_configuration)
 2741             graphics_draw_mode(this_->gra, draw_mode_end);
 2742     }
 2743     return 1;
 2744 }
 2745 
 2746 int navit_set_attr(struct navit *this_, struct attr *attr) {
 2747     return navit_set_attr_do(this_, attr, 0);
 2748 }
 2749 
 2750 int navit_get_attr(struct navit *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter) {
 2751     struct message *msg;
 2752     struct coord *c;
 2753     int len,offset;
 2754     int ret=1;
 2755 
 2756     switch (type) {
 2757     case attr_message:
 2758         msg = navit_get_messages(this_);
 2759 
 2760         if (!msg) {
 2761             return 0;
 2762         }
 2763 
 2764         len = 0;
 2765         while (msg) {
 2766             len += strlen(msg->text) + 1;
 2767             msg = msg->next;
 2768         }
 2769         attr->u.str = g_malloc(len + 1);
 2770 
 2771         msg = navit_get_messages(this_);
 2772         offset = 0;
 2773         while (msg) {
 2774             g_stpcpy((attr->u.str + offset), msg->text);
 2775             offset += strlen(msg->text);
 2776             attr->u.str[offset] = '\n';
 2777             offset++;
 2778 
 2779             msg = msg->next;
 2780         }
 2781 
 2782         attr->u.str[len] = '\0';
 2783         break;
 2784     case attr_imperial:
 2785         attr->u.num=this_->imperial;
 2786         break;
 2787     case attr_bookmark_map:
 2788         attr->u.map=bookmarks_get_map(this_->bookmarks);
 2789         break;
 2790     case attr_bookmarks:
 2791         attr->u.bookmarks=this_->bookmarks;
 2792         break;
 2793     case attr_callback_list:
 2794         attr->u.callback_list=this_->attr_cbl;
 2795         break;
 2796     case attr_center:
 2797         c=transform_get_center(this_->trans);
 2798         transform_to_geo(transform_get_projection(this_->trans), c, &this_->center);
 2799         attr->u.coord_geo=&this_->center;
 2800         break;
 2801     case attr_destination:
 2802         if (! this_->destination_valid)
 2803             return 0;
 2804         attr->u.pcoord=&this_->destination;
 2805         break;
 2806     case attr_displaylist:
 2807         attr->u.displaylist=this_->displaylist;
 2808         return (attr->u.displaylist != NULL);
 2809     case attr_follow:
 2810         if (!this_->vehicle)
 2811             return 0;
 2812         attr->u.num=this_->vehicle->follow_curr;
 2813         break;
 2814     case attr_former_destination_map:
 2815         attr->u.map=this_->former_destination;
 2816         break;
 2817     case attr_graphics:
 2818         attr->u.graphics=this_->gra;
 2819         ret=(attr->u.graphics != NULL);
 2820         break;
 2821     case attr_gui:
 2822         attr->u.gui=this_->gui;
 2823         ret=(attr->u.gui != NULL);
 2824         break;
 2825     case attr_layer:
 2826         ret=attr_generic_get_attr(this_->attrs, NULL, type, attr, iter?(struct attr_iter *)&iter->iter:NULL);
 2827         break;
 2828     case attr_layout:
 2829         if (iter) {
 2830             if (iter->u.list) {
 2831                 iter->u.list=g_list_next(iter->u.list);
 2832             } else {
 2833                 iter->u.list=this_->layouts;
 2834             }
 2835             if (!iter->u.list)
 2836                 return 0;
 2837             attr->u.layout=(struct layout *)iter->u.list->data;
 2838         } else {
 2839             attr->u.layout=this_->layout_current;
 2840         }
 2841         break;
 2842     case attr_map:
 2843         if (iter && this_->mapsets) {
 2844             if (!iter->u.mapset_handle) {
 2845                 iter->u.mapset_handle=mapset_open((struct mapset *)this_->mapsets->data);
 2846             }
 2847             attr->u.map=mapset_next(iter->u.mapset_handle, 0);
 2848             if(!attr->u.map) {
 2849                 mapset_close(iter->u.mapset_handle);
 2850                 return 0;
 2851             }
 2852         } else {
 2853             return 0;
 2854         }
 2855         break;
 2856     case attr_mapset:
 2857         attr->u.mapset=this_->mapsets->data;
 2858         ret=(attr->u.mapset != NULL);
 2859         break;
 2860     case attr_navigation:
 2861         attr->u.navigation=this_->navigation;
 2862         break;
 2863     case attr_orientation:
 2864         attr->u.num=this_->orientation;
 2865         break;
 2866     case attr_osd:
 2867         ret=attr_generic_get_attr(this_->attrs, NULL, type, attr, iter?(struct attr_iter *)&iter->iter:NULL);
 2868         break;
 2869     case attr_osd_configuration:
 2870         attr->u.num=this_->osd_configuration;
 2871         break;
 2872     case attr_pitch:
 2873         attr->u.num=round(transform_get_pitch(this_->trans)*sqrt(this_->w*this_->h)/sqrt(
 2874                               240*320)); // Pitch corrected for window resolution
 2875         break;
 2876     case attr_projection:
 2877         if(this_->trans) {
 2878             attr->u.num=transform_get_projection(this_->trans);
 2879         } else {
 2880             return 0;
 2881         }
 2882         break;
 2883     case attr_route:
 2884         attr->u.route=this_->route;
 2885         break;
 2886     case attr_speech:
 2887         if(this_->speech) {
 2888             attr->u.speech=this_->speech;
 2889         } else {
 2890             return  0;
 2891         }
 2892         break;
 2893     case attr_timeout:
 2894         attr->u.num=this_->center_timeout;
 2895         break;
 2896     case attr_tracking:
 2897         attr->u.num=this_->tracking_flag;
 2898         break;
 2899     case attr_trackingo:
 2900         attr->u.tracking=this_->tracking;
 2901         break;
 2902     case attr_transformation:
 2903         attr->u.transformation=this_->trans;
 2904         break;
 2905     case attr_vehicle:
 2906         if(iter) {
 2907             if(iter->u.list) {
 2908                 iter->u.list=g_list_next(iter->u.list);
 2909             } else {
 2910                 iter->u.list=this_->vehicles;
 2911             }
 2912             if(!iter->u.list)
 2913                 return 0;
 2914             attr->u.vehicle=((struct navit_vehicle*)iter->u.list->data)->vehicle;
 2915         } else {
 2916             if(this_->vehicle) {
 2917                 attr->u.vehicle=this_->vehicle->vehicle;
 2918             } else {
 2919                 return 0;
 2920             }
 2921         }
 2922         break;
 2923     case attr_vehicleprofile:
 2924         if (iter) {
 2925             if(iter->u.list) {
 2926                 iter->u.list=g_list_next(iter->u.list);
 2927             } else {
 2928                 iter->u.list=this_->vehicleprofiles;
 2929             }
 2930             if(!iter->u.list)
 2931                 return 0;
 2932             attr->u.vehicleprofile=iter->u.list->data;
 2933         } else {
 2934             attr->u.vehicleprofile=this_->vehicleprofile;
 2935         }
 2936         break;
 2937     case attr_zoom:
 2938         attr->u.num=transform_get_scale(this_->trans);
 2939         break;
 2940     case attr_autozoom_active:
 2941         attr->u.num=this_->autozoom_active;
 2942         break;
 2943     case attr_follow_cursor:
 2944         attr->u.num=this_->follow_cursor;
 2945         break;
 2946     case attr_waypoints_flag:
 2947         attr->u.num=this_->waypoints_flag;
 2948         break;
 2949     default:
 2950         dbg(lvl_debug, "calling generic getter method for attribute type %s", attr_to_name(type))
 2951         return navit_object_get_attr((struct navit_object *) this_, type, attr, iter);
 2952     }
 2953     attr->type=type;
 2954     return ret;
 2955 }
 2956 
 2957 /**
 2958  * @brief Select the default layout by name
 2959  *
 2960  * @param this_ The navit instance
 2961  * @param name The new default layout's name
 2962  *
 2963  * @return The first layout match (if any), or NULL if there was no match
 2964  */
 2965 struct layout *navit_get_layout_by_name(struct navit *this_, const char *layout_name) {
 2966     struct attr_iter *iter;
 2967     struct attr layout_attr;
 2968     struct layout *result = NULL;
 2969 
 2970     if (!layout_name)
 2971         return NULL;
 2972     iter=navit_attr_iter_new(NULL);
 2973     while (navit_get_attr(this_, attr_layout, &layout_attr, iter)) {
 2974         if (strcmp(layout_attr.u.layout->name, layout_name) == 0) {
 2975             result = layout_attr.u.layout;
 2976         }
 2977     }
 2978     navit_attr_iter_destroy(iter);
 2979     return result;
 2980 }
 2981 
 2982 /**
 2983  * @brief Set the current layout
 2984  *
 2985  * @param this_ The navit instance
 2986  * @param layout The layout to set as default (if NULL, we will set the current layout according to the default name stored in this_->default_layout_name
 2987  *
 2988  * @note If argument @p layout is NULL and the default layout name in the config file does not exist or has not been provided in the config file, the default layout is unchanged
 2989  */
 2990 void navit_update_current_layout(struct navit *this_, struct layout *layout) {
 2991     struct layout *default_layout = NULL;
 2992 
 2993     if (layout) {
 2994         this_->layout_current=layout;
 2995     } else {
 2996         if (this_->default_layout_name) {   /* If a default layout name was provided */
 2997             default_layout=navit_get_layout_by_name(this_, this_->default_layout_name);
 2998             if (default_layout) {
 2999                 dbg(lvl_debug, "Found the config-specified default layout '%s'", this_->default_layout_name);
 3000                 this_->layout_current=default_layout;
 3001                 return;
 3002             } else {
 3003                 dbg(lvl_warning, "No definition exists in config for specified default layout '%s'", this_->default_layout_name);
 3004             }
 3005         }
 3006     }
 3007 }
 3008 
 3009 static int navit_add_log(struct navit *this_, struct log *log) {
 3010     struct attr type_attr;
 3011     if (!log_get_attr(log, attr_type, &type_attr, NULL))
 3012         return 0;
 3013     if (!strcmp(type_attr.u.str, "textfile_debug")) {
 3014         char *header = "type=track_tracked\n";
 3015         if (this_->textfile_debug_log)
 3016             return 0;
 3017         log_set_header(log, header, strlen(header));
 3018         this_->textfile_debug_log=log;
 3019         return 1;
 3020     }
 3021     return 0;
 3022 }
 3023 
 3024 static int navit_add_layout(struct navit *this_, struct layout *layout) {
 3025     struct attr active;
 3026     int is_default=0;
 3027     int is_active=0;
 3028     this_->layouts = g_list_append(this_->layouts, layout);
 3029     /** check if we want to immediately activate this layout.
 3030      * Unfortunately we have concurring conditions about when to activate
 3031      * a layout:
 3032      * - A layout could bear the "active" property
 3033      * - A layout's name could match this_->default_layout_name
 3034      * This cannot be fully resolved, as we cannot predict the future, so
 3035      * lets set the last parsed layout active, which either matches default_layout_name or
 3036      * bears the "active" tag, or is the first layout ever parsed.
 3037      */
 3038     if((layout->name != NULL) && (this_->default_layout_name != NULL)) {
 3039         if (strcmp(layout->name, this_->default_layout_name) == 0)
 3040             is_default = 1;
 3041     }
 3042     layout_get_attr(layout, attr_active, &active, NULL);
 3043     if(active.u.num)
 3044         is_active = 1;
 3045     dbg(lvl_debug, "add layout '%s' is_default %d, is_active %d", layout->name, is_default, is_active);
 3046     if(is_default || is_active || !this_->layout_current) {
 3047         this_->layout_current=layout;
 3048         return 1;
 3049     }
 3050     return 0;
 3051 }
 3052 
 3053 int navit_add_attr(struct navit *this_, struct attr *attr) {
 3054     int ret=1;
 3055     switch (attr->type) {
 3056     case attr_callback:
 3057         navit_add_callback(this_, attr->u.callback);
 3058         break;
 3059     case attr_log:
 3060         ret=navit_add_log(this_, attr->u.log);
 3061         break;
 3062     case attr_gui:
 3063         ret=navit_set_gui(this_, attr->u.gui);
 3064         break;
 3065     case attr_graphics:
 3066         ret=navit_set_graphics(this_, attr->u.graphics);
 3067         break;
 3068     case attr_layout:
 3069         navit_add_layout(this_, attr->u.layout);
 3070         break;
 3071     case attr_route:
 3072         this_->route=attr->u.route;
 3073         break;
 3074     case attr_mapset:
 3075         this_->mapsets = g_list_append(this_->mapsets, attr->u.mapset);
 3076         break;
 3077     case attr_navigation:
 3078         this_->navigation=attr->u.navigation;
 3079         break;
 3080     case attr_osd:
 3081         break;
 3082     case attr_recent_dest:
 3083         this_->recentdest_count = attr->u.num;
 3084         break;
 3085     case attr_speech:
 3086         this_->speech=attr->u.speech;
 3087         break;
 3088     case attr_trackingo:
 3089         this_->tracking=attr->u.tracking;
 3090         break;
 3091     case attr_vehicle:
 3092         ret=navit_add_vehicle(this_, attr->u.vehicle);
 3093         break;
 3094     case attr_vehicleprofile:
 3095         this_->vehicleprofiles=g_list_append(this_->vehicleprofiles, attr->u.vehicleprofile);
 3096         break;
 3097     case attr_autozoom_min:
 3098         this_->autozoom_min = attr->u.num;
 3099         break;
 3100     case attr_autozoom_max:
 3101         this_->autozoom_max = attr->u.num;
 3102         break;
 3103     case attr_layer:
 3104     case attr_script:
 3105     case attr_traffic:
 3106         break;
 3107     default:
 3108         return 0;
 3109     }
 3110     if (ret)
 3111         this_->attrs=attr_generic_add_attr(this_->attrs, attr);
 3112     callback_list_call_attr_2(this_->attr_cbl, attr->type, this_, attr);
 3113     return ret;
 3114 }
 3115 
 3116 int navit_remove_attr(struct navit *this_, struct attr *attr) {
 3117     int ret=1;
 3118     switch (attr->type) {
 3119     case attr_callback:
 3120         navit_remove_callback(this_, attr->u.callback);
 3121         break;
 3122     case attr_vehicle:
 3123     case attr_osd:
 3124         this_->attrs=attr_generic_remove_attr(this_->attrs, attr);
 3125         return 1;
 3126     default:
 3127         return 0;
 3128     }
 3129     return ret;
 3130 }
 3131 
 3132 struct attr_iter *
 3133 navit_attr_iter_new(void * unused) {
 3134     return g_new0(struct attr_iter, 1);
 3135 }
 3136 
 3137 void navit_attr_iter_destroy(struct attr_iter *iter) {
 3138     g_free(iter);
 3139 }
 3140 
 3141 void navit_add_callback(struct navit *this_, struct callback *cb) {
 3142     callback_list_add(this_->attr_cbl, cb);
 3143 }
 3144 
 3145 void navit_remove_callback(struct navit *this_, struct callback *cb) {
 3146     callback_list_remove(this_->attr_cbl, cb);
 3147 }
 3148 
 3149 static int coord_not_set(struct coord c) {
 3150     return !(c.x || c.y);
 3151 }
 3152 
 3153 /**
 3154  * Toggle the cursor update : refresh the map each time the cursor has moved (instead of only when it reaches a border)
 3155  *
 3156  * @param this_ The navit instance
 3157  * @param nv vehicle to draw
 3158  * @param pnt Screen coordinates of the vehicle. If NULL, position stored in nv is used.
 3159  * @returns nothing
 3160  */
 3161 
 3162 static void navit_vehicle_draw(struct navit *this_, struct navit_vehicle *nv, struct point *pnt) {
 3163     struct point cursor_pnt;
 3164     enum projection pro;
 3165 
 3166     if (this_->blocked||coord_not_set(nv->coord))
 3167         return;
 3168     if (pnt)
 3169         cursor_pnt=*pnt;
 3170     else {
 3171         pro=transform_get_projection(this_->trans_cursor);
 3172         if (!pro)
 3173             return;
 3174         transform(this_->trans_cursor, pro, &nv->coord, &cursor_pnt, 1, 0, 0, NULL);
 3175     }
 3176     vehicle_draw(nv->vehicle, this_->gra, &cursor_pnt, nv->dir-transform_get_yaw(this_->trans_cursor), nv->speed);
 3177 }
 3178 
 3179 /**
 3180  * @brief Called when the position of a vehicle changes.
 3181  *
 3182  * This function is called when the position of any configured vehicle changes and triggers all actions
 3183  * that need to happen in response, such as:
 3184  * <ul>
 3185  * <li>Switching between day and night layout (based on the new position timestamp)</li>
 3186  * <li>Updating position, bearing and speed of {@code nv} with the data of the active vehicle
 3187  * (which may be different from the vehicle reporting the update)</li>
 3188  * <li>Invoking callbacks for {@code navit}'s {@code attr_position} and {@code attr_position_coord_geo}
 3189  * attributes</li>
 3190  * <li>Triggering an update of the vehicle's position on the map and, if needed, an update of the
 3191  * visible map area ad orientation</li>
 3192  * <li>Logging a new track point, if enabled</li>
 3193  * <li>Updating the position on the route</li>
 3194  * <li>Stopping navigation if the destination has been reached</li>
 3195  * </ul>
 3196  *
 3197  * @param this_ The navit object
 3198  * @param nv The {@code navit_vehicle} which reported a new position
 3199  */
 3200 static void navit_vehicle_update_position(struct navit *this_, struct navit_vehicle *nv) {
 3201     struct attr attr_valid, attr_dir, attr_speed, attr_pos;
 3202     struct pcoord cursor_pc;
 3203     struct point cursor_pnt, *pnt=&cursor_pnt;
 3204     struct tracking *tracking=NULL;
 3205     struct pcoord *pc;
 3206     enum projection pro=transform_get_projection(this_->trans_cursor);
 3207     int count;
 3208     int (*get_attr)(void *, enum attr_type, struct attr *, struct attr_iter *);
 3209     void *attr_object;
 3210     char *destination_file;
 3211     char *description;
 3212 
 3213     profile(0,NULL);
 3214     if (this_->ready == 3)
 3215         navit_layout_switch(this_);
 3216     if (this_->vehicle == nv && this_->tracking_flag)
 3217         tracking=this_->tracking;
 3218     if (tracking) {
 3219         tracking_update(tracking, nv->vehicle, this_->vehicleprofile, pro);
 3220         attr_object=tracking;
 3221         get_attr=(int (*)(void *, enum attr_type, struct attr *, struct attr_iter *))tracking_get_attr;
 3222     } else {
 3223         attr_object=nv->vehicle;
 3224         get_attr=(int (*)(void *, enum attr_type, struct attr *, struct attr_iter *))vehicle_get_attr;
 3225     }
 3226     if (get_attr(attr_object, attr_position_valid, &attr_valid, NULL))
 3227         if (!attr_valid.u.num != attr_position_valid_invalid)
 3228             return;
 3229     if (! get_attr(attr_object, attr_position_direction, &attr_dir, NULL) ||
 3230             ! get_attr(attr_object, attr_position_speed, &attr_speed, NULL) ||
 3231             ! get_attr(attr_object, attr_position_coord_geo, &attr_pos, NULL)) {
 3232         profile(0,"return 2\n");
 3233         return;
 3234     }
 3235     nv->dir=*attr_dir.u.numd;
 3236     nv->speed=*attr_speed.u.numd;
 3237     transform_from_geo(pro, attr_pos.u.coord_geo, &nv->coord);
 3238     if (nv != this_->vehicle) {
 3239         if (this_->ready == 3)
 3240             navit_vehicle_draw(this_, nv, NULL);
 3241         profile(0,"return 3\n");
 3242         return;
 3243     }
 3244     cursor_pc.x = nv->coord.x;
 3245     cursor_pc.y = nv->coord.y;
 3246     cursor_pc.pro = pro;
 3247     if (this_->route) {
 3248         if (tracking)
 3249             route_set_position_from_tracking(this_->route, tracking, pro);
 3250         else
 3251             route_set_position(this_->route, &cursor_pc);
 3252     }
 3253     callback_list_call_attr_0(this_->attr_cbl, attr_position);
 3254     navit_textfile_debug_log(this_, "type=trackpoint_tracked");
 3255     if (this_->ready == 3) {
 3256         if (this_->gui && nv->speed > 2)
 3257             navit_disable_suspend();
 3258 
 3259         transform(this_->trans_cursor, pro, &nv->coord, &cursor_pnt, 1, 0, 0, NULL);
 3260         if (this_->button_pressed != 1 && this_->follow_cursor && nv->follow_curr <= nv->follow &&
 3261                 (nv->follow_curr == 1 || !transform_within_border(this_->trans_cursor, &cursor_pnt, this_->border)))
 3262             navit_set_center_cursor_draw(this_);
 3263         else
 3264             navit_vehicle_draw(this_, nv, pnt);
 3265 
 3266         if (nv->follow_curr > 1)
 3267             nv->follow_curr--;
 3268         else
 3269             nv->follow_curr=nv->follow;
 3270     }
 3271     callback_list_call_attr_2(this_->attr_cbl, attr_position_coord_geo, this_, nv->vehicle);
 3272 
 3273     /* Finally, if we reached our destination, stop navigation. */
 3274     if (this_->route) {
 3275         switch(route_destination_reached(this_->route)) {
 3276         case 1:
 3277             description=route_get_destination_description(this_->route, 0);
 3278             route_remove_waypoint(this_->route);
 3279             count=route_get_destination_count(this_->route);
 3280             pc=g_alloca(sizeof(*pc)*count);
 3281             route_get_destinations(this_->route, pc, count);
 3282             destination_file = bookmarks_get_destination_file(TRUE);
 3283             bookmarks_append_destinations(this_->former_destination, destination_file, pc, count, type_former_itinerary_part,
 3284                                           description, this_->recentdest_count);
 3285             g_free(destination_file);
 3286             g_free(description);
 3287             break;
 3288         case 2:
 3289             destination_file = bookmarks_get_destination_file(TRUE);
 3290             bookmarks_append_destinations(this_->former_destination, destination_file, NULL, 0, type_former_itinerary_part, NULL,
 3291                                           this_->recentdest_count);
 3292             navit_set_destination(this_, NULL, NULL, 0);
 3293             g_free(destination_file);
 3294             break;
 3295         }
 3296     }
 3297     profile(0,"return 5\n");
 3298 }
 3299 
 3300 /**
 3301  * @brief Called when a status attribute of a vehicle changes.
 3302  *
 3303  * This function is called when the {@code position_fix_type}, {@code position_sats_used} or {@code position_hdop}
 3304  * attribute of any configured vehicle changes.
 3305  *
 3306  * The function checks if {@code nv} refers to the active vehicle and if {@code type} is one of the above types.
 3307  * If this is the case, it invokes the callback functions for {@code navit}'s respective attributes.
 3308  *
 3309  * Future actions that need to happen when one of these three attribute changes for any vehicle should be
 3310  * implemented here.
 3311  *
 3312  * @param this_ The navit object
 3313  * @param nv The {@code navit_vehicle} which reported a new status attribute
 3314  * @param type The type of attribute with has changed
 3315  */
 3316 static void navit_vehicle_update_status(struct navit *this_, struct navit_vehicle *nv, enum attr_type type) {
 3317     if (this_->vehicle != nv)
 3318         return;
 3319     switch(type) {
 3320     case attr_position_fix_type:
 3321     case attr_position_sats_used:
 3322     case attr_position_hdop:
 3323         callback_list_call_attr_2(this_->attr_cbl, type, this_, nv->vehicle);
 3324         break;
 3325     default:
 3326         return;
 3327     }
 3328 }
 3329 
 3330 /**
 3331  * Set the position of the vehicle
 3332  *
 3333  * @param navit The navit instance
 3334  * @param c The coordinate to set as position
 3335  * @returns nothing
 3336  */
 3337 
 3338 void navit_set_position(struct navit *this_, struct pcoord *c) {
 3339     if (this_->route) {
 3340         route_set_position(this_->route, c);
 3341         callback_list_call_attr_0(this_->attr_cbl, attr_position);
 3342     }
 3343     if (this_->ready == 3)
 3344         navit_draw(this_);
 3345 }
 3346 
 3347 static int navit_set_vehicleprofile(struct navit *this_, struct vehicleprofile *vp) {
 3348     if (this_->vehicleprofile == vp)
 3349         return 0;
 3350     this_->vehicleprofile=vp;
 3351     if (this_->route)
 3352         route_set_profile(this_->route, this_->vehicleprofile);
 3353     return 1;
 3354 }
 3355 
 3356 int navit_set_vehicleprofile_name(struct navit *this_, char *name) {
 3357     struct attr attr;
 3358     GList *l;
 3359     l=this_->vehicleprofiles;
 3360     while (l) {
 3361         if (vehicleprofile_get_attr(l->data, attr_name, &attr, NULL)) {
 3362             if (!strcmp(attr.u.str, name)) {
 3363                 navit_set_vehicleprofile(this_, l->data);
 3364                 return 1;
 3365             }
 3366         }
 3367         l=g_list_next(l);
 3368     }
 3369     return 0;
 3370 }
 3371 
 3372 static void navit_set_vehicle(struct navit *this_, struct navit_vehicle *nv) {
 3373     struct attr attr;
 3374     this_->vehicle=nv;
 3375     if (nv && vehicle_get_attr(nv->vehicle, attr_profilename, &attr, NULL)) {
 3376         if (navit_set_vehicleprofile_name(this_, attr.u.str))
 3377             return;
 3378     }
 3379     if (!this_->vehicleprofile) { // When deactivating vehicle, keep the last profile if any
 3380         if (!navit_set_vehicleprofile_name(this_,"car")) {
 3381             /* We do not have a fallback "car" profile
 3382             * so lets set any profile */
 3383             GList *l;
 3384             l=this_->vehicleprofiles;
 3385             if (l) {
 3386                 this_->vehicleprofile=l->data;
 3387                 if (this_->route)
 3388                     route_set_profile(this_->route, this_->vehicleprofile);
 3389             }
 3390         }
 3391     } else {
 3392         if (this_->route)
 3393             route_set_profile(this_->route, this_->vehicleprofile);
 3394     }
 3395 }
 3396 
 3397 /**
 3398  * @brief Registers a new vehicle.
 3399  *
 3400  * @param this_ The navit instance
 3401  * @param v The vehicle to register
 3402  * @return True for success
 3403  */
 3404 static int navit_add_vehicle(struct navit *this_, struct vehicle *v) {
 3405     struct navit_vehicle *nv=g_new0(struct navit_vehicle, 1);
 3406     struct attr follow, active, animate;
 3407     nv->vehicle=v;
 3408     nv->follow=0;
 3409     nv->last.x = 0;
 3410     nv->last.y = 0;
 3411     nv->animate_cursor=0;
 3412     if ((vehicle_get_attr(v, attr_follow, &follow, NULL)))
 3413         nv->follow=follow.u.num;
 3414     nv->follow_curr=nv->follow;
 3415     this_->vehicles=g_list_append(this_->vehicles, nv);
 3416     if ((vehicle_get_attr(v, attr_active, &active, NULL)) && active.u.num)
 3417         navit_set_vehicle(this_, nv);
 3418     if ((vehicle_get_attr(v, attr_animate, &animate, NULL)))
 3419         nv->animate_cursor=animate.u.num;
 3420     nv->callback.type=attr_callback;
 3421     nv->callback.u.callback=callback_new_attr_2(callback_cast(navit_vehicle_update_position), attr_position_coord_geo,
 3422                             this_, nv);
 3423     vehicle_add_attr(nv->vehicle, &nv->callback);
 3424     nv->callback.u.callback=callback_new_attr_3(callback_cast(navit_vehicle_update_status), attr_position_fix_type, this_,
 3425                             nv, attr_position_fix_type);
 3426     vehicle_add_attr(nv->vehicle, &nv->callback);
 3427     nv->callback.u.callback=callback_new_attr_3(callback_cast(navit_vehicle_update_status), attr_position_sats_used, this_,
 3428                             nv, attr_position_sats_used);
 3429     vehicle_add_attr(nv->vehicle, &nv->callback);
 3430     nv->callback.u.callback=callback_new_attr_3(callback_cast(navit_vehicle_update_status), attr_position_hdop, this_, nv,
 3431                             attr_position_hdop);
 3432     vehicle_add_attr(nv->vehicle, &nv->callback);
 3433     vehicle_set_attr(nv->vehicle, &this_->self);
 3434     return 1;
 3435 }
 3436 
 3437 
 3438 
 3439 
 3440 struct gui *
 3441 navit_get_gui(struct navit *this_) {
 3442     return this_->gui;
 3443 }
 3444 
 3445 struct transformation *
 3446 navit_get_trans(struct navit *this_) {
 3447     return this_->trans;
 3448 }
 3449 
 3450 struct route *
 3451 navit_get_route(struct navit *this_) {
 3452     return this_->route;
 3453 }
 3454 
 3455 struct navigation *
 3456 navit_get_navigation(struct navit *this_) {
 3457     return this_->navigation;
 3458 }
 3459 
 3460 struct displaylist *
 3461 navit_get_displaylist(struct navit *this_) {
 3462     return this_->displaylist;
 3463 }
 3464 
 3465 /*todo : make it switch to nightlayout when we are in a tunnel */
 3466 void navit_layout_switch(struct navit *n) {
 3467 
 3468     int currTs=0;
 3469     struct attr iso8601_attr,geo_attr,valid_attr,layout_attr;
 3470     double trise,tset,trise_actual;
 3471     struct layout *l;
 3472     int year, month, day;
 3473     int after_sunrise = FALSE;
 3474     int after_sunset = FALSE;
 3475 
 3476     if (navit_get_attr(n,attr_layout,&layout_attr,NULL)!=1) {
 3477         return; //No layout - nothing to switch
 3478     }
 3479     if (!n->vehicle)
 3480         return;
 3481     l=layout_attr.u.layout;
 3482 
 3483     if (l->dayname || l->nightname) {
 3484         //Ok, we know that we have profile to switch
 3485 
 3486         //Check that we aren't calculating too fast
 3487         if (vehicle_get_attr(n->vehicle->vehicle, attr_position_time_iso8601,&iso8601_attr,NULL)==1) {
 3488             currTs=iso8601_to_secs(iso8601_attr.u.str);
 3489             dbg(lvl_debug,"currTs: %u:%u",currTs%86400/3600,((currTs%86400)%3600)/60);
 3490         }
 3491         dbg(lvl_debug,"prevTs: %u:%u",n->prevTs%86400/3600,((n->prevTs%86400)%3600)/60);
 3492 
 3493         if (n->auto_switch == FALSE)
 3494             return;
 3495 
 3496         if (currTs-(n->prevTs)<60) {
 3497             //We've have to wait a little
 3498             return;
 3499         }
 3500 
 3501         if (sscanf(iso8601_attr.u.str,"%d-%02d-%02dT",&year,&month,&day) != 3)
 3502             return;
 3503         if (vehicle_get_attr(n->vehicle->vehicle, attr_position_valid, &valid_attr,NULL)
 3504                 && valid_attr.u.num==attr_position_valid_invalid) {
 3505             return; //No valid fix yet
 3506         }
 3507         if (vehicle_get_attr(n->vehicle->vehicle, attr_position_coord_geo,&geo_attr,NULL)!=1) {
 3508             //No position - no sun
 3509             return;
 3510         }
 3511         //We calculate sunrise anyway, cause it is needed both for day and for night
 3512         if (__sunriset__(year,month,day,geo_attr.u.coord_geo->lng,geo_attr.u.coord_geo->lat,-5,1,&trise,&tset)!=0) {
 3513             dbg(lvl_debug,"near the pole sun never rises/sets, so we should never switch profiles");
 3514             dbg(lvl_debug,"trise: %u:%u",HOURS(trise),MINUTES(trise));
 3515             dbg(lvl_debug,"tset: %u:%u",HOURS(tset),MINUTES(tset));
 3516             n->prevTs=currTs;
 3517             return;
 3518         }
 3519         trise_actual=trise;
 3520         dbg(lvl_debug,"trise: %u:%u",HOURS(trise),MINUTES(trise));
 3521         dbg(lvl_debug,"tset: %u:%u",HOURS(tset),MINUTES(tset));
 3522         dbg(lvl_debug,"dayname = %s, name =%s ",l->dayname, l->name);
 3523         dbg(lvl_debug,"nightname = %s, name = %s ",l->nightname, l->name);
 3524         if (HOURS(trise)*60+MINUTES(trise)<(currTs%86400)/60) {
 3525             after_sunrise = TRUE;
 3526         }
 3527 
 3528         if (((HOURS(tset)*60+MINUTES(tset)<(currTs%86400)/60)) ||
 3529                 ((HOURS(trise_actual)*60+MINUTES(trise_actual)>(currTs%86400)/60))) {
 3530             after_sunset = TRUE;
 3531         }
 3532         if (after_sunrise && !after_sunset && l->dayname) {
 3533             navit_set_layout_by_name(n,l->dayname);
 3534             dbg(lvl_debug,"layout set to day");
 3535         } else if (after_sunset && l->nightname) {
 3536             navit_set_layout_by_name(n,l->nightname);
 3537             dbg(lvl_debug,"layout set to night");
 3538         }
 3539         n->prevTs=currTs;
 3540     }
 3541 }
 3542 
 3543 /**
 3544  * @brief this command is used to change the layout and enable/disable the automatic layout switcher
 3545  *
 3546  * @param this_ The navit instance
 3547  * @param function unused
 3548  * @param in input attributes in[0], a string, see usage below
 3549  * @param out output attribute unused
 3550  *
 3551  *
 3552  * usage :
 3553  * manual        : disable autoswitcher
 3554  * auto          : enable autoswitcher
 3555  * manual_toggle : disable autoswitcher and toggle between day / night layout
 3556  * manual_day    : disable autoswitcher and set to day layout
 3557  * manual_night  : disable autoswitcher and set to night layout
 3558  *
 3559  * todo : make it return the state of the autoswitcher and
 3560  * the version of the active layout (day/night/undefined)
 3561  */
 3562 static
 3563 int navit_cmd_switch_layout_day_night(struct navit *this_, char *function, struct attr **in, struct attr *** out) {
 3564 
 3565     if (!(in && in[0] && ATTR_IS_STRING(in[0]->type))) {
 3566         return 0;
 3567     }
 3568 
 3569     dbg(lvl_debug," called with mode =%s",in[0]->u.str);
 3570 
 3571     if (!this_->layout_current)
 3572         return 0;
 3573 
 3574     if (!this_->vehicle)
 3575         return 0;
 3576 
 3577     if (!strcmp(in[0]->u.str,"manual")) {
 3578         this_->auto_switch = FALSE;
 3579     } else if (!strcmp(in[0]->u.str,"auto")) {
 3580         this_->auto_switch = TRUE;
 3581         this_->prevTs = 0;
 3582         navit_layout_switch(this_);
 3583     } else if (!strcmp(in[0]->u.str,"manual_toggle")) {
 3584         if (this_->layout_current->dayname) {
 3585             navit_set_layout_by_name(this_,this_->layout_current->dayname);
 3586             this_->auto_switch = FALSE;
 3587             dbg(lvl_debug,"toggeled layout to = %s",this_->layout_current->name);
 3588         } else if (this_->layout_current->nightname) {
 3589             navit_set_layout_by_name(this_,this_->layout_current->nightname);
 3590             this_->auto_switch = FALSE;
 3591             dbg(lvl_debug,"toggeled layout to = %s",this_->layout_current->name);
 3592         }
 3593     } else if (!strcmp(in[0]->u.str,"manual_day") && this_->layout_current->dayname) {
 3594         navit_set_layout_by_name(this_,this_->layout_current->dayname);
 3595         this_->auto_switch = FALSE;
 3596         dbg(lvl_debug,"switched layout to = %s",this_->layout_current->name);
 3597     } else if (!strcmp(in[0]->u.str,"manual_night") && this_->layout_current->nightname) {
 3598         navit_set_layout_by_name(this_,this_->layout_current->nightname);
 3599         this_->auto_switch = FALSE;
 3600         dbg(lvl_debug,"switched layout to = %s",this_->layout_current->name);
 3601     }
 3602 
 3603     dbg(lvl_debug,"auto = %i",this_->auto_switch);
 3604     return 0;
 3605 }
 3606 
 3607 int navit_set_vehicle_by_name(struct navit *n,const char *name) {
 3608     struct vehicle *v;
 3609     struct attr_iter *iter;
 3610     struct attr vehicle_attr, name_attr;
 3611 
 3612     iter=navit_attr_iter_new(NULL);
 3613 
 3614     while (navit_get_attr(n,attr_vehicle,&vehicle_attr,iter)) {
 3615         v=vehicle_attr.u.vehicle;
 3616         vehicle_get_attr(v,attr_name,&name_attr,NULL);
 3617         if (name_attr.type==attr_name) {
 3618             if (!strcmp(name,name_attr.u.str)) {
 3619                 navit_set_attr(n,&vehicle_attr);
 3620                 navit_attr_iter_destroy(iter);
 3621                 return 1;
 3622             }
 3623         }
 3624     }
 3625     navit_attr_iter_destroy(iter);
 3626     return 0;
 3627 }
 3628 
 3629 int navit_set_layout_by_name(struct navit *n,const char *name) {
 3630     struct layout *l;
 3631     struct attr_iter iter;
 3632     struct attr layout_attr;
 3633 
 3634     iter.u.list=0x00;
 3635 
 3636     if (navit_get_attr(n,attr_layout,&layout_attr,&iter)!=1) {
 3637         return 0; //No layouts - nothing to do
 3638     }
 3639     if (iter.u.list==NULL) {
 3640         return 0;
 3641     }
 3642 
 3643     iter.u.list=g_list_first(iter.u.list);
 3644 
 3645     while(iter.u.list) {
 3646         l=(struct layout*)iter.u.list->data;
 3647         if (!strcmp(name,l->name)) {
 3648             layout_attr.u.layout=l;
 3649             layout_attr.type=attr_layout;
 3650             navit_set_attr(n,&layout_attr);
 3651             iter.u.list=g_list_first(iter.u.list);
 3652             return 1;
 3653         }
 3654         iter.u.list=g_list_next(iter.u.list);
 3655     }
 3656 
 3657     iter.u.list=g_list_first(iter.u.list);
 3658     return 0;
 3659 }
 3660 
 3661 void navit_disable_suspend() {
 3662     gui_disable_suspend(global_navit->gui);
 3663     callback_list_call_attr_0(global_navit->attr_cbl,attr_unsuspend);
 3664 }
 3665 
 3666 /**
 3667  * @brief Blocks or unblocks redraw operations.
 3668  *
 3669  * The {@code block} parameter specifies the operation to carry out:
 3670  *
 3671  * {@code block > 0} cancels all draw operations in progress and blocks future operations. It sets flag 1 of the
 3672  * {@code blocked} member. If draw operations in progress were canceled, flag 2 is also set.
 3673  *
 3674  * {@code block = 0} unblocks redraw operations, resetting {@code blocked} to 0. If flag 2 was previously set,
 3675  * indicating that draw operations had been previously canceled, a redraw is triggered.
 3676  *
 3677  * {@code block < 0} unblocks redraw operations and forces a redraw. As above, {@code blocked} is reset to 0.
 3678  *
 3679  * @param this_ The navit instance
 3680  * @param block The operation to perform, see description
 3681  *
 3682  * @return {@code true} if a redraw operation was triggered, {@code false} if not
 3683  */
 3684 int navit_block(struct navit *this_, int block) {
 3685     if (block > 0) {
 3686         this_->blocked |= 1;
 3687         if (graphics_draw_cancel(this_->gra, this_->displaylist))
 3688             this_->blocked |= 2;
 3689         return 0;
 3690     }
 3691     if ((this_->blocked & 2) || block < 0) {
 3692         this_->blocked=0;
 3693         navit_draw(this_);
 3694         return 1;
 3695     }
 3696     this_->blocked=0;
 3697     return 0;
 3698 }
 3699 
 3700 /**
 3701  * @brief Returns whether redraw operations are currently blocked.
 3702  */
 3703 int navit_get_blocked(struct navit *this_) {
 3704     return this_->blocked;
 3705 }
 3706 
 3707 void navit_destroy(struct navit *this_) {
 3708     dbg(lvl_debug,"enter %p",this_);
 3709     GList *mapsets;
 3710     struct map * map;
 3711     struct attr attr;
 3712     graphics_draw_cancel(this_->gra, this_->displaylist);
 3713 
 3714     mapsets = this_->mapsets;
 3715     while (mapsets) {
 3716         GList *maps = NULL;
 3717         struct mapset_handle *msh;
 3718         msh = mapset_open(mapsets->data);
 3719         while (msh && (map = mapset_next(msh, 0))) {
 3720             /* Add traffic map (identified by the `attr_traffic` attribute) to list of maps to remove */
 3721             if (map_get_attr(map, attr_traffic, &attr, NULL))
 3722                 maps = g_list_append(maps, map);
 3723         }
 3724         mapset_close(msh);
 3725 
 3726         /* Remove traffic maps, if any */
 3727         while (maps) {
 3728             attr.type = attr_map;
 3729             attr.u.map = maps->data;
 3730             mapset_remove_attr(mapsets->data, &attr);
 3731             attr_free_content(&attr);
 3732             maps = g_list_next(maps);
 3733         }
 3734         if (maps)
 3735             g_list_free(maps);
 3736         mapsets = g_list_next(mapsets);
 3737     }
 3738 
 3739     callback_list_call_attr_1(this_->attr_cbl, attr_destroy, this_);
 3740     attr_list_free(this_->attrs);
 3741 
 3742     if(cmd_int_var_hash) {
 3743         g_hash_table_destroy(cmd_int_var_hash);
 3744         cmd_int_var_hash=NULL;
 3745     }
 3746     if(cmd_attr_var_hash) {
 3747         g_hash_table_destroy(cmd_attr_var_hash);
 3748         cmd_attr_var_hash=NULL;
 3749     }
 3750     if(cmd_int_var_stack) {
 3751         g_list_foreach(cmd_int_var_stack, (GFunc)attr_free_g, NULL);
 3752         g_list_free(cmd_int_var_stack);
 3753         cmd_int_var_stack=NULL;
 3754     }
 3755 
 3756     if (this_->bookmarks) {
 3757         char *center_file = bookmarks_get_center_file(TRUE);
 3758         bookmarks_write_center_to_file(this_->bookmarks, center_file);
 3759         g_free(center_file);
 3760         bookmarks_destroy(this_->bookmarks);
 3761     }
 3762 
 3763     callback_destroy(this_->nav_speech_cb);
 3764     callback_destroy(this_->roadbook_callback);
 3765     callback_destroy(this_->popup_callback);
 3766     callback_destroy(this_->motion_timeout_callback);
 3767     callback_destroy(this_->progress_cb);
 3768 
 3769     if(this_->gra) {
 3770         graphics_remove_callback(this_->gra, this_->resize_callback);
 3771         graphics_remove_callback(this_->gra, this_->button_callback);
 3772         graphics_remove_callback(this_->gra, this_->motion_callback);
 3773         graphics_remove_callback(this_->gra, this_->predraw_callback);
 3774     }
 3775 
 3776     callback_destroy(this_->resize_callback);
 3777     callback_destroy(this_->motion_callback);
 3778     callback_destroy(this_->predraw_callback);
 3779 
 3780     callback_destroy(this_->route_cb);
 3781     if (this_->route)
 3782         route_destroy(this_->route);
 3783 
 3784     map_destroy(this_->former_destination);
 3785 
 3786     graphics_displaylist_destroy(this_->displaylist);
 3787 
 3788     graphics_free(this_->gra);
 3789 
 3790     g_free(this_);
 3791 }
 3792 
 3793 struct object_func navit_func = {
 3794     attr_navit,
 3795     (object_func_new)navit_new,
 3796     (object_func_get_attr)navit_get_attr,
 3797     (object_func_iter_new)navit_attr_iter_new,
 3798     (object_func_iter_destroy)navit_attr_iter_destroy,
 3799     (object_func_set_attr)navit_set_attr,
 3800     (object_func_add_attr)navit_add_attr,
 3801     (object_func_remove_attr)navit_remove_attr,
 3802     (object_func_init)navit_init,
 3803     (object_func_destroy)navit_destroy,
 3804     (object_func_dup)NULL,
 3805     (object_func_ref)navit_object_ref,
 3806     (object_func_unref)navit_object_unref,
 3807 };
 3808 
 3809 /** @} */