diff options
Diffstat (limited to 'src/libr-gtk.c')
-rw-r--r-- | src/libr-gtk.c | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/src/libr-gtk.c b/src/libr-gtk.c new file mode 100644 index 0000000..f746aa8 --- /dev/null +++ b/src/libr-gtk.c @@ -0,0 +1,443 @@ +/* + * + * Copyright (c) 2008-2009 Erich Hoover + * + * libr GTK support - Convenience functions for using resources in GTK applications + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This program 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * To provide feedback, report bugs, or otherwise contact me: + * ehoover at mines dot edu + * + */ + +/* Include compile-time parameters */ +#include "config.h" + +#include "libr.h" +#include "libr-gtk.h" +#include "libr-icons.h" +#include "tempfiles.h" + +/* For loading GTK/GDK images */ +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <glib.h> + +/* For loading GLADE files */ +#include <glade/glade.h> + +/* For loading GTK+ Builder files */ +#include <gtk/gtk.h> + +/* For malloc/free */ +#include <stdlib.h> + +/* For string handling */ +#include <string.h> + +typedef gchar * (*GladeFileCallback)(GladeXML *, const gchar *, guint *); +GladeFileCallback glade_set_file_callback(GladeFileCallback callback, gpointer user_data); + +/* Use weak binding for all glade and GTK+ requirements */ +#pragma weak glade_set_file_callback + +#pragma weak gtk_window_set_default_icon_list +#pragma weak gdk_pixbuf_loader_get_pixbuf +#pragma weak gtk_builder_add_from_string +#pragma weak gdk_pixbuf_loader_set_size +#pragma weak g_type_check_instance_cast +#pragma weak gtk_builder_add_from_file +#pragma weak glade_xml_new_from_buffer +#pragma weak gdk_pixbuf_loader_write +#pragma weak gdk_pixbuf_loader_close +#pragma weak gdk_pixbuf_loader_new +#pragma weak g_signal_connect_data +#pragma weak g_signal_connect +#pragma weak gtk_builder_new +#pragma weak g_object_unref +#pragma weak glade_xml_new +#pragma weak g_list_append +#pragma weak glade_init +#pragma weak gtk_init +#pragma weak g_free + +#define GLADE_SECTION ".glade" +#define BUILDER_SECTION ".ui" + +/* + * Handle the resource request from libglade + */ +gchar *libr_glade_read_resource(GladeXML *gladefile, const gchar *filename, guint *size, gpointer user_data) +{ + return libr_malloc((libr_file *) user_data, (char *) filename, (size_t *) size); +} + +/* + * Handle the resource request from GtkBuilder + */ +gboolean libr_gtk_read_resource(GtkBuilder *builder, const gchar *filename, gchar **data, gsize *size, GError **error, gpointer user_data) +{ + if(data == NULL) + return FALSE; + *data = libr_malloc((libr_file *) user_data, (char *) filename, (size_t *) size); + if(*data == NULL) + return FALSE; + return TRUE; +} + +/* + * Load the libglade resource appropriately for the currently installed version + * (AKA, hurray hacks!) + */ +GladeXML *libr_new_glade(libr_file *handle, char *gladefile, size_t gladefile_size) +{ + if(glade_set_file_callback) /* The not-yet (ever?) existing way */ + { + /* Register a callback for libglade to load our resources */ + if(glade_set_file_callback((GladeFileCallback) libr_glade_read_resource, handle) != NULL) + printf("warning: over-wrote an application callback!\n"); + /* Initialize libglade almost as usual, just use a buffer instead of a file */ + return glade_xml_new_from_buffer(gladefile, gladefile_size, NULL, NULL); + } + else /* The hacky way */ + { + char *glade_file[PATH_MAX]; + GladeXML *ret = NULL; + char *temp_folder; + + temp_folder = libr_extract_resources(handle); + if(temp_folder == NULL) + return NULL; + strcpy((char*)glade_file, temp_folder); + strcat((char*)glade_file, "/"); + strcat((char*)glade_file, GLADE_SECTION); + ret = glade_xml_new((char*)glade_file, NULL, NULL); + if(ret == NULL) + cleanup_folder(temp_folder); + else + register_folder_cleanup(temp_folder); + return ret; + } +} + +/* + * Load the GtkBuilder resource appropriately for the currently installed version + * (AKA, hurray hacks!) + */ +int libr_new_builder(libr_file *handle, char *builderfile, size_t builderfile_size, GtkBuilder *builder) +{ + /* Register a callback for GtkBuilder to load our resources */ + if(g_signal_connect(builder, "load-resource", (GCallback) libr_gtk_read_resource, handle)) + { + /* Initialize GtkBuilder almost as usual, just use a buffer instead of a file */ + if(gtk_builder_add_from_string(builder, builderfile, builderfile_size, NULL) == 0) + return false; + return true; + } + else /* The hacky way */ + { + char *builder_file[PATH_MAX]; + char *temp_folder; + int ret = false; + + temp_folder = libr_extract_resources(handle); + if(temp_folder == NULL) + return false; + strcpy((char*)builder_file, temp_folder); + strcat((char*)builder_file, "/"); + strcat((char*)builder_file, BUILDER_SECTION); + ret = gtk_builder_add_from_file(builder, (char*)builder_file, NULL); + if(ret == 0) + cleanup_folder(temp_folder); + else + register_folder_cleanup(temp_folder); + g_free(temp_folder); + return (ret != 0); + } +} + +/* + * Return a GTK icon list + */ +EXPORT_FN IconList *libr_gtk_iconlist(libr_file *handle) +{ + int sizes[] = {16, 32, 48, 96, 128}; + IconList *icons = NULL; + GdkPixbuf *icon = NULL; + int sizes_len = 5, i; + + if(handle == NULL) + { + /* Must pass a file handle to obtain the icons from */ + return NULL; + } + if(gtk_init == NULL) + { + /* GTK+ was not linked with the application */ + return false; + } + /* Go through the list of GTK "required" image sizes and build the icons */ + for(i=0;i<sizes_len;i++) + { + libr_icon *icon_handle = libr_icon_geticon_bysize(handle, sizes[i]); + GdkPixbufLoader *stream = gdk_pixbuf_loader_new(); + char *iconfile = NULL; + size_t iconfile_size; + + if(icon_handle == NULL) + { + /* Failed to find an icon */ + printf("Failed to find an icon\n"); + continue; + } + iconfile = libr_icon_malloc(icon_handle, &iconfile_size); + if(iconfile == NULL) + { + /* Failed to obtain embedded icon */ + continue; + } + libr_icon_close(icon_handle); + /* TODO: Use the "size-prepared" signal to properly scale the width and height +void user_function (GdkPixbufLoader *loader, gint width, gint height, gpointer user_data) + */ + gdk_pixbuf_loader_set_size(stream, sizes[i], sizes[i]); + if(!gdk_pixbuf_loader_write(stream, (unsigned char *)iconfile, iconfile_size, NULL)) + { + /* Failed to process image */ + continue; + } + if(!gdk_pixbuf_loader_close(stream, NULL)) + { + /* Failed to create image */ + continue; + } + icon = gdk_pixbuf_loader_get_pixbuf(stream); + if(icon == NULL) + { + /* Failed to convert image to pixbuf */ + continue; + } + icons = g_list_append(icons, icon); + } + return icons; +} + +/* + * Shared GtkBuilder resource loading + */ +GtkBuilder *libr_gtk_load_internal(libr_file *handle, char *resource_name) +{ + GtkBuilder *builder = NULL; + size_t builder_length; + char *builder_data; + + /* Obtain the GtkBuilder XML definition */ + builder_data = libr_malloc(handle, resource_name, &builder_length); + if(builder_data == NULL) + { + /* Failed to obtain embedded GtkBuilder definition file */ + goto failed; + } + /* Setup the GtkBuilder environment */ + builder = gtk_builder_new(); + if(builder == NULL) + goto failed; + if(!libr_new_builder(handle, builder_data, builder_length, builder)) + { + /* Failed to build interface from resource file */ + g_object_unref(G_OBJECT(builder)); + goto failed; + } +failed: + free(builder_data); + return builder; +} + +/* + * Load the requested GtkBuilder resource and any applicable icons + */ +EXPORT_FN int libr_gtk_load(BuilderHandle **gtk_ret, char *resource_name) +{ + libr_file *handle; + int ret = false; + + if(gtk_ret == NULL) + { + /* Why on earth would you call this without obtaining the handle to the resource? */ + return false; + } + if(gtk_builder_new == NULL) + { + /* GtkBuilder was not linked with the application */ + return false; + } + /* Obtain the handle to the executable */ + if((handle = libr_open(NULL, LIBR_READ)) == NULL) + { + /* "Failed to open this executable (%s) for resources", progname() */ + return false; + } + register_internal_handle(handle); + *gtk_ret = libr_gtk_load_internal(handle, resource_name); + if(*gtk_ret == NULL) + goto failed; + ret = true; +failed: + if(!ret) + libr_close(handle); + return ret; +} + +/* + * Automatically load the ".ui" GtkBuilder resource and any applicable icons + */ +EXPORT_FN int libr_gtk_autoload(BuilderHandle **gtk_ret, IconList **icons_ret, int set_default_icon) +{ + GList *icons = NULL; + libr_file *handle; + int ret = false; + + if(gtk_ret == NULL) + { + /* Why on earth would you call this without obtaining the handle to the resource? */ + return false; + } + if(gtk_builder_new == NULL) + { + /* GtkBuilder was not linked with the application */ + return false; + } + /* Obtain the handle to the executable */ + if((handle = libr_open(NULL, LIBR_READ)) == NULL) + { + /* "Failed to open this executable (%s) for resources", progname() */ + return false; + } + register_internal_handle(handle); + /* Obtain the icons from the ELF binary */ + icons = libr_gtk_iconlist(handle); + /* Set the embedded icons as the default icon list (if requested) */ + if(icons != NULL && set_default_icon) + gtk_window_set_default_icon_list(icons); + *gtk_ret = libr_gtk_load_internal(handle, BUILDER_SECTION); + if(*gtk_ret == NULL) + goto failed; + if(icons_ret) + *icons_ret = icons; + ret = true; +failed: + if(!ret) + libr_close(handle); + return ret; +} + +/* + * Shared libglade resource loading + */ +GladeXML *libr_glade_load_internal(libr_file *handle, char *resource_name) +{ + GladeXML *glade = NULL; + size_t glade_length; + char *glade_data; + + /* Obtain the GLADE XML definition */ + glade_data = libr_malloc(handle, resource_name, &glade_length); + if(glade_data == NULL) + { + /* Failed to obtain embedded glade file */ + goto failed; + } + /* Initialize libglade appropriate for the available version */ + glade = libr_new_glade(handle, glade_data, glade_length); + if(glade == NULL) + { + /* Failed to initialize embedded glade file */ + goto failed; + } +failed: + free(glade_data); + return glade; +} + +/* + * Load the requested libglade resource and any applicable icons + */ +EXPORT_FN int libr_glade_load(GladeHandle **glade_ret, char *resource_name) +{ + libr_file *handle; + int ret = false; + + if(glade_ret == NULL) + { + /* Why on earth would you call this without obtaining the handle to the resource? */ + return false; + } + if(glade_init == NULL) + { + /* libglade was not linked with the application */ + return false; + } + /* Obtain the handle to the executable */ + if((handle = libr_open(NULL, LIBR_READ)) == NULL) + { + /* "Failed to open this executable (%s) for resources", progname() */ + return false; + } + register_internal_handle(handle); + *glade_ret = libr_glade_load_internal(handle, resource_name); + if(*glade_ret == NULL) + goto failed; + ret = true; +failed: + if(!ret) + libr_close(handle); + return ret; +} + +/* + * Automatically load the ".glade" resource and any applicable icons + */ +EXPORT_FN int libr_glade_autoload(GladeHandle **glade_ret, IconList **icons_ret, int set_default_icon) +{ + libr_file *handle = NULL; + GList *icons = NULL; + + if(glade_ret == NULL) + { + /* Why on earth would you call this without obtaining the handle to the resource? */ + return false; + } + if(glade_init == NULL) + { + /* libglade was not linked with the application */ + return false; + } + /* Obtain the handle to the executable */ + if((handle = libr_open(NULL, LIBR_READ)) == NULL) + { + /* "Failed to open this executable (%s) for resources", progname() */ + return false; + } + register_internal_handle(handle); + icons = libr_gtk_iconlist(handle); + /* Set the embedded icons as the default icon list (if requested) */ + if(icons != NULL && set_default_icon) + gtk_window_set_default_icon_list(icons); + /* Return the libglade and icon handles for the application */ + *glade_ret = libr_glade_load_internal(handle, GLADE_SECTION); + if(icons_ret) + *icons_ret = icons; + return true; +} |