
#include "gtk-local.h"

#include "gtk-graph.h"

#include "magnify-tool.h"
#include "gtk-toolbar.h"
#include "gtv/event-stack.h"
#include "zoom-tool.h"
#include "message-c.h"

#ifndef darwin
#include <malloc.h>
#else
#include <stdlib.h>
#endif

#if 0
/* 1 byte integers */
typedef guchar ggtk_colormap_index;
#else
/* 2 bytes integers */
typedef gushort ggtk_colormap_index;
#endif

#define NPEN 16
#define GTK "GTK"

static int Width_default;
static int Height_default;

static int pencil_colors[NPEN];
static int pix_colors[NCOL];

static GdkDisplay *display;
static GdkScreen *screen;
static int screen_width;
static int screen_height;

static void _check_task(char *proc)
{
    if (gtv_called_from_main()) {
        ggtk_c_message(seve_e, GTK, "%s: call from main thread", proc);
    }
}

static void _ggtk_init_genv(ggtk_env_t *env)
{
    init_genv( (G_env *)env);
    env->post_refresh_handler = NULL;
    env->post_refresh_handler_data = NULL;
    env->line_width = 1;
    env->line_style = GDK_LINE_SOLID;
    env->cap_style = GDK_CAP_PROJECTING;
    env->join_style = GDK_JOIN_MITER;
}

static G_env *ggtk_creer_genv(void)
{
    ggtk_env_t *env;

    if ((env = (ggtk_env_t *)calloc(1, sizeof(ggtk_env_t))) != NULL) {
        _ggtk_init_genv( env);
    } else {
        ggtk_c_message(seve_e, GTK, "Fail to allocate new genv");
    }
    return (G_env *)env;
}

static void ggtk_get_corners( G_env *env, int x[3], int y[3])
{
    int width, height;

    width = screen_width - env->Width_graphique;
    height = screen_height - env->Height_graphique;
    x[0] = 0;
    x[1] = width >> 1;
    x[2] = width;
    y[2] = 0;
    y[1] = height >> 1;
    y[0] = height;
}

static void ggtk_move_window( G_env *_env, int _x, int _y)
{
    if (((ggtk_env_t *)_env)->main_widget == NULL ||
     ((ggtk_env_t *)_env)->main_widget->window == NULL)
        return;
    gdk_window_move( ((ggtk_env_t *)_env)->main_widget->window, _x, _y);
    //printf( "leave ggtk_move_window\n");
}

static void ggtk_resize_window( G_env *_env, int _width, int _height)
{
    if (((ggtk_env_t *)_env)->main_widget == NULL ||
     ((ggtk_env_t *)_env)->main_widget->window == NULL)
        return;
    if (_width < 2 || _height < 2 || _width > screen_width || _height >
     screen_height) {
        ggtk_c_message(seve_w, GTK,
         "ggtk_resize_window: invalid values (%d %d)", _width, _height);
        return;
    }
    gdk_window_resize( ((ggtk_env_t *)_env)->main_widget->window, _width, _height);
}

static void ggtk_destroy_window( G_env *env)
{
    gtk_widget_destroy( ((ggtk_env_t *)env)->main_widget);
}

void ggtk_set_post_refresh_handler( ggtk_env_t *genv, ggtk_gpointer_handler_t h, gpointer user_data)
{
    genv->post_refresh_handler = h;
    genv->post_refresh_handler_data = user_data;
}

void ggtk_call_post_refresh_handler( ggtk_env_t *genv)
{
    if (genv->post_refresh_handler != NULL)
        genv->post_refresh_handler( genv->post_refresh_handler_data);
}

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

static void ggtk_refresh_window( fortran_type adr_dir, int mode, G_env *env)
{
    ggtk_env_t *genv = (ggtk_env_t *)env;

#ifdef GAG_USE_CAIRO
    //cairo_set_line_width (genv->cr, 0.5);
#else
    GdkRectangle rect = {0, 0, env->Width_graphique, env->Height_graphique};

    gdk_window_begin_paint_rect(genv->win_graph, &rect);
#endif
    gtv_refresh_win( adr_dir, env, mode);
#ifdef NO_CALL_TO_PUSH_REFRESH_WITH_NULL_GENV_DURING_ZOOM
    ggtk_call_post_refresh_handler( genv);
#endif
#ifdef GAG_USE_CAIRO
    //cairo_destroy( genv->cr);
#else
    gdk_window_end_paint(genv->win_graph);
#endif
    //printf("ggtk_refresh_window: %d\n", env->fen_num);
}

