 /*
  * Khoros: $Id: lgetimage.c,v 1.2 1991/10/02 00:04:50 khoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: lgetimage.c,v 1.2 1991/10/02 00:04:50 khoros Exp $";
#endif

 /*
  * $Log: lgetimage.c,v $
 * Revision 1.2  1991/10/02  00:04:50  khoros
 * HellPatch2
 *
  */

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1991, University of New Mexico.  All rights reserved.
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as to the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including, for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"        /* Copyright 1991 by UNM */

/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 >>>>
 >>>>         File Name: lgetimage.c
 >>>>
 >>>>      Program Name: getimage
 >>>>
 >>>> Date Last Updated: Mon Sep 23 16:25:26 1991 
 >>>>
 >>>>          Routines: lgetimage - the library call for getimage
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#include "xvinclude.h"


/* -library_includes */
#include "xvutils.h"

#ifndef min
#define min(x,y)        (((x) < (y)) ? (x) : (y))
#endif

#ifndef max
#define max(x,y)        (((x) > (y)) ? (x) : (y))
#endif

#define cursor_width 16
#define cursor_height 16
#define cursor_x_hot 8
#define cursor_y_hot 8

static char cursor_bits[] = {
   0xf1, 0x8f, 0x9e, 0x79, 0x86, 0x61, 0x8a, 0x51, 0x93, 0x49, 0xa1, 0x85,
   0xc1, 0x83, 0xff, 0xff, 0xff, 0xff, 0xc1, 0x83, 0xa1, 0x85, 0x93, 0xc9,
   0x8a, 0x51, 0x86, 0x61, 0x9e, 0x79, 0xf1, 0x8f};
/* -library_includes_end */


/****************************************************************
*
* Routine Name: lgetimage - library call for getimage
*
* Purpose:
*
* Input:
*    
*    image:         xvimage  structure  containing  the  image  to  be
*                   returned.
*    
*    bitmap:        an integer flag indicating that the  khoros  image
*                   is to be in bitmap form, regardless of display.
*    
*    subimage:      image is to be interactively extracted from the  a
*                   portion of the rootwindow (display screen).
*    
*    display_name   The name of the (host:display)  where  the  target
*                   window  resides.  If the display_name is NULL then
*                   XOpenDisplay() will  use  the  user's  environment
*                   variable DISPLAY.
*    
*    

* Output:
*    
*    image:         holds the khoros image  result  of  the  X  Window
*                   image.
*    
*    

*
* Written By: Mark Young
*    
*    

****************************************************************/


/* -library_def */
int
lgetimage(image, bitmap, subimage, window_name, all, decor, display_name)

struct  xvimage **image;
int     bitmap, subimage, all, decor;
char    *window_name, *display_name;
/* -library_def_end */

