home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ARM Club 3
/
TheARMClub_PDCD3.iso
/
programs
/
desktop
/
newbar
/
Source
/
NewBar
/
c
/
hacky
< prev
next >
Wrap
Text File
|
1998-08-07
|
12KB
|
328 lines
/* 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;
}