static void ggtk_flush_window( )
{
    gdk_display_flush( display);
}

static void ggtk_clear_window( G_env *env)
{
    //printf("ggtk_clear_window: %d\n", env->fen_num);
    gdk_window_clear( ((ggtk_env_t *)env)->win_graph);
}

static void ggtk_invalidate_window( G_env *env)
{
    gtk_widget_queue_draw( ((ggtk_env_t *)env)->drawing_area);
}

static int ggtk_get_image_width( int w)
{
    return w;
}

static void ggtk_create_edit_lut_window()
{
}

static void _ggtk_set_rgb( ggtk_env_t *genv, GdkColor *c)
{
#ifdef GAG_USE_CAIRO
    cairo_set_source_rgb( genv->cr,
     (float)c->red / MAX_INTENSITY,
     (float)c->green / MAX_INTENSITY,
     (float)c->blue / MAX_INTENSITY);
#else
    gdk_gc_set_function( genv->gc, GDK_COPY);
    gdk_gc_set_rgb_fg_color( genv->gc, c);
#endif
}

static void ggtk_pen_invert( G_env *env)
{
    ggtk_env_t *genv = (ggtk_env_t *)env;

#ifdef GAG_USE_CAIRO
    cairo_set_source_rgb(genv->cr, 1., 1., 1.);
    // CAIRO_OPERATOR_DIFFERENCE requires cairo >= 1.9.2
    cairo_set_operator(genv->cr, CAIRO_OPERATOR_DIFFERENCE);
#else
    gdk_gc_set_function( genv->gc, GDK_INVERT);
#endif
}

static void ggtk_pen_rgb( G_env *env, int r, int g, int b)
{
    GdkColor c;
    c.red = r;
    c.green = g;
    c.blue = b;
    _ggtk_set_rgb((ggtk_env_t *)env, &c);
}

static void ggtk_pen_color( G_env *env, char *color)
{
    GdkColor c;
    if (!gdk_color_parse( color, &c)) {
        ggtk_c_message(seve_e, GTK, "Unknown color: %s", color);
        return;
    }
    _ggtk_set_rgb((ggtk_env_t *)env, &c);
}

static void ggtk_fill_poly( G_env *env, int nb_pts, int *x, int *y)
{
    ggtk_env_t *genv = (ggtk_env_t *)env;
    int i;
#ifndef GAG_USE_CAIRO
#define _SIZE_POINTS_BUF 1024
    GdkPoint pointsBuf[_SIZE_POINTS_BUF];
    GdkPoint *points;

    //gdk_threads_enter( );
    if (nb_pts > _SIZE_POINTS_BUF) {
        points = (GdkPoint *) malloc( nb_pts * sizeof(GdkPoint));
    } else {
        points = pointsBuf;
    }
#endif
    //_check_task("ggtk_fill_poly");
#ifdef GAG_USE_CAIRO
    cairo_move_to( genv->cr, x[0], y[0]);
    for (i = 1; i < nb_pts; i++) {
        cairo_line_to( genv->cr, x[i], y[i]);
    }
    cairo_close_path( genv->cr);
    cairo_fill( genv->cr);
#else
    for (i = 0; i < nb_pts; i++) {
        points[i].x = x[i];
        points[i].y = y[i];
    }
    gdk_draw_polygon( genv->win_graph, genv->gc, TRUE, points, nb_pts);
    if (nb_pts > _SIZE_POINTS_BUF) {
        free(points);
    }
#endif
    //gdk_threads_leave( );
}

static void ggtk_ask_for_corners( int *ax, int *bx, int *ay, int *by)
{
}

static void ggtk_other_curs( G_env *env, char *cde)
{
}

static void ggtk_weigh( G_env *env, int weight)
{
    ggtk_env_t *genv = (ggtk_env_t *)env;
    _check_task("ggtk_weigh");
    //gdk_threads_enter( );

#ifdef GAG_USE_CAIRO
    //printf( "%d\n", weight);
    if (!weight)
        weight = 1;
    cairo_set_line_width( genv->cr, weight);
#else
    genv->line_width = weight;
    gdk_gc_set_line_attributes( genv->gc, genv->line_width, genv->line_style,
        genv->cap_style, genv->join_style);
#endif
    //gdk_threads_leave( );
}

