2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include <glib/gi18n.h>
29 #include "preferences.h"
33 typedef struct _List
{
38 /* a circular linked list, a pointer to the tail, and the tail points to the head */
39 /* this is so we can free the last */
40 static List
*queue_tail
= NULL
;
41 static int queue_count
= 0;
43 static guint32 queue_size
= 0;
44 static guint32 max_queue_size
= VIK_CONFIG_MAPCACHE_SIZE
;
47 static GHashTable
*cache
= NULL
;
49 static GMutex
*mc_mutex
= NULL
;
51 #define HASHKEY_FORMAT_STRING "%d-%d-%d-%d-%d-%d-%.3f-%.3f"
52 #define HASHKEY_FORMAT_STRING_NOSHRINK_NOR_ALPHA "%d-%d-%d-%d-%d-"
54 #define VIKING_PREFERENCES_GROUP_KEY "viking.globals"
55 #define VIKING_PREFERENCES_NAMESPACE "viking.globals."
57 static VikLayerParamScale params_scales
[] = {
58 /* min, max, step, digits (decimal places) */
62 static VikLayerParam prefs
[] = {
63 { VIKING_PREFERENCES_NAMESPACE
"mapcache_size", VIK_LAYER_PARAM_UINT
, VIK_LAYER_GROUP_NONE
, N_("Mapcache memory size (MB):"), VIK_LAYER_WIDGET_HSCALE
, params_scales
, NULL
},
66 void a_mapcache_init ()
68 VikLayerParamData tmp
;
69 tmp
.u
= VIK_CONFIG_MAPCACHE_SIZE
/ 1024 / 1024;
70 a_preferences_register(prefs
, tmp
, VIKING_PREFERENCES_GROUP_KEY
);
72 mc_mutex
= g_mutex_new();
73 cache
= g_hash_table_new_full ( g_str_hash
, g_str_equal
, g_free
, g_object_unref
);
76 static void cache_add(gchar
*key
, GdkPixbuf
*pixbuf
)
78 /* TODO: Check if already exists */
79 g_hash_table_insert ( cache
, key
, pixbuf
);
80 queue_size
+= gdk_pixbuf_get_rowstride(pixbuf
) * gdk_pixbuf_get_height(pixbuf
);
85 static void cache_remove(const gchar
*key
)
87 GdkPixbuf
*buf
= g_hash_table_lookup ( cache
, key
);
89 queue_size
-= gdk_pixbuf_get_rowstride(buf
) * gdk_pixbuf_get_height(buf
);
92 g_hash_table_remove ( cache
, key
);
96 /* returns key from head, adds on newtailkey to tail. */
97 static gchar
*list_shift_add_entry ( gchar
*newtailkey
)
99 gchar
*oldheadkey
= queue_tail
->next
->key
;
100 queue_tail
->next
->key
= newtailkey
;
101 queue_tail
= queue_tail
->next
;
105 static gchar
*list_shift ()
107 gchar
*oldheadkey
= queue_tail
->next
->key
;
108 List
*oldhead
= queue_tail
->next
;
109 queue_tail
->next
= queue_tail
->next
->next
;
114 /* adds key to tail */
115 static void list_add_entry ( gchar
*key
)
117 List
*newlist
= g_malloc ( sizeof ( List
) );
120 newlist
->next
= queue_tail
->next
;
121 queue_tail
->next
= newlist
;
122 queue_tail
= newlist
;
124 newlist
->next
= newlist
;
125 queue_tail
= newlist
;
129 void a_mapcache_add ( GdkPixbuf
*pixbuf
, gint x
, gint y
, gint z
, guint8 type
, guint zoom
, guint8 alpha
, gdouble xshrinkfactor
, gdouble yshrinkfactor
)
131 gchar
*key
= g_strdup_printf ( HASHKEY_FORMAT_STRING
, x
, y
, z
, type
, zoom
, alpha
, xshrinkfactor
, yshrinkfactor
);
134 g_mutex_lock(mc_mutex
);
135 cache_add(key
, pixbuf
);
137 // TODO: that should be done on preference change only...
138 max_queue_size
= a_preferences_get(VIKING_PREFERENCES_NAMESPACE
"mapcache_size")->u
* 1024 * 1024;
140 if ( queue_size
> max_queue_size
) {
141 gchar
*oldkey
= list_shift_add_entry ( key
);
142 cache_remove(oldkey
);
144 while ( queue_size
> max_queue_size
&&
145 (queue_tail
->next
!= queue_tail
) ) { /* make sure there's more than one thing to delete */
146 oldkey
= list_shift ();
147 cache_remove(oldkey
);
150 /* chop off 'start' etc */
152 list_add_entry ( key
);
153 /* business as usual */
155 g_mutex_unlock(mc_mutex
);
157 if ( (++tmp
== 100 )) { g_print("DEBUG: queue count=%d %u\n", queue_count
, queue_size
); tmp
=0; }
160 GdkPixbuf
*a_mapcache_get ( gint x
, gint y
, gint z
, guint8 type
, guint zoom
, guint8 alpha
, gdouble xshrinkfactor
, gdouble yshrinkfactor
)
163 g_snprintf ( key
, sizeof(key
), HASHKEY_FORMAT_STRING
, x
, y
, z
, type
, zoom
, alpha
, xshrinkfactor
, yshrinkfactor
);
164 return g_hash_table_lookup ( cache
, key
);
167 void a_mapcache_remove_all_shrinkfactors ( gint x
, gint y
, gint z
, guint8 type
, guint zoom
)
170 List
*loop
= queue_tail
;
174 if ( queue_tail
== NULL
)
177 g_snprintf ( key
, sizeof(key
), HASHKEY_FORMAT_STRING_NOSHRINK_NOR_ALPHA
, x
, y
, z
, type
, zoom
);
180 g_mutex_lock(mc_mutex
);
181 /* TODO: check logic here */
184 if ( strncmp(tmp
->key
, key
, len
) == 0 )
186 cache_remove(tmp
->key
);
187 if ( tmp
== loop
) /* we deleted the last thing in the queue! */
188 loop
= queue_tail
= NULL
;
190 loop
->next
= tmp
->next
;
191 if ( tmp
== queue_tail
)
192 queue_tail
= tmp
->next
;
200 } while ( loop
&& (loop
!= queue_tail
|| tmp
== NULL
) );
202 /* loop thru list, looking for the one, compare first whatever chars */
204 g_mutex_unlock(mc_mutex
);
207 void a_mapcache_flush ()
209 List
*loop
= queue_tail
;
212 if ( queue_tail
== NULL
)
215 g_mutex_lock(mc_mutex
);
218 cache_remove(tmp
->key
);
219 if ( tmp
== queue_tail
) /* we deleted the last thing in the queue */
220 loop
= queue_tail
= NULL
;
222 loop
->next
= tmp
->next
;
227 g_mutex_unlock(mc_mutex
);
230 void a_mapcache_uninit ()
232 g_hash_table_destroy ( cache
);