home *** CD-ROM | disk | FTP | other *** search
-
- /* hacky.c */
-
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include "swis.h"
- #include "OS:wimp.h"
- #include "OS:wimpspriteop.h"
- #include "OS:wimpreadsysinfo.h"
- #include "Dreamscape:task.h"
- #include "Dreamscape:x.h"
-
- #ifdef MemCheck_MEMCHECK
- #include "MemCheck:memcheck.h"
- #endif
-
- #include "ibarpatch.h"
- #include "debug.h"
-
-
- #define MODULE_NAME "hacky"
-
-
- /* This function extracts the text and sprite info given an icon block and
- its icon flags. If necessary, it copies indirected text or sprite data
- from the other task. */
- ibarpatch_icon_properties *ibarpatch_extract_info(wimp_t task,
- wimp_icon_flags flags, const wimp_icon_data *data)
- {
- os_error *e;
- ibarpatch_icon_properties *i = malloc(sizeof(ibarpatch_icon_properties));
- if(!i) x_throw_message(x_msg_memory());
-
- DEBUGF("Extracting icon info: ");
-
- /* Use Wimp area by default, but the value may be changed later. */
- i->sprite.area = 0;
- /* By default, sprite pointers are not exchanged. */
- i->sprite.is_ptr = 0;
-
- /* So, what are our choices of icon type? */
- if(flags & wimp_ICON_INDIRECTED) {
- if(flags & wimp_ICON_TEXT) {
-
- /* Handle indirected, text + sprite icons */
- /* Assumes that these always have a sprite */
-
- const int overflow = 40, validation_max = 256;
- char *c, *buffer, *t;
-
- DEBUGF("text+sprite icon");
-
- /* Copy indirected text */
- c = i->text = malloc(data->indirected_text.size + overflow + 1);
- if(!c) x_throw_message(x_msg_memory());
- t = c + data->indirected_text.size + overflow;
- e = xwimp_transfer_block(task, (byte *) data->indirected_text.text,
- dscape_task_get_handle(), (byte *) c,
- data->indirected_text.size + overflow);
- if(!e) {
- while(*c >= 32 && c < t) ++c;
- *c = 0;
- }
- else {
- strcpy(i->text, "<failed>");
- DEBUGF1(", text transfer error `%s'", e->errmess);
- }
- DEBUGF2(", text `%s' (at 0x%p)", i->text, data->indirected_text.text);
-
- /* Copy validation string and extract sprite name */
- c = i->sprite.id.name = malloc(16);
- t = buffer = malloc(validation_max);
- if(!c || !t) x_throw_message(x_msg_memory());
- /* Horrid I know, because it doesn't free it properly on failure */
- if(xwimp_transfer_block(task, (byte *)
- data->indirected_text.validation, dscape_task_get_handle(),
- (byte *) buffer, validation_max)) { goto sprite_failed; }
- buffer[validation_max-1] = 0; /* Add emergency terminator */
- DEBUGF2(", validation string `%s' (at 0x%p)", buffer,
- data->indirected_text.validation);
- /* Search until we find an `s' (sprite) term */
- while(*t != 's' && *t != 'S' && /* An `s' term? */
- (t == buffer || t[-1] != ';') && /* Start of a term? */
- *t >= 32) /* End of string? */
- { if(*t == '\\') t += 2; else ++t; } /* Handle escape char */
- /* If we found an `s' term, copy the sprite name */
- if(*t == 's' || *t == 'S') {
- char *begin = ++t;
- /* If the icon has its selected flag set, skip to the second
- sprite name */
- if(flags & wimp_ICON_SELECTED) {
- DEBUGF(", icon selected");
- while(*t != ';' && *t != ',' && *t > 32) ++t;
- if(*t != ',') t = begin; else ++t;
- }
- while(*t != ';' && *t != ',' && *t > 32)
- *c++ = *t++;
- *c = 0;
- }
- else {
- sprite_failed: /* If that failed, use a default sprite */
- strcpy(c, "badibicon");
- }
- free(buffer);
- DEBUGF1(", sprite `%s'\n", i->sprite.id.name);
- }
- else {
- /* Handle indirected, sprite-only icons */
- DEBUGF("indirected sprite icon");
-
- /* Sprite is referred to by name, so copy the name */
- if(data->indirected_sprite.area == wimpspriteop_AREA ||
- data->indirected_sprite.size) {
- char *c = i->sprite.id.name = malloc(16);
- if(!c) x_throw_message(x_msg_memory());
- if(xwimp_transfer_block(task, (byte *) data->indirected_sprite.id,
- dscape_task_get_handle(), (byte *) c, 16))
- { free(i->sprite.id.name); goto ind_failed; }
- while(*c > 32 && (c - i->sprite.id.name) < 16) ++c;
- *c = 0;
- DEBUGF1(", sprite name `%s'", i->sprite.id.name);
- }
-
- /* Ho ho, this is fun. The app has a sprite in its own sprite pool,
- so we must copy it into our own wimpslot. */
- if(data->indirected_sprite.area != wimpspriteop_AREA) {
- /* We do this the suboptimal way. First, we transfer the first 4
- bytes of the area to find out how large it is. Then we transfer
- the whole thing. There are always two transfers, which would be
- the unavoidable worst case anyway. (Guesses could be made to
- reduce it to one transfer, but this is simpler.) */
- osspriteop_area *sdata;
- int size;
- if(xwimp_transfer_block(task, (byte *) data->indirected_sprite.area,
- dscape_task_get_handle(), (byte *) &size, 4))
- { goto ind_failed; }
- DEBUGF1(", copying sprite area (size %i)", size);
- if(size <= 16) {
- /* If the size was read as zero (or a stupidly low value), set it
- defensively to 10k. This is necessary for SwiftJPEG, which
- doesn't bother filling in its size (broken!). However, well
- done for providing source so I could check my suspicions! */
- size = 10 * 1024;
- DEBUGF1(", fiddled size to %i", size);
- }
- sdata = malloc(size);
- if(!sdata) x_throw_message(x_msg_memory());
- if(xwimp_transfer_block(task, (byte *) data->indirected_sprite.area,
- dscape_task_get_handle(), (byte *) sdata, size))
- { free(sdata); goto ind_failed; }
- i->sprite.area = sdata;
-
- /* Sprite is *not* referred to by name, so fiddle the sprite pointer
- so that it points within our sprite area. */
- if(!data->indirected_sprite.size) {
- i->sprite.id.ptr = (osspriteop_id) ((char *) sdata +
- (int) data->indirected_sprite.id -
- (int) data->indirected_sprite.area);
- i->sprite.is_ptr = 1;
- DEBUGF(", uses sprite pointer");
- }
- }
- /* If a data transfer failed, we jump here and fill in a default
- sprite name. */
- if(0) {
- ind_failed:
- i->sprite.id.name = malloc(16);
- if(!i->sprite.id.name) x_throw_message(x_msg_memory());
- strcpy(i->sprite.id.name, "badibicon");
- i->sprite.is_ptr = 0;
- i->sprite.area = 0;
- }
- i->text = 0;
- DEBUGF("\n");
- }
- }
- else {
- /* Handle non-indirected icons */
- /* Assumes that these are going to be sprite-only */
-
- /* Copy the sprite name */
- char *c = i->sprite.id.name = malloc(16);
- if(!c) x_throw_message(x_msg_memory());
- memcpy(c, data->sprite, 12);
- while(*c > 32 && (c - i->sprite.id.name) < 12) ++c;
- *c = 0;
- i->text = 0;
- DEBUGF1("non-indirected sprite icon, name `%s'\n", i->sprite.id.name);
- }
- return i;
- }
-
- /* Frees the data returned by ibarpatch_extract_info(), all except for the
- sprite area (which is typically passed to the iconbar gadget to keep). */
- void ibarpatch_free_info(ibarpatch_icon_properties *info)
- {
- if(!info) return;
-
- free(info->text);
- if(!info->sprite.is_ptr) free(info->sprite.id.name);
- free(info);
- }
-
-
- #define MAGIC_TASK_WORD 0x4B534154
-
- /* This function allows you to alter a window's flags. Via hackery, this
- will work on any Wimp version. Like Wimp_SetIconState, this takes flags
- to clear and flags to invert. Does not mind if the window is open or
- not. */
- void set_window_flags(wimp_w window, wimp_window_flags eor_bits,
- wimp_window_flags clear_bits)
- {
- int wimp_vsn;
- LOGFUNC(set_window_flags);
-
- /* This all depends on the Wimp version. */
- wimp_vsn = wimpreadsysinfo_version();
- /* Wimp 3.68 is the version that comes with RISC OS 3.7. */
- if(wimp_vsn > 368) {
- /* We are running under a new version (the Nested Wimp). This lets us
- change window flags via a SWI. Thanks to an anonymous informant
- who provided documentation. :-) */
- wimp_window_state block;
- wimp_window_flags old_flags;
- wimp_w parent_window;
- unsigned align_flags;
- DEBUGF("Using Nested Wimp SWI to set window flags\n");
-
- /* Read the current window block. */
- block.w = window;
- _swi(Wimp_GetWindowState, _IN(1)|_IN(2)|_OUT(3)|_OUT(4), &block,
- MAGIC_TASK_WORD, &parent_window, &align_flags);
- old_flags = block.flags;
- block.flags = (block.flags &~ clear_bits) ^ eor_bits;
-
- /* Set the flags with new-form Wimp_OpenWindow. The block from
- Wimp_GetWindowInfo corresponds to that required by Wimp_OpenWindow. */
- /* If the window wasn't open before, we don't want it open now, so send
- it to very bottom of stack. */
- if(!(old_flags & wimp_WINDOW_OPEN)) block.next = wimp_HIDDEN;
- _swi(Wimp_OpenWindow, _IN(1)|_IN(2)|_IN(3)|_IN(4), &block,
- MAGIC_TASK_WORD, parent_window,
- align_flags | 1 /* Set window flags */);
-
- /* If the window was closed before, make sure it's closed now. */
- if(!(old_flags & wimp_WINDOW_OPEN)) wimp_close_window(window);
- }
- else {
- /* We are running on an old Wimp version. This is where it gets fun.
- We have to hack the Wimp's workspace to change the flags; luckily
- we only have to do this on known versions. Thanks to Stewart Brodie
- for his explanation of how to do this. */
- int offset;
- char *wp = ((char *) window) - 1;
- wimp_window *block;
- DEBUGF("Using hackery to set window flags\n");
-
- #ifdef MemCheck_MEMCHECK
- MemCheck_RegisterMiscBlock(wp, sizeof(wimp_window) + 100);
- #endif
-
- /* Check window is valid. */
- if(!window ||
- ((int) window < 0 && (int) window > -10) ||
- ((int) window & 3) != 1 ||
- wp[0] != 'W' || wp[1] != 'i' || wp[2] != 'n' || wp[3] != 'd')
- x_throw_message("Illegal window handle when hacking workspace");
-
- /* Find offset of window block. */
- if(wimp_vsn >= 350 && wimp_vsn <= 368) offset = 80;
- else if(wimp_vsn >= 310 && wimp_vsn <= 324) offset = 72;
- else { offset = 0; /* Suppress warning */
- x_throw_message("Can't hack workspace on this Wimp version"); }
- block = (wimp_window *) (wp + offset);
-
- /* Make some checks */
- if(!(block->title_flags & (wimp_ICON_TEXT | wimp_ICON_FILLED) &&
- ~block->title_flags & wimp_ICON_SPRITE &&
- block->scroll_outer == 3 &&
- block->scroll_inner == 1))
- x_throw_message("Can't hack Wimp workspace "
- "(reason: block doesn't look like a window)");
-
- /* On a debug build, make more comprehensive checks. */
- #ifdef DEBUG
- {
- wimp_window_info got;
- got.w = window;
- wimp_get_window_info_header_only(&got);
- /* Check our block with what the Wimp tells us.
- Don't bother checking it all. */
- if(!(got.title_flags == block->title_flags &&
- got.work_flags == block->work_flags &&
- got.sprite_area == block->sprite_area &&
- got.next == block->next))
- x_throw_message("Can't hack Wimp workspace (check failed)");
- }
- #endif
-
- /* Now fiddle with the Wimp's data. */
- block->flags = (block->flags &~ clear_bits) ^ eor_bits;
-
- #ifdef MemCheck_MEMCHECK
- MemCheck_UnRegisterMiscBlock(wp);
- #endif
- }
- }
-
- /* Returns the task handle of the task owning the given Wimp window (and
- icon). Returns 0 if unsuccessful. Icon handle will usually be -1. */
- wimp_t task_handle_from_window(wimp_w window, int icon)
- {
- wimp_t owning_task;
- wimp_message msg;
- LOGFUNC(task_handle_from_window);
- if(!window) return 0;
-
- /* Send a fake message to the other window. */
- msg.size = 5*4;
- msg.my_ref = msg.your_ref = 0;
- msg.action = -1;
- if(xwimp_send_message_to_window(wimp_USER_MESSAGE_ACKNOWLEDGE, &msg,
- window, icon, &owning_task)) return 0;
- return owning_task;
- }
-