/*
* An example that shows how an X application can "swallow" another, running,
* X application.
*
* From: Ricky Ralston <rlr@wscoe5.atl.hp.com>
*/

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Intrinsic.h>
#include <X11/Xatom.h>
#include <Xm/Xm.h>
#include <Xm/DrawingA.h>
#include <Xm/Protocols.h>

Window XmuClientWindow ();
static Window TryChildren ();
XErrorHandler ErrorHandler();
Window GetClient();
void ResizeExposeCallback();

#define SW_EVENTS   (PropertyChangeMask | StructureNotifyMask |\
                     ResizeRedirectMask | SubstructureNotifyMask)

Window winid;
Window draw;

char *name;

void ResizeExposeCallback( w, client_data, call_data)
    Widget w;
    XtPointer client_data;
    XmDrawingAreaCallbackStruct * call_data;
{
    XEvent *event = call_data->event;
    Window win = call_data->window;
    Display *display = XtDisplay(w);

    if (event->xexpose.count == 0)
    {
        if (winid)
        {
            XClearWindow(display, winid);
            XMapSubwindows(display, winid);
            XMapWindow(display,winid);
        }
    }

}

main(argc, argv)
    int argc;
    char **argv;
{
    Widget topLevel;
    Widget drawArea;
    XtAppContext app_context;

    winid = NULL;
    draw = NULL;

    if (argv[1]) name = strdup(argv[1]);
    else printf("You must supply a class name\n");

    topLevel = XtVaAppInitialize(&app_context, "Swallow",
                                 NULL, 0, &argc, argv, NULL,
                                 XmNallowShellResize, TRUE,
                                 XmNrecomputeSize, TRUE,
                                 XmNheight, 700,
                                 XmNwidth, 600,
                                 NULL);

    XtRealizeWidget(topLevel);
    XSetErrorHandler((XErrorHandler)ErrorHandler);

    drawArea=XtVaCreateManagedWidget( "drawArea", xmDrawingAreaWidgetClass, 
                                      topLevel, NULL);
    draw = XtWindow(drawArea);

    XtAddCallback(drawArea, XmNexposeCallback, ResizeExposeCallback, NULL);
    XtAddCallback(drawArea, XmNresizeCallback, ResizeExposeCallback, NULL);

    winid = GetClient(XtDisplay(topLevel));
    XFlush(XtDisplay(topLevel));

    XtAppMainLoop( app_context);

}

Window XmuClientWindow (dpy, win)
    Display *dpy; 
    Window win;
{
    Atom WM_STATE;
    Atom type = None;
    int format;
    unsigned long nitems, after;
    unsigned char *data;
    Window inf;

    WM_STATE = XInternAtom(dpy, "WM_STATE", True);
    if (!WM_STATE)
        return win;
    XGetWindowProperty(dpy, win, WM_STATE, 0, 0, False, AnyPropertyType,
                       &type, &format, &nitems, &after, &data);
    if (type)
        return win;
    inf = TryChildren(dpy, win, WM_STATE);
    if (!inf)
        inf = win;
    return inf;
}

static Window TryChildren (dpy, win, WM_STATE)
    Display *dpy; 
    Window win; 
    Atom WM_STATE;
{
    Window root, parent;
    Window *children;
    unsigned int nchildren;
    unsigned int i;
    Atom type = None;
    int format;
    unsigned long nitems, after;
    unsigned char *data;
    Window inf = 0;

    if (!XQueryTree(dpy, win, &root, &parent, &children, &nchildren))
        return 0;
    for (i = 0; !inf && (i < nchildren); i++)
    {
        XGetWindowProperty(dpy, children[i], WM_STATE, 0, 0, False,
                           AnyPropertyType, &type, &format, &nitems,
                           &after, &data);
        if (type)
            inf = children[i];
    }
    for (i = 0; !inf && (i < nchildren); i++)
        inf = TryChildren(dpy, children[i], WM_STATE);
    if (children) XFree((char *)children);
    return inf;
}

Window GetClient(display)
    Display *display;
{
    XClassHint *classhint;
    Window dummy, *children = NULL, client;
    unsigned nchildren = 0;
    int i = 0;
    XTextProperty text_prop;
    XSetWindowAttributes win_att;
    XWindowChanges windowChanges;

    if (!XQueryTree (display, DefaultRootWindow(display),
                     &dummy, &dummy, &children, &nchildren)) return (NULL);

    for (i=nchildren; i >= 0; i--)
    {
        if ((client = XmuClientWindow (display, children[i])) != None)
        {

            classhint = XAllocClassHint ();

            if ((XGetClassHint(display, client, classhint)) != 0)
            {
                /* Print out the class name and per-instance name */
                if (!(strcmp(classhint->res_class, name)))
                {

                    XSync(display, False);
                    XUnmapWindow(display,client);
                    XFlush(display);
                    win_att.override_redirect = True;
                    XChangeWindowAttributes(display, client, 
                                            CWOverrideRedirect, &win_att);
                    XFlush(display);
                    XReparentWindow(display, client, draw, 10, 10);
                    XFlush(display);
                    XReparentWindow(display, client, draw, 10, 10);
                    XFlush(display);
                    windowChanges.border_width=0;
                    XConfigureWindow(display, client, CWBorderWidth, 
                                     &windowChanges);
                    XSelectInput(display,client,SW_EVENTS);
                    XFlush(display);
                    if (classhint->res_name) XFree(classhint->res_name);
                    if (classhint->res_class) XFree(classhint->res_class);
                    XFree(classhint);
                    return (client);
                }
            }

            if (classhint->res_name) XFree(classhint->res_name);
            if (classhint->res_class) XFree(classhint->res_class);
            XFree(classhint);
        }
    }

    return (NULL);
}


XErrorHandler ErrorHandler(dpy, event)
    Display *dpy;
    XErrorEvent *event;
{

  if((event->error_code == BadWindow)|| (event->error_code==BadDrawable))
    return 0 ;

  fprintf(stderr,"ErrorHandler - *** internal error ***\n");
  fprintf(stderr,"Request %d, Error %d\n", event->request_code,
           event->error_code);

}