#define _DASH_SIZE 4
static void ggtk_dash( G_env *env, int flag_dash, int ds[_DASH_SIZE])
{
    ggtk_env_t *genv = (ggtk_env_t *)env;

    _check_task("ggtk_dash");
    //gdk_threads_enter( );
#ifdef GAG_USE_CAIRO
    if (flag_dash) {
        int i;
        double dash_list[_DASH_SIZE];

        for (i = 0; i < _DASH_SIZE; i++)
            dash_list[i] = ds[i];

        cairo_set_dash( genv->cr, dash_list, _DASH_SIZE, 0);
    } else {
        cairo_set_dash( genv->cr, NULL, 0, 0);
    }
#else
    if (flag_dash) {
        int i;
        gint8 dash_list[_DASH_SIZE];

        for (i = 0; i < _DASH_SIZE; i++)
            dash_list[i] = ds[i];
        gdk_gc_set_dashes( genv->gc, 0, dash_list, _DASH_SIZE);
        genv->line_style = GDK_LINE_ON_OFF_DASH;
        genv->cap_style = GDK_CAP_BUTT;
    } else {
        genv->line_style = GDK_LINE_SOLID;
        genv->cap_style = GDK_CAP_PROJECTING;
    }
    gdk_gc_set_line_attributes( genv->gc, genv->line_width, genv->line_style,
        genv->cap_style, genv->join_style);
#endif
    //gdk_threads_leave( );
}

static void ggtk_ximage_loadrgb( int red[], int green[], int blue[], int n,
 int dir)
{
}

static GdkColor *_default_colormap = NULL;
static int _default_colormap_size = 0;

GdkColor *ggtk_default_colormap()
{
    return _default_colormap;
}

int ggtk_default_colormap_size()
{
    return _default_colormap_size;
}

void ggtk_xcolormap_set_default( size_t colormap)
{
    _default_colormap = (GdkColor *)colormap;
    _default_colormap_size = *(int *)((GdkColor *)colormap - 1);
}

size_t ggtk_xcolormap_create( float red[], float green[], float blue[], int n, int is_default)
{
    GdkColor *colormap;
    GdkColor *color;
    int i;

    if ((colormap = (GdkColor *)calloc(n + 1, sizeof(GdkColor))) == NULL) {
        ggtk_c_message(seve_e, GTK, "Fail to allocate  colormap");
        return 0;
    }
    *(int *)colormap = n;
    colormap++;

    for (i = 0, color = colormap; i < n; i++, color++) {
        color->red   = (int)  (red[i] * MAX_INTENSITY + 0.5);
        color->green = (int)(green[i] * MAX_INTENSITY + 0.5);
        color->blue  = (int) (blue[i] * MAX_INTENSITY + 0.5);
    }
    if (is_default) {
        ggtk_xcolormap_set_default( (size_t)colormap);
    }
    return (size_t)colormap;
}

void ggtk_xcolormap_delete( size_t colormap)
{
    free( (GdkColor *)colormap - 1);
}

static int ggtk_ximage_inquire( int *lcol, int *ocol, int *nx,
    int *ny, int *is_color, int *is_static)
{
    *lcol = 65536; /* The most we can encode on 2-byte integers */
    *ocol = 0;
    *is_color = 1;
    *is_static = 1;
    *nx = Width_default;
    *ny = Height_default;
    return 1;
}

