/* * Copyright 2005 James Bursa * * 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 . */ /** \file * Theme auto-installing. */ #include #include #include #include #include "utils/nsoption.h" #include "utils/log.h" #include "utils/messages.h" #include "netsurf/content.h" #include "content/hlcache.h" #include "desktop/theme.h" #include "riscos/dialog.h" #include "riscos/gui.h" #include "riscos/theme.h" #include "riscos/wimp.h" #include "riscos/wimp_event.h" static struct hlcache_handle *theme_install_content = NULL; static struct theme_descriptor theme_install_descriptor; wimp_w dialog_theme_install; static void theme_install_close(wimp_w w); static nserror theme_install_callback(struct hlcache_handle *handle, const hlcache_event *event, void *pw); /** * Handle a CONTENT_THEME that has started loading. */ void theme_install_start(struct hlcache_handle *c) { assert(c != NULL); assert(content_get_type(c) == CONTENT_THEME); if (ro_gui_dialog_open_top(dialog_theme_install, NULL, 0, 0)) { ro_warn_user("ThemeInstActive", 0); return; } /* stop theme sitting in memory cache */ content_invalidate_reuse_data(c); hlcache_handle_replace_callback(c, theme_install_callback, NULL); ro_gui_set_icon_string(dialog_theme_install, ICON_THEME_INSTALL_MESSAGE, messages_get("ThemeInstDown"), true); ro_gui_set_icon_shaded_state(dialog_theme_install, ICON_THEME_INSTALL_INSTALL, true); ro_gui_wimp_event_register_close_window(dialog_theme_install, theme_install_close); } /** * Fill in theme_install_descriptor from received theme data. * * \param source_data received data * \param source_size size of data * \return true if data is a correct theme, false on error * * If the data is a correct theme, theme_install_descriptor is filled in. */ static bool theme_install_read(const uint8_t *source_data, size_t source_size) { const void *data = source_data; if (source_size < sizeof(struct theme_file_header)) return false; if (!ro_gui_theme_read_file_header(&theme_install_descriptor, (struct theme_file_header *) data)) return false; if (source_size - sizeof(struct theme_file_header) != theme_install_descriptor.compressed_size) return false; return true; } /** * Callback for fetchcache() for theme install fetches. */ nserror theme_install_callback(struct hlcache_handle *handle, const hlcache_event *event, void *pw) { switch (event->type) { case CONTENT_MSG_DONE: { const uint8_t *source_data; size_t source_size; int author_indent = 0; char buffer[256]; theme_install_content = handle; source_data = content_get_source_data(handle, &source_size); if (!theme_install_read(source_data, source_size)) { ro_warn_user("ThemeInvalid", 0); theme_install_close(dialog_theme_install); break; } /* remove '© ' from the start of the data */ if (theme_install_descriptor.author[0] == '©') author_indent++; while (theme_install_descriptor.author[author_indent] == ' ') author_indent++; snprintf(buffer, sizeof buffer, messages_get("ThemeInstall"), theme_install_descriptor.name, &theme_install_descriptor.author[author_indent]); buffer[sizeof buffer - 1] = '\0'; ro_gui_set_icon_string(dialog_theme_install, ICON_THEME_INSTALL_MESSAGE, buffer, true); ro_gui_set_icon_shaded_state(dialog_theme_install, ICON_THEME_INSTALL_INSTALL, false); } break; case CONTENT_MSG_ERROR: theme_install_close(dialog_theme_install); ro_warn_user(event->data.error, 0); break; default: break; } return NSERROR_OK; } /** * Install the downloaded theme. * * \param w the theme install window handle */ bool ro_gui_theme_install_apply(wimp_w w) { char theme_save[256]; char *theme_file; struct theme_descriptor *theme_install; os_error *error; char *fix; const uint8_t *source_data; size_t source_size; assert(theme_install_content); /* convert spaces to hard spaces */ theme_file = strdup(theme_install_descriptor.name); if (!theme_file) { NSLOG(netsurf, INFO, "malloc failed"); ro_warn_user("NoMemory", 0); return false; } for (fix = theme_file; *fix != '\0'; fix++) if (*fix == ' ') *fix = 160; /* hard space */ /* simply overwrite previous theme versions */ snprintf(theme_save, sizeof theme_save, "%s.%s", nsoption_charp(theme_save), theme_file); theme_save[sizeof theme_save - 1] = '\0'; source_data = content_get_source_data(theme_install_content, &source_size); error = xosfile_save_stamped(theme_save, 0xffd, (byte *) source_data, (byte *) source_data + source_size); if (error) { NSLOG(netsurf, INFO, "xosfile_save_stamped: 0x%x: %s", error->errnum, error->errmess); ro_warn_user("ThemeInstallErr", 0); free(theme_file); return false; } /* apply the new theme */ ro_gui_theme_get_available(); theme_install = ro_gui_theme_find(theme_file); if (!theme_install || !ro_gui_theme_apply(theme_install)) { ro_warn_user("ThemeApplyErr", 0); } else { nsoption_set_charp(theme, strdup(theme_install->leafname)); } free(theme_file); ro_gui_save_options(); return true; } /** * Close the theme installer and free resources. */ void theme_install_close(wimp_w w) { if (theme_install_content) hlcache_handle_release(theme_install_content); theme_install_content = NULL; }