home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Fish 1
/
GoldFishApril1994_CD1.img
/
d1xx
/
d112
/
bully
/
placewindow.c
< prev
next >
Wrap
C/C++ Source or Header
|
1987-11-15
|
11KB
|
344 lines
/*
* placewindow - starts a program, and make the window look like you want it
* to, not like the person who wrote the program wants it to.
*
* Copyright (c) 1987, Mike Meyer
* This program can be redistributed freely, under two conditions:
* 1) The source must be part of the distribution.
* 2) This copyright notice must stay attached to the source.
*
* usage: placewindow windowname geometry [ command ]
*
* windowname is a proper prefix of the title for the window
* that we're going to change.
*
* geometry describes where the window should be, and how it should
* look. This is an enhanced version of the con: syntax for
* specifying where a window should go. The full spec is
* X/Y/W/H/e. Postive X (Y) specifies the offset from the
* left (top) edge of the screen to the left (top) edge of
* the window. Negative X (Y) specifes the offset from the
* right (bottom) edge of the screen to the right (bottom)
* edge of the window. W and H are the width and height of
* the window, respectively. Zero values for those means to
* make the window as long as possible in that direction.
* Obviously, you can't specify -X and 0 W, or -Y and 0 H.
* The "e", if present, means that the maximum sizes for the
* window should be set to -1 (any value you can mouse to).
* Nearly any piece of this can be left off. If the value is
* not specified (i.e., you didn't put in enough geometry to
* reach it) then it is left unmodified. If you actually put
* in the gemoetry specification, but don't put in a number
* (i.e. "////") then the missing values are treated as zero.
*
* Simple examples: "////", "////e" and "-////" all specify
* max-sized windows. The "e" makes the max-sized window the
* screen size, and makes the window that big. "-" positions the
* window against the right edge of the screen if it's smaller
* than the screen. '10////', '10////', '10////e' and '10////e'
* all specify windows that are max-height, and stretch as far
* as they can from 10 pixels to the right of the left edge of
* the screen. The two with the "e" make the max-size window
* the screen size. The first two are synonyms, as are the
* last two. '10//100e' will be a window that start 10 pixels
* to the right of the left edge of the screen, is 100 pixels
* wide, and stretches from the top to the bottom of the
* screen. '10/10//100e' will be a window with it's upper left
* corner at 10, 10, is 100 pixels high, and stretches from
* the left to the right edge of the screen. '10/10/100/100e'
* and '10/10/100/100/e' both describe a 100 by 100 window with
* it's upper left corner at 10, 10 that has had it's maximum
* window sizes changed to the screen sizes. For leaving things
* off, '3/10' and '3/10e' would be a window the same size as
* the default, at location 3, 10. Note that '///' and '///e' are
* windows at 0, 0 with max-size X, and Y left alone, but '////'
* and '////e' are full-screen windows. Finally, a lone "e" will
* leave the window alone, but change it's maximum size but
* otherwise leave it alone.
*
* command consists of all following arguments, and is a command to be
* executed before we try resizing the window. If command is
* given, we'll try to find the window at 1-second intervals
* one minute (roughly), so that command can create the window.
* If command isn't specified, we just look for the window
* once.
*
* Warning: Negative W and H values in the geometry aren't supported,
* and I ain't going to say what happens if you use them.
* Sanity checks are done on the size/position. Rather than
* abort and have you try again, it trys to do something
* sane. Improvements on this code are welcome.
*/
#include <stdio.h>
#ifndef AZTEC
#include <string.h>
#include <dos.h>
#else
#include <ctype.h>
#endif
#include <libraries/dos.h>
#include <exec/types.h>
#include <intuition/intuitionbase.h>
/*
* Declare names for the error returns.
*/
#define OK 0
#define ARG_ERROR 100
#define NO_INTUITION 200
#define NO_MEMORY 300
#define COMMAND_ERROR 400
#define NO_WINDOW 500
#define BAD_ARGS 600
struct IntuitionBase *IntuitionBase;
void
main(argc, argv) char **argv; {
register short counter, length, width, height, x, y ;
register char *out, *in, *geometry ;
register struct Window *w ;
register struct Screen *s ;
long lock ;
short xminusp, yminusp ;
char *command ;
/*
* Error processing - we need at least two args + our name
*/
if (argc < 3) {
fprintf(stderr,
"usage: %s windowname geometry [ command ... ]\n",
argv[0]) ;
exit(ARG_ERROR) ;
}
/*
* If only have two arguments, then it's a window name and a geomtry.
* We're only going to try once, so set the counter for one try.
* Otherwise, we need to run the command, and retry 60 times (for up
* to a minute.
*/
if (argc == 3) counter = 1 ;
else {
/*
* We want to run the command first, so that it has as much time as possible
* to get the window open before we go looking for it. To do that, we need to
* turn the args list into a string for execution. Step one is to count
* the total number of characters, with one extra for pad.
*/
for (length = 0, counter = 3; counter < argc; counter++)
length += strlen(argv[counter]) + 1 ;
/*
* Step two is to get space for the command to reside in.
*/
if ((command = (char *) malloc(length + 4)) == NULL) {
fprintf(stderr,
"%s: Couldn't get %d bytes", argv[0], length) ;
exit(NO_MEMORY) ;
}
/*
* Step three is to put the "run " into the buffer.
*/
(void) strcpy(command, "run ") ;
/*
* And step four is to copy the strings into it.
*/
for (out = &command[4], counter = 3; counter < argc; counter++){
for (in = argv[counter]; *in;)
*out++ = *in++ ;
*out++ = ' ' ;
}
*out = '\0' ;
/*
* Now, just execute the rest of the args as a command.
*/
if (!Execute(command, 0, 0)) {
fprintf(stderr, "%s: %s failed\n", argv[0], argv[3]) ;
exit(COMMAND_ERROR) ;
}
counter = 60 ;
}
/*
* Parsing the geometry turned out to be the nasty part of this program,
* probably because I tried to do it ad hoc. It took almost no time after
* I sat down and wrote out the bnf. Which is:
*
* geometry ::= spec flag
* flag ::= 'e' | '/' 'e' | nil
* spec ::= pos_spec
* | pos_spec '/' pos_spec
* | pos_spec '/' pos_spec '/' dim_spec
* | pos_spec '/' pos_spec '/' dim_spec '/' dim_spec
* pos_spec ::= number | '-' | '-' number | nil
* dim_spec ::= number | nil
* number ::= a string of digits, of course.
* nil ::= an empty string
*
* Following that, parsing is easy. First, set up the defaults values
* if things are missing. Then, for the two pos_spec pieces, check
* for a minus sign. If it's there, bump the pointer and note that this
* is a negative value. For all the pieces, you then check to see
* if you've come to the flags part (end of string or a 'e'), and
* drop to finished parsing if so. Otherwise, you translate the string
* of digits to a number (an empty string is 0), and check to see if
* there's a trailing '/' that needs to be skipped. Then on to the
* next piece. At the end of all of this, the pointer is left pointing
* to any 'e' that may be there.
*/
geometry = argv[2] ;
x = y = width = height = -1 ;
xminusp = yminusp = FALSE ;
/* X */ if (*geometry == '-') {
geometry += 1 ;
xminusp = TRUE ;
}
if (*geometry == '\0' || *geometry == 'e' || *geometry == 'E')
goto parse_over ;
x = atoi(geometry) ;
#ifndef AZTEC
geometry += strspn(geometry, "0123456789") ;
#else
while (isdigit(*geometry))
++geometry;
#endif
if (*geometry == '/') geometry += 1 ;
/* Y */ if (*geometry == '-') {
geometry += 1 ;
yminusp = TRUE ;
}
if (*geometry == '\0' || *geometry == 'e' || *geometry == 'E')
goto parse_over ;
y = atoi(geometry) ;
#ifndef AZTEC
geometry += strspn(geometry, "0123456789") ;
#else
while (isdigit(*geometry))
++geometry;
#endif
if (*geometry == '/') geometry += 1 ;
/* W */ if (*geometry == '\0' || *geometry == 'e' || *geometry == 'E')
goto parse_over ;
width = atoi(geometry) ;
#ifndef AZTEC
geometry += strspn(geometry, "0123456789") ;
#else
while (isdigit(*geometry))
++geometry;
#endif
if (*geometry == '/') geometry += 1 ;
/* H */ if (*geometry == '\0' || *geometry == 'e' || *geometry == 'E')
goto parse_over ;
height = atoi(geometry) ;
#ifndef AZTEC
geometry += strspn(geometry, "0123456789") ;
#else
while (isdigit(*geometry))
++geometry;
#endif
if (*geometry == '/') geometry += 1 ;
parse_over:
/*
* Fix the case on the flag.
*/
if (*geometry == 'E') *geometry = 'e' ;
/*
* Now, verify that we didn't get both negative offsets & unspecified
* dimensions.
*/
if ((xminusp && width == 0) || (yminusp && height == 0)) {
fprintf(stderr, "%s: Bad geometry %s, to many defaults!\n",
argv[0], argv[2]) ;
exit(BAD_ARGS) ;
}
/*
* Now, get IntuitionBase so we can find the window we need.
*/
if ((IntuitionBase = (struct IntuitionBase *)
OpenLibrary("intuition.library", 0)) == NULL) {
fprintf(stderr, "%s: Can't open intuition\n", argv[0]) ;
exit(NO_INTUITION) ;
}
/*
* We need to know how much of the window title to check.
*/
length = strlen(argv[1]) ;
/*
* Now, until we find the window, or have tried for over a minute,
* keep trying to find the window we're looking for.
*/
for (;;) {
lock = LockIBase(0L) ;
for (s = IntuitionBase->FirstScreen; s; s = s->NextScreen)
for (w = s->FirstWindow; w; w = w->NextWindow)
if (strncmp(w->Title, argv[1], length) == 0)
goto found_it ;
UnlockIBase(lock) ;
if (--counter) Delay(TICKS_PER_SECOND) ;
else break ;
} ;
/*
* We never found the window. Clean up, and go tell the user.
* go.
*/
fprintf(stderr, "%s: Couldn't find window %s\n", argv[0], argv[1]) ;
CloseLibrary(IntuitionBase) ;
exit(NO_WINDOW) ;
/*
* Find it. The rest of this block deals with fixing the window sizing
* to be reasonable, and actually doing the sizing.
*/
found_it:
if (*geometry == 'e') WindowLimits(w, 0, 0, -1, -1) ;
/*
* Get absolute width & height values.
*/
if (width == 0) width = s->Width - x ;
else if (width == -1) width = w->Width ;
if (height == 0) height = s->Height - y ;
else if (height == -1) height = w->Height ;
/*
* and sanity check them.
*/
if (width > w->MaxWidth) width = w->MaxWidth ;
if (width > s->Width) width = s->Width ;
if (width < w->MinWidth) width = w->MinWidth ;
if (height > w->MaxHeight) height = w->MaxHeight ;
if (height > s->Height) height = s->Height ;
if (height < w->MinHeight) height = w->MinHeight ;
/*
* find absolute x & y values.
*/
if (xminusp) x = s->Width - width - x ;
else if (x == -1) x = w->LeftEdge ;
if (yminusp) y = s->Height - height - y ;
else if (y == -1) y = w->TopEdge ;
/*
* now sanity check them.
*/
if (x >= s->Width || x < 0) x = 0 ;
if (y >= s->Height || y < 0) y = 0 ;
/*
* Now sanity check the whole
* package.
*/
if (x + width > s->Width) x = s->Width - width ;
if (y + height > s->Height) y = s->Height - height ;
/*
* Now we can set the sizes.
*/
SizeWindow(w, width - w->Width, height - w->Height) ;
MoveWindow(w, x - w->LeftEdge, y - w->TopEdge) ;
/*
* And clean up and exit.
*/
UnlockIBase(lock) ;
CloseLibrary(IntuitionBase) ;
exit(OK) ;
}