netsurf/gtk/resources.c

359 lines
9.1 KiB
C
Raw Normal View History

/*
* Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* \file
* Implementation of gtk builtin resource handling.
*
* This presents a unified interface to the rest of the codebase to
* obtain resources. Note this is not anything to do with the resource
* scheme handling beyond possibly providing the underlying data.
*
*/
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
#include "utils/log.h"
#include "utils/filepath.h"
#include "gtk/compat.h"
#include "gtk/resources.h"
#ifdef WITH_BUILTIN_PIXBUF
#ifdef __GNUC__
extern const guint8 menu_cursor_pixdata[] __attribute__ ((__aligned__ (4)));
#else
extern const guint8 menu_cursor_pixdata[];
#endif
#endif
enum nsgtk_resource_type_e {
NSGTK_RESOURCE_FILE,
NSGTK_RESOURCE_GLIB,
NSGTK_RESOURCE_INLINE,
};
struct nsgtk_resource_s {
const char *name;
unsigned int len;
enum nsgtk_resource_type_e type;
char *path;
};
static struct nsgtk_resource_s ui_resource[] = {
{ "netsurf", 7, NSGTK_RESOURCE_FILE, NULL },
{ "tabcontents", 10, NSGTK_RESOURCE_FILE, NULL },
{ "password", 8, NSGTK_RESOURCE_FILE, NULL },
{ "login", 5, NSGTK_RESOURCE_FILE, NULL },
{ "ssl", 3, NSGTK_RESOURCE_FILE, NULL },
{ "toolbar", 7, NSGTK_RESOURCE_FILE, NULL },
{ "downloads", 9, NSGTK_RESOURCE_FILE, NULL },
{ "history", 7, NSGTK_RESOURCE_FILE, NULL },
{ "options", 7, NSGTK_RESOURCE_FILE, NULL },
{ "hotlist", 7, NSGTK_RESOURCE_FILE, NULL },
{ "cookies", 7, NSGTK_RESOURCE_FILE, NULL },
{ "viewdata", 8, NSGTK_RESOURCE_FILE, NULL },
{ "warning", 7, NSGTK_RESOURCE_FILE, NULL },
{ NULL, 0, NSGTK_RESOURCE_FILE, NULL },
};
static struct nsgtk_resource_s gen_resource[] = {
{ "favicon.png", 11, NSGTK_RESOURCE_FILE, NULL },
{ "netsurf.xpm", 11, NSGTK_RESOURCE_FILE, NULL },
{ "menu_cursor.png", 15, NSGTK_RESOURCE_FILE, NULL },
{ NULL, 0, NSGTK_RESOURCE_FILE, NULL },
};
/* exported interface documented in gtk/resources.h */
GdkCursor *nsgtk_create_menu_cursor(void)
{
GdkCursor *cursor = NULL;
GdkPixbuf *pixbuf;
nserror res;
const char *resname = "menu_cursor.png";
res = nsgdk_pixbuf_new_from_resname(resname, &pixbuf);
if (res == NSERROR_OK) {
cursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(),
pixbuf, 0, 3);
g_object_unref(pixbuf);
}
return cursor;
}
/*
* locate a resource
*
* The way GTK accesses resource files has changed greatly between
* releases. This initilises the interface that hides all the
* implementation details from the rest of the code.
*
* If the GResource is not enabled or the item cannot be found in the
* compiled in resources the files will be loaded directly from disc
* instead.
*
* \param respath A string vector containing the valid resource search paths
* \param ui_res A resource entry to initialise
*/
static nserror
init_resource(char **respath, struct nsgtk_resource_s *resource)
{
int resnamelen;
char *resname;
#ifdef WITH_BUILTIN_PIXBUF
if (strncmp(resource->name, "menu_cursor.png", resource->len) == 0) {
resource->path = (char *)&menu_cursor_pixdata[0];
resource->type = NSGTK_RESOURCE_INLINE;
LOG("Found builtin for %s", resource->name);
return NSERROR_OK;
}
#endif
#ifdef WITH_GRESOURCE
gboolean present;
resnamelen = snprintf(NULL, 0, "/org/netsurf/%s", resource->name);
resname = malloc(resnamelen + 1);
if (resname == NULL) {
return NSERROR_NOMEM;
}
snprintf(resname, resnamelen + 1, "/org/netsurf/%s", resource->name);
present = g_resources_get_info(resname,
G_RESOURCE_LOOKUP_FLAGS_NONE,
NULL, NULL, NULL);
if (present == TRUE) {
/* found an entry in the resources */
resource->path = resname;
resource->type = NSGTK_RESOURCE_GLIB;
LOG("Found gresource path %s", resource->path);
return NSERROR_OK;
}
LOG("gresource \"%s\" not found", resname);
free(resname);
#endif
resname = filepath_find(respath, resource->name);
if (resname == NULL) {
LOG("Unable to find resource %s on resource path",
resource->name);
return NSERROR_NOT_FOUND;
}
/* found an entry on the path */
resource->path = resname;
resource->type = NSGTK_RESOURCE_FILE;
LOG("Found file resource path %s", resource->path);
return NSERROR_OK;
}
/*
* locate a ui resource
*
* UI resources need their resource name changing to account for gtk versions
*
* \param respath A string vector containing the valid resource search paths
* \param ui_res A resource entry to initialise
*/
static nserror init_ui_resource(char **respath, struct nsgtk_resource_s *ui_res)
{
#if GTK_CHECK_VERSION(3,0,0)
int gtkv = 3;
#else
int gtkv = 2;
#endif
int resnamelen;
char *resname;
struct nsgtk_resource_s resource;
nserror res;
resnamelen = ui_res->len + 10; /* allow for the expanded ui name */
resname = malloc(resnamelen);
if (resname == NULL) {
return NSERROR_NOMEM;
}
snprintf(resname, resnamelen, "%s.gtk%d.ui", ui_res->name, gtkv);
resource.name = resname;
resource.len = ui_res->len;
resource.path = NULL;
res = init_resource(respath, &resource);
ui_res->path = resource.path;
ui_res->type = resource.type;
free(resname);
return res;
}
#define SHOW_GRESOURCE
/**
* Initialise UI resource table
*
*/
nserror nsgtk_init_resources(char **respath)
{
struct nsgtk_resource_s *resource;
nserror res;
#ifdef SHOW_GRESOURCE
const char *nspath = "/org/netsurf";
char **reslist;
char **cur;
GError* gerror = NULL;
reslist = g_resources_enumerate_children(nspath,G_RESOURCE_LOOKUP_FLAGS_NONE, &gerror);
if (gerror) {
LOG("gerror %s", gerror->message);
g_error_free(gerror);
} else {
cur = reslist;
while (cur != NULL && *cur != NULL) {
LOG("gres %s", *cur);
cur++;
}
g_strfreev(reslist);
}
#endif
/* walk the ui resource table and initialise all its members */
resource = &ui_resource[0];
while (resource->name != NULL) {
res = init_ui_resource(respath, resource);
if (res != NSERROR_OK) {
return res;
}
resource++;
}
/* walk the general resource table and initialise all its members */
resource = &gen_resource[0];
while (resource->name != NULL) {
res = init_resource(respath, resource);
if (res != NSERROR_OK) {
return res;
}
resource++;
}
return NSERROR_OK;
}
static struct nsgtk_resource_s *
find_resource_from_name(const char *resname, struct nsgtk_resource_s *resource)
{
/* find resource from name */
while ((resource->name != NULL) &&
((resname[0] != resource->name[0]) ||
(strncmp(resource->name, resname, resource->len) != 0))) {
resource++;
}
return resource;
}
/* exported interface documented in gtk/resources.h */
nserror
nsgdk_pixbuf_new_from_resname(const char *resname, GdkPixbuf **pixbuf_out)
{
struct nsgtk_resource_s *resource;
GdkPixbuf *new_pixbuf = NULL;
GError* error = NULL;
resource = find_resource_from_name(resname, &gen_resource[0]);
if (resource->name == NULL) {
return NSERROR_NOT_FOUND;
}
switch (resource->type) {
case NSGTK_RESOURCE_FILE:
new_pixbuf = gdk_pixbuf_new_from_file(resource->path, &error);
break;
case NSGTK_RESOURCE_GLIB:
new_pixbuf = gdk_pixbuf_new_from_resource(resource->path, &error);
break;
case NSGTK_RESOURCE_INLINE:
#ifdef WITH_BUILTIN_PIXBUF
new_pixbuf = gdk_pixbuf_new_from_inline(-1, (const guint8 *)resource->path, FALSE, NULL);
#endif
break;
}
if (new_pixbuf == NULL) {
LOG("Unable to create pixbuf from file for %s with path %s \"%s\"",
resource->name, resource->path, error->message);
g_error_free(error);
return NSERROR_INIT_FAILED;
}
*pixbuf_out = new_pixbuf;
return NSERROR_OK;
}
/* exported interface documented in gtk/resources.h */
nserror
nsgtk_builder_new_from_resname(const char *resname, GtkBuilder **builder_out)
{
GtkBuilder *new_builder;
struct nsgtk_resource_s *ui_res;
GError* error = NULL;
ui_res = find_resource_from_name(resname, &ui_resource[0]);
if (ui_res->name == NULL) {
return NSERROR_NOT_FOUND;
}
new_builder = gtk_builder_new();
if (ui_res->type == NSGTK_RESOURCE_FILE) {
if (!gtk_builder_add_from_file(new_builder,
ui_res->path,
&error)) {
LOG("Unable to add UI builder from file for %s with path %s \"%s\"",
ui_res->name, ui_res->path, error->message);
g_error_free(error);
g_object_unref(G_OBJECT(new_builder));
return NSERROR_INIT_FAILED;
}
} else {
if (!nsgtk_builder_add_from_resource(new_builder,
ui_res->path,
&error)) {
LOG("Unable to add UI builder from resource for %s with path %s \"%s\"",
ui_res->name, ui_res->path, error->message);
g_error_free(error);
g_object_unref(G_OBJECT(new_builder));
return NSERROR_INIT_FAILED;
}
}
*builder_out = new_builder;
return NSERROR_OK;
}