
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/shm.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>

#include "x11-window.h"
#include "x11-graph.h"
#include "gtv/event-stack.h"
#include "gcore/gcomm.h"
#include "gx11-message-c.h"

static void post_flush( )
{
    if (sic_post_command_text_from( "GTVL\\FLUSH", SIC_SILENT_MODE) == -1)
        XBell( display, 0);
}

int gesterreurs( Display * canal_aff, XErrorEvent * errev)
{
    /* DO NOTHING */
    return (1);
}

int run_gtv_window( void *data)
{
    char *arg = "undefined";

    return run_gtv_window_args( 1, &arg);
}

Bool match_any_event(Display *display, XEvent *event, XPointer arg)
{
    return True;
}

int run_gtv_window_args( int argc, char **argv)
{
    XEvent evenem;
    char *getenv( );
    Atom *win_properties;
    Atom type_read;
    int format_read;
    unsigned long nb_read, bytes_left;
    unsigned char *data_prop;
    XWindowAttributes winattr;
    unsigned long event_mask;

    char dum, *nom_atome;
    int i, fen_id, nb_properties;
    task_id_t pid, masterpid;

    masterpid = sic_get_master_task_id( );

    if (x11_open_display( NULL))
        return 1;

    XSetErrorHandler( gesterreurs);

    event_mask = PropertyChangeMask;

    XSelectInput( display, root_win, event_mask);

    while (1) {
#if 0
        if (!XCheckIfEvent( display, &evenem, match_any_event, NULL)) {
            gtv_pop_events();
            XNextEvent( display, &evenem);
        }
#else
        XNextEvent( display, &evenem);
#endif
        switch (evenem.type) {

        case PropertyNotify:
            /* Return list of root window properties in array win_properties */
            win_properties = XListProperties( display, root_win, &nb_properties);

            for (i = 0; i < nb_properties; i++) {
                nom_atome = XGetAtomName( display, win_properties[i]);

                if (strncmp( nom_atome, "NEWWIN_", 7) == 0) {
                    sscanf( &nom_atome[7], "%d%c%d", &pid, &dum, &fen_id);
                    if (pid == masterpid) {
                        XGetWindowProperty( display, root_win, win_properties[i], 0, 8192, 0,
                                           AnyPropertyType, &type_read, &format_read, &nb_read, &bytes_left, &data_prop);


                        gx11_c_message(seve_t, argv[0], "NEWWIN:%s", nom_atome);

                        /* get attributes---especially the backingstore */
                        if (XGetWindowAttributes( display, fen_id, &winattr) == 0) {
                            gx11_c_message(seve_e, argv[0], "Failed to get window attributes. Abort.");
                            sic_do_exit( -1);
                        }
                        gx11_c_message(seve_t, argv[0], "new win %d\n", fen_id);

                        /* This second event mask will enable redraw 
                           on non-backingstore displays and trap killed windows */

                        event_mask = ((winattr.backing_store == NotUseful) ||
                                      (winattr.backing_store == WhenMapped)) ?
                         ExposureMask | StructureNotifyMask : StructureNotifyMask;

                        XSelectInput( display, fen_id, event_mask);
                        XFree( data_prop);
                        /* printf( "del prop\n"); */
                        XDeleteProperty( display, root_win, win_properties[i]);
                    }
                }
                XFree( nom_atome);
            }
            XFree( win_properties);
            break;

        case ConfigureNotify:
            while (XCheckTypedWindowEvent(display, evenem.xconfigure.window,
                ConfigureNotify, &evenem))
                ;
            {
                G_env *env;

                env = (G_env *)x11_get_integer_property(evenem.xconfigure.window, "GENV");
                if (env != NULL)
                    gtv_on_resize( env, evenem.xconfigure.width,
                     evenem.xconfigure.height);
            }
            break;

        case Expose:
            if (1) {
                Region region;
                XRectangle rectangle;

                /* start with an empty region */
                region=XCreateRegion();
                /* add this event and any Expose Events in queue to region */
                do {
                    rectangle.x=(short)evenem.xexpose.x;
                    rectangle.y=(short)evenem.xexpose.y;
                    rectangle.width=(unsigned short) evenem.xexpose.width;
                    rectangle.height=(unsigned short) evenem.xexpose.height;

                    /* union this rect into a region */
                    XUnionRectWithRegion(&rectangle, region, region);
                } while(XCheckTypedWindowEvent(display, evenem.xexpose.window,
                    Expose, &evenem));

                //XSetRegion(display,gc,region);
            }
            {
                G_env *env;

                env = (G_env *)x11_get_integer_property(evenem.xexpose.window, "GENV");
                if (env != NULL) {
                    gtv_refresh( env, GTV_REFRESH_MODE_UPDATE);
                }
            }
            break;

        case DestroyNotify:
            while (XCheckWindowEvent(display, evenem.xdestroywindow.window,
                -1, &evenem))
                ;
            XSync( display, False);
            {
                G_env *env;

                env = (G_env *)x11_get_integer_property(evenem.xdestroywindow.window, "GENV");
                if (env != NULL) {
                    x11_set_integer_property( ((gx11_env_t *)env)->win_graph, "GENV", 0);
                    x11_on_destroy( env);
                }
            }
            break;

        default:
            gx11_c_message(seve_t, argv[0],
                "Unknown Event, window %d: x=%d,y=%d,w=%d,h=%d",
                (int)evenem.xexpose.window,
                evenem.xexpose.x,
                evenem.xexpose.y,
                evenem.xexpose.width,
                evenem.xexpose.height);
        }
    }
}