/* -library_code */
{
        unsigned long gcmask;
        unsigned int width = 0,
                     height = 0;

        int     screen_num, grab, x1, x2, y1, y2,
                x = 0,
                y = 0;

        GC      gc;
        Cursor  cursor;         /* the cursor used by XGrabMouse */
        XGCValues xgcv;
        Display *display;
        XEvent  event1, event2;
        Window  workspace, window, rootwindow, find_window();
        struct xvimage *create_pixmap_image(), *create_bitmap_image();


        display = XOpenDisplay(display_name);
        if (display == NULL)                                          
        {
                (void) fprintf (stderr,"\n\nlxvgetimage: Could not open a ");
                (void) fprintf (stderr,"connection for the specified display.\n");
                return(0);
        }
        screen_num = XDefaultScreen(display);
        rootwindow = RootWindow(display, screen_num);

        /*
         * Grab the mouse so that the user can select either the
         * window or area of the screen they desire to dump.
         */
        if (all == FALSE && window_name == NULL)
        {
           grab = XGrabPointer(display, rootwindow, False, ButtonPressMask,
                            GrabModeAsync, GrabModeAsync, None, NULL,
                            CurrentTime);
           if (grab != GrabSuccess)
           {
                (void) fprintf(stderr,"\n\nlxvgetimage:  Could not grab");
                (void) fprintf(stderr,"pointer for the specified display.\n\n");
                return(0);
           }
        }

        /* set up the graphics context to be used with graphics windows */
        xgcv.function       = GXinvert;
        xgcv.subwindow_mode = IncludeInferiors;
        gcmask = GCFunction  | GCSubwindowMode;

        gc = XCreateGC(display, rootwindow, gcmask, &xgcv);  

        /*
         * Check to see if the user wishes to dump a window or
         * extract the image from a portion of the screen (subimage).
         */
        if (window_name != NULL)
        {
           if (!(workspace = find_window(display, rootwindow, window_name)))
           {
              fprintf(stderr, "getimage:\n");
              fprintf(stderr, "Error: Unable to find a window with an id or\n");
              fprintf(stderr, "name of '%s'\n\n", window_name);
              return(FALSE);
           }
        }
        else if (all)
        {
           workspace = rootwindow;
        }
        else if (subimage)
        {
           /*
            * Get a portion or subimage of the window/screen rather than
            * entire one.
            *
            * "Please select the first corner of the window/screen to be 
            *  coverted to an Khoros Image file (IFF). Selection is made by 
            *  depressing the mouse button on the desired X window and 
            *  while keeping the mouse button depressed moving the mouse 
            *  to second corner of the screen.  The second corner is selected 
            *  when releasing the mouse button."
            */
           (void) fprintf(stderr,"\n\nPlease select the first corner of the ");
           (void) fprintf(stderr,"window/screen to be coverted to\n");
           (void) fprintf(stderr,"an Khoros Image file. Selection is made ");
           (void) fprintf(stderr,"by depressing the mouse button\n");
           (void) fprintf(stderr,"on the desired X window and while keeping ");
           (void) fprintf(stderr,"the mouse button depressed\n");
           (void) fprintf(stderr,"moving the mouse to second corner of the ");
           (void) fprintf(stderr,"screen.  The second corner is\n");
           (void) fprintf(stderr,"selected when releasing the mouse button.");
           (void) fprintf(stderr,"\n\n");

           /* Get the first corner */
           do {
              XNextEvent(display, &event1);
           } while(event1.type != ButtonPress);

           XChangeActivePointerGrab(display,PointerMotionMask|ButtonReleaseMask,
                                    NULL, CurrentTime);

           /* Get the second corner */
           x1 = x2 = event1.xbutton.x_root;
           y1 = y2 = event1.xbutton.y_root;
           do {
              x = min(x1,x2);
              y = min(y1,y2);
              width = max(x1,x2) - x;
              height = max(y1,y2) - y;

              /* 
               * Draw a rubberband box around the image to let the user
               * know how to what area they are selecting.
               */
              XDrawRectangle(display, rootwindow, gc, x, y, width, height);
              XFlush(display);
              XNextEvent(display, &event2);
              XDrawRectangle(display, rootwindow, gc, x, y, width, height);

              if (event2.type == MotionNotify)
              {
                 x2 = event2.xmotion.x_root;
                 y2 = event2.xmotion.y_root;
              }

           } while(event2.type != ButtonRelease);

           workspace = event1.xbutton.root;
        }
        else
        {
           /*
            * Get the entire window rather than a portion or subimage of one.
            *
            * "Please select the window to be coverted to an Khoros Image file.
            *  Selection is made by clicking the mouse on the desired X window".
            */
           (void) fprintf(stderr,"\n\nPlease select the window to be coverted");
           (void) fprintf(stderr," to an Khoros Image file.\n");
           (void) fprintf(stderr,"Selection is made by clicking the mouse on ");
           (void) fprintf(stderr,"the desired X window.\n\n");

           /* Get the window to be dumped */
           do {
              XNextEvent(display, &event1);
           } while(event1.type != ButtonPress);

           if (event1.xbutton.subwindow != 0)
              workspace = event1.xbutton.subwindow;
           else
              workspace = event1.xbutton.window;
        }

        /*
         * Release the pointer, so that other events can occur.  This
         * should really be done after getting the image, but the image 
         * routines take such a long time!
         */
        if (all == FALSE && window_name == NULL)
        {
           XUngrabPointer(display, CurrentTime);
        }

        if (subimage && ((width == 0) || (height == 0)))
        {
            fprintf(stderr, "getimage:\n");
            fprintf(stderr, "Error: cannot create a VIFF image of \n");
            fprintf(stderr, "zero width or zero height.\n");
            return(FALSE);
        }

        if (decor == FALSE)
        {
           if (window = XmuClientWindow(display, workspace))
              workspace = window;
        }

        if (bitmap)
           *image = create_bitmap_image(display, screen_num, workspace, 
                                        subimage, x, y, width, height);
        else
           *image = create_pixmap_image(display, screen_num, workspace, 
                                        subimage, x, y, width, height);
        XFreeGC(display, gc);
        return(1);

}

Window find_window(display, rootwindow, name)

Display *display;
Window  rootwindow;
char    *name;
{
        char     *string;
        int      i, status;
        unsigned int num_children;
        Window   window, root, parent, *children;


        if (!XQueryTree(display, rootwindow, &root, &parent, &children,
                  &num_children))
        {
           return(NULL);
        }

        window = strtol(name, &string, 0);
        if (string != name && string[0] == '\0')
           return(window);

        for (i = 0; i < num_children; i++)
        {
            if (XFetchName(display, children[i], &string))
            {
               status = strcmp(name, string);
               XFree(string);
               if (status == 0)
               {
                  window = children[i];
                  break;
               }
            }

            if (window = XmuClientWindow(display, children[i]))
            {
               if (XFetchName(display, window, &string))
               {
                  status = strcmp(name, string);
                  XFree(string);
                  if (status == 0)
                  {
                     window = children[i];
                     break;
                  }
               }
            }
        }
        XFree((char *) children);

        if (i < num_children)
           return(window);
        else
           return(NULL);
}
/* -library_code_end */