void ggtk_draw_image( GdkWindow *window, ggtk_env_t *genv, size_t *adr_data,
 int n_x0, int n_y0, int n_larg, int n_haut, size_t colormap)
{
    ggtk_colormap_index *data = (ggtk_colormap_index *)adr_data;
    GdkColor *color;
#ifdef GAG_USE_CAIRO
    int i, j, k;
    cairo_surface_t *s;
    cairo_format_t format;
    int stride;
    unsigned char *cbuf;
#else
    int i;
    GdkVisual *visual;
    int dim;
    guchar *buf;
    guchar *pos;
#endif

    color = (GdkColor *)colormap;
#ifdef GAG_USE_CAIRO
    // N.B: format can be changed to CAIRO_FORMAT_ARGB32 to use
    // the first 8 bits as the alpha channel
    // TODO(mpl): the order is supposed to be a r g b, but we get them 
    // as b g r a; there must be some endianness at play -> look for 
    // another format that is endian agnostic.
    format = CAIRO_FORMAT_RGB24;
    stride = cairo_format_stride_for_width( format, n_larg);
    if (stride <= 0) {
        ggtk_c_message(seve_e,GTK,"Invalid stride");
        return;
    }
    cbuf = malloc(stride * n_haut);
    k = 0;
    for (j = 0; j < n_haut; j++) {
        for (i = 0; i < n_larg; i++) {
            cbuf[j*stride+i*4] = (unsigned char)(color[data[k]].blue >> 8);
            cbuf[j*stride+i*4+1] = (unsigned char)(color[data[k]].green >> 8);
            cbuf[j*stride+i*4+2] = (unsigned char)(color[data[k]].red >> 8);
            cbuf[j*stride+i*4+3] = 123; // alpha channel. unused with CAIRO_FORMAT_RGB24.
            k++;
        }
    }
    s = cairo_image_surface_create_for_data( cbuf, format, n_larg, n_haut, stride);
    cairo_set_source_surface( genv->cr, s, n_x0, n_y0);
    cairo_paint(genv->cr);
    free(cbuf);
#else
    visual = gdk_drawable_get_visual( window);
    dim = n_larg * n_haut;
    pos = buf = malloc(dim * 3 * sizeof(ggtk_colormap_index));
    for (i = 0; i < dim; i++) {
        *pos++ = color[data[i]].red >> (16 - visual->red_prec);
        *pos++ = color[data[i]].green >> (16 - visual->green_prec);
        *pos++ = color[data[i]].blue >> (16 - visual->blue_prec);
    }
    gdk_draw_rgb_image( window, genv->gc, n_x0, n_y0, n_larg, n_haut,
    GDK_RGB_DITHER_NONE, buf, n_larg * 3);
    free( buf);
#endif
}

void ggtk_draw_rgb( G_env *env, size_t *r, size_t *g, size_t *b, int n_x0, int n_y0, int n_larg, int n_haut)
{
    GdkWindow *window;
    int i;
#ifdef GAG_USE_CAIRO
    int j,k;
    cairo_surface_t *s;
    cairo_format_t format;
    int stride;
    unsigned char *cbuf;
#else
    GdkGC *gc;
    GdkVisual *visual;
    int dim;
    guchar *buf;
    guchar *pos;
#endif

    ggtk_env_t *genv = (ggtk_env_t *)env;
#ifdef GAG_USE_CAIRO
    format = CAIRO_FORMAT_RGB24;
    stride = cairo_format_stride_for_width( format, n_larg);
    if (stride <= 0) {
        ggtk_c_message(seve_e,GTK,"Invalid stride");
        return;
    }
    cbuf = malloc(stride * n_haut);
    k = 0;
    for (j = 0; j < n_haut; j++) {
        for (i = 0; i < n_larg; i++) {
            cbuf[j*stride+i*4] = (unsigned char)(((gushort*)b)[k] >> 8);
            cbuf[j*stride+i*4+1] = (unsigned char)(((gushort*)g)[k] >> 8);
            cbuf[j*stride+i*4+2] = (unsigned char)(((gushort*)r)[k] >> 8);
            cbuf[j*stride+i*4+3] = 123; // alpha channel. unused with CAIRO_FORMAT_RGB24.
            k++;
        }
    }
    s = cairo_image_surface_create_for_data( cbuf, format, n_larg, n_haut, stride);
    cairo_set_source_surface( genv->cr, s, n_x0, n_y0);
    cairo_paint(genv->cr);
    free(cbuf);
#else
    window = genv->win_graph;
    gc = genv->gc;
    visual = gdk_drawable_get_visual( window);
    dim = n_larg * n_haut;
    pos = buf = malloc(dim * 3);
    for (i = 0; i < dim; i++) {
        *pos++ = ((gushort*)r)[i] >> (16 - visual->red_prec);
        *pos++ = ((gushort*)g)[i] >> (16 - visual->green_prec);
        *pos++ = ((gushort*)b)[i] >> (16 - visual->blue_prec);
    }
    gdk_draw_rgb_image( window, gc, n_x0, n_y0, n_larg, n_haut,
     GDK_RGB_DITHER_NONE, buf, n_larg * 3);
    free( buf);
#endif
}

/* ggtk_affiche_image1 invert red and blue colors */
#define ggtk_affiche_image2 ggtk_affiche_image

