From 403f12872d55a71b04287ed828be0c63be19e856 Mon Sep 17 00:00:00 2001 From: Richard Wilson Date: Mon, 4 Oct 2004 23:54:42 +0000 Subject: [project @ 2004-10-04 23:54:42 by rjw] Moved GIF file reading to image/, optimisation of plotting for GIFs, JNGs, PNGs and JPEGs, initial work for toolbar customisation. Possibly some other things too. svn path=/import/netsurf/; revision=1301 --- riscos/bitmap.c | 46 ++- riscos/bitmap.h | 1 + riscos/gif.c | 242 ------------ riscos/gif.h | 35 -- riscos/gifread.c | 1038 ---------------------------------------------------- riscos/gifread.h | 98 ----- riscos/gui.h | 11 +- riscos/hotlist.c | 12 +- riscos/menus.c | 248 ++++++++++++- riscos/options.h | 3 - riscos/save_draw.c | 4 +- riscos/theme.c | 83 ++++- riscos/theme.h | 15 +- riscos/window.c | 11 +- 14 files changed, 380 insertions(+), 1467 deletions(-) delete mode 100644 riscos/gif.c delete mode 100644 riscos/gif.h delete mode 100644 riscos/gifread.c delete mode 100644 riscos/gifread.h (limited to 'riscos') diff --git a/riscos/bitmap.c b/riscos/bitmap.c index 892aed3b6..b758e82e7 100644 --- a/riscos/bitmap.c +++ b/riscos/bitmap.c @@ -39,8 +39,11 @@ struct bitmap *bitmap_create(int width, int height) osspriteop_area *sprite_area; osspriteop_header *sprite; + if ((width == 0) || (height == 0)) + return NULL; + area_size = 16 + 44 + width * height * 4; - bitmap = calloc(area_size, 1); + bitmap = calloc(sizeof(struct bitmap) + area_size, 1); if (!bitmap) return NULL; @@ -54,7 +57,7 @@ struct bitmap *bitmap_create(int width, int height) /* sprite control block */ sprite = (osspriteop_header *) (sprite_area + 1); sprite->size = area_size - 16; - memset(sprite->name, 0x00, 12); +/* memset(sprite->name, 0x00, 12); */ strncpy(sprite->name, "bitmap", 12); sprite->width = width - 1; sprite->height = height - 1; @@ -67,6 +70,40 @@ struct bitmap *bitmap_create(int width, int height) } +/** + * Sets whether a bitmap should be plotted opaque + * + * \param bitmap a bitmap, as returned by bitmap_create() + * \param opaque whether the bitmap should be plotted opaque + */ +void bitmap_set_opaque(struct bitmap *bitmap, bool opaque) +{ + assert(bitmap); + bitmap->opaque = opaque; +} + + +/** + * Tests whether a bitmap has an opaque alpha channel + * + * \param bitmap a bitmap, as returned by bitmap_create() + * \return whether the bitmap is opaque + */ +bool bitmap_test_opaque(struct bitmap *bitmap) +{ + assert(bitmap); + char *sprite = bitmap_get_buffer(bitmap); + unsigned int width = bitmap_get_rowstride(bitmap); + osspriteop_header *sprite_header = + (osspriteop_header *) (&(bitmap->sprite_area) + 1); + unsigned int height = (sprite_header->height + 1); + unsigned int size = width * height; + for (unsigned int i = 3; i < size; i += 4) + if (sprite[i] != 0xff) + return false; + return true; +} + /** * Return a pointer to the pixel data in a bitmap. * @@ -80,7 +117,7 @@ struct bitmap *bitmap_create(int width, int height) char *bitmap_get_buffer(struct bitmap *bitmap) { assert(bitmap); - return ((char *) bitmap) + 16 + 44; + return ((char *) (&(bitmap->sprite_area))) + 16 + 44; } @@ -124,7 +161,8 @@ bool bitmap_redraw(struct content *c, int x, int y, { return image_redraw(&(c->bitmap->sprite_area), x, y, width, height, c->width * 2, c->height * 2, background_colour, - false, false, IMAGE_PLOT_TINCT_ALPHA); + false, false, ((c->bitmap->opaque) ? + IMAGE_PLOT_TINCT_OPAQUE : IMAGE_PLOT_TINCT_ALPHA)); } diff --git a/riscos/bitmap.h b/riscos/bitmap.h index 4c8545cb4..17ff16340 100644 --- a/riscos/bitmap.h +++ b/riscos/bitmap.h @@ -11,6 +11,7 @@ struct osspriteop_area; struct bitmap { + bool opaque; osspriteop_area sprite_area; }; diff --git a/riscos/gif.c b/riscos/gif.c deleted file mode 100644 index 3f450b209..000000000 --- a/riscos/gif.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * This file is part of NetSurf, http://netsurf.sourceforge.net/ - * Licensed under the GNU General Public License, - * http://www.opensource.org/licenses/gpl-license - * Copyright 2003 John M Bell - * Copyright 2004 Richard Wilson - */ - -#include -#include -#include -#include -#include "oslib/osfile.h" -#include "oslib/osspriteop.h" -#include "netsurf/utils/config.h" -#include "netsurf/content/content.h" -#include "netsurf/riscos/gif.h" -#include "netsurf/riscos/gifread.h" -#include "netsurf/riscos/gui.h" -#include "netsurf/riscos/image.h" -#include "netsurf/riscos/options.h" -#include "netsurf/utils/log.h" -#include "netsurf/utils/messages.h" -#include "netsurf/utils/utils.h" - - -/* GIF FUNCTIONALITY - ================= - - All GIFs are dynamically decompressed using the routines that gifread.c - provides. Whilst this allows support for progressive decoding, it is - not implemented here as NetSurf currently does not provide such support. - - [rjw] - Sun 4th April 2004 -*/ - -#ifdef WITH_GIF - -static void nsgif_animate(void *p); - - -bool nsgif_create(struct content *c, const char *params[]) { - union content_msg_data msg_data; - /* Initialise our data structure - */ - c->data.gif.gif = calloc(sizeof(gif_animation), 1); - if (!c->data.gif.gif) { - msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - warn_user("NoMemory", 0); - return false; - } - c->data.gif.current_frame = 0; - return true; -} - - -bool nsgif_convert(struct content *c, int iwidth, int iheight) { - int res; - struct gif_animation *gif; - union content_msg_data msg_data; - - /* Create our animation - */ - gif = c->data.gif.gif; - gif->gif_data = c->source_data; - gif->buffer_size = c->source_size; - gif->buffer_position = 0; // Paranoid - - /* Initialise the GIF - */ - res = gif_initialise(gif); - switch (res) { - case GIF_INSUFFICIENT_MEMORY: - msg_data.error = messages_get("NoMemory"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - warn_user("NoMemory", 0); - return false; - case GIF_INSUFFICIENT_DATA: - case GIF_DATA_ERROR: - msg_data.error = messages_get("BadGIF"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; - } - - /* Abort on bad GIFs - */ - if ((gif->frame_count_partial == 0) || (gif->width == 0) || - (gif->height == 0)) { - msg_data.error = messages_get("BadGIF"); - content_broadcast(c, CONTENT_MSG_ERROR, msg_data); - return false; - } - - /* Store our content width and description - */ - c->width = gif->width; - c->height = gif->height; - c->title = malloc(100); - if (c->title) { - snprintf(c->title, 100, messages_get("GIFTitle"), c->width, c->height, c->source_size); - } - c->size += (gif->width * gif->height * 4) + 16 + 44 + 100; - - /* Initialise the first frame so if we try to use the image data directly prior to - a plot we get some sensible data - */ - gif_decode_frame(c->data.gif.gif, 0); - - /* Schedule the animation if we have one - */ - if (gif->frame_count > 1) { - schedule(gif->frames[0].frame_delay, nsgif_animate, c); - } - - /* Exit as a success - */ - c->status = CONTENT_STATUS_DONE; - return true; -} - - -bool nsgif_redraw(struct content *c, int x, int y, - int width, int height, - int clip_x0, int clip_y0, int clip_x1, int clip_y1, - float scale, unsigned long background_colour) { - - int previous_frame; - unsigned int frame, current_frame; - - /* If we have a gui_window then we work from there, if not we use the global - settings. We default to the first image if we don't have a GUI as we are - drawing a thumbnail unless something has gone very wrong somewhere else. - */ - if (ro_gui_current_redraw_gui) { - if (ro_gui_current_redraw_gui->option.animate_images) { - current_frame = c->data.gif.current_frame; - } else { - current_frame = 0; - } - } else { - if (c->data.gif.gif->loop_count == 0) { - current_frame = 0; - } else { - if (c->data.gif.gif->frame_count > 1) { - current_frame = c->data.gif.gif->frame_count - 1; - } else { - current_frame = 0; - } - } - } - - /* Decode from the last frame to the current frame - */ - if (current_frame < c->data.gif.gif->decoded_frame) { - previous_frame = 0; - } else { - previous_frame = c->data.gif.gif->decoded_frame + 1; - - } - for (frame = previous_frame; frame <= current_frame; frame++) { - gif_decode_frame(c->data.gif.gif, frame); - } - - return image_redraw(c->data.gif.gif->frame_image, x, y, width, - height, c->width * 2, c->height * 2, - background_colour, false, false, - IMAGE_PLOT_TINCT_ALPHA); -} - - -void nsgif_destroy(struct content *c) -{ - /* Free all the associated memory buffers - */ - schedule_remove(nsgif_animate, c); - gif_finalise(c->data.gif.gif); - free(c->data.gif.gif); -} - - -/** Performs any necessary animation. - - @param c The content to animate -*/ -void nsgif_animate(void *p) -{ - struct content *c = p; - union content_msg_data data; - int delay; - - /* Advance by a frame, updating the loop count accordingly - */ - c->data.gif.current_frame++; - if (c->data.gif.current_frame == c->data.gif.gif->frame_count) { - c->data.gif.current_frame = 0; - - /* A loop count of 0 has a special meaning of infinite - */ - if (c->data.gif.gif->loop_count != 0) { - c->data.gif.gif->loop_count--; - if (c->data.gif.gif->loop_count == 0) { - c->data.gif.current_frame = c->data.gif.gif->frame_count - 1; - c->data.gif.gif->loop_count = -1; - } - } - } - - - /* Continue animating if we should - */ - if (c->data.gif.gif->loop_count >= 0) { - delay = c->data.gif.gif->frames[c->data.gif.current_frame].frame_delay; - if (delay < option_minimum_gif_delay) delay = option_minimum_gif_delay; - schedule(delay, nsgif_animate, c); - } - - /* area within gif to redraw */ - data.redraw.x = c->data.gif.gif->frames[c->data.gif.current_frame].redraw_x; - data.redraw.y = c->data.gif.gif->frames[c->data.gif.current_frame].redraw_y; - data.redraw.width = c->data.gif.gif->frames[c->data.gif.current_frame].redraw_width; - data.redraw.height = c->data.gif.gif->frames[c->data.gif.current_frame].redraw_height; - - /* redraw background (true) or plot on top (false) */ - if (c->data.gif.current_frame > 0) { - data.redraw.full_redraw = - c->data.gif.gif->frames[c->data.gif.current_frame - 1].redraw_required; - } else { - data.redraw.full_redraw = true; - } - - /* other data */ - data.redraw.object = c; - data.redraw.object_x = 0; - data.redraw.object_y = 0; - data.redraw.object_width = c->width; - data.redraw.object_height = c->height; - - content_broadcast(c, CONTENT_MSG_REDRAW, data); -} - -#endif diff --git a/riscos/gif.h b/riscos/gif.h deleted file mode 100644 index 891991b4a..000000000 --- a/riscos/gif.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * This file is part of NetSurf, http://netsurf.sourceforge.net/ - * Licensed under the GNU General Public License, - * http://www.opensource.org/licenses/gpl-license - * Copyright 2003 Philip Pemberton - * Copyright 2004 Richard Wilson - */ - -#ifndef _NETSURF_RISCOS_GIF_H_ -#define _NETSURF_RISCOS_GIF_H_ - -#include "netsurf/riscos/gifread.h" - -struct content; - -struct content_gif_data { - - /* The GIF data - */ - struct gif_animation *gif; - - /** The current frame number of the GIF to display, [0...(max-1)] - */ - unsigned int current_frame; -}; - -bool nsgif_create(struct content *c, const char *params[]); -bool nsgif_convert(struct content *c, int width, int height); -void nsgif_destroy(struct content *c); -bool nsgif_redraw(struct content *c, int x, int y, - int width, int height, - int clip_x0, int clip_y0, int clip_x1, int clip_y1, - float scale, unsigned long background_colour); - -#endif diff --git a/riscos/gifread.c b/riscos/gifread.c deleted file mode 100644 index 64038ea6e..000000000 --- a/riscos/gifread.c +++ /dev/null @@ -1,1038 +0,0 @@ -/* - * This file is part of NetSurf, http://netsurf.sourceforge.net/ - * Licensed under the GNU General Public License, - * http://www.opensource.org/licenses/gpl-license - * Copyright 2004 Richard Wilson - */ - - -#include -#include -#include -#include "gifread.h" -#include "netsurf/utils/log.h" -#include "oslib/osspriteop.h" -#include "oslib/osfile.h" - - -/* READING GIF FILES - ================= - - The functions provided by this file allow for efficient progressive GIF - decoding. Whilst the initialisation does not ensure that there is - sufficient image data to complete the entire frame, it does ensure that - the information provided is valid. Any subsequent attempts to decode an - initialised GIF are guaranteed to succeed, and any bytes of the image - not present are assumed to be totally transparent. - - To begin decoding a GIF, the 'gif' structure must be initialised with - the 'gif_data' and 'buffer_size' set to their initial values. The - 'buffer_position' should initially be 0, and will be internally updated - as the decoding commences. The caller should then repeatedly call - gif_initialise() with the structure until the function returns 1, or - no more data is avaliable. - - Once the initialisation has begun, the decoder completes the variables - 'frame_count' and 'frame_count_partial'. The former being the total - number of frames that have been successfully initialised, and the - latter being the number of frames that a partial amount of data is - available for. This assists the caller in managing the animation whilst - decoding is continuing. - - To decode a frame, the caller must use gif_decode_frame() which updates - the current 'frame_image' to reflect the desired frame. The required - 'background_action' is also updated to reflect how the frame should be - plotted. The caller must not assume that the current 'frame_image' will - be valid between calls if initialisation is still occuring, and should - either always request that the frame is decoded (no processing will - occur if the 'decoded_frame' has not been invalidated by initialisation) - or perform the check itself. - - It should be noted that gif_finalise() should always be called, even if - no frames were initialised. - - [rjw] - Fri 2nd April 2004 -*/ - - - -/* Internal GIF routines -*/ -static int gif_initialise_sprite(struct gif_animation *gif, unsigned int width, unsigned int height); -static int gif_initialise_frame(struct gif_animation *gif); -static unsigned int gif_interlaced_line(int height, int y); - - - -/* Internal LZW routines -*/ -static int gif_next_LZW(struct gif_animation *gif); -static int gif_next_code(struct gif_animation *gif, int code_size); -#define gif_read_LZW(gif) ((stack_pointer > stack) ? *--stack_pointer : gif_next_LZW(gif)) - -/* General LZW values. They are shared for all GIFs being decoded, and - thus we can't handle progressive decoding efficiently without having - the data for each image which would use an extra 10Kb or so per GIF. -*/ -static unsigned char buf[280]; -static int maskTbl[16] = {0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, - 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff}; -static int table[2][(1<< GIF_MAX_LZW)]; -static int stack[(1 << GIF_MAX_LZW) * 2]; -static int *stack_pointer; -static int code_size, set_code_size; -static int max_code, max_code_size; -static int clear_code, end_code; -static int curbit, lastbit, get_done, last_byte; -static int return_clear; -static int zero_data_block = FALSE; - -/* Whether to clear the decoded image rather than plot -*/ -static int clear_image = FALSE; - - -/* Initialises any workspace held by the animation and attempts to decode - any information that hasn't already been decoded. - If an error occurs, all previously decoded frames are retained. - - @return GIF_FRAME_DATA_ERROR for GIF frame data error - GIF_INSUFFICIENT_FRAME_DATA for insufficient data to process - any more frames - GIF_INSUFFICIENT_MEMORY for memory error - GIF_DATA_ERROR for GIF error - GIF_INSUFFICIENT_DATA for insufficient data to do anything - 0 for successful decoding - 1 for successful decoding (all frames completely read) -*/ -int gif_initialise(struct gif_animation *gif) { - unsigned char *gif_data; - unsigned int index; - int return_value; - unsigned int frame; - osspriteop_header *header; - - /* Check for sufficient data to be a GIF - */ - if (gif->buffer_size < 13) return GIF_INSUFFICIENT_DATA; - - /* Get our current processing position - */ - gif_data = gif->gif_data + gif->buffer_position; - - /* See if we should initialise the GIF - */ - if (gif->buffer_position == 0) { - - /* We want everything to be NULL before we start so we've no chance - of freeing bad pointers (paranoia) - */ - gif->frame_image = NULL; - gif->frames = NULL; - gif->local_colour_table = NULL; - gif->global_colour_table = NULL; - - /* The caller may have been lazy and not reset any values - */ - gif->frame_count = 0; - gif->frame_count_partial = 0; - gif->decoded_frame = 0xffffffff; - - /* Check we are a GIF - */ - if (strncmp(gif_data, "GIF", 3) != 0) { -// LOG(("Invalid GIF header - should be 'GIF'")); - return GIF_DATA_ERROR; - } - gif_data += 3; - - /* Check we are a GIF type 87a or 89a - */ - if ((strncmp(gif_data, "87a", 3) != 0) && - (strncmp(gif_data, "89a", 3) != 0)) { -// LOG(("Unknown GIF format - proceeding anyway")); - } - gif_data += 3; - - /* Get our GIF data. - */ - gif->width = gif_data[0] | (gif_data[1] << 8); - gif->height = gif_data[2] | (gif_data[3] << 8); - gif->global_colours = (gif_data[4] & 0x80); - gif->colour_table_size = (2 << (gif_data[4] & 0x07)); - gif->background_colour = gif_data[5]; - gif->aspect_ratio = gif_data[6]; - gif->dirty_frame = -1; - gif->loop_count = 1; - gif_data += 7; - - /* Some broken GIFs report the size as the screen size they were created in. As - such, we detect for the common cases and set the sizes as 0 if they are found - which results in the GIF being the maximum size of the frames. - */ - if (((gif->width == 640) && (gif->width == 480)) || - ((gif->width == 640) && (gif->width == 512)) || - ((gif->width == 800) && (gif->width == 600)) || - ((gif->width == 1280) && (gif->width == 1024))) { - gif->width = 0; - gif->height = 0; - } - - /* Allocate some data irrespective of whether we've got any colour tables. We - always get the maximum size in case a GIF is lying to us. It's far better - to give the wrong colours than to trample over some memory somewhere. - */ - gif->global_colour_table = (unsigned int *)calloc(GIF_MAX_COLOURS, sizeof(int)); - gif->local_colour_table = (unsigned int *)calloc(GIF_MAX_COLOURS, sizeof(int)); - if ((gif->global_colour_table == NULL) || (gif->local_colour_table == NULL)) { - gif_finalise(gif); - return GIF_INSUFFICIENT_MEMORY; - } - - /* Set the first colour to a value that will never occur in reality so we - know if we've processed it - */ - gif->global_colour_table[0] = 0xaa000000; - - /* Initialise enough workspace for 4 frame initially - */ - if ((gif->frames = (gif_frame *)malloc(sizeof(gif_frame))) == NULL) { - gif_finalise(gif); - return GIF_INSUFFICIENT_MEMORY; - } - gif->frame_holders = 1; - - /* Initialise the sprite header - */ - if ((gif->frame_image = (osspriteop_area *)malloc(sizeof(osspriteop_area) + - sizeof(osspriteop_header) + (gif->width * gif->height * 4))) == NULL) { - gif_finalise(gif); - return GIF_INSUFFICIENT_MEMORY; - } - gif->frame_image->size = sizeof(osspriteop_area) + sizeof(osspriteop_header) + - (gif->width * gif->height * 4); - gif->frame_image->sprite_count = 1; - gif->frame_image->first = 16; - gif->frame_image->used = gif->frame_image->size; - header = (osspriteop_header*)((char*)gif->frame_image + - gif->frame_image->first); - header->size = sizeof(osspriteop_header) + (gif->width * gif->height * 4); - memset(header->name, 0x00, 12); - strcpy(header->name, "gif"); - header->left_bit = 0; - header->right_bit = 31; - header->width = gif->width - 1; - header->height = gif->height - 1; - header->image = sizeof(osspriteop_header); - header->mask = sizeof(osspriteop_header); - header->mode = (os_mode) 0x301680b5; - - /* Remember we've done this now - */ - gif->buffer_position = gif_data - gif->gif_data; - } - - /* Do the colour map if we haven't already. As the top byte is always 0xff or 0x00 - depending on the transparency we know if it's been filled in. - */ - if (gif->global_colour_table[0] == 0xaa000000) { - /* Check for a global colour map signified by bit 7 - */ - if (gif->global_colours) { - if (gif->buffer_size < (gif->colour_table_size * 3 + 12)) { - return GIF_INSUFFICIENT_DATA; - } -// LOG(("Found global colour table with %i entries", gif->colour_table_size)); - for (index = 0; index < gif->colour_table_size; index++) { - gif->global_colour_table[index] = gif_data[0] | (gif_data[1] << 8) | - (gif_data[2] << 16) | 0xff000000; - gif_data += 3; - } - gif->buffer_position = (gif_data - gif->gif_data); - } else { -// LOG(("No global colour table")); - /* Create a default colour table with the first two colours as black and white - */ - gif->global_colour_table[0] = 0xff000000; - gif->global_colour_table[1] = 0xffffffff; - } - } - - /* Repeatedly try to decode frames - */ - while ((return_value = gif_initialise_frame(gif)) == 0); - - /* Update the redraw areas now we know the full data set - */ - if (gif->frame_count_partial > 0) { - /* Set the redraw for the first frame to the maximum frame size - */ - gif->frames[0].redraw_x = 0; - gif->frames[0].redraw_y = 0; - gif->frames[0].redraw_width = gif->width; - gif->frames[0].redraw_height = gif->height; - - /* We now work backwards to update the redraw characteristics of frames - with clear codes to stop a snowball effect of the redraw areas. It doesn't - really make much difference for most images, and will not work as well - (ie will not optimise as well as for a single-pass call, but still works) - for multiple calls to this routine when decoding progressively. - */ - for (frame = gif->frame_count_partial - 1; frame > 0; frame--) { - if (gif->frames[frame].redraw_required) { - if (gif->frames[frame].redraw_x > gif->frames[frame - 1].redraw_x) { - gif->frames[frame].redraw_width += - (gif->frames[frame].redraw_x - gif->frames[frame - 1].redraw_x); - gif->frames[frame].redraw_x = gif->frames[frame - 1].redraw_x; - } - if (gif->frames[frame].redraw_y > gif->frames[frame - 1].redraw_y) { - gif->frames[frame].redraw_height += - (gif->frames[frame].redraw_y - gif->frames[frame - 1].redraw_y); - gif->frames[frame].redraw_y = gif->frames[frame - 1].redraw_y; - } - if ((gif->frames[frame - 1].redraw_x + gif->frames[frame - 1].redraw_width) > - (gif->frames[frame].redraw_x + gif->frames[frame].redraw_width)) { - gif->frames[frame].redraw_width = - (gif->frames[frame - 1].redraw_x + gif->frames[frame - 1].redraw_width) - - gif->frames[frame].redraw_x; - } - if ((gif->frames[frame - 1].redraw_y + gif->frames[frame - 1].redraw_height) > - (gif->frames[frame].redraw_y + gif->frames[frame].redraw_height)) { - gif->frames[frame].redraw_height = - (gif->frames[frame - 1].redraw_y + gif->frames[frame - 1].redraw_height) - - gif->frames[frame].redraw_y; - } - } - } - - } - - /* If there was a memory error tell the caller - */ - if ((return_value == GIF_INSUFFICIENT_MEMORY) || - (return_value == GIF_DATA_ERROR)) { - return return_value; - } - - /* If we didn't have some frames then a GIF_INSUFFICIENT_DATA becomes a - GIF_INSUFFICIENT_FRAME_DATA - */ - if ((return_value == GIF_INSUFFICIENT_DATA) && (gif->frame_count_partial > 0)) { - return_value = GIF_INSUFFICIENT_FRAME_DATA; - } - - /* Return how many we got - */ - return return_value; -} - - - -/** Updates the sprite memory size - - @return -3 for a memory error - 0 for success -*/ -static int gif_initialise_sprite(struct gif_animation *gif, unsigned int width, unsigned int height) { - struct osspriteop_area *buffer; - struct osspriteop_header *header; - unsigned int max_width; - unsigned int max_height; - unsigned int frame_bytes; - - /* Check if we've changed - */ - if ((width <= gif->width) && (height <= gif->height)) return 0; - - /* Get our maximum values - */ - max_width = (width > gif->width) ? width : gif->width; - max_height = (height > gif->height) ? height : gif->height; - frame_bytes = max_width * max_height * 4 + - sizeof(osspriteop_header) + sizeof(osspriteop_area); - - /* Allocate some more memory - */ - if ((buffer = (osspriteop_area *)realloc(gif->frame_image, frame_bytes)) == NULL) { - return GIF_INSUFFICIENT_MEMORY; - } - gif->frame_image = buffer; - - /* Update the sizes - */ - gif->width = max_width; - gif->height = max_height; - - /* Update our sprite image - */ - buffer->size = frame_bytes; - buffer->used = frame_bytes; - header = (osspriteop_header*)((char*)gif->frame_image + - gif->frame_image->first); - header->size = frame_bytes - sizeof(osspriteop_area); - header->width = max_width - 1; - header->height = max_height - 1; - - /* Invalidate our currently decoded image - */ - gif->decoded_frame = 0xffffffff; - return 0; -} - - -/* Attempts to initialise the next frame - - @return -4 for insufficient data to process the entire frame - -3 for a memory error - -2 for a data error - -1 for insufficient data to process anything - 0 for success - 1 for success (GIF terminator found) -*/ -int gif_initialise_frame(struct gif_animation *gif) { - unsigned int frame; - gif_frame *temp_buf; - - unsigned char *gif_data, *gif_end; - int gif_bytes; - unsigned int flags = 0; - unsigned int background_action; - unsigned int width, height, offset_x, offset_y; - unsigned int extension_size, colour_table_size; - unsigned int block_size; - unsigned int more_images; - unsigned int first_image; - - /* Get the frame to decode and our data position - */ - frame = gif->frame_count; - - /* Get our buffer position etc. - */ - gif_data = (unsigned char *)(gif->gif_data + gif->buffer_position); - gif_end = (unsigned char *)(gif->gif_data + gif->buffer_size); - gif_bytes = (gif_end - gif_data); - - /* Check we have enough data for at least the header, or if we've finished - */ - if ((gif_bytes > 0) && (gif_data[0] == 0x3b)) return 1; - if (gif_bytes < 11) return -1; - - /* We could theoretically get some junk data that gives us millions of frames, so - we ensure that we don't have a silly number - */ - if (frame > 4096) return GIF_DATA_ERROR; - - /* Get some memory to store our pointers in etc. - */ - if (gif->frame_holders <= frame) { - /* Allocate more memory - */ - if ((temp_buf = (gif_frame *)realloc(gif->frames, - (frame + 1) * sizeof(gif_frame))) == NULL) { - return GIF_INSUFFICIENT_MEMORY; - } - gif->frames = temp_buf; - - /* Remember we allocated it - */ - gif->frame_holders = frame + 1; - } - - /* Store our frame pointer. We would do it when allocating except we - start off with one frame allocated so we can always use realloc. - */ - gif->frames[frame].frame_pointer = gif->buffer_position; - gif->frames[frame].frame_delay = 100; // Paranoia - gif->frames[frame].redraw_required = 0; // Paranoia - - /* Invalidate any previous decoding we have of this frame - */ - if (gif->decoded_frame == frame) gif->decoded_frame = 0xffffffff; - - /* We pretend to initialise the frames, but really we just skip over all - the data contained within. This is all basically a cut down version of - gif_decode_frame that doesn't have any of the LZW bits in it. - */ - more_images = 1; - first_image = 1; - while (more_images != 0) { - - /* Ensure we have some data - */ - if ((gif_end - gif_data) < 10) return GIF_INSUFFICIENT_FRAME_DATA; - - /* Decode the extensions - */ - background_action = 0; - while (gif_data[0] == 0x21) { - /* Get the extension size - */ - extension_size = gif_data[2]; - - /* Check we've enough data for the extension then header - */ - if ((gif_end - gif_data) < (int)(extension_size + 13)) return GIF_INSUFFICIENT_FRAME_DATA; - - /* Graphic control extension - store the frame delay. - */ - if (gif_data[1] == 0xf9) { - gif->frames[frame].frame_delay = gif_data[4] | (gif_data[5] << 8); - background_action = ((gif_data[3] & 0x1c) >> 2); - more_images = ((gif->frames[frame].frame_delay) == 0); - - /* Application extension - handle NETSCAPE2.0 looping - */ - } else if ((gif_data[1] == 0xff) && - (gif_data[2] == 0x0b) && - (strncmp(gif_data + 3, "NETSCAPE2.0", 11) == 0) && - (gif_data[14] == 0x03) && - (gif_data[15] == 0x01)) { - gif->loop_count = gif_data[16] | (gif_data[17] << 8); - } - - /* Move to the first sub-block - */ - gif_data += 2; - - /* Skip all the sub-blocks - */ - while (gif_data[0] != 0x00) { - gif_data += gif_data[0] + 1; - if ((gif_end - gif_data) < 10) return GIF_INSUFFICIENT_FRAME_DATA; - } - gif_data++; - } - - /* We must have at least one image descriptor - */ - if (gif_data[0] != 0x2c) return GIF_FRAME_DATA_ERROR; - - /* Do some simple boundary checking - */ - offset_x = gif_data[1] | (gif_data[2] << 8); - offset_y = gif_data[3] | (gif_data[4] << 8); - width = gif_data[5] | (gif_data[6] << 8); - height = gif_data[7] | (gif_data[8] << 8); - - /* Set up the redraw characteristics. We have to check for extending the area - due to multi-image frames. - */ - if (first_image == 0) { - if (gif->frames[frame].redraw_x > offset_x) { - gif->frames[frame].redraw_width += (gif->frames[frame].redraw_x - offset_x); - gif->frames[frame].redraw_x = offset_x; - } - if (gif->frames[frame].redraw_y > offset_y) { - gif->frames[frame].redraw_height += (gif->frames[frame].redraw_y - offset_y); - gif->frames[frame].redraw_y = offset_y; - } - if ((offset_x + width) > (gif->frames[frame].redraw_x + gif->frames[frame].redraw_width)) { - gif->frames[frame].redraw_width = (offset_x + width) - gif->frames[frame].redraw_x; - } - if ((offset_y + height) > (gif->frames[frame].redraw_y + gif->frames[frame].redraw_height)) { - gif->frames[frame].redraw_height = (offset_y + height) - gif->frames[frame].redraw_y; - } - } else { - first_image = 0; - gif->frames[frame].redraw_x = offset_x; - gif->frames[frame].redraw_y = offset_y; - gif->frames[frame].redraw_width = width; - gif->frames[frame].redraw_height = height; - } - - /* if we are clearing the background then we need to redraw enough to cover the previous - frame too - */ - if ((background_action == 2) || (background_action == 3)) { - gif->frames[frame].redraw_required = 1; - } - - /* Boundary checking - shouldn't ever happen except with junk data - */ - if (gif_initialise_sprite(gif, (offset_x + width), (offset_y + height))) { - return GIF_INSUFFICIENT_MEMORY; - } - - /* Decode the flags - */ - flags = gif_data[9]; - colour_table_size = 2 << (flags & 0x07); - - /* Move our data onwards and remember we've got a bit of this frame - */ - gif_data += 10; - gif_bytes = (gif_end - gif_data); - gif->frame_count_partial = frame + 1; - - /* Skip the local colour table - */ - if (flags & 0x80) { - gif_data += 3 * colour_table_size; - if ((gif_bytes = (gif_end - gif_data)) < 0) return GIF_INSUFFICIENT_FRAME_DATA; - } - - /* Ensure we have a correct code size - */ - if (gif_data[0] > GIF_MAX_LZW) return GIF_DATA_ERROR; - - /* Move our data onwards - */ - gif_data++; - if (--gif_bytes < 0) return GIF_INSUFFICIENT_FRAME_DATA; - - /* Repeatedly skip blocks until we get a zero block or run out of data - */ - block_size = 0; - while (block_size != 1) { - /* Skip the block data - */ - block_size = gif_data[0] + 1; - if ((gif_bytes -= block_size) < 0) return GIF_INSUFFICIENT_FRAME_DATA; - gif_data += block_size; - } - - /* Check for end of data - */ - if ((gif_bytes < 1) || (gif_data[0] == 0x3b)) more_images = 0; - } - - /* Check if we've finished - */ - if (gif_bytes < 1) { - return GIF_INSUFFICIENT_FRAME_DATA; - } else { - gif->buffer_position = gif_data - gif->gif_data; - gif->frame_count = frame + 1; - if (gif_data[0] == 0x3b) return 1; - } - return 0; -} - - -/** Decodes a GIF frame. - - @return GIF_FRAME_DATA_ERROR for GIF frame data error - GIF_INSUFFICIENT_FRAME_DATA for insufficient data to complete the frame - GIF_DATA_ERROR for GIF error (invalid frame header) - GIF_INSUFFICIENT_DATA for insufficient data to do anything - 0 for successful decoding -*/ -int gif_decode_frame(struct gif_animation *gif, unsigned int frame) { - unsigned int index = 0; - unsigned char *gif_data; - unsigned char *gif_end; - int gif_bytes; - unsigned int width, height, offset_x, offset_y; - unsigned int flags, colour_table_size, interlace; - unsigned int *colour_table; - unsigned int *frame_data = 0; // Set to 0 for no warnings - unsigned int *frame_scanline; - unsigned int extension_size; - unsigned int background_action; - int transparency_index = -1; - unsigned int save_buffer_position; - unsigned int return_value = 0; - unsigned int x, y, decode_y, burst_bytes; - unsigned int block_size; - register int colour; - unsigned int more_images; - - /* Ensure we have a frame to decode - */ - if (frame > gif->frame_count_partial) return GIF_INSUFFICIENT_DATA; - if ((!clear_image) && (frame == gif->decoded_frame)) return 0; - - /* If the previous frame was dirty, remove it - */ - if (!clear_image) { - if (gif->decoded_frame == gif->dirty_frame) { - clear_image = TRUE; - if (frame != 0) gif_decode_frame(gif, gif->dirty_frame); - clear_image = FALSE; - } - gif->dirty_frame = -1; - } - - /* Get the start of our frame data and the end of the GIF data - */ - gif_data = gif->gif_data + gif->frames[frame].frame_pointer; - gif_end = gif->gif_data + gif->buffer_size; - gif_bytes = (gif_end - gif_data); - - /* Check we have enough data for the header - */ - if (gif_bytes < 9) return GIF_INSUFFICIENT_DATA; - - /* Clear the previous frame totally. We can't just pretend we've got a smaller - sprite and clear what we need as some frames have multiple images which would - produce errors. - */ - frame_data = (unsigned int*)((char *)gif->frame_image + gif->frame_image->first + sizeof(osspriteop_header)); - if (!clear_image) { - if ((frame == 0) || (gif->decoded_frame == 0xffffffff)) { - memset((char*)frame_data, 0x00, gif->width * gif->height * sizeof(int)); - } - gif->decoded_frame = frame; - } - - /* Save the buffer position - */ - save_buffer_position = gif->buffer_position; - gif->buffer_position = gif_data - gif->gif_data; - - /* We've got to do this more than one time if we've got multiple images - */ - more_images = 1; - while (more_images != 0) { - background_action = 0; - - /* Ensure we have some data - */ - gif_data = gif->gif_data + gif->buffer_position; - if ((gif_end - gif_data) < 10) return GIF_INSUFFICIENT_FRAME_DATA; - - /* Decode the extensions - */ - while (gif_data[0] == 0x21) { - - /* Get the extension size - */ - extension_size = gif_data[2]; - - /* Check we've enough data for the extension then header - */ - if ((gif_end - gif_data) < (int)(extension_size + 13)) return GIF_INSUFFICIENT_FRAME_DATA; - - /* Graphic control extension - store the frame delay. - */ - if (gif_data[1] == 0xf9) { - flags = gif_data[3]; - if (flags & 0x01) transparency_index = gif_data[6]; - background_action = ((flags & 0x1c) >> 2); - more_images = ((gif_data[4] | (gif_data[5] << 8)) == 0); - } - /* Move to the first sub-block - */ - gif_data += 2; - - /* Skip all the sub-blocks - */ - while (gif_data[0] != 0x00) { - gif_data += gif_data[0] + 1; - if ((gif_end - gif_data) < 10) return GIF_INSUFFICIENT_FRAME_DATA; - } - gif_data++; - } - - /* Decode the header - */ - if (gif_data[0] != 0x2c) return GIF_DATA_ERROR; - offset_x = gif_data[1] | (gif_data[2] << 8); - offset_y = gif_data[3] | (gif_data[4] << 8); - width = gif_data[5] | (gif_data[6] << 8); - height = gif_data[7] | (gif_data[8] << 8); - - /* Boundary checking - shouldn't ever happen except unless the data has been - modified since initialisation. - */ - if ((offset_x + width > gif->width) || (offset_y + height > gif->height)) { - return GIF_DATA_ERROR; - } - - /* Decode the flags - */ - flags = gif_data[9]; - colour_table_size = 2 << (flags & 0x07); - interlace = flags & 0x40; - - /* Move through our data - */ - gif_data += 10; - gif_bytes = (int)(gif_end - gif_data); - - /* Set up the colour table - */ - if (flags & 0x80) { - if (gif_bytes < (int)(3 * colour_table_size)) return GIF_INSUFFICIENT_FRAME_DATA; - colour_table = gif->local_colour_table; - if (!clear_image) { - for (index = 0; index < colour_table_size; index++) { - colour_table[index] = gif_data[0] | (gif_data[1] << 8) | - (gif_data[2] << 16) | 0xff000000; - gif_data += 3; - } - } else { - gif_data += 3 * colour_table_size; - } - gif_bytes = (int)(gif_end - gif_data); - } else { - colour_table = gif->global_colour_table; - } - - /* If we are clearing the image we just clear, if not decode - */ - if (!clear_image) { - /* Set our dirty status - */ - if ((background_action == 2) || (background_action == 3)) { - gif->dirty_frame = frame; - } - - /* Initialise the LZW decoding - */ - set_code_size = gif_data[0]; - gif->buffer_position = (gif_data - gif->gif_data) + 1; - - /* Set our code variables - */ - code_size = set_code_size + 1; - clear_code = (1 << set_code_size); - end_code = clear_code + 1; - max_code_size = clear_code << 1; - max_code = clear_code + 2; - curbit = lastbit = 0; - last_byte = 2; - get_done = 0; - return_clear = 1; - stack_pointer = stack; - - /* Decompress the data - */ - for (y = 0; y < height; y++) { - if (interlace) { - decode_y = gif_interlaced_line(height, y) + offset_y; - } else { - decode_y = y + offset_y; - } - frame_scanline = frame_data + offset_x + (decode_y * gif->width); - - /* Rather than decoding pixel by pixel, we try to burst out streams - of data to remove the need for end-of data checks every pixel. - */ - x = width; - while (x-- > 0) { - /* Do the first pixel to get the stack of some sort - */ - if ((colour = gif_read_LZW(gif)) >= 0) { - if (colour != transparency_index) { - *frame_scanline = colour_table[colour]; - } - frame_scanline++; - } else { - return_value = GIF_INSUFFICIENT_FRAME_DATA; - goto gif_decode_frame_exit; - } - - /* Try to burst some bytes out - */ - burst_bytes = (stack_pointer - stack); - if (burst_bytes > x) burst_bytes = x; - x -= burst_bytes; - while (burst_bytes-- > 0) { - if ((colour = *--stack_pointer) != transparency_index) { - *frame_scanline = colour_table[colour]; - } - frame_scanline++; - } - } - } - } else { - /* Clear our frame - */ - if ((background_action == 2) || (background_action == 3)) { - for (y = 0; y < height; y++) { - frame_scanline = frame_data + offset_x + ((offset_y + y) * gif->width); - memset(frame_scanline, 0x00, width * 4); - } - } - - /* Repeatedly skip blocks until we get a zero block or run out of data - */ - gif_bytes = gif->buffer_size - gif->buffer_position; - gif_data = gif->gif_data + gif->buffer_size; - block_size = 0; - while (block_size != 1) { - /* Skip the block data - */ - block_size = gif_data[0] + 1; - if ((gif_bytes -= block_size) < 0) { - return_value = GIF_INSUFFICIENT_FRAME_DATA; - goto gif_decode_frame_exit; - } - gif_data += block_size; - } - } -gif_decode_frame_exit: - - /* Check for end of data - */ - gif_bytes = gif->buffer_size - gif->buffer_position; - if ((gif_bytes < 1) || (gif_data[0] == 0x3b)) more_images = 0; - gif->buffer_position++; - } - - /* Restore the buffer position - */ - gif->buffer_position = save_buffer_position; - - /* Success! - */ - return return_value; - -} - -static unsigned int gif_interlaced_line(int height, int y) { - if ((y << 3) < height) return (y << 3); - y -= ((height + 7) >> 3); - if ((y << 3) < (height - 4)) return (y << 3) + 4; - y -= ((height + 3) >> 3); - if ((y << 2) < (height - 2)) return (y << 2) + 2; - y -= ((height + 1) >> 2); - return (y << 1) + 1; -} - -/* Releases any workspace held by the animation -*/ -void gif_finalise(struct gif_animation *gif) { - /* Release all our memory blocks - */ - free(gif->frame_image); - gif->frame_image = NULL; - free(gif->frames); - gif->frames = NULL; - free(gif->local_colour_table); - gif->local_colour_table = NULL; - free(gif->global_colour_table); - gif->global_colour_table = NULL; -} - - -static int gif_next_LZW(struct gif_animation *gif) { - static int firstcode, oldcode; - int code, incode; - unsigned int i, block_size; - - while ((code = gif_next_code(gif, code_size)) >= 0) { - if (code == clear_code) { - /* Check we have a valid clear code - */ - if (clear_code >= (1 << GIF_MAX_LZW)) return -2; - - /* Initialise our table - */ - memset(table, 0x00, (1 << GIF_MAX_LZW) * 8); - for (i = 0; i < (unsigned int)clear_code; ++i) { - table[1][i] = i; - } - - /* Update our LZW parameters - */ - code_size = set_code_size + 1; - max_code_size = clear_code << 1; - max_code = clear_code + 2; - stack_pointer = stack; - do { - firstcode = oldcode = gif_next_code(gif, code_size); - } while (firstcode == clear_code); - return firstcode; - } - - if (code == end_code) { - /* Skip to the end of our data so multi-image GIFs work - */ - if (zero_data_block) return -2; - block_size = 0; - while (block_size != 1) { - block_size = gif->gif_data[gif->buffer_position] + 1; - gif->buffer_position += block_size; - } - return -2; - } - - /* Fill the stack with some data - */ - incode = code; - - if (code >= max_code) { - *stack_pointer++ = firstcode; - code = oldcode; - } - - while (code >= clear_code) { - *stack_pointer++ = table[1][code]; - if (code == table[0][code]) return(code); - if (((char *)stack_pointer - (char *)stack) >= (int)sizeof(stack)) return(code); - code = table[0][code]; - } - - *stack_pointer++ = firstcode = table[1][code]; - - if ((code = max_code) < (1 << GIF_MAX_LZW)) { - table[0][code] = oldcode; - table[1][code] = firstcode; - ++max_code; - if ((max_code >= max_code_size) && (max_code_size < (1 << GIF_MAX_LZW))) { - max_code_size = max_code_size << 1; - ++code_size; - } - } - - oldcode = incode; - - if (stack_pointer > stack) return *--stack_pointer; - } - return code; -} - - -static int gif_next_code(struct gif_animation *gif, int code_size) { - int i, j, end, count; - long ret; - unsigned char *gif_data; - - if (return_clear) { - return_clear = 0; - return clear_code; - } - - end = curbit + code_size; - if (end >= lastbit) { - if (get_done) return -1; - buf[0] = buf[last_byte - 2]; - buf[1] = buf[last_byte - 1]; - - /* Get the next block - */ - gif_data = gif->gif_data + gif->buffer_position; - zero_data_block = ((count = gif_data[0]) == 0); - if ((gif->buffer_position + count) >= gif->buffer_size) return -1; - if (count == 0) { - get_done = 1; - } else { - memcpy(&buf[2], gif_data + 1, count); - } - gif->buffer_position += count + 1; - - /* Update our variables - */ - last_byte = 2 + count; - curbit = (curbit - lastbit) + 16; - lastbit = (2 + count) << 3; - end = curbit + code_size; - } - - j = end >> 3; - i = curbit >> 3; - if (i == j) { - ret = (long)buf[i]; - } else if (i + 1 == j) { - ret = (long)buf[i] | ((long)buf[i+1] << 8); - } else { - ret = (long)buf[i] | ((long)buf[i+1] << 8) | ((long)buf[i+2] << 16); - } - - ret = (ret >> (curbit % 8)) & maskTbl[code_size]; - curbit += code_size; - return (int)ret; -} diff --git a/riscos/gifread.h b/riscos/gifread.h deleted file mode 100644 index 5e956aff7..000000000 --- a/riscos/gifread.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * This file is part of NetSurf, http://netsurf.sourceforge.net/ - * Licensed under the GNU General Public License, - * http://www.opensource.org/licenses/gpl-license - * Copyright 2004 Richard Wilson - */ - -/** \file - * Progressive animated GIF file decoding (interface). - */ - -#ifndef _NETSURF_RISCOS_GIFREAD_H_ -#define _NETSURF_RISCOS_GIFREAD_H_ - -#include "oslib/osspriteop.h" - -/* Error return values -*/ -#define GIF_INSUFFICIENT_FRAME_DATA -1 -#define GIF_FRAME_DATA_ERROR -2 -#define GIF_INSUFFICIENT_DATA -3 -#define GIF_DATA_ERROR -4 -#define GIF_INSUFFICIENT_MEMORY -5 - -/* Colour map size constant. Because we don't want to allocate - memory each time we decode a frame we get enough so all frames - will fit in there. -*/ -#define GIF_MAX_COLOURS 256 - -/* Maximum LZW bits available -*/ -#define GIF_MAX_LZW 12 - -/* The GIF frame dats -*/ -typedef struct gif_frame { - /* Frame data - */ - unsigned int frame_pointer; - unsigned int frame_delay; - - /* Redraw characteristics - */ - unsigned int redraw_required; - unsigned int redraw_x; - unsigned int redraw_y; - unsigned int redraw_width; - unsigned int redraw_height; - -} gif_frame; - - -/* A simple hold-all for our GIF data -*/ -typedef struct gif_animation { - /* Encoded GIF data - */ - unsigned char *gif_data; - unsigned int buffer_position; - unsigned int buffer_size; - - /* Progressive decoding data - */ - unsigned int global_colours; - unsigned int frame_holders; - unsigned int colour_table_size; - - /* Animation data - */ - unsigned int decoded_frame; - int loop_count; - gif_frame *frames; - - /* Decoded GIF data - */ - unsigned int width; - unsigned int height; - unsigned int frame_count; - unsigned int frame_count_partial; - unsigned int background_colour; - unsigned int aspect_ratio; - unsigned int *global_colour_table; - unsigned int *local_colour_table; - - /* Decoded frame data - */ - unsigned int dirty_frame; // Frame needs erasing before next - osspriteop_area *frame_image; -} gif_animation; - -/* Function declarations -*/ -int gif_initialise(struct gif_animation *gif); -int gif_decode_frame(struct gif_animation *gif, unsigned int frame); -void gif_finalise(struct gif_animation *gif); - -#endif diff --git a/riscos/gui.h b/riscos/gui.h index b6c68e07d..f2394e641 100644 --- a/riscos/gui.h +++ b/riscos/gui.h @@ -32,7 +32,7 @@ extern wimp_w dialog_info, dialog_saveas, dialog_config, dialog_config_br, extern wimp_w history_window; extern wimp_w hotlist_window; extern wimp_menu *iconbar_menu, *browser_menu, *combo_menu, *hotlist_menu, - *proxyauth_menu, *languages_menu; + *proxyauth_menu, *languages_menu, *toolbar_menu; extern int iconbar_menu_height; extern struct form_control *current_gadget; extern bool gui_reformat_pending; @@ -98,6 +98,7 @@ struct gui_window { }; +extern struct toolbar *current_toolbar; extern struct gui_window *current_gui; extern struct gui_window *ro_gui_current_redraw_gui; extern struct gui_window *ro_gui_current_zoom_gui; @@ -265,9 +266,8 @@ bool ro_gui_print_keypress(wimp_key *key); #define ICON_TOOLBAR_BOOKMARK 8 #define ICON_TOOLBAR_SCALE 9 #define ICON_TOOLBAR_SEARCH 10 -#define ICON_TOOLBAR_UP 11 -#define ICON_TOOLBAR_URL 12 // Must be after highest toolbar icon -#define ICON_TOOLBAR_THROBBER 13 +#define ICON_TOOLBAR_URL 11 // Must be after highest toolbar icon +#define ICON_TOOLBAR_THROBBER 12 /* icon numbers for hotlist toolbars */ #define ICON_TOOLBAR_CREATE 0 @@ -275,8 +275,7 @@ bool ro_gui_print_keypress(wimp_key *key); #define ICON_TOOLBAR_EXPAND 2 #define ICON_TOOLBAR_OPEN 3 #define ICON_TOOLBAR_LAUNCH 4 -#define ICON_TOOLBAR_SORT 5 -#define ICON_TOOLBAR_HOTLIST_LAST 6 +#define ICON_TOOLBAR_HOTLIST_LAST 5 /* icon numbers for toolbar status window */ #define ICON_STATUS_RESIZE 0 diff --git a/riscos/hotlist.c b/riscos/hotlist.c index 3b787a536..f7ed7516b 100644 --- a/riscos/hotlist.c +++ b/riscos/hotlist.c @@ -2296,9 +2296,17 @@ bool ro_gui_hotlist_keypress(int key) { void ro_gui_hotlist_toolbar_click(wimp_pointer* pointer) { int selection; - /* Reject Menu clicks + /* Store the toolbar */ - if (pointer->buttons == wimp_CLICK_MENU) return; + current_toolbar = hotlist_toolbar; + + /* Handle Menu clicks + */ + if (pointer->buttons == wimp_CLICK_MENU) { + ro_gui_create_menu(toolbar_menu, pointer->pos.x, + pointer->pos.y, NULL); + return; + } /* Handle the buttons appropriately */ diff --git a/riscos/menus.c b/riscos/menus.c index eb368e7de..cdf2592f8 100644 --- a/riscos/menus.c +++ b/riscos/menus.c @@ -48,6 +48,7 @@ static void translate_menu(wimp_menu *menu); static void build_languages_menu(void); static void ro_gui_menu_prepare_images(void); static void ro_gui_menu_prepare_window(void); +static void ro_gui_menu_prepare_theme(void); static void ro_gui_menu_prepare_toolbars(void); static void ro_gui_menu_prepare_render(void); static void ro_gui_menu_prepare_help(int forced); @@ -196,7 +197,7 @@ static wimp_MENU(5) image_menu = { /* Toolbar submenu */ -static wimp_MENU(4) toolbar_menu = { +static wimp_MENU(4) show_toolbar_menu = { { "Toolbars" }, 7,2,7,0, 300, 44, 0, { { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "ToolButtons" } }, @@ -321,7 +322,7 @@ static wimp_MENU(3) hotlist_expand = { { { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "All" } }, { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Folders" } }, - { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Links" } }, + { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Links" } } } }; @@ -332,7 +333,7 @@ static wimp_MENU(3) hotlist_collapse = { { { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "All" } }, { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Folders" } }, - { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Links" } }, + { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Links" } } } }; @@ -342,7 +343,7 @@ static wimp_MENU(3) hotlist_save = { { { wimp_MENU_GIVE_WARNING, (wimp_menu*)1, DEFAULT_FLAGS, { "URI" } }, { wimp_MENU_GIVE_WARNING, (wimp_menu*)1, DEFAULT_FLAGS, { "URL" } }, - { wimp_MENU_LAST | wimp_MENU_GIVE_WARNING, (wimp_menu*)1, DEFAULT_FLAGS, { "HTML" } }, + { wimp_MENU_LAST | wimp_MENU_GIVE_WARNING, (wimp_menu*)1, DEFAULT_FLAGS, { "HTML" } } } }; @@ -355,7 +356,7 @@ static wimp_MENU(5) hotlist_file = { { wimp_MENU_GIVE_WARNING, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Save" } }, { wimp_MENU_GIVE_WARNING | wimp_MENU_SEPARATE, (wimp_menu *)1, DEFAULT_FLAGS, { "Export" } }, { 0, (wimp_menu *)&hotlist_expand, DEFAULT_FLAGS, { "Expand" } }, - { wimp_MENU_LAST, (wimp_menu *)&hotlist_collapse, DEFAULT_FLAGS, { "Collapse" } }, + { wimp_MENU_LAST, (wimp_menu *)&hotlist_collapse, DEFAULT_FLAGS, { "Collapse" } } } }; @@ -369,7 +370,7 @@ static wimp_MENU(5) hotlist_select = { { wimp_MENU_GIVE_WARNING, (wimp_menu *)1, DEFAULT_FLAGS, { "Edit" } }, { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Launch" } }, { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Delete" } }, - { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "ResetUsage" } }, + { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "ResetUsage" } } } }; @@ -382,7 +383,7 @@ static wimp_MENU(4) hotlist_root = { { 0, (wimp_menu *)&hotlist_file, DEFAULT_FLAGS, { "Hotlist" } }, { wimp_MENU_GIVE_WARNING, (wimp_menu *)&hotlist_select, DEFAULT_FLAGS, { "Selection" } }, { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "SelectAll" } }, - { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Clear" } }, + { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "Clear" } } } }; wimp_menu *hotlist_menu = (wimp_menu *)&hotlist_root; @@ -393,17 +394,75 @@ wimp_menu *hotlist_menu = (wimp_menu *)&hotlist_root; static wimp_MENU(3) proxy_menu = { { "ProxyAuth" }, 7,2,7,0, 200, 44, 0, { - { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "ProxyNone" } }, - { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "ProxyBasic" } }, - { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "ProxyNTLM" } }, + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "ProxyNone" } }, + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "ProxyBasic" } }, + { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "ProxyNTLM" } } } }; wimp_menu *proxyauth_menu = (wimp_menu *) &proxy_menu; + +/* Toolbar icon submenus. + The index of the name must be identical to the toolbar icon number. +*/ +static wimp_MENU(11) toolbar_browser = { + { "Icons" }, 7,2,7,0, 200, 44, 0, + { + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "IconBack" } }, + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "IconForward" } }, + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "IconStop" } }, + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "IconReload" } }, + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "IconHome" } }, + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "IconHistory" } }, + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "IconSave" } }, + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "IconPrint" } }, + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "IconHotlist" } }, + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "IconScale" } }, + { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "IconSearch" } } + } +}; +wimp_menu *toolbar_browser_menu = (wimp_menu *)&toolbar_browser; + +static wimp_MENU(5) toolbar_hotlist = { + { "Icons" }, 7,2,7,0, 200, 44, 0, + { + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "IconCreate" } }, + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "IconDelete" } }, + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "IconExpand" } }, + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "IconOpen" } }, + { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "IconLaunch" } } + } +}; +wimp_menu *toolbar_hotlist_menu = (wimp_menu *)&toolbar_hotlist; + +/* Toolbar icon menu +*/ +static wimp_MENU(5) toolbar = { + { "Toolbar" }, 7,2,7,0, 200, 44, 0, + { + { 0, (wimp_menu *)&toolbar_browser, DEFAULT_FLAGS, { "Icons" } }, + { 0, (wimp_menu *)&show_toolbar_menu, DEFAULT_FLAGS, { "Toolbars" } }, + { 0, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "AddGap" } }, + { wimp_MENU_SEPARATE, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "DeleteGap" } }, + { wimp_MENU_LAST, wimp_NO_SUB_MENU, DEFAULT_FLAGS, { "LockToolbar" } } + } +}; +wimp_menu *toolbar_menu = (wimp_menu *)&toolbar; + + +/* Current toolbar +*/ +struct toolbar *current_toolbar; +static struct toolbar_icon *current_toolbar_icon; + /* Languages popup menu (used in browser choices dialog) */ wimp_menu *languages_menu = NULL; +/* Toolbar menu +*/ +wimp_menu *toolbar_icon_menu = NULL; + /* Font popup menu (used in font choices dialog) */ static wimp_menu *font_menu = NULL; @@ -418,7 +477,7 @@ static wimp_menu *browser_selection_menu = (wimp_menu *)&selection_menu; static wimp_menu *browser_navigate_menu = (wimp_menu *)&navigate_menu; static wimp_menu *browser_view_menu = (wimp_menu *)&view_menu; static wimp_menu *browser_image_menu = (wimp_menu *)&image_menu; -static wimp_menu *browser_toolbar_menu = (wimp_menu *)&toolbar_menu; +static wimp_menu *browser_toolbar_menu = (wimp_menu *)&show_toolbar_menu; static wimp_menu *browser_render_menu = (wimp_menu *)&render_menu; static wimp_menu *browser_window_menu = (wimp_menu *)&window_menu; static wimp_menu *browser_utilities_menu = (wimp_menu *)&utilities_menu; @@ -466,6 +525,10 @@ void ro_gui_menus_init(void) translate_menu(hotlist_save_menu); translate_menu(hotlist_select_menu); + translate_menu(toolbar_menu); + translate_menu(toolbar_browser_menu); + translate_menu(toolbar_hotlist_menu); + translate_menu(proxyauth_menu); build_languages_menu(); @@ -565,7 +628,7 @@ void build_languages_menu(void) languages_menu = temp; languages_menu->entries[entries].menu_flags = 0; languages_menu->entries[entries].sub_menu = wimp_NO_SUB_MENU; - languages_menu->entries[entries].icon_flags = wimp_ICON_TEXT | wimp_ICON_FILLED | wimp_ICON_INDIRECTED | (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT); + languages_menu->entries[entries].icon_flags = DEFAULT_FLAGS | wimp_ICON_INDIRECTED; languages_menu->entries[entries].data.indirected_text.text = lang_name; languages_menu->entries[entries].data.indirected_text.validation = (char *)-1; languages_menu->entries[entries].data.indirected_text.size = strlen(lang_name) + 1; @@ -622,11 +685,25 @@ void ro_gui_create_menu(wimp_menu *menu, int x, int y, struct gui_window *g) else menu->entries[1].icon_flags |= wimp_ICON_SHADED; if ((current_gui->bw) && (current_gui->bw->current_content)) { - menu->entries[0].icon_flags &= ~wimp_ICON_SHADED; + menu->entries[0].icon_flags &= ~wimp_ICON_SHADED; } else { - menu->entries[0].icon_flags |= wimp_ICON_SHADED; + menu->entries[0].icon_flags |= wimp_ICON_SHADED; + } + + } else if (menu == toolbar_menu) { + state.w = current_toolbar->toolbar_handle; + error = xwimp_get_window_state(&state); + if (error) { + LOG(("xwimp_get_window_state: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return; } + current_toolbar_icon = ro_gui_theme_toolbar_get_icon(current_toolbar, + x - state.visible.x0, y - state.visible.y0); + LOG(("Toolbar (%i,%i)", x - state.visible.x0, y - state.visible.y0)); + ro_gui_menu_prepare_theme(); } else if (menu == hotlist_menu) { ro_gui_menu_prepare_hotlist(); } @@ -665,7 +742,9 @@ void ro_gui_popup_menu(wimp_menu *menu, wimp_w w, wimp_i i) void ro_gui_menu_selection(wimp_selection *selection) { - char url[80]; + struct toolbar_icon *icon; + struct toolbar_icon *next; + char url[80]; wimp_pointer pointer; wimp_window_state state; os_error *error; @@ -695,6 +774,66 @@ void ro_gui_menu_selection(wimp_selection *selection) break; } + } else if (current_menu == toolbar_menu) { + switch (selection->items[0]) { + case 0: /* Icons-> */ + if (selection->items[1] == -1) break; + next = current_toolbar->icon; + while ((icon = next) != NULL) { + next = icon->next; + if (icon->icon_number == selection->items[1]) { + icon->display = !icon->display; + } + } + current_toolbar->reformat_buttons = true; + height = current_toolbar->height; + ro_gui_theme_process_toolbar(current_toolbar, -1); + if ((height != current_toolbar->height) && (current_gui)) + ro_gui_window_update_dimensions(current_gui, + height - current_toolbar->height); + if ((height != current_toolbar->height) && + (current_toolbar == hotlist_toolbar)) { + xwimp_force_redraw(hotlist_window, 0, -16384, 16384, 16384); + } + ro_gui_menu_prepare_theme(); + + break; + case 1: /* Toolbars-> */ + switch (selection->items[1]) { + case 0: + current_toolbar->display_buttons = + !current_toolbar->display_buttons; + break; + case 1: + current_toolbar->display_url = + !current_toolbar->display_url; + break; + case 2: + current_toolbar->display_throbber = + !current_toolbar->display_throbber; + break; + case 3: + current_toolbar->display_status = + !current_toolbar->display_status; + break; + } + current_toolbar->reformat_buttons = true; + height = current_toolbar->height; + ro_gui_theme_process_toolbar(current_toolbar, -1); + if ((height != current_toolbar->height) && (current_gui)) + ro_gui_window_update_dimensions(current_gui, + height - current_toolbar->height); + ro_gui_menu_prepare_theme(); + break; + case 2: /* Add separator */ + break; + case 3: /* Remove separator */ + break; + case 4: /* Lock toolbar */ + current_toolbar->locked = !current_toolbar->locked; + ro_gui_menu_prepare_theme(); + break; + } } else if (current_menu == hotlist_menu) { switch (selection->items[0]) { case 0: /* Hotlist-> */ @@ -1398,7 +1537,7 @@ void ro_gui_prepare_navigate(struct gui_window *gui) { /* Set the scale view icon */ if (c) { - if (update_menu) menu.entries[0].icon_flags &= ~wimp_ICON_SHADED; + if (update_menu) menu.entries[0].icon_flags &= ~wimp_ICON_SHADED; if (t) { ro_gui_set_icon_shaded_state(t->toolbar_handle, ICON_TOOLBAR_SEARCH, false); ro_gui_set_icon_shaded_state(t->toolbar_handle, ICON_TOOLBAR_SCALE, false); @@ -1406,7 +1545,7 @@ void ro_gui_prepare_navigate(struct gui_window *gui) { ro_gui_set_icon_shaded_state(t->toolbar_handle, ICON_TOOLBAR_PRINT, false); } } else { - if (update_menu) menu.entries[0].icon_flags |= wimp_ICON_SHADED; + if (update_menu) menu.entries[0].icon_flags |= wimp_ICON_SHADED; if (t) { ro_gui_set_icon_shaded_state(t->toolbar_handle, ICON_TOOLBAR_SEARCH, true); ro_gui_set_icon_shaded_state(t->toolbar_handle, ICON_TOOLBAR_SCALE, true); @@ -1526,16 +1665,85 @@ static void ro_gui_menu_prepare_window(void) { } +/** + * Update toolbar menu status + */ +static void ro_gui_menu_prepare_theme(void) { + struct toolbar_icon *icon; + struct toolbar_icon *next; + wimp_menu *sub_menu; + + if (!current_toolbar) return; + + /* Set the icon states + */ + if (current_toolbar->display_buttons) { + toolbar_menu->entries[0].icon_flags &= ~wimp_ICON_SHADED; + toolbar_menu->entries[2].icon_flags &= ~wimp_ICON_SHADED; + toolbar_menu->entries[3].icon_flags &= ~wimp_ICON_SHADED; + if (current_toolbar->type == THEME_BROWSER_TOOLBAR) { + toolbar_menu->entries[0].sub_menu = toolbar_browser_menu; + } else if (current_toolbar->type == THEME_HOTLIST_TOOLBAR) { + toolbar_menu->entries[0].sub_menu = toolbar_hotlist_menu; + } else { + LOG(("Unknown toolbar type")); + return; /* unknown toolbar type */ + } + sub_menu = toolbar_menu->entries[0].sub_menu; + next = current_toolbar->icon; + while ((icon = next) != NULL) { + next = icon->next; + if (icon->icon_number >= 0) { + if (icon->width == 0) { + sub_menu->entries[icon->icon_number].icon_flags |= + wimp_ICON_SHADED; + sub_menu->entries[icon->icon_number].menu_flags &= + ~wimp_MENU_TICKED; + } else { + if (icon->display) { + sub_menu->entries[icon->icon_number].menu_flags |= + wimp_MENU_TICKED; + } else { + sub_menu->entries[icon->icon_number].menu_flags &= + ~wimp_MENU_TICKED; + } + } + } + } + } else { + toolbar_menu->entries[0].icon_flags |= wimp_ICON_SHADED; + toolbar_menu->entries[2].icon_flags |= wimp_ICON_SHADED; + toolbar_menu->entries[3].icon_flags |= wimp_ICON_SHADED; + } + + /* Set the toolbars submenu state + */ + if (current_gui) { + toolbar_menu->entries[1].icon_flags &= ~wimp_ICON_SHADED; + ro_gui_menu_prepare_toolbars(); + } else { + toolbar_menu->entries[1].icon_flags |= wimp_ICON_SHADED; + } + + /* Set the locked state + */ + if (current_toolbar->locked) { + toolbar_menu->entries[4].menu_flags |= wimp_MENU_TICKED; + } else { + toolbar_menu->entries[4].menu_flags &= ~wimp_MENU_TICKED; + } +} + /** * Update toolbar menu status */ static void ro_gui_menu_prepare_toolbars(void) { int index; struct toolbar *toolbar; - if (current_menu != browser_menu) return; /* Check we have a toolbar */ + if (!current_gui) return; toolbar = current_gui->toolbar; /* Set our ticks, or shade everything if there's no toolbar @@ -1545,7 +1753,7 @@ static void ro_gui_menu_prepare_toolbars(void) { browser_toolbar_menu->entries[index].icon_flags &= ~wimp_ICON_SHADED; browser_toolbar_menu->entries[index].menu_flags &= ~wimp_MENU_TICKED; } - if ((toolbar->descriptor) && (toolbar->descriptor->theme)) { + if ((toolbar->descriptor) && (toolbar->descriptor->theme)) { if (toolbar->display_buttons) browser_toolbar_menu->entries[0].menu_flags |= wimp_MENU_TICKED; if (toolbar->display_throbber) browser_toolbar_menu->entries[2].menu_flags |= wimp_MENU_TICKED; } else { @@ -1720,7 +1928,7 @@ void ro_gui_menu_object_reload(void) /** * Display a menu of options for a form select control. * - * \param bw browser window containing form control + * \param bw browser window containing form control * \param control form control of type GADGET_SELECT */ diff --git a/riscos/options.h b/riscos/options.h index b7b22d64f..66970ca28 100644 --- a/riscos/options.h +++ b/riscos/options.h @@ -40,7 +40,6 @@ extern int option_window_screen_width; extern int option_window_screen_height; extern bool option_window_stagger; extern bool option_window_size_clone; -extern int option_minimum_gif_delay; extern bool option_background_images; extern bool option_background_blending; extern bool option_buffer_animations; @@ -99,7 +98,6 @@ int option_window_screen_width = 0; \ int option_window_screen_height = 0; \ bool option_window_stagger = true; \ bool option_window_size_clone = true; \ -int option_minimum_gif_delay = 10; \ bool option_background_images = true; \ bool option_background_blending = true; \ bool option_buffer_animations = true; \ @@ -158,7 +156,6 @@ bool option_font_ufont = false; { "window_screen_height", OPTION_INTEGER, &option_window_screen_height }, \ { "window_stagger", OPTION_BOOL, &option_window_stagger }, \ { "window_size_clone", OPTION_BOOL, &option_window_size_clone }, \ -{ "minimum_gif_delay", OPTION_INTEGER, &option_minimum_gif_delay }, \ { "background_images", OPTION_BOOL, &option_background_images }, \ { "background_blending", OPTION_BOOL, &option_background_blending }, \ { "buffer_animations", OPTION_BOOL, &option_buffer_animations }, \ diff --git a/riscos/save_draw.c b/riscos/save_draw.c index 297cc34d2..b4e775532 100644 --- a/riscos/save_draw.c +++ b/riscos/save_draw.c @@ -725,7 +725,7 @@ static bool add_graphic(struct content *content, struct box *box, #endif #ifdef WITH_GIF case CONTENT_GIF: - sprite_length = ((osspriteop_header*)((char*)content->data.gif.gif->frame_image+content->data.gif.gif->frame_image->first))->size; + sprite_length = ((osspriteop_header*)((char*)&content->bitmap->sprite_area+content->bitmap->sprite_area.first))->size; break; #endif #ifdef WITH_SPRITE @@ -768,7 +768,7 @@ static bool add_graphic(struct content *content, struct box *box, #endif #ifdef WITH_GIF case CONTENT_GIF: - memcpy((char*)ds+16, (char*)content->data.gif.gif->frame_image+content->data.gif.gif->frame_image->first, (unsigned)sprite_length); + memcpy((char*)ds+16, (char*)&content->bitmap->sprite_area+content->bitmap->sprite_area.first, (unsigned)sprite_length); break; #endif #ifdef WITH_SPRITE diff --git a/riscos/theme.c b/riscos/theme.c index 8d9b1378f..62488f1dd 100644 --- a/riscos/theme.c +++ b/riscos/theme.c @@ -35,16 +35,6 @@ #define THEME_THROBBER_MEMORY 12 #define THEME_STATUS_MEMORY 256 -struct toolbar_icon { - int icon_number; /**< wimp icon number */ - bool display; /**< whether to display the icon */ - int width; /**< icon width */ - int height; /**< icon height */ - char name[12]; /**< icon name */ - char validation[40]; /**< validation string */ - struct toolbar_icon *next; /**< next toolbar icon, or NULL for no more */ -}; - struct theme_file_header { unsigned int magic_value; unsigned int parser_version; @@ -96,8 +86,8 @@ static wimp_window theme_toolbar_window = { 12, 1, {""}, - 0/*, - { } */ + 0, + { } }; @@ -763,7 +753,7 @@ bool ro_gui_theme_update_toolbar(struct theme_descriptor *descriptor, struct too new_icon.icon.data.indirected_text.size = 1; new_icon.icon.flags = wimp_ICON_TEXT | wimp_ICON_SPRITE | wimp_ICON_INDIRECTED | wimp_ICON_HCENTRED | wimp_ICON_VCENTRED | - (wimp_BUTTON_CLICK << wimp_ICON_BUTTON_TYPE_SHIFT); + (wimp_BUTTON_RELEASE_DRAG << wimp_ICON_BUTTON_TYPE_SHIFT); if (toolbar->descriptor) { new_icon.icon.flags |= (toolbar->descriptor->browser_background << wimp_ICON_BG_COLOUR_SHIFT); @@ -1024,8 +1014,30 @@ bool ro_gui_theme_process_toolbar(struct toolbar *toolbar, int width) { int old_height = toolbar->height; int old_width = toolbar->toolbar_current; struct toolbar_icon *toolbar_icon; + struct toolbar_icon *last_icon = NULL; bool visible_icon = false; + /* Disable lone separators + */ + if (toolbar->reformat_buttons) { + visible_icon = false; + toolbar_icon = toolbar->icon; + while (toolbar_icon) { + if (toolbar_icon->icon_number < 0) { + toolbar_icon->display = visible_icon; + visible_icon = false; + } else if (toolbar_icon->width > 0) { + visible_icon |= toolbar_icon->display; + } + if (toolbar_icon->display) last_icon = toolbar_icon; + toolbar_icon = toolbar_icon->next; + } + if ((last_icon) && (last_icon->icon_number < 0)) { + last_icon->display = false; + } + visible_icon = false; + } + /* Find the parent window handle if we need to process the status window, or the caller has requested we calculate the width ourself. */ @@ -1129,6 +1141,8 @@ bool ro_gui_theme_process_toolbar(struct toolbar *toolbar, int width) { visible_icon = true; bottom_edge = (toolbar->height - toolbar_icon->height) / 2; + toolbar_icon->x = left_edge; + toolbar_icon->y = bottom_edge; xwimp_resize_icon(toolbar->toolbar_handle, toolbar_icon->icon_number, left_edge, bottom_edge, @@ -1313,6 +1327,14 @@ void ro_gui_theme_destroy_toolbar(struct toolbar *toolbar) { free(toolbar); } + +/** + * Adds a toolbar icon to the end of a toolbar + * + * \param toolbar the toolbar to add the icon to the end of + * \param name the icon name, or NULL for a separator + * \param icon_number the RISC OS Wimp icon number for the icon (not used for separators) + */ void ro_gui_theme_add_toolbar_icon(struct toolbar *toolbar, const char *name, int icon_number) { if (!toolbar) return; struct toolbar_icon *toolbar_icon; @@ -1320,7 +1342,10 @@ void ro_gui_theme_add_toolbar_icon(struct toolbar *toolbar, const char *name, in /* Separators are really a sprite called "separator" */ - if (name == NULL) name = "separator"; + if (name == NULL) { + name = "separator"; + icon_number = -1; + } /* Create a new toolbar */ @@ -1405,3 +1430,33 @@ void ro_gui_theme_update_toolbar_icon(struct toolbar *toolbar, struct toolbar_ic void ro_gui_theme_destroy_toolbar_icon(struct toolbar_icon *icon) { free(icon); } + + +/** + * Returns the toolbar icon at a specified position + * + * \param toolbar the toolbar to examine + * \param x the x co-ordinate to check + * \param y the y co-ordinate to check + * \return the toolbar icon at the specified position, or NULL for no icon + */ +struct toolbar_icon *ro_gui_theme_toolbar_get_icon(struct toolbar *toolbar, int x, int y) { + struct toolbar_icon *icon; + icon = toolbar->icon; +/* FINISH ME */ + return NULL; +} + +/** + * Returns whether a separator can follow the specified icon + * + * \param icon the icon to check + * \return whether a separator can follow + */ +bool ro_gui_theme_toolbar_separator_following(struct toolbar_icon *icon) { + while (icon) { + if (icon->display) return (icon->width > 0); + icon = icon->next; + } + return false; +} diff --git a/riscos/theme.h b/riscos/theme.h index 1ab6793e3..8e34ff66b 100644 --- a/riscos/theme.h +++ b/riscos/theme.h @@ -19,7 +19,17 @@ typedef enum { THEME_HOTLIST_TOOLBAR } toolbar_type; -struct toolbar_icon; +struct toolbar_icon { + int icon_number; /**< wimp icon number */ + bool display; /**< whether to display the icon */ + int x; /**< icon x position (valid only when displayed) */ + int y; /**< icon y position (valid only when displayed) */ + int width; /**< icon width */ + int height; /**< icon height */ + char name[12]; /**< icon name */ + char validation[40]; /**< validation string */ + struct toolbar_icon *next; /**< next toolbar icon, or NULL for no more */ +}; struct theme { osspriteop_area *sprite_area; /**< sprite area for theme */ @@ -48,6 +58,7 @@ struct toolbar { struct toolbar_icon *icon; /**< first toolbar icon (read only) */ struct theme_descriptor *descriptor; /**< theme descriptor (read only) */ toolbar_type type; /**< toolbar type (read only) */ + bool locked; /**< toolbar is locked from editing */ }; struct theme_descriptor { @@ -82,5 +93,7 @@ void ro_gui_theme_resize_toolbar_status(struct toolbar *toolbar); bool ro_gui_theme_process_toolbar(struct toolbar *toolbar, int width); void ro_gui_theme_destroy_toolbar(struct toolbar *toolbar); +struct toolbar_icon *ro_gui_theme_toolbar_get_icon(struct toolbar *toolbar, int x, int y); +bool ro_gui_theme_toolbar_separator_following(struct toolbar_icon *icon); #endif diff --git a/riscos/window.c b/riscos/window.c index 9f0c7dcf6..a1e9ff8bc 100644 --- a/riscos/window.c +++ b/riscos/window.c @@ -1064,10 +1064,17 @@ void ro_gui_toolbar_click(struct gui_window *g, wimp_pointer *pointer) { char url[80]; - /* Reject Menu clicks + /* Store the toolbar */ - if (pointer->buttons == wimp_CLICK_MENU) + current_toolbar = g->toolbar; + + /* Handle Menu clicks + */ + if (pointer->buttons == wimp_CLICK_MENU) { + ro_gui_create_menu(toolbar_menu, pointer->pos.x, + pointer->pos.y, g); return; + } /* Handle the buttons appropriately */ -- cgit v1.2.3