1
/* icon_manager.c - gfxmenu icon manager. */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2008,2009 Free Software Foundation, Inc.
6
* GRUB 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 3 of the License, or
9
* (at your option) any later version.
11
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
20
#include <grub/types.h>
21
#include <grub/misc.h>
24
#include <grub/gui_string_util.h>
25
#include <grub/bitmap.h>
26
#include <grub/bitmap_scale.h>
27
#include <grub/menu.h>
28
#include <grub/icon_manager.h>
31
/* Currently hard coded to '.png' extension. */
32
static const char icon_extension[] = ".png";
34
typedef struct icon_entry
37
struct grub_video_bitmap *bitmap;
38
struct icon_entry *next;
41
struct grub_gfxmenu_icon_manager
47
/* Icon cache: linked list w/ dummy head node. */
48
struct icon_entry cache;
52
/* Create a new icon manager and return a point to it. */
53
grub_gfxmenu_icon_manager_t
54
grub_gfxmenu_icon_manager_new (void)
56
grub_gfxmenu_icon_manager_t mgr;
57
mgr = grub_malloc (sizeof (*mgr));
65
/* Initialize the dummy head node. */
66
mgr->cache.class_name = 0;
67
mgr->cache.bitmap = 0;
73
/* Destroy the icon manager MGR, freeing all resources used by it.
75
Note: Any bitmaps returned by grub_gfxmenu_icon_manager_get_icon()
76
are destroyed and must not be used by the caller after this function
79
grub_gfxmenu_icon_manager_destroy (grub_gfxmenu_icon_manager_t mgr)
81
grub_gfxmenu_icon_manager_clear_cache (mgr);
82
grub_free (mgr->theme_path);
86
/* Clear the icon cache. */
88
grub_gfxmenu_icon_manager_clear_cache (grub_gfxmenu_icon_manager_t mgr)
92
for (cur = mgr->cache.next; cur; cur = next)
95
grub_free (cur->class_name);
96
grub_video_bitmap_destroy (cur->bitmap);
102
/* Set the theme path. If the theme path is changed, the icon cache
105
grub_gfxmenu_icon_manager_set_theme_path (grub_gfxmenu_icon_manager_t mgr,
108
/* Clear the cache if the theme path has changed. */
109
if (((mgr->theme_path == 0) != (path == 0))
110
|| (grub_strcmp (mgr->theme_path, path) != 0))
111
grub_gfxmenu_icon_manager_clear_cache (mgr);
113
grub_free (mgr->theme_path);
114
mgr->theme_path = path ? grub_strdup (path) : 0;
117
/* Set the icon size. When icons are requested from the icon manager,
118
they are scaled to this size before being returned. If the size is
119
changed, the icon cache is cleared. */
121
grub_gfxmenu_icon_manager_set_icon_size (grub_gfxmenu_icon_manager_t mgr,
122
int width, int height)
124
/* If the width or height is changed, we must clear the cache, since the
125
scaled bitmaps are stored in the cache. */
126
if (width != mgr->icon_width || height != mgr->icon_height)
127
grub_gfxmenu_icon_manager_clear_cache (mgr);
129
mgr->icon_width = width;
130
mgr->icon_height = height;
133
/* Try to load an icon for the specified CLASS_NAME in the directory DIR.
134
Returns 0 if the icon could not be loaded, or returns a pointer to a new
135
bitmap if it was successful. */
136
static struct grub_video_bitmap *
137
try_loading_icon (grub_gfxmenu_icon_manager_t mgr,
138
const char *dir, const char *class_name)
143
path = grub_malloc (grub_strlen (dir) + grub_strlen (class_name)
144
+ grub_strlen (icon_extension) + 3);
148
grub_strcpy (path, dir);
149
l = grub_strlen (path);
150
if (path[l-1] != '/')
155
grub_strcat (path, class_name);
156
grub_strcat (path, icon_extension);
158
struct grub_video_bitmap *raw_bitmap;
159
grub_video_bitmap_load (&raw_bitmap, path);
161
grub_errno = GRUB_ERR_NONE; /* Critical to clear the error!! */
165
struct grub_video_bitmap *scaled_bitmap;
166
grub_video_bitmap_create_scaled (&scaled_bitmap,
167
mgr->icon_width, mgr->icon_height,
169
GRUB_VIDEO_BITMAP_SCALE_METHOD_BEST);
170
grub_video_bitmap_destroy (raw_bitmap);
174
grub_error (grub_errno, "failed to scale icon");
178
return scaled_bitmap;
181
/* Get the icon for the specified class CLASS_NAME. If an icon for
182
CLASS_NAME already exists in the cache, then a reference to the cached
183
bitmap is returned. If it is not cached, then it is loaded and cached.
184
If no icon could be could for CLASS_NAME, then 0 is returned. */
185
static struct grub_video_bitmap *
186
get_icon_by_class (grub_gfxmenu_icon_manager_t mgr, const char *class_name)
188
/* First check the icon cache. */
190
for (entry = mgr->cache.next; entry; entry = entry->next)
192
if (grub_strcmp (entry->class_name, class_name) == 0)
193
return entry->bitmap;
196
if (! mgr->theme_path)
199
/* Otherwise, we search for an icon to load. */
200
char *theme_dir = grub_get_dirname (mgr->theme_path);
202
struct grub_video_bitmap *icon;
204
/* First try the theme's own icons, from "grub/themes/NAME/icons/" */
205
icons_dir = grub_resolve_relative_path (theme_dir, "icons/");
208
icon = try_loading_icon (mgr, icons_dir, class_name);
209
grub_free (icons_dir);
212
grub_free (theme_dir);
217
icondir = grub_env_get ("icondir");
219
icon = try_loading_icon (mgr, icondir, class_name);
222
/* No icon was found. */
223
/* This should probably be noted in the cache, so that a search is not
224
performed each time an icon for CLASS_NAME is requested. */
228
/* Insert a new cache entry for this icon. */
229
entry = grub_malloc (sizeof (*entry));
232
grub_video_bitmap_destroy (icon);
235
entry->class_name = grub_strdup (class_name);
236
entry->bitmap = icon;
237
entry->next = mgr->cache.next;
238
mgr->cache.next = entry; /* Link it into the cache. */
239
return entry->bitmap;
242
/* Get the best available icon for ENTRY. Beginning with the first class
243
listed in the menu entry and proceeding forward, an icon for each class
244
is searched for. The first icon found is returned. The returned icon
245
is scaled to the size specified by
246
grub_gfxmenu_icon_manager_set_icon_size().
248
Note: Bitmaps returned by this function are destroyed when the
249
icon manager is destroyed.
251
struct grub_video_bitmap *
252
grub_gfxmenu_icon_manager_get_icon (grub_gfxmenu_icon_manager_t mgr,
253
grub_menu_entry_t entry)
255
struct grub_menu_entry_class *c;
256
struct grub_video_bitmap *icon;
258
/* Try each class in succession. */
260
for (c = entry->classes->next; c && ! icon; c = c->next)
261
icon = get_icon_by_class (mgr, c->name);