static void ggtk_affiche_image2( G_env *env, size_t *adr_data, int n_x0,
    int n_y0, int n_larg, int n_haut, int val_trou, size_t colormap)
{
    ggtk_env_t *genv = (ggtk_env_t *)env;

    _check_task("ggtk_affiche_image2");
    ggtk_draw_image( genv->win_graph, genv, adr_data, n_x0, n_y0, n_larg,
     n_haut, colormap);
}

static void ggtk_clal( G_env *env)
{
    if (((ggtk_env_t *)env)->main_widget == NULL ||
     ((ggtk_env_t *)env)->main_widget->window == NULL)
        return;
    gdk_window_raise( ((ggtk_env_t *)env)->main_widget->window);
}

static void ggtk_clpl( G_env *env)
{
    if (((ggtk_env_t *)env)->main_widget == NULL ||
     ((ggtk_env_t *)env)->main_widget->window == NULL)
        return;
    gdk_window_lower( ((ggtk_env_t *)env)->main_widget->window);
}

static void ggtk_cmdwin()
{
}

static void ggtk_size( G_env *env, int *width, int *height)
{
    *width = env->Width_graphique;
    *height = env->Height_graphique;
}

static void ggtk_screen_size( int *width, int *height)
{
    *width = screen_width;
    *height = screen_height;
}

static void ggtk_flush_points( G_env *env, struct _point tabpts[], int npts)
{
    if (npts) {
        ggtk_env_t *genv = (ggtk_env_t *)env;
        int i;
#ifdef GAG_USE_CAIRO
        cairo_t *cr = genv->cr;
        cairo_move_to( cr, tabpts[0].x, tabpts[0].y);
        for (i = 1; i < npts; i++) {
            cairo_line_to( cr, tabpts[i].x, tabpts[i].y);
        }
        cairo_stroke( cr);
#else
        _check_task("ggtk_flush_points");
        if (npts ==1 || (npts == 2 && tabpts[0].x == tabpts[1].x && tabpts[0].y ==
         tabpts[1].y)) {
            /* Should remove this obsolete npts==2 test above */
            gdk_draw_point( genv->win_graph, genv->gc, tabpts[0].x,
             tabpts[0].y);
        } else {
            GdkPoint points[sizeof(env->tabpts) / sizeof(env->tabpts[0])];

            for (i = 0; i < npts; i++) {
                points[i].x = tabpts[i].x;
                points[i].y = tabpts[i].y;
            }
            gdk_draw_lines( genv->win_graph, genv->gc, points, npts);
        }
#endif
    }
}

static void ggtk_close( void)
{
#if 1
    /* don't quit main loop on "dev none" because menus and dialogs need it */
    return;
#else
    //printf( "ggtk_close\n");
    gtk_main_quit();
#endif
}

static void ggtk_quit( void)
{
    gtk_main_quit();
}

static void ggtk_new_graph(
    int backg,
    G_env *env,
    char *dirname,
    int width, int height,
    fortran_type dir_cour,
    int reuse)
{

    /* check values */
#define GTV_MINIMAL_WIDTH 100
    if (width  < 0)  width = GTV_MINIMAL_WIDTH;
    if (height < 0)  height = GTV_MINIMAL_WIDTH;

    /* Gardons ces dimensions pour les autres */
    if (width > 1) {
        Width_default = width;
    } else {
        width = Width_default;
    }
    if (height > 1) {
        Height_default = height;
    } else {
        height = Height_default;
    }

    env->adr_dir = dir_cour;

    if (reuse) {
        gtv_push_clear( env);
    } else {
        static ggtk_toolbar_args_t args;
        ggtk_env_t *genv = (ggtk_env_t *)env;

        env->win_backg = backg;
        env->Width_graphique = width;
        env->Height_graphique = height;
        env->update_gtv_lut = 1;
        //args.herit.cmap = cmap;
        strcpy( args.herit.lut_path, sic_s_get_logical_path( "GAG_LUT:"));
        strcpy( args.herit.tmp_path, sic_s_get_logical_path( "GAG_TMP:"));
        args.herit.pix_colors = pix_colors;
        args.herit.named_colors = NULL;
        args.herit.pencil_colors = pencil_colors;
        args.herit.ncells = 0;
        args.herit.ncells_pen = 0;

        args.herit.win_graph = 0;
        args.herit.win_width = width;
        args.herit.win_height = height;
        args.herit.win_main = 0;
        args.env = genv;
        args.window_name = dirname;

        launch_gtv_main_loop( NULL);
        gtv_push_create_window( (gtv_toolbar_args_t *)&args);
        // sic_wait_widget_created( ) must be called by caller (createwindow_wait)

        ggtk_c_message(seve_t,GTK,"new win id %ld", (size_t)genv->win_graph);
        //ggtk_c_message(seve_t,GTK,"cmap %d",          (int)cmap);
        ggtk_c_message(seve_t,GTK,"pix_colors %d",    pix_colors[0]);
        //ggtk_c_message(seve_t,GTK,"ncells %d",        ncells);
        ggtk_c_message(seve_t,GTK,"pencil_colors %d", pencil_colors[0]);
        //ggtk_c_message(seve_t,GTK,"ncells_pen %d",    ncells_pen);
    }
}

