home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 053.lha / PlaceWindow.c < prev    next >
C/C++ Source or Header  |  1986-11-20  |  12KB  |  344 lines

  1. /*
  2.  * placewindow - starts a program, and make the window look like you want it
  3.  * to, not like the person who wrote the program wants it to.
  4.  *
  5.  * Copyright (c) 1987, Mike Meyer
  6.  * This program can be redistributed freely, under two conditions:
  7.  *    1) The source must be part of the distribution.
  8.  *    2) This copyright notice must stay attached to the source.
  9.  *
  10.  * usage: placewindow windowname geometry [ command ]
  11.  *
  12.  *    windowname is a proper prefix of the title for the window
  13.  *        that we're going to change.
  14.  *
  15.  *    geometry describes where the window should be, and how it should
  16.  *        look. This is an enhanced version of the con: syntax for
  17.  *        specifying where a window should go. The full spec is
  18.  *        X/Y/W/H/e. Postive X (Y) specifies the offset from the
  19.  *        left (top) edge of the screen to the left (top) edge of
  20.  *        the window. Negative X (Y) specifes the offset from the
  21.  *        right (bottom) edge of the screen to the right (bottom)
  22.  *        edge of the window. W and H are the width and height of
  23.  *        the window, respectively. Zero values for those means to
  24.  *        make the window as long as possible in that direction.
  25.  *        Obviously, you can't specify -X and 0 W, or -Y and 0 H.
  26.  *        The "e", if present, means that the maximum sizes for the
  27.  *        window should be set to -1 (any value you can mouse to).
  28.  *        Nearly any piece of this can be left off. If the value is
  29.  *        not specified (i.e., you didn't put in enough geometry to
  30.  *        reach it) then it is left unmodified. If you actually put
  31.  *        in the gemoetry specification, but don't put in a number
  32.  *        (i.e. "////") then the missing values are treated as zero.
  33.  *
  34.  *        Simple examples: "////", "////e" and "-////" all specify
  35.  *        max-sized windows. The "e" makes the max-sized window the
  36.  *        screen size, and makes the window that big. "-" positions the
  37.  *        window against the right edge of the screen if it's smaller
  38.  *        than the screen. '10////', '10////', '10////e' and '10////e'
  39.  *        all specify windows that are max-height, and stretch as far
  40.  *        as they can from 10 pixels to the right of the left edge of
  41.  *        the screen. The two with the "e" make the max-size window
  42.  *        the screen size. The first two are synonyms, as are the
  43.  *        last two. '10//100e' will be a window that start 10 pixels
  44.  *        to the right of the left edge of the screen, is 100 pixels
  45.  *        wide, and stretches from the top to the bottom of the
  46.  *        screen. '10/10//100e' will be a window with it's upper left
  47.  *        corner at 10, 10, is 100 pixels high, and stretches from
  48.  *        the left to the right edge of the screen. '10/10/100/100e'
  49.  *        and '10/10/100/100/e' both describe a 100 by 100 window with
  50.  *        it's upper left corner at 10, 10 that has had it's maximum
  51.  *        window sizes changed to the screen sizes. For leaving things
  52.  *        off, '3/10' and '3/10e' would be a window the same size as
  53.  *        the default, at location 3, 10. Note that '///' and '///e' are
  54.  *        windows at 0, 0 with max-size X, and Y left alone, but '////'
  55.  *        and '////e' are full-screen windows. Finally, a lone "e" will
  56.  *        leave the window alone, but change it's maximum size but
  57.  *        otherwise leave it alone.
  58.  *
  59.  *    command consists of all following arguments, and is a command to be
  60.  *        executed before we try resizing the window. If command is
  61.  *        given, we'll try to find the window at 1-second intervals
  62.  *        one minute (roughly), so that command can create the window.
  63.  *        If command isn't specified, we just look for the window
  64.  *        once.
  65.  *
  66.  *    Warning: Negative W and H values in the geometry aren't supported,
  67.  *        and I ain't going to say what happens if you use them.
  68.  *        Sanity checks are done on the size/position. Rather than
  69.  *        abort and have you try again, it trys to do something
  70.  *        sane. Improvements on this code are welcome.
  71.  */
  72.  
  73. #include <stdio.h>
  74. #ifndef AZTEC
  75. #include <string.h>
  76. #include <dos.h>
  77. #else
  78. #include <ctype.h>
  79. #endif
  80. #include <libraries/dos.h>
  81. #include <exec/types.h>
  82. #include <intuition/intuitionbase.h>
  83.  
  84. /*
  85.  * Declare names for the error returns.
  86.  */
  87. #define    OK        0
  88. #define ARG_ERROR    100
  89. #define NO_INTUITION    200
  90. #define NO_MEMORY    300
  91. #define COMMAND_ERROR    400
  92. #define    NO_WINDOW    500
  93. #define    BAD_ARGS    600
  94.  
  95. struct IntuitionBase *IntuitionBase;
  96.  
  97. void
  98. main(argc, argv) char **argv; {
  99.     register short        counter, length, width, height, x, y ;
  100.     register char        *out, *in, *geometry ;
  101.     register struct Window    *w ;
  102.     register struct Screen    *s ;
  103.     long            lock ;
  104.     short            xminusp, yminusp ;
  105.     char            *command ;
  106.  
  107. /*
  108.  * Error processing - we need at least two args + our name
  109.  */
  110.     if (argc < 3) {
  111.         fprintf(stderr,
  112.             "usage: %s windowname geometry [ command ... ]\n",
  113.             argv[0]) ;
  114.         exit(ARG_ERROR) ;
  115.         }
  116. /*
  117.  * If only have two arguments, then it's a window name and a geomtry.
  118.  * We're only going to try once, so set the counter for one try.
  119.  * Otherwise, we need to run the command, and retry 60 times (for up
  120.  * to a minute.
  121.  */
  122.     if (argc == 3) counter = 1 ;
  123.     else {
  124. /*
  125.  * We want to run the command first, so that it has as much time as possible
  126.  * to get the window open before we go looking for it. To do that, we need to
  127.  * turn the args list into a string for execution. Step one is to count
  128.  * the total number of characters, with one extra for pad.
  129.  */
  130.         for (length = 0, counter = 3; counter < argc; counter++)
  131.             length += strlen(argv[counter]) + 1 ;
  132. /*
  133.  * Step two is to get space for the command to reside in.
  134.  */
  135.         if ((command = (char *) malloc(length + 4)) == NULL) {
  136.             fprintf(stderr,
  137.                 "%s: Couldn't get %d bytes", argv[0], length) ;
  138.             exit(NO_MEMORY) ;
  139.             }
  140. /*
  141.  * Step three is to put the "run " into the buffer.
  142.  */
  143.         (void) strcpy(command, "run ") ;
  144. /*
  145.  * And step four is to copy the strings into it. 
  146.  */
  147.         for (out = &command[4], counter = 3; counter < argc; counter++){
  148.             for (in = argv[counter]; *in;)
  149.                 *out++ = *in++ ;
  150.             *out++ = ' ' ;
  151.             }
  152.         *out = '\0' ;
  153. /*
  154.  * Now, just execute the rest of the args as a command.
  155.  */
  156.         if (!Execute(command, 0, 0)) {
  157.             fprintf(stderr, "%s: %s failed\n", argv[0], argv[3]) ;
  158.             exit(COMMAND_ERROR) ;
  159.             }
  160.         counter = 60 ;
  161.         }
  162. /*
  163.  * Parsing the geometry turned out to be the nasty part of this program,
  164.  * probably because I tried to do it ad hoc. It took almost no time after
  165.  * I sat down and wrote out the bnf. Which is:
  166.  *
  167.  *    geometry ::= spec flag
  168.  *    flag ::= 'e' | '/' 'e' | nil
  169.  *    spec ::=  pos_spec
  170.  *        | pos_spec '/' pos_spec
  171.  *        | pos_spec '/' pos_spec '/' dim_spec
  172.  *        | pos_spec '/' pos_spec '/' dim_spec '/' dim_spec
  173.  *    pos_spec ::= number | '-' | '-' number | nil
  174.  *    dim_spec ::= number | nil
  175.  *    number ::= a string of digits, of course.
  176.  *    nil ::= an empty string
  177.  *
  178.  * Following that, parsing is easy. First, set up the defaults values
  179.  * if things are missing. Then, for the two pos_spec pieces, check
  180.  * for a minus sign. If it's there, bump the pointer and note that this
  181.  * is a negative value. For all the pieces, you then check to see
  182.  * if you've come to the flags part (end of string or a 'e'), and
  183.  * drop to finished parsing if so. Otherwise, you translate the string
  184.  * of digits to a number (an empty string is 0), and check to see if
  185.  * there's a trailing '/' that needs to be skipped. Then on to the
  186.  * next piece. At the end of all of this, the pointer is left pointing
  187.  * to any 'e' that may be there.
  188.  */
  189.     geometry = argv[2] ;
  190.     x = y = width = height = -1 ;
  191.     xminusp = yminusp = FALSE ;
  192.  
  193. /* X */    if (*geometry == '-') {
  194.         geometry += 1 ;
  195.         xminusp = TRUE ;
  196.         }
  197.     if (*geometry == '\0' || *geometry == 'e' || *geometry == 'E')
  198.         goto parse_over ;
  199.     x = atoi(geometry) ;
  200. #ifndef AZTEC
  201.     geometry += strspn(geometry, "0123456789") ;
  202. #else
  203.     while (isdigit(*geometry))
  204.         ++geometry;
  205. #endif
  206.     if (*geometry == '/') geometry += 1 ;
  207.  
  208. /* Y */    if (*geometry == '-') {
  209.         geometry += 1 ;
  210.         yminusp = TRUE ;
  211.         }
  212.     if (*geometry == '\0' || *geometry == 'e' || *geometry == 'E')
  213.         goto parse_over ;
  214.     y = atoi(geometry) ;
  215. #ifndef AZTEC
  216.     geometry += strspn(geometry, "0123456789") ;
  217. #else
  218.     while (isdigit(*geometry))
  219.         ++geometry;
  220. #endif
  221.     if (*geometry == '/') geometry += 1 ;
  222.  
  223. /* W */    if (*geometry == '\0' || *geometry == 'e' || *geometry == 'E')
  224.         goto parse_over ;
  225.     width = atoi(geometry) ;
  226. #ifndef AZTEC
  227.     geometry += strspn(geometry, "0123456789") ;
  228. #else
  229.     while (isdigit(*geometry))
  230.         ++geometry;
  231. #endif
  232.     if (*geometry == '/') geometry += 1 ;
  233.  
  234. /* H */    if (*geometry == '\0' || *geometry == 'e' || *geometry == 'E')
  235.         goto parse_over ;
  236.     height = atoi(geometry) ;
  237. #ifndef AZTEC
  238.     geometry += strspn(geometry, "0123456789") ;
  239. #else
  240.     while (isdigit(*geometry))
  241.         ++geometry;
  242. #endif
  243.     if (*geometry == '/') geometry += 1 ;
  244.  
  245. parse_over:
  246. /*
  247.  * Fix the case on the flag.
  248.  */
  249.     if (*geometry == 'E') *geometry = 'e' ;
  250. /*
  251.  * Now, verify that we didn't get both negative offsets & unspecified
  252.  * dimensions.
  253.  */
  254.     if ((xminusp && width == 0) || (yminusp && height == 0)) {
  255.         fprintf(stderr, "%s: Bad geometry %s, to many defaults!\n",
  256.             argv[0], argv[2]) ;
  257.         exit(BAD_ARGS) ;
  258.         }
  259. /*
  260.  * Now, get IntuitionBase so we can find the window we need.
  261.  */
  262.     if ((IntuitionBase = (struct IntuitionBase *)
  263.         OpenLibrary("intuition.library", 0)) == NULL) {
  264.         fprintf(stderr, "%s: Can't open intuition\n", argv[0]) ;
  265.         exit(NO_INTUITION) ;
  266.         }
  267. /*
  268.  * We need to know how much of the window title to check.
  269.  */
  270.     length = strlen(argv[1]) ;
  271. /*
  272.  * Now, until we find the window, or have tried for over a minute,
  273.  * keep trying to find the window we're looking for.
  274.  */
  275.     for (;;) {
  276.         lock = LockIBase(0L) ;
  277.         for (s = IntuitionBase->FirstScreen; s; s = s->NextScreen)
  278.             for (w = s->FirstWindow; w; w = w->NextWindow)
  279.                 if (strncmp(w->Title, argv[1], length) ==  0)
  280.                     goto found_it ;
  281.         UnlockIBase(lock) ;
  282.         if (--counter) Delay(TICKS_PER_SECOND) ;
  283.         else break ;
  284.         } ;
  285. /*
  286.  * We never found the window. Clean up, and go tell the user.
  287.  * go.
  288.  */
  289.     fprintf(stderr, "%s: Couldn't find window %s\n", argv[0], argv[1]) ;
  290.     CloseLibrary(IntuitionBase) ;
  291.     exit(NO_WINDOW) ;
  292. /*
  293.  * Find it. The rest of this block deals with fixing the window sizing
  294.  * to be reasonable, and actually doing the sizing.
  295.  */
  296. found_it:
  297.     if (*geometry == 'e') WindowLimits(w, 0, 0, -1, -1) ;
  298. /*
  299.  * Get absolute width & height values.
  300.  */
  301.     if (width == 0) width = s->Width - x ;
  302.     else if (width == -1) width = w->Width ;
  303.     if (height == 0) height = s->Height - y ;
  304.     else if (height == -1) height = w->Height ;
  305. /*
  306.  * and sanity check them.
  307.  */
  308.     if (width > w->MaxWidth) width = w->MaxWidth ;
  309.     if (width > s->Width) width = s->Width ;
  310.     if (width < w->MinWidth) width = w->MinWidth ;
  311.     if (height > w->MaxHeight) height = w->MaxHeight ;
  312.     if (height > s->Height) height = s->Height ;
  313.     if (height < w->MinHeight) height = w->MinHeight ;
  314. /*
  315.  * find absolute x & y values.
  316.  */
  317.     if (xminusp) x = s->Width - width - x ;
  318.     else if (x == -1) x = w->LeftEdge ;
  319.     if (yminusp) y = s->Height - height - y ;
  320.     else if (y == -1) y = w->TopEdge ;
  321. /*
  322.  * now sanity check them.
  323.  */
  324.     if (x >= s->Width || x < 0) x = 0 ;
  325.     if (y >= s->Height || y < 0) y = 0 ;
  326. /*
  327.  * Now sanity check the whole
  328.  * package.
  329.  */
  330.     if (x + width > s->Width) x = s->Width - width ;
  331.     if (y + height > s->Height) y = s->Height - height ;
  332. /*
  333.  * Now we can set the sizes.
  334.  */
  335.     SizeWindow(w, width - w->Width, height - w->Height) ;
  336.     MoveWindow(w, x - w->LeftEdge, y - w->TopEdge) ;
  337. /*
  338.  * And clean up and exit.
  339.  */
  340.     UnlockIBase(lock) ;
  341.     CloseLibrary(IntuitionBase) ;
  342.     exit(OK) ;
  343.     }
  344.