doc@s.cc.purdue.edu (Craig Norborg) (06/22/87)
Here is the source to placewindow as promised by Mike Meyer. If you wish for this to compile using AZTEC, you must use the -DAZTEC switch while compiling. I did the AZTEC port, and do not totally guarantee it, but it seems to work just fine. Without the -DAZTEC, your running virgin mwm code. -Craig Norborg # This is a shell archive. # Remove everything above and including the cut line. # Then run the rest of the file through sh. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: Shell Archiver # Run the following text with /bin/sh to create: # placewindow.c # This archive created: Mon Jun 22 01:57:53 1987 # By: Craig Norborg (Purdue University Computing Center) cat << \SHAR_EOF > placewindow.c /* * 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) ; } SHAR_EOF # End of shell archive exit 0