static int ggtk_open_x(
    int cross               /* !=0 if the user wants crosshair cursor  */
)
{
    void ggtk_init();
    ggtk_init();

    /* Get display characteristics */
    display = gdk_display_get_default();
    screen = gdk_display_get_default_screen(display);
    screen_width = gdk_screen_get_width(screen);
    screen_height = gdk_screen_get_height(screen);
    ggtk_c_message(
        seve_d, GTK, "Screen pixels : width: %d, height: %d", screen_width,
        screen_height
    );

    return 1;
}

G_env *ggtk_new_genv_from( G_env *ref_genv, GtkWidget *drawing_area, int width,
 int height, gboolean connect_expose)
{
    G_env *genv;

    genv = ggtk_creer_genv();
    genv->adr_dir = ref_genv->adr_dir;
    genv->win_backg = ref_genv->win_backg;
    ggtk_attach_window_genv( (ggtk_env_t *)genv, drawing_area, drawing_area,
     connect_expose);

    return genv;
}

static int _on_event( void *event)
{
    //printf( " on_event: %s\n", gtv_event_name(event));
    gtv_on_event( event);
    // do not call again
    return FALSE;
}

static void ggtk_push_event( void *event)
{
    //printf( " push_event: %s\n", gtv_event_name(event));
    g_idle_add(_on_event, (gpointer)event);
}

static void ggtk_activate_lens( G_env *genv)
{
    ggtk_activate_magnify( NULL, genv);
}

static graph_api_t s_ggtk_graph_api = {
    ggtk_creer_genv,
    ggtk_destroy_window,
    ggtk_refresh_window,
    NULL,
    NULL,
    ggtk_flush_window,
    ggtk_move_window,
    ggtk_resize_window,
    ggtk_invalidate_window,
    ggtk_clear_window,
    ggtk_get_corners,
    ggtk_get_image_width,
    ggtk_new_graph,
    ggtk_create_edit_lut_window,
    ggtk_open_x,
    ggtk_pen_invert,
    ggtk_pen_rgb,
    ggtk_pen_color,
    ggtk_fill_poly,
    ggtk_activate_zoom,
    ggtk_ask_for_corners,
    ggtk_other_curs,
    ggtk_weigh,
    ggtk_dash,
    NULL,
    ggtk_ximage_loadrgb,
    ggtk_xcolormap_create,
    ggtk_xcolormap_set_default,
    ggtk_xcolormap_delete,
    ggtk_ximage_inquire,
    ggtk_affiche_image,
    ggtk_draw_rgb,
    ggtk_clal,
    ggtk_clpl,
    ggtk_cmdwin,
    ggtk_size,
    ggtk_screen_size,
    ggtk_flush_points,
    ggtk_close,
    ggtk_create_drawing_area,
    ggtk_push_event,
    ggtk_quit,
    ggtk_activate_lens,
};

#ifdef GAG_USE_STATICLINK
#define init_graph_api CFC_EXPORT_NAME( init_graph_api)

void CFC_API init_graph_api()
#elif defined(WIN32)
// to force link of ggtk into greg
void ggtk_entry( )
{
}
BOOL APIENTRY DllMain( HANDLE hInstance, 
                      DWORD ul_reason_being_called, LPVOID lpReserved)
#else
__attribute__((constructor))
static void ggtk_on_init( )
#endif
{
#if defined(WIN32) && !defined(GAG_USE_STATICLINK)
    if (ul_reason_being_called == DLL_PROCESS_ATTACH) {
#endif
#if !defined(GAG_USE_STATICLINK)
    void ggtk_init_gui();
    ggtk_init_gui();
#endif
    set_graph_api( &s_ggtk_graph_api);
#if defined(WIN32) && !defined(GAG_USE_STATICLINK)
    }
    return TRUE;
#endif
}

