NetSurf
resources.c
Go to the documentation of this file.
1/*
2 * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf 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; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/**
20 * \file
21 * Implementation of gtk builtin resource handling.
22 *
23 * This presents a unified interface to the rest of the codebase to
24 * obtain resources. Note this is not anything to do with the resource
25 * scheme handling beyond possibly providing the underlying data.
26 *
27 */
28
29#include <stdlib.h>
30#include <string.h>
31#include <gtk/gtk.h>
32
33#include "utils/log.h"
34#include "utils/filepath.h"
35
36#include "gtk/compat.h"
37#include "gtk/resources.h"
38
39/** log contents of gresource /org/netsource */
40#ifdef WITH_GRESOURCE
41#define SHOW_GRESOURCE
42#undef SHOW_GRESOURCE
43#endif
44
45#ifdef WITH_BUILTIN_PIXBUF
46#ifdef __GNUC__
47extern const guint8 menu_cursor_pixdata[] __attribute__ ((__aligned__ (4)));
48extern const guint8 favicon_pixdata[] __attribute__ ((__aligned__ (4)));
49extern const guint8 netsurf_pixdata[] __attribute__ ((__aligned__ (4)));
50#else
51extern const guint8 menu_cursor_pixdata[];
52extern const guint8 favicon_pixdata[];
53extern const guint8 netsurf_pixdata[];
54#endif
55#endif
56
57/** type of resource entry */
59 NSGTK_RESOURCE_FILE, /**< entry is a file on disc */
60 NSGTK_RESOURCE_GLIB, /**< entry is a gresource accessed by path */
61 NSGTK_RESOURCE_DIRECT, /**< entry is a gresource accesed by gbytes */
62 NSGTK_RESOURCE_INLINE, /**< entry is compiled in accessed by pointer */
63};
64
65/** resource entry */
67 const char *name;
68 unsigned int len;
70 char *path;
71};
72
73#define RES_ENTRY(name) { name, sizeof((name)) - 1, NSGTK_RESOURCE_FILE, NULL }
74
75/** resources that are used for gtk builder */
76static struct nsgtk_resource_s ui_resource[] = {
77 RES_ENTRY("netsurf"),
78 RES_ENTRY("tabcontents"),
79 RES_ENTRY("password"),
80 RES_ENTRY("toolbar"),
81 RES_ENTRY("downloads"),
82 RES_ENTRY("globalhistory"),
83 RES_ENTRY("localhistory"),
84 RES_ENTRY("options"),
85 RES_ENTRY("hotlist"),
86 RES_ENTRY("cookies"),
87 RES_ENTRY("viewdata"),
88 RES_ENTRY("warning"),
89 RES_ENTRY("pageinfo"),
90 { NULL, 0, NSGTK_RESOURCE_FILE, NULL },
91};
92
93/** resources that are used as pixbufs */
95 RES_ENTRY("favicon.png"),
96 RES_ENTRY("netsurf.xpm"),
97 RES_ENTRY("menu_cursor.png"),
98 RES_ENTRY("icons/local-history.png"),
99 RES_ENTRY("icons/show-cookie.png"),
100 RES_ENTRY("icons/24x24/actions/page-info-insecure.png"),
101 RES_ENTRY("icons/24x24/actions/page-info-internal.png"),
102 RES_ENTRY("icons/24x24/actions/page-info-local.png"),
103 RES_ENTRY("icons/24x24/actions/page-info-secure.png"),
104 RES_ENTRY("icons/24x24/actions/page-info-warning.png"),
105 RES_ENTRY("icons/48x48/actions/page-info-insecure.png"),
106 RES_ENTRY("icons/48x48/actions/page-info-internal.png"),
107 RES_ENTRY("icons/48x48/actions/page-info-local.png"),
108 RES_ENTRY("icons/48x48/actions/page-info-secure.png"),
109 RES_ENTRY("icons/48x48/actions/page-info-warning.png"),
110 RES_ENTRY("throbber/throbber0.png"),
111 RES_ENTRY("throbber/throbber1.png"),
112 RES_ENTRY("throbber/throbber2.png"),
113 RES_ENTRY("throbber/throbber3.png"),
114 RES_ENTRY("throbber/throbber4.png"),
115 RES_ENTRY("throbber/throbber5.png"),
116 RES_ENTRY("throbber/throbber6.png"),
117 RES_ENTRY("throbber/throbber7.png"),
118 RES_ENTRY("throbber/throbber8.png"),
119 { NULL, 0, NSGTK_RESOURCE_FILE, NULL },
120};
121
122/** resources that are used for direct data access */
124 RES_ENTRY("welcome.html"),
125 RES_ENTRY("credits.html"),
126 RES_ENTRY("licence.html"),
127 RES_ENTRY("default.css"),
128 RES_ENTRY("adblock.css"),
129 RES_ENTRY("internal.css"),
130 RES_ENTRY("quirks.css"),
131 RES_ENTRY("netsurf.png"),
132 RES_ENTRY("default.ico"),
133 RES_ENTRY("icons/arrow-l.png"),
134 RES_ENTRY("icons/content.png"),
135 RES_ENTRY("icons/directory2.png"),
136 RES_ENTRY("icons/directory.png"),
137 RES_ENTRY("icons/hotlist-add.png"),
138 RES_ENTRY("icons/hotlist-rmv.png"),
139 RES_ENTRY("icons/search.png"),
140 RES_ENTRY("languages"),
141 RES_ENTRY("accelerators"),
142 RES_ENTRY("Messages"),
143 { NULL, 0, NSGTK_RESOURCE_FILE, NULL },
144};
145
146
147/* exported interface documented in gtk/resources.h */
149{
150 GdkCursor *cursor = NULL;
151 GdkPixbuf *pixbuf;
152 nserror res;
153
154 res = nsgdk_pixbuf_new_from_resname("menu_cursor.png", &pixbuf);
155 if (res == NSERROR_OK) {
156 cursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(),
157 pixbuf, 0, 3);
158 g_object_unref(pixbuf);
159 }
160
161 return cursor;
162}
163
164
165/**
166 * locate a resource
167 *
168 * The way GTK accesses resource files has changed greatly between
169 * releases. This initilises the interface that hides all the
170 * implementation details from the rest of the code.
171 *
172 * If the GResource is not enabled or the item cannot be found in the
173 * compiled in resources the files will be loaded directly from disc
174 * instead.
175 *
176 * \param respath A string vector containing the valid resource search paths
177 * \param resource A resource entry to initialise
178 */
179static nserror
180init_resource(char **respath, struct nsgtk_resource_s *resource)
181{
182 char *resname;
183#ifdef WITH_GRESOURCE
184 int resnamelen;
185 gboolean present;
186 const gchar * const *langv;
187 int langc = 0;
188
189 langv = g_get_language_names();
190
191 /* look for resource under per language paths */
192 while (langv[langc] != NULL) {
193 /* allocate and fill a full resource name path buffer */
194 resnamelen = snprintf(NULL, 0,
195 "/org/netsurf/%s/%s",
196 langv[langc], resource->name);
197 resname = malloc(resnamelen + 1);
198 if (resname == NULL) {
199 return NSERROR_NOMEM;
200 }
201 snprintf(resname, resnamelen + 1,
202 "/org/netsurf/%s/%s",
203 langv[langc], resource->name);
204
205 /* check if resource is present */
206 present = g_resources_get_info(resname,
207 G_RESOURCE_LOOKUP_FLAGS_NONE,
208 NULL, NULL, NULL);
209 if (present == TRUE) {
210 /* found an entry in the resources */
211 resource->path = resname;
212 resource->type = NSGTK_RESOURCE_GLIB;
213 NSLOG(netsurf, INFO, "Found gresource path %s",
214 resource->path);
215 return NSERROR_OK;
216 }
217 NSLOG(netsurf, DEEPDEBUG,
218 "gresource \"%s\" not found", resname);
219 free(resname);
220
221 langc++;
222 }
223
224 /* allocate and fill a full resource name path buffer with no language*/
225 resnamelen = snprintf(NULL, 0, "/org/netsurf/%s", resource->name);
226 resname = malloc(resnamelen + 1);
227 if (resname == NULL) {
228 return NSERROR_NOMEM;
229 }
230 snprintf(resname, resnamelen + 1, "/org/netsurf/%s", resource->name);
231
232 present = g_resources_get_info(resname,
233 G_RESOURCE_LOOKUP_FLAGS_NONE,
234 NULL, NULL, NULL);
235 if (present == TRUE) {
236 /* found an entry in the resources */
237 resource->path = resname;
238 resource->type = NSGTK_RESOURCE_GLIB;
239 NSLOG(netsurf, INFO, "Found gresource path %s",
240 resource->path);
241 return NSERROR_OK;
242 }
243 NSLOG(netsurf, DEEPDEBUG, "gresource \"%s\" not found", resname);
244 free(resname);
245
246#endif
247
248 /* look for file on disc */
249 resname = filepath_find(respath, resource->name);
250 if (resname != NULL) {
251 /* found an entry on the path */
252 resource->path = resname;
253 resource->type = NSGTK_RESOURCE_FILE;
254
255 NSLOG(netsurf, INFO,
256 "Found file resource path %s", resource->path);
257 return NSERROR_OK;
258 }
259
260 NSLOG(netsurf, INFO, "Unable to find resource %s on resource path",
261 resource->name);
262
263 return NSERROR_NOT_FOUND;
264}
265
266/**
267 * locate and setup a direct resource
268 *
269 * Direct resources have general type of NSGTK_RESOURCE_GLIB but have
270 * g_resources_lookup_data() applied and the result stored so the data
271 * can be directly accessed without additional processing.
272 *
273 * \param respath A string vector containing the valid resource search paths
274 * \param resource A resource entry to initialise
275 */
276static nserror
277init_direct_resource(char **respath, struct nsgtk_resource_s *resource)
278{
279 nserror res;
280
281 res = init_resource(respath, resource);
282
283#ifdef WITH_GRESOURCE
284 if ((res == NSERROR_OK) &&
285 (resource->type == NSGTK_RESOURCE_GLIB)) {
286 /* found gresource we can convert */
287 GBytes *data;
288
289 data = g_resources_lookup_data(resource->path,
290 G_RESOURCE_LOOKUP_FLAGS_NONE,
291 NULL);
292 if (data != NULL) {
293 resource->type = NSGTK_RESOURCE_DIRECT;
294 resource->path = (char *)data;
295 }
296 }
297#endif
298
299 return res;
300}
301
302/**
303 * locate a pixbuf resource
304 *
305 * Pixbuf resources can be compiled inline
306 *
307 * \param respath A string vector containing the valid resource search paths
308 * \param resource A resource entry to initialise
309 */
310static nserror
311init_pixbuf_resource(char **respath, struct nsgtk_resource_s *resource)
312{
313#ifdef WITH_BUILTIN_PIXBUF
314 if (strncmp(resource->name, "menu_cursor.png", resource->len) == 0) {
315 resource->path = (char *)&menu_cursor_pixdata[0];
316 resource->type = NSGTK_RESOURCE_INLINE;
317 NSLOG(netsurf, INFO, "Found builtin for %s", resource->name);
318 return NSERROR_OK;
319 }
320
321 if (strncmp(resource->name, "netsurf.xpm", resource->len) == 0) {
322 resource->path = (char *)&netsurf_pixdata[0];
323 resource->type = NSGTK_RESOURCE_INLINE;
324 NSLOG(netsurf, INFO, "Found builtin for %s", resource->name);
325 return NSERROR_OK;
326 }
327
328 if (strncmp(resource->name, "favicon.png", resource->len) == 0) {
329 resource->path = (char *)&favicon_pixdata[0];
330 resource->type = NSGTK_RESOURCE_INLINE;
331 NSLOG(netsurf, INFO, "Found builtin for %s", resource->name);
332 return NSERROR_OK;
333 }
334#endif
335 return init_resource(respath, resource);
336}
337
338/**
339 * locate a ui resource
340 *
341 * UI resources need their resource name changing to account for gtk versions
342 *
343 * \param respath A string vector containing the valid resource search paths
344 * \param ui_res A resource entry to initialise
345 */
346static nserror init_ui_resource(char **respath, struct nsgtk_resource_s *ui_res)
347{
348 int resnamelen;
349 char *resname;
350 struct nsgtk_resource_s resource;
351 nserror res;
352
353 resnamelen = ui_res->len + 10; /* allow for the expanded ui name */
354
355 resname = malloc(resnamelen);
356 if (resname == NULL) {
357 return NSERROR_NOMEM;
358 }
359 snprintf(resname, resnamelen, "%s.ui", ui_res->name);
360 resource.name = resname;
361 resource.len = ui_res->len;
362 resource.path = NULL;
363
364 res = init_resource(respath, &resource);
365
366 ui_res->path = resource.path;
367 ui_res->type = resource.type;
368
369 free(resname);
370
371 return res;
372}
373
374/**
375 * Find a resource entry by name.
376 *
377 * \param resname The resource name to match.
378 * \param resource The list of resources entries to search.
379 */
380static struct nsgtk_resource_s *
381find_resource_from_name(const char *resname, struct nsgtk_resource_s *resource)
382{
383 /* find resource from name */
384 while ((resource->name != NULL) &&
385 ((resname[0] != resource->name[0]) ||
386 (strncmp(resource->name, resname, resource->len) != 0))) {
387 resource++;
388 }
389 return resource;
390}
391
392#ifdef SHOW_GRESOURCE
393/**
394 * Debug dump of all resources compiled in via GResource.
395 */
396static void list_gresource(void)
397{
398 const char *nspath = "/org/netsurf";
399 char **reslist;
400 char **cur;
401 GError* gerror = NULL;
402 reslist = g_resources_enumerate_children(nspath,
403 G_RESOURCE_LOOKUP_FLAGS_NONE,
404 &gerror);
405 if (gerror) {
406 NSLOG(netsurf, INFO, "gerror %s", gerror->message);
407 g_error_free(gerror);
408
409 } else {
410 cur = reslist;
411 while (cur != NULL && *cur != NULL) {
412 NSLOG(netsurf, INFO, "gres %s", *cur);
413 cur++;
414 }
415 g_strfreev(reslist);
416 }
417}
418#endif
419
420/**
421 * Initialise UI resource table
422 *
423 */
424/* exported interface documented in gtk/resources.h */
426{
427 struct nsgtk_resource_s *resource;
428 nserror res;
429
430#ifdef SHOW_GRESOURCE
431 list_gresource();
432#endif
433
434 /* iterate the ui resource table and initialise all its members */
435 resource = &ui_resource[0];
436 while (resource->name != NULL) {
437 res = init_ui_resource(respath, resource);
438 if (res != NSERROR_OK) {
439 return res;
440 }
441 resource++;
442 }
443
444 /* iterate the pixbuf resource table and initialise all its members */
445 resource = &pixbuf_resource[0];
446 while (resource->name != NULL) {
447 res = init_pixbuf_resource(respath, resource);
448 if (res != NSERROR_OK) {
449 return res;
450 }
451 resource++;
452 }
453
454 /* iterate the direct resource table and initialise all its members */
455 resource = &direct_resource[0];
456 while (resource->name != NULL) {
457 res = init_direct_resource(respath, resource);
458 if (res != NSERROR_OK) {
459 return res;
460 }
461 resource++;
462 }
463
464 return NSERROR_OK;
465}
466
467
468/* exported interface documented in gtk/resources.h */
470nsgdk_pixbuf_new_from_resname(const char *resname, GdkPixbuf **pixbuf_out)
471{
472 struct nsgtk_resource_s *resource;
473 GdkPixbuf *new_pixbuf = NULL;
474 GError* error = NULL;
475
476 resource = find_resource_from_name(resname, &pixbuf_resource[0]);
477 if (resource->name == NULL) {
478 return NSERROR_NOT_FOUND;
479 }
480
481 switch (resource->type) {
483 new_pixbuf = gdk_pixbuf_new_from_file(resource->path, &error);
484 break;
485
487#ifdef WITH_GRESOURCE
488 new_pixbuf = gdk_pixbuf_new_from_resource(resource->path, &error);
489#endif
490 break;
491
493#ifdef WITH_BUILTIN_PIXBUF
494 new_pixbuf = gdk_pixbuf_new_from_inline(-1, (const guint8 *)resource->path, FALSE, &error);
495#endif
496 break;
497
499 /* pixbuf resources are not currently direct */
500 break;
501 }
502
503 if (new_pixbuf == NULL) {
504 if (error != NULL) {
505 NSLOG(netsurf, INFO,
506 "Unable to create pixbuf from file for %s with path %s \"%s\"",
507 resource->name,
508 resource->path,
509 error->message);
510 g_error_free(error);
511 } else {
512 NSLOG(netsurf, INFO,
513 "Unable to create pixbuf from file for %s with path %s",
514 resource->name,
515 resource->path);
516 }
517 return NSERROR_INIT_FAILED;
518 }
519 *pixbuf_out = new_pixbuf;
520
521 return NSERROR_OK;
522}
523
524/* exported interface documented in gtk/resources.h */
526nsgtk_builder_new_from_resname(const char *resname, GtkBuilder **builder_out)
527{
528 GtkBuilder *new_builder;
529 struct nsgtk_resource_s *ui_res;
530 GError* error = NULL;
531
532 ui_res = find_resource_from_name(resname, &ui_resource[0]);
533 if (ui_res->name == NULL) {
534 return NSERROR_NOT_FOUND;
535 }
536
537 new_builder = gtk_builder_new();
538
539 if (ui_res->type == NSGTK_RESOURCE_FILE) {
540 if (!gtk_builder_add_from_file(new_builder,
541 ui_res->path,
542 &error)) {
543 NSLOG(netsurf, INFO,
544 "Unable to add UI builder from file for %s with path %s \"%s\"",
545 ui_res->name,
546 ui_res->path,
547 error->message);
548 g_error_free(error);
549 g_object_unref(G_OBJECT(new_builder));
550 return NSERROR_INIT_FAILED;
551 }
552 } else {
553 if (!nsgtk_builder_add_from_resource(new_builder,
554 ui_res->path,
555 &error)) {
556 NSLOG(netsurf, INFO,
557 "Unable to add UI builder from resource for %s with path %s \"%s\"",
558 ui_res->name,
559 ui_res->path,
560 error->message);
561 g_error_free(error);
562 g_object_unref(G_OBJECT(new_builder));
563 return NSERROR_INIT_FAILED;
564 }
565 }
566
567 *builder_out = new_builder;
568
569 return NSERROR_OK;
570}
571
572/* exported interface documented in gtk/resources.h */
574nsgtk_data_from_resname(const char *resname,
575 const uint8_t ** data_out,
576 size_t *data_size_out)
577{
578#ifdef WITH_GRESOURCE
579 struct nsgtk_resource_s *resource;
580 GBytes *data;
581 const gchar *buffer;
582 gsize buffer_length;
583
584 resource = find_resource_from_name(resname, &direct_resource[0]);
585 if ((resource->name == NULL) ||
586 (resource->type != NSGTK_RESOURCE_DIRECT)) {
587 return NSERROR_NOT_FOUND;
588 }
589
590 data = (GBytes *)resource->path;
591
592 buffer_length = 0;
593 buffer = g_bytes_get_data(data, &buffer_length);
594
595 if (buffer == NULL) {
596 return NSERROR_NOMEM;
597 }
598
599 *data_out = (const uint8_t *)buffer;
600 *data_size_out = (size_t)buffer_length;
601
602 return NSERROR_OK;
603#else
604 /** \todo consider adding compiled inline resources for things
605 * other than pixbufs.
606 */
607 return NSERROR_NOT_FOUND;
608#endif
609}
610
611/* exported interface documented in gtk/resources.h */
613nsgtk_path_from_resname(const char *resname, const char **path_out)
614{
615 struct nsgtk_resource_s *resource;
616
617 resource = find_resource_from_name(resname, &direct_resource[0]);
618 if ((resource->name == NULL) ||
619 (resource->type != NSGTK_RESOURCE_FILE)) {
620 return NSERROR_NOT_FOUND;
621 }
622
623 *path_out = (const char *)resource->path;
624
625 return NSERROR_OK;
626}
static const __attribute__((used))
Definition: gui.c:358
static osspriteop_area * buffer
The buffer characteristics.
Definition: buffer.c:55
guint nsgtk_builder_add_from_resource(GtkBuilder *builder, const gchar *resource_path, GError **error)
Parses a resource file containing a GtkBuilder UI definition and merges it with the current contents ...
Definition: compat.c:646
Compatibility functions for older GTK versions (interface)
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_NOT_FOUND
Requested item not found.
Definition: errors.h:34
@ NSERROR_INIT_FAILED
Initialisation failed.
Definition: errors.h:38
@ NSERROR_NOMEM
Memory exhaustion.
Definition: errors.h:32
@ NSERROR_OK
No error.
Definition: errors.h:30
char * filepath_find(char **respathv, const char *filename)
Searches an array of resource paths for a file.
Definition: filepath.c:129
Utility routines to obtain paths to file resources.
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
GdkCursor * nsgtk_create_menu_cursor(void)
Creates a menu cursor from internal resources.
Definition: resources.c:148
nserror nsgtk_data_from_resname(const char *resname, const uint8_t **data_out, size_t *data_size_out)
Get direct pointer to resource data.
Definition: resources.c:574
nserror nsgtk_init_resources(char **respath)
Initialise UI resource table.
Definition: resources.c:425
nserror nsgtk_builder_new_from_resname(const char *resname, GtkBuilder **builder_out)
Create gtk builder object for the named ui resource.
Definition: resources.c:526
static nserror init_pixbuf_resource(char **respath, struct nsgtk_resource_s *resource)
locate a pixbuf resource
Definition: resources.c:311
static struct nsgtk_resource_s pixbuf_resource[]
resources that are used as pixbufs
Definition: resources.c:94
static struct nsgtk_resource_s ui_resource[]
resources that are used for gtk builder
Definition: resources.c:76
static struct nsgtk_resource_s direct_resource[]
resources that are used for direct data access
Definition: resources.c:123
nsgtk_resource_type_e
log contents of gresource /org/netsource
Definition: resources.c:58
@ NSGTK_RESOURCE_INLINE
entry is compiled in accessed by pointer
Definition: resources.c:62
@ NSGTK_RESOURCE_DIRECT
entry is a gresource accesed by gbytes
Definition: resources.c:61
@ NSGTK_RESOURCE_FILE
entry is a file on disc
Definition: resources.c:59
@ NSGTK_RESOURCE_GLIB
entry is a gresource accessed by path
Definition: resources.c:60
static nserror init_ui_resource(char **respath, struct nsgtk_resource_s *ui_res)
locate a ui resource
Definition: resources.c:346
nserror nsgdk_pixbuf_new_from_resname(const char *resname, GdkPixbuf **pixbuf_out)
Create gdk pixbuf for the named ui resource.
Definition: resources.c:470
nserror nsgtk_path_from_resname(const char *resname, const char **path_out)
Get path to resource data.
Definition: resources.c:613
static struct nsgtk_resource_s * find_resource_from_name(const char *resname, struct nsgtk_resource_s *resource)
Find a resource entry by name.
Definition: resources.c:381
#define RES_ENTRY(name)
Definition: resources.c:73
static nserror init_resource(char **respath, struct nsgtk_resource_s *resource)
locate a resource
Definition: resources.c:180
static nserror init_direct_resource(char **respath, struct nsgtk_resource_s *resource)
locate and setup a direct resource
Definition: resources.c:277
Interface to gtk builtin resource handling.
Interface to utility string handling.
resource entry
Definition: resources.c:66
const char * name
Definition: resources.c:67
unsigned int len
Definition: resources.c:68
enum nsgtk_resource_type_e type
Definition: resources.c:69