
#include "gtk-dialog.h"

#include "ggui/dialog.h"
#include "gcore/gcomm.h"
#include "gsys/gag_trace.h"
#include "gcore/glaunch.h"
#include "gtv/event-stack.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include "gtk/gtk.h"

#define _GGTK_USE_DIALOG

#define GGTK_USE_TABLE
#define GGTK_USE_FRAME 1
#define GGTK_USE_EXPANDER 1

#define GGTK_CONTAINER_BORDER 5
#define GGTK_ROW_SPACING 3
#define GGTK_COL_SPACING 3
#define GGTK_BUTTON_BOX_SPACING 5

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

#define GTK_SLIDER_MAXIMUM 1000

static char ggtk_window_title[TITLELENGTH];
static char ggtk_helpfilename[HLPFILELNGTH];
static char ggtk_main_command[COMMANDLENGTH];

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

/* GTK widget implementation */
static void dialog_info_create_group_box( dialog_info_t *dialog);
static void dialog_separator_add( dialog_info_t *dialog);
static void dialog_chain_add( dialog_info_t *dialog, chain_struct *chain);
static void dialog_slider_add( dialog_info_t *dialog, slider_struct *slider);
static void slider_info_set_value( widget_info_t *widget_info, double value);
static void logic_info_get_value( widget_info_t *widget_info);
static void logic_info_set_value( widget_info_t *widget_info, int value);
static void chain_info_get_value( widget_info_t *widget_info);
static void chain_info_set_value( widget_info_t *widget_info, const char *value);
static void choice_info_get_value( widget_info_t *widget_info);
static void choice_info_set_value( widget_info_t *widget_info, const char *value);
static void file_info_get_value( widget_info_t *widget_info);
static void file_info_set_value( widget_info_t *widget_info, const char *value);
static void dialog_show_add( dialog_info_t *dialog, show_struct *show);
static void dialog_logic_add( dialog_info_t *dialog, logic_struct *logic);
static void dialog_browser_add( dialog_info_t *dialog, file_struct *file);
static void dialog_choice_add( dialog_info_t *dialog, choice_struct *choice);
static void dialog_button_add( dialog_info_t *dialog, button_struct *button);
static void dialog_close( dialog_info_t *dialog);

/* GTK widget interface */
static widget_api_t ggtk_widget_api = {
    dialog_info_create_group_box,
    dialog_separator_add,
    dialog_chain_add,
    chain_info_get_value,
    chain_info_set_value,
    dialog_slider_add,
    slider_info_set_value,
    dialog_show_add,
    dialog_logic_add,
    logic_info_get_value,
    logic_info_set_value,
    dialog_browser_add,
    file_info_get_value,
    file_info_set_value,
    dialog_choice_add,
    choice_info_get_value,
    choice_info_set_value,
    dialog_button_add,
    NULL, /* dialog_on_create_item */
    dialog_close,
};

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

typedef struct {
    dialog_info_t _herits;
    GtkWidget *window;
    GtkWidget *help_window;
    GtkWidget *scrolled_window;
    GtkWidget *container;
    GtkWidget *frame;
    int new_frame;
    GtkWidget *frame_box;
#ifndef GGTK_USE_TABLE
    GtkWidget *left_column;
    GtkWidget *right_column;
#else
    GtkWidget *table;
    int table_row_count;
    int table_col_count;
#endif
    GtkWidget *line_box;
    int disable_close_dialog;
} ggtk_dialog_info_t;

typedef struct {
    choice_struct *choice; // herits from widget_info_struct
    int need_redraw; // herits from widget_info_struct
    GtkWidget *widget;
} ggtk_choice_info_t;

typedef struct {
    slider_struct *slider; // herits from widget_info_struct
    int need_redraw; // herits from widget_info_struct
    GtkWidget *widget;
    GtkWidget *text_widget;
} ggtk_slider_info_t;

typedef struct {
    button_struct *button; // herits from widget_info_struct
    int need_redraw; // herits from widget_info_struct
    ggtk_dialog_info_t *dialog;
    GtkToolItem *option_button;
    GtkWidget *window;
    GtkWidget *help_window;
} ggtk_button_info_t;

typedef struct {
    logic_struct *logic; // herits from widget_info_struct
    int need_redraw; // herits from widget_info_struct
    GtkWidget *widget;
} ggtk_logic_info_t;

typedef struct {
    chain_struct *chain; // herits from widget_info_struct
    int need_redraw; // herits from widget_info_struct
    GtkWidget *widget;
} ggtk_chain_info_t;

typedef struct {
    file_struct *file; // herits from widget_info_struct
    int need_redraw; // herits from widget_info_struct
    GtkWidget *window;
    GtkWidget *text_widget;
} ggtk_file_info_t;

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


static ggtk_dialog_info_t *win_dialog_info_new()
{
    ggtk_dialog_info_t *ret;
    ret = calloc( 1, sizeof( *ret));
    ret->window = NULL;
    ret->help_window = NULL;
    ret->scrolled_window = NULL;
    ret->container = NULL;
    ret->frame = NULL;
    ret->new_frame = 0;
    ret->frame_box = NULL;
#ifndef GGTK_USE_TABLE
    ret->left_column = NULL;
    ret->right_column = NULL;
#else
    ret->table = NULL;
    ret->table_row_count = 0;
    ret->table_col_count = 0;
#endif
    ret->line_box = NULL;
    ret->disable_close_dialog = 0;
    return ret;
}

static void ggtk_dialog_info_delete( ggtk_dialog_info_t *dialog)
{
    free( dialog);
}

static ggtk_choice_info_t *ggtk_choice_info_new( choice_struct *choice)
{
    ggtk_choice_info_t *ret;
    ret = widget_info_new( sizeof( *ret), choice);
    return ret;
}

static ggtk_slider_info_t *ggtk_slider_info_new( slider_struct *slider)
{
    ggtk_slider_info_t *ret;
    ret = widget_info_new( sizeof( *ret), slider);
    return ret;
}

static ggtk_button_info_t *ggtk_button_info_new( button_struct *button)
{
    ggtk_button_info_t *ret;
    ret = widget_info_new( sizeof( *ret), button);
    return ret;
}

static ggtk_logic_info_t *ggtk_logic_info_new( logic_struct *logic)
{
    ggtk_logic_info_t *ret;
    ret = widget_info_new( sizeof( *ret), logic);
    return ret;
}

static ggtk_chain_info_t *ggtk_chain_info_new( chain_struct *chain)
{
    ggtk_chain_info_t *ret;
    ret = widget_info_new( sizeof( *ret), chain);
    return ret;
}

static ggtk_file_info_t *ggtk_file_info_new( file_struct *file)
{
    ggtk_file_info_t *ret;
    ret = widget_info_new( sizeof( *ret), file);
    return ret;
}

static void ggtk_text_field_set( GtkWidget *w, char *value)
{
    gtk_entry_set_text( GTK_ENTRY(w), value);
}

static void ggtk_text_field_set_real( GtkWidget *w, double value)
{
    char dum[80];

    sprintf( dum, "%.5g", value);
    ggtk_text_field_set( w, dum);
}

#ifndef _GGTK_USE_DIALOG
static GtkWidget *ggtk_hbutton_box_new( )
{
    GtkWidget *button_bar;

    button_bar = gtk_hbutton_box_new( );
    gtk_button_box_set_layout( GTK_BUTTON_BOX(button_bar),
     GTK_BUTTONBOX_SPREAD);
    gtk_box_set_spacing( GTK_BOX(button_bar), GGTK_BUTTON_BOX_SPACING);
    gtk_container_set_border_width( GTK_CONTAINER(button_bar),
     GGTK_CONTAINER_BORDER);

    return button_bar;
}
#endif

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

static void toggled( GtkToggleButton *togglebutton, ggtk_logic_info_t *logic_info)
{
    logic_info_set_value( logic_info, gtk_toggle_button_get_active(
     togglebutton));
    update_other_widgets( &ggtk_widget_api, logic_info->logic);
}

static void destroy_help( GtkWidget *widget, ggtk_button_info_t *button_info)
{
    ggtk_dialog_info_t *dialog = (ggtk_dialog_info_t *)g_object_get_data(
     G_OBJECT(widget), "DIALOG_INFO");
    if (dialog != NULL)
        dialog->help_window = NULL;
    if (button_info != NULL)
        button_info->help_window = NULL;
}

#ifndef _GGTK_USE_DIALOG
static void popdown_help( GtkWidget *w, GtkWidget *window)
{
    gtk_widget_destroy( window);
}

static void popdown_button_help( GtkWidget *w, ggtk_button_info_t *button_info)
{
    gtk_widget_unmap( button_info->help_window);
}
#endif

static void _on_cancel_help(GtkDialog *dialog, gint response_id, gpointer
 user_data)
{
    if (user_data != NULL) {
        gtk_widget_unmap( ((ggtk_button_info_t *)user_data)->help_window);
    } else {
        gtk_widget_destroy( GTK_WIDGET(dialog));
    }
}

static GtkWidget *display_help( char *help_file, char *variable_name, ggtk_button_info_t *button_info)
{
    GtkWidget *w;
    GtkWidget *main_box;
    GtkWidget *text_view;
    GtkTextBuffer *buffer;
    GtkWidget *scrolled_win;
#ifndef _GGTK_USE_DIALOG
    GtkWidget *button;
#endif
    static char text[HLPTEXTLNGTH];
    int nrows, ncols;

    if (button_info != NULL && button_info->help_window != NULL) {
        gtk_widget_map( button_info->help_window);
        return button_info->help_window;
    }

    gdialog_build_help( help_file, variable_name, text, &ncols, &nrows);

    /* Create a new window */
#ifdef _GGTK_USE_DIALOG
    w = gtk_dialog_new();
#else
    w = gtk_window_new( GTK_WINDOW_TOPLEVEL);
#endif
    /* Set the window title */
    gtk_window_set_title( GTK_WINDOW(w),
        variable_name != NULL ? variable_name : "Help");

    /* Set a handler */
    g_signal_connect( w, "destroy", G_CALLBACK(destroy_help), button_info);

    /* Sets the border width of the window. */
    gtk_container_set_border_width( GTK_CONTAINER(w), 1);

#ifdef _GGTK_USE_DIALOG
    main_box = gtk_dialog_get_content_area(GTK_DIALOG(w));
#else
    main_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    gtk_container_add( GTK_CONTAINER(w), main_box);
#endif

    scrolled_win = gtk_scrolled_window_new( NULL, NULL);
    gtk_widget_set_hexpand(scrolled_win, TRUE);
    gtk_widget_set_vexpand(scrolled_win, TRUE);
    gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scrolled_win),
     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
    gtk_container_add( GTK_CONTAINER(main_box), scrolled_win);

    text_view = gtk_text_view_new( );
    gtk_text_view_set_editable( GTK_TEXT_VIEW(text_view), FALSE);
    buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(text_view));
    gtk_text_buffer_set_text( buffer, text, -1);
    gtk_container_add( GTK_CONTAINER(scrolled_win), text_view);

#ifdef _GGTK_USE_DIALOG
    gtk_dialog_add_button(GTK_DIALOG(w), "_Close", GTK_RESPONSE_CLOSE);
    g_signal_connect(w, "response", G_CALLBACK(_on_cancel_help), button_info);
#else
    button = gtk_button_new_with_label( "Dismiss");
    if (button_info != NULL)
        g_signal_connect( button, "clicked",
         G_CALLBACK(popdown_button_help), button_info);
    else
        g_signal_connect( button, "clicked",
         G_CALLBACK(popdown_help), w);
    gtk_box_pack_start( GTK_BOX(main_box), button, FALSE, FALSE, 0);
#endif

    GtkRequisition min, nat;
    gtk_widget_get_preferred_size( text_view, &min, &nat);
    gtk_window_set_default_size( GTK_WINDOW(w), nat.width, nat.height);

    gtk_widget_show_all( w);

    if (button_info != NULL)
        button_info->help_window = w;

    return w;
}

static void popup_widget_helpshell( GtkWidget *w, generic_struct *generic)
{
    button_struct *b;

    if (!generic->window_id) {
        display_help( ggtk_helpfilename, generic->variable, NULL);
        return;
    }

    b = widget_find_button_from_window_id( generic->window_id);
    if (b != NULL)
        display_help( b->helptxt, generic->variable, NULL);
}

static void popup_button_helpshell( GtkWidget *w, ggtk_button_info_t
 *button_info)
{
    display_help( button_info->button->helptxt, NULL, button_info);
}

#ifdef GTK_USE_OLD_FILE_SELECTION
static gboolean destroy_fselshell( GtkWidget *widget, GdkEvent *event,
 ggtk_file_info_t *file_info)
{
    file_info->window = NULL;
    return FALSE;
}

static void fsel_ok( GtkWidget *w, ggtk_file_info_t *file_info)
{
    file_info_set_value( file_info, gtk_file_selection_get_filename(
     GTK_FILE_SELECTION(file_info->window)));
    update_other_widgets( &ggtk_widget_api, file_info->file);
    gtk_widget_unmap( file_info->window);
}

static void fsel_cancel( GtkWidget *w, ggtk_file_info_t *file_info)
{
    gtk_widget_unmap( file_info->window);
}
#else

static void ggtk_file_chooser_add_filter( GtkWidget *dialog, const char *pattern)
{
    GtkFileFilter* filter;

    filter = gtk_file_filter_new();
    gtk_file_filter_set_name( filter, pattern);
    gtk_file_filter_add_pattern( filter, pattern);
    gtk_file_chooser_add_filter( GTK_FILE_CHOOSER(dialog), filter);
}
#endif

static void ggtk_create_fileselbox( GtkWidget *w, ggtk_file_info_t *file_info)
{
    file_struct *file;
#ifndef GTK_USE_OLD_FILE_SELECTION
    GtkWidget *dialog;
#endif

    if (file_info->window != NULL) {
        gtk_widget_map( file_info->window);
        return;
    }

    file = file_info->file;

#ifndef GTK_USE_OLD_FILE_SELECTION
    dialog = gtk_file_chooser_dialog_new( file->label, NULL,
     GTK_FILE_CHOOSER_ACTION_OPEN, "_Cancel", GTK_RESPONSE_CANCEL,
     "_Open", GTK_RESPONSE_ACCEPT, NULL);

    /* Apply the default filter */
    if (file->filter[0]) {
        ggtk_file_chooser_add_filter( dialog, file->filter);
        ggtk_file_chooser_add_filter( dialog, "*");
    }

    /* Highlights and adds the default selection */
    /* to the selected list */
    if (file->userchain[0])
        gtk_file_chooser_set_filename( GTK_FILE_CHOOSER(dialog),
         file->userchain);

    if (gtk_dialog_run( GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
        file_info_set_value( file_info, gtk_file_chooser_get_filename(
         GTK_FILE_CHOOSER(dialog)));
        update_other_widgets( &ggtk_widget_api, file_info->file);
    }
    gtk_widget_destroy( dialog);

#else
    file_info->window = gtk_file_selection_new( file->label);
    g_signal_connect( file_info->window, "delete_event",
     G_CALLBACK(destroy_fselshell), file_info);
    g_signal_connect(
     GTK_FILE_SELECTION(file_info->window)->ok_button, "clicked",
     (GCallback)fsel_ok, file_info);
    g_signal_connect(
     GTK_FILE_SELECTION(file_info->window)->cancel_button,
     "clicked", (GCallback)fsel_cancel, file_info);

    /* Apply the default filter */
    gtk_file_selection_complete( GTK_FILE_SELECTION(file_info->window),
     file->filter);

    /* Highlights and adds the default selection */
    /* to the selected list */
    gtk_file_selection_set_filename( GTK_FILE_SELECTION(file_info->window),
     file->userchain);

    gtk_widget_show( file_info->window);
#endif
}

static void select_chain( GtkWidget *w, ggtk_choice_info_t *choice_info)
{
    choice_info_get_value( choice_info);
    update_other_widgets( &ggtk_widget_api, choice_info->choice);
}

static void close_button_dialog( GtkWidget *w, ggtk_button_info_t *button_info)
{
    button_struct *button = button_info->button;

    if (on_close_dialog( &ggtk_widget_api, (dialog_info_t *)button_info->dialog,
     button->command, widget_get_index( button)) == -1)
        gdk_display_beep(gtk_widget_get_display(w));
}

static void click_option_menu( GtkWidget *w, ggtk_button_info_t *button_info)
{
    gulong connect_id = 0;
    GtkToolItem *option_button;

    option_button = button_info->option_button;
    gtk_tool_button_set_label( GTK_TOOL_BUTTON(option_button), button_info->button->title);
    // remove old handler
    connect_id = (gulong)(gsize)g_object_get_data( G_OBJECT(option_button), "CONNECT_ID");
    if (connect_id)
        g_signal_handler_disconnect( option_button, connect_id);
    // set new handler
    connect_id = g_signal_connect( option_button, "clicked",
     G_CALLBACK(close_button_dialog), button_info);
    g_object_set_data( G_OBJECT(option_button), "CONNECT_ID", (gpointer)(gsize)connect_id);
    close_button_dialog( w, button_info);
}

static ggtk_dialog_info_t *ggtk_dialog_create( GtkWidget *window, int dialog_id)
{
    ggtk_dialog_info_t *dialog;

    dialog = win_dialog_info_new();
    g_object_set_data( G_OBJECT(window), "DIALOG_INFO", dialog);
    dialog->window = window;
    dialog->container = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    
    gtk_widget_set_hexpand(dialog->container, TRUE);
    gtk_widget_set_vexpand(dialog->container, TRUE);

    dialog->frame = NULL;
    dialog->new_frame = FALSE;
    dialog->frame_box = NULL;

    dialog_info_prepare( (dialog_info_t *)dialog, dialog_id);
    dialog_info_build( &ggtk_widget_api, (dialog_info_t *)dialog, dialog_id);

    return dialog;
}

static gboolean destroy_moreoption( GtkWidget *widget, GdkEvent *event, ggtk_button_info_t *button_info)
{
    button_info->window = NULL;
    save_context( &ggtk_widget_api, button_info->button->popup_window_id, 1);
    return FALSE;
}

static void popdown_moreoption( GtkWidget *w, ggtk_button_info_t *button_info)
{
    gtk_widget_unmap( button_info->window);
}

static void close_moreoption_dialog( widget_info_struct *widget_info)
{
    if (widget_info->generic->type == BUTTON) {
        ggtk_button_info_t *button_info = (ggtk_button_info_t *)widget_info;
        if (button_info->window != NULL) {
            //printf( "before gtk_widget_destroy3\n");
            gtk_widget_destroy( button_info->window);
        }
        if (button_info->help_window != NULL) {
            //printf( "before gtk_widget_destroy4\n");
            gtk_widget_destroy( button_info->help_window);
        }
        if (button_info->dialog != NULL) {
            ggtk_dialog_info_delete( button_info->dialog);
        }
    }
}

static void _on_more_response(GtkDialog *dialog, gint response_id, gpointer
 user_data)
{
    ggtk_button_info_t *button_info = (ggtk_button_info_t *)user_data;

    switch (response_id) {
    case GTK_RESPONSE_OK:
        close_button_dialog( NULL, button_info);
        break;
    case GTK_RESPONSE_CLOSE:
        popdown_moreoption( NULL, button_info);
        break;
    case GTK_RESPONSE_HELP:
        popup_button_helpshell( NULL, button_info);
        break;
    }
}

/* Create the default 3-button row at the bottom of menus hidden 
behind buttons in the Main menu */
static GtkWidget *create_actionarea( ggtk_button_info_t *button_info)
{
#ifdef _GGTK_USE_DIALOG
    gtk_dialog_add_button(GTK_DIALOG(button_info->window), "Go",
     GTK_RESPONSE_OK);
    gtk_dialog_add_button(GTK_DIALOG(button_info->window), "_Close",
     GTK_RESPONSE_CLOSE);
    gtk_dialog_add_button(GTK_DIALOG(button_info->window), "_Help",
     GTK_RESPONSE_HELP);
    g_signal_connect(button_info->window, "response",
     G_CALLBACK(_on_more_response), button_info);

     return NULL;
#else
    GtkWidget *button_bar;
    GtkWidget *item;

    button_bar = ggtk_hbutton_box_new( );

    item = gtk_button_new_with_label( "Go");
    g_signal_connect( item, "clicked",
     G_CALLBACK(close_button_dialog), button_info);
    gtk_container_add( GTK_CONTAINER(button_bar), item);

    item = gtk_button_new_with_label( "Dismiss");
    g_signal_connect( item, "clicked",
     G_CALLBACK(popdown_moreoption), button_info);
    gtk_container_add( GTK_CONTAINER(button_bar), item);

    item = gtk_button_new_with_label( "Help");
    g_signal_connect( item, "clicked",
     G_CALLBACK(popup_button_helpshell), button_info);
    gtk_container_add( GTK_CONTAINER(button_bar), item);

    return button_bar;
#endif
}

static GtkWidget *ggtk_dialog_make_scrollable( ggtk_dialog_info_t *dialog)
{
#ifdef _GGTK_NO_SCROLLED_WINDOW
    return dialog->container;
#else
    GtkWidget *scroll_w;
    GtkWidget *viewport;

    viewport = gtk_viewport_new( NULL, NULL);
    gtk_widget_set_hexpand(viewport, TRUE);
    gtk_widget_set_vexpand(viewport, TRUE);
    gtk_container_add( GTK_CONTAINER(viewport), dialog->container);

    scroll_w = dialog->scrolled_window = gtk_scrolled_window_new( NULL, NULL);
    gtk_widget_set_hexpand(scroll_w, TRUE);
    gtk_widget_set_vexpand(scroll_w, TRUE);
    // don't show scrollbars before to be sure they are needed
    gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scroll_w),
     GTK_POLICY_NEVER, GTK_POLICY_NEVER);

    gtk_container_add( GTK_CONTAINER(scroll_w), viewport);
    return scroll_w;
#endif
}

static void _manage_scrolled_window_size( ggtk_dialog_info_t *dialog)
{
    GtkRequisition min_req, nat_req;
    gint max_height;
    gboolean resizable;
    GtkPolicyType policy;

    gtk_widget_get_preferred_size( dialog->container, &min_req, &nat_req);

    GdkDisplay *display = gtk_widget_get_display(dialog->window);
    GdkMonitor *monitor = gdk_display_get_primary_monitor(display);
    GdkRectangle geom = {0};
    if (monitor)
        gdk_monitor_get_geometry(monitor, &geom);
    else
        geom.height = 1000;

    max_height = geom.height;

    if (nat_req.height * 1.0 > max_height * .9) {
        resizable = TRUE;
        policy = GTK_POLICY_AUTOMATIC;
    } else {
#ifdef _ADAPT_WINDOW_ON_EXPANDER
        resizable = FALSE;
        policy = GTK_POLICY_NEVER;
#else
        resizable = TRUE;
        policy = GTK_POLICY_AUTOMATIC;
#endif
    }
    gtk_window_set_resizable( GTK_WINDOW(dialog->window), resizable);
    gtk_scrolled_window_set_policy(
     GTK_SCROLLED_WINDOW(dialog->scrolled_window), GTK_POLICY_NEVER, policy);
}

/* Pops the Floating Windows for menus hidden behind buttons in the
Main menu */
static void popup_moreoptionshell( GtkWidget *w, ggtk_button_info_t *button_info)
{
    GtkWidget *main_box;
    GtkWidget *dialog_box;
    GtkWidget *actionarea;

    if (button_info->window != NULL) {
        gtk_widget_map( button_info->window);
        return;
    }

    /* Create a new window */
#ifdef _GGTK_USE_DIALOG
    button_info->window = gtk_dialog_new();
#else
    button_info->window = gtk_window_new( GTK_WINDOW_TOPLEVEL);
#endif
#ifdef _ADAPT_WINDOW_ON_EXPANDER
    gtk_window_set_resizable(button_info->window, FALSE);
#endif
    /* Set the window title */
    gtk_window_set_title( GTK_WINDOW(button_info->window), button_info->button->moretxt);

    /* Set a handler for delete_event */
    g_signal_connect( button_info->window, "delete_event",
     G_CALLBACK(destroy_moreoption), button_info);

    /* Sets the border width of the window. */
    gtk_container_set_border_width( GTK_CONTAINER(button_info->window), 1);

#ifdef _GGTK_USE_DIALOG
    main_box = gtk_dialog_get_content_area(GTK_DIALOG(button_info->window));
#else
    main_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
#endif

    button_info->dialog = ggtk_dialog_create( button_info->window,
     button_info->button->popup_window_id);
    if (button_info->dialog->container != NULL) {
        dialog_box = ggtk_dialog_make_scrollable( button_info->dialog);
        gtk_box_pack_start( GTK_BOX(main_box), dialog_box, TRUE, TRUE, 0);
        gtk_box_pack_start( GTK_BOX(main_box), gtk_separator_new(GTK_ORIENTATION_HORIZONTAL), FALSE, FALSE, 0);
    } else {
        dialog_box = NULL;
    }

    actionarea = create_actionarea( button_info);

#ifndef _GGTK_USE_DIALOG
    gtk_box_pack_start( GTK_BOX(main_box), actionarea, FALSE, FALSE, 0);
    gtk_container_add( GTK_CONTAINER(button_info->window), main_box);
#endif
    gtk_widget_show_all( button_info->window);

    if (dialog_box != NULL) {
        _manage_scrolled_window_size( button_info->dialog);
    }
}

static void change_value( GtkRange *range, ggtk_slider_info_t *slider_info)
{
    slider_struct *slider;

    slider = slider_info->slider;
    slider->uservalue = gtk_range_get_value( range);
    ggtk_text_field_set_real( slider_info->text_widget, slider->uservalue);
    update_other_widgets( &ggtk_widget_api, slider);
}

static void update_slider( GtkRange *range, ggtk_slider_info_t *slider_info)
{
    const char *dum;
    static int s_recur = 0;

    if (s_recur)
        return;
    s_recur++;

    dum = gtk_entry_get_text( GTK_ENTRY(slider_info->text_widget));
    slider_info_set_value( slider_info, atof( dum));
    update_other_widgets( &ggtk_widget_api, slider_info->slider);

    s_recur--;
}

#ifdef GGTK_USE_TABLE
static void ggtk_dialog_manage_row( ggtk_dialog_info_t *dialog)
{
    if (dialog->table_col_count == 0) {
        dialog->table_col_count = 2;
        dialog->table_row_count++;
    }
    dialog->table_col_count--;
}
#endif

static void ggtk_dialog_pack( GtkWidget *box, GtkWidget *w)
{
    gtk_box_pack_start( GTK_BOX(box), w, FALSE, FALSE, 0);
}

/* Not used
static void ggtk_dialog_pack_expand( GtkWidget *box, GtkWidget *w)
{
    gtk_box_pack_start( GTK_BOX(box), w, TRUE, FALSE, 0);
}
*/

static GtkWidget *_first_focusable_widget = NULL;

static void ggtk_dialog_pack_fill( GtkWidget *box, GtkWidget *w)
{
    gtk_box_pack_start( GTK_BOX(box), w, TRUE, TRUE, 0);
    if (_first_focusable_widget == NULL && gtk_widget_get_can_focus( w)) {
        _first_focusable_widget = w;
    }
}

static void ggtk_dialog_pack_in_container( ggtk_dialog_info_t *dialog, GtkWidget
 *w)
{
    ggtk_dialog_pack( dialog->container, w);
}

static void ggtk_dialog_pack_in_left_column( ggtk_dialog_info_t *dialog,
 GtkWidget *w)
{
#ifndef GGTK_USE_TABLE
    ggtk_dialog_pack_fill( dialog->left_column, w);
#else
    ggtk_dialog_manage_row( dialog);
    gtk_grid_attach(GTK_GRID(dialog->table), w, 0, dialog->table_row_count, 1, 1);
#endif
}

static void ggtk_dialog_pack_in_right_column( ggtk_dialog_info_t *dialog,
 GtkWidget *w)
{
#ifndef GGTK_USE_TABLE
    ggtk_dialog_pack_fill( dialog->right_column, w);
#else
    ggtk_dialog_manage_row( dialog);
    gtk_grid_attach(GTK_GRID(dialog->table), w, 1, dialog->table_row_count, 1, 1);
#endif
}

static void ggtk_dialog_pack_in_line_box( ggtk_dialog_info_t *dialog, GtkWidget
 *w)
{
    ggtk_dialog_pack( dialog->line_box, w);
}

static void ggtk_dialog_pack_in_line_box_fill( ggtk_dialog_info_t *dialog,
 GtkWidget *w)
{
    ggtk_dialog_pack_fill( dialog->line_box, w);
}

static void ggtk_dialog_create_line_box( ggtk_dialog_info_t *dialog)
{
    dialog->line_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
    ggtk_dialog_pack_in_right_column( dialog, dialog->line_box);
}

static void ggtk_dialog_label_new( ggtk_dialog_info_t *ggtk_dialog, widget_t
 *generic)
{
    GtkWidget *w;

    w = gtk_button_new_with_label( ((generic_struct *)generic)->label);
    gtk_button_set_relief( GTK_BUTTON(w), GTK_RELIEF_NONE);
    gtk_widget_set_can_focus( w, FALSE);
    /* GTK3: align the label inside the button */
    GtkWidget *child = gtk_bin_get_child(GTK_BIN(w));
    if (GTK_IS_LABEL(child)) {
        gtk_label_set_xalign(GTK_LABEL(child), 1.0);
        gtk_label_set_yalign(GTK_LABEL(child), 0.5);
    }
    g_signal_connect( w, "clicked",
     G_CALLBACK(popup_widget_helpshell), generic);
    ggtk_dialog_pack_in_left_column( ggtk_dialog, w);
}

/****************************************************************************/
/* Widget API implementation for GTK **************************************/

static void dialog_info_create_group_box( dialog_info_t *dialog)
{
    ggtk_dialog_info_t *ggtk_dialog = (ggtk_dialog_info_t *)dialog;
    GtkWidget *box;

#ifndef GGTK_USE_TABLE
    box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);

    ggtk_dialog->left_column = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    ggtk_dialog_pack( box, ggtk_dialog->left_column);

    ggtk_dialog->right_column = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    ggtk_dialog_pack_fill( box, ggtk_dialog->right_column);
#else
    box = gtk_grid_new();
    gtk_container_set_border_width( GTK_CONTAINER(box), GGTK_CONTAINER_BORDER);
    gtk_grid_set_row_spacing( GTK_GRID(box), GGTK_ROW_SPACING);
    gtk_grid_set_column_spacing( GTK_GRID(box), GGTK_COL_SPACING);
    ggtk_dialog->table = box;
    ggtk_dialog->table_row_count = 0;
    ggtk_dialog->table_col_count = 0;
#endif

    if (GGTK_USE_FRAME && !ggtk_dialog->new_frame) {
        ggtk_dialog->frame = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
        gtk_container_set_border_width( GTK_CONTAINER(ggtk_dialog->frame),
         GGTK_CONTAINER_BORDER);
        ggtk_dialog_pack_in_container( ggtk_dialog, ggtk_dialog->frame);
    }
    if (ggtk_dialog->frame) {
        gtk_container_add( GTK_CONTAINER(ggtk_dialog->frame), box);
        ggtk_dialog->new_frame = FALSE;
    } else {
        ggtk_dialog_pack_in_container( ggtk_dialog, box);
    }
}

static void dialog_separator_add( dialog_info_t *dialog)
{
    ggtk_dialog_pack_in_container( (ggtk_dialog_info_t *)dialog,
     gtk_separator_new(GTK_ORIENTATION_HORIZONTAL));
}

static void update_entry( GtkRange *range, ggtk_chain_info_t *chain_info)
{
    static int s_recur = 0;

    if (s_recur)
        return;
    s_recur++;

    chain_info_get_value( (widget_info_t *)chain_info);
    update_other_widgets( &ggtk_widget_api, chain_info->chain);

    s_recur--;
}

static void dialog_chain_add( dialog_info_t *dialog, chain_struct *chain)
{
    ggtk_dialog_info_t *ggtk_dialog = (ggtk_dialog_info_t *)dialog;
    ggtk_chain_info_t *chain_info = ggtk_chain_info_new( chain);
    
    chain_info->widget = gtk_entry_new();
    gtk_editable_set_editable( GTK_EDITABLE(chain_info->widget), chain->editable);
    gtk_entry_set_text( GTK_ENTRY(chain_info->widget), chain->userchain);
    gtk_widget_set_hexpand(chain_info->widget, TRUE);
    g_signal_connect( chain_info->widget, "changed",
     G_CALLBACK(update_entry), chain_info);
    ggtk_dialog_pack_in_right_column( ggtk_dialog, chain_info->widget);

    ggtk_dialog_label_new( ggtk_dialog, chain);
}

static void dialog_slider_add( dialog_info_t *dialog, slider_struct *slider)
{
    ggtk_dialog_info_t *ggtk_dialog = (ggtk_dialog_info_t *)dialog;
    ggtk_slider_info_t *slider_info;

    ggtk_dialog_create_line_box( ggtk_dialog);

    slider_info = ggtk_slider_info_new( slider);

    slider_info->text_widget = gtk_entry_new( );
    g_object_set(slider_info->text_widget, "width-chars", 8, NULL);
    ggtk_text_field_set_real( slider_info->text_widget, slider->uservalue);
    g_signal_connect( slider_info->text_widget, "changed",
     G_CALLBACK(update_slider), slider_info);
    ggtk_dialog_pack_in_line_box( ggtk_dialog, slider_info->text_widget);

    slider_info->widget = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL,
     slider->min, slider->min + slider->width, slider->width / GTK_SLIDER_MAXIMUM);
    gtk_range_set_value( GTK_RANGE(slider_info->widget), slider->uservalue);
    g_signal_connect( slider_info->widget, "value-changed",
     G_CALLBACK(change_value), slider_info);
    ggtk_dialog_pack_in_line_box_fill( ggtk_dialog, slider_info->widget);
    ggtk_dialog_label_new( ggtk_dialog, slider);
}

static void slider_info_set_value( widget_info_t *widget_info, double value)
{
    ggtk_slider_info_t *slider_info = (ggtk_slider_info_t *)widget_info;
    slider_struct *slider;
    double corrected_value;
    double eps;

    slider = slider_info->slider;
    eps = slider->width / 1e5;
    corrected_value = MINI(MAXI(slider->min, value), slider->min +
     slider->width);
    if (fabs( corrected_value - value) > eps || fabs( corrected_value -
     slider->uservalue) > eps) {
        slider->uservalue = corrected_value;
        gtk_range_set_value( GTK_RANGE(slider_info->widget), slider->uservalue);
        ggtk_text_field_set_real( slider_info->text_widget, slider->uservalue);
    }
}

static void logic_info_get_value( widget_info_t *widget_info)
{
    ggtk_logic_info_t *logic_info = (ggtk_logic_info_t *)widget_info;

    logic_info->logic->userlogic = gtk_toggle_button_get_active(
     GTK_TOGGLE_BUTTON(logic_info->widget));
}

static void logic_info_set_value( widget_info_t *widget_info, int value)
{
    ggtk_logic_info_t *logic_info = (ggtk_logic_info_t *)widget_info;
    logic_struct *logic;

    logic = logic_info->logic;
    logic->userlogic = value;
    gtk_button_set_label( GTK_BUTTON(logic_info->widget), logic->userlogic ?
     "Yes" : "No");
    gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(logic_info->widget),
     logic->userlogic);
}

static void chain_info_get_value( widget_info_t *widget_info)
{
    ggtk_chain_info_t *chain_info = (ggtk_chain_info_t *)widget_info;

    strncpy( chain_info->chain->userchain, gtk_entry_get_text(
     GTK_ENTRY(chain_info->widget)), CHAINLENGTH);
}

static void chain_info_set_value( widget_info_t *widget_info, const char *value)
{
    ggtk_chain_info_t *chain_info = (ggtk_chain_info_t *)widget_info;
    chain_struct *chain;

    chain = chain_info->chain;
    strcpy( chain->userchain, value);
    ggtk_text_field_set( chain_info->widget, chain->userchain);
}

static void choice_info_get_value( widget_info_t *widget_info)
{
    ggtk_choice_info_t *choice_info = (ggtk_choice_info_t *)widget_info;
    choice_struct *choice;

    choice = choice_info->choice;

    if (choice->mode) {
        int index;

        index = gtk_combo_box_get_active( GTK_COMBO_BOX(choice_info->widget));
        choice_set_index( choice, index);
    } else {
        char *text = gtk_combo_box_text_get_active_text(
         GTK_COMBO_BOX_TEXT(choice_info->widget));
        if (text) {
            strncpy( choice->userchoice, text, CHAINLENGTH);
            g_free(text);
        }
    }
}

static void choice_info_set_value( widget_info_t *widget_info, const char
 *value)
{
    ggtk_choice_info_t *choice_info = (ggtk_choice_info_t *)widget_info;
    choice_struct *choice;

    choice = choice_info->choice;
    if (value != NULL) {
        strcpy( choice->userchoice, value);
    }
    if (choice->mode) {
        int active_index = choice_get_index( choice);
        if (active_index >= 0)
            gtk_combo_box_set_active( GTK_COMBO_BOX(choice_info->widget),
             active_index);
    } else {
        GtkWidget *child = gtk_bin_get_child(GTK_BIN(choice_info->widget));
        ggtk_text_field_set( child, choice->userchoice);
    }
}

static void file_info_get_value( widget_info_t *widget_info)
{
    ggtk_file_info_t *file_info = (ggtk_file_info_t *)widget_info;

    strncpy( file_info->file->userchain, gtk_entry_get_text(GTK_ENTRY(
     file_info->text_widget)), CHAINLENGTH);
}

static void file_info_set_value( widget_info_t *widget_info, const char *value)
{
    ggtk_file_info_t *file_info = (ggtk_file_info_t *)widget_info;
    file_struct *file;

    file = file_info->file;
    strcpy( file->userchain, value);
    ggtk_text_field_set( file_info->text_widget, file->userchain);
}

static void expander_activated( GtkExpander *expander, ggtk_dialog_info_t
 *dialog)
{
    GtkRequisition min_req, nat_req;

    // should call another routine in _manage_scrolled_window_size to
    // negotiate new size
    gtk_widget_get_preferred_size( dialog->container, &min_req, &nat_req);

    _manage_scrolled_window_size( dialog);
}

static void dialog_show_add( dialog_info_t *dialog, show_struct *show)
{
    ggtk_dialog_info_t *ggtk_dialog = (ggtk_dialog_info_t *)dialog;
    GtkWidget *w;

    if (!GGTK_USE_FRAME || ggtk_dialog->new_frame) {
        w = gtk_label_new( show->text);
        if (GGTK_USE_FRAME) {
            gtk_label_set_xalign( GTK_LABEL(w), 0.5);
        } else {
            gtk_label_set_xalign( GTK_LABEL(w), 0.0);
        }
        gtk_label_set_yalign( GTK_LABEL(w), 0.5);
    } else {
        if (GGTK_USE_EXPANDER) {
            w = gtk_expander_new_with_mnemonic(show->text);
            gtk_expander_set_expanded( GTK_EXPANDER(w), TRUE);
            g_signal_connect( w, "activate",
             G_CALLBACK(expander_activated), ggtk_dialog);
        } else {
            w = gtk_frame_new( show->text);
            //gtk_frame_set_shadow_type( GTK_FRAME(ggtk_dialog->frame),
            // GTK_SHADOW_NONE);
            gtk_container_set_border_width( GTK_CONTAINER(w),
             GGTK_CONTAINER_BORDER);
        }
        ggtk_dialog->frame = w;
        ggtk_dialog->frame_box = NULL;
    }

    if (ggtk_dialog->new_frame) {
        if (ggtk_dialog->frame_box == NULL) {
            ggtk_dialog->frame_box = ggtk_dialog->frame;
            ggtk_dialog->frame = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
            gtk_container_set_border_width( GTK_CONTAINER(ggtk_dialog->frame),
             GGTK_CONTAINER_BORDER);
            gtk_container_add( GTK_CONTAINER(ggtk_dialog->frame_box),
             ggtk_dialog->frame);
        }
        gtk_container_add( GTK_CONTAINER(ggtk_dialog->frame), w);
    } else {
        ggtk_dialog_pack_in_container( ggtk_dialog, w);
        ggtk_dialog->new_frame = GGTK_USE_FRAME;
    }
}

static void dialog_logic_add( dialog_info_t *dialog, logic_struct *logic)
{
    ggtk_dialog_info_t *ggtk_dialog = (ggtk_dialog_info_t *)dialog;
    ggtk_logic_info_t *logic_info;

    logic_info = ggtk_logic_info_new( logic);

    logic_info->widget = gtk_check_button_new( );
    logic_info_set_value( logic_info, logic->userlogic);
    g_signal_connect( logic_info->widget, "toggled",
     G_CALLBACK(toggled), logic_info);
    ggtk_dialog_pack_in_right_column( ggtk_dialog, logic_info->widget);

    ggtk_dialog_label_new( ggtk_dialog, logic);
}

static void update_browser( GtkRange *range, ggtk_file_info_t *file_info)
{
    static int s_recur = 0;

    if (s_recur)
        return;
    s_recur++;

    file_info_get_value( (widget_info_t *)file_info);
    update_other_widgets( &ggtk_widget_api, file_info->file);

    s_recur--;
}

static void dialog_browser_add( dialog_info_t *dialog, file_struct *file)
{
    ggtk_dialog_info_t *ggtk_dialog = (ggtk_dialog_info_t *)dialog;
    ggtk_file_info_t *file_info;
    GtkWidget *button;

    ggtk_dialog_create_line_box( ggtk_dialog);

    file_info = ggtk_file_info_new( file);

    file_info->text_widget = gtk_entry_new( );
    gtk_entry_set_text( GTK_ENTRY(file_info->text_widget), file->userchain);
    g_signal_connect( file_info->text_widget, "changed",
     G_CALLBACK(update_browser), file_info);
    ggtk_dialog_pack_in_line_box_fill( ggtk_dialog, file_info->text_widget);

    button = gtk_button_new_with_label( "File");
    g_signal_connect( button, "clicked",
     G_CALLBACK(ggtk_create_fileselbox), file_info);
    ggtk_dialog_pack_in_line_box( ggtk_dialog, button);

    ggtk_dialog_label_new( ggtk_dialog, file);
}

static void dialog_choice_add( dialog_info_t *dialog, choice_struct *choice)
{
    ggtk_dialog_info_t *ggtk_dialog = (ggtk_dialog_info_t *)dialog;
    ggtk_choice_info_t *choice_info;
    int k;

    choice_info = ggtk_choice_info_new( choice);

    if (choice->mode)
        choice_info->widget = gtk_combo_box_text_new( );
    else
        choice_info->widget = gtk_combo_box_text_new_with_entry( );
    for (k = 0; k < choice->nchoices; k++) {
        gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(choice_info->widget),
         choice->choices[k]);
    }
    /* update widget */
    choice_info_set_value( choice_info, NULL);

    g_signal_connect( choice_info->widget, "changed",
     G_CALLBACK(select_chain), choice_info);
    ggtk_dialog_pack_in_right_column( ggtk_dialog, choice_info->widget);

    ggtk_dialog_label_new( ggtk_dialog, choice);
}

static void dialog_button_add( dialog_info_t *dialog, button_struct *button)
{
    ggtk_dialog_info_t *ggtk_dialog = (ggtk_dialog_info_t *)dialog;
    ggtk_button_info_t *button_info;
    GtkWidget *hbox;
    GtkWidget *w;

    button_info = ggtk_button_info_new( button);

    hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
    w = gtk_button_new_with_label( button->title);
    g_signal_connect( w, "clicked",
     G_CALLBACK(close_button_dialog), button_info);
    ggtk_dialog_pack_fill( hbox, w);

    if (strlen( button->moretxt) > 1) {
        w = gtk_button_new_with_label( button->moretxt);
        g_signal_connect( w, "clicked",
         G_CALLBACK(popup_moreoptionshell), button_info);
        ggtk_dialog_pack_fill( hbox, w);
    }

    if (strlen( button->moretxt) > 1) {
        w = gtk_button_new_with_label( "Help");
        g_signal_connect( w, "clicked",
         G_CALLBACK(popup_button_helpshell), button_info);
        ggtk_dialog_pack_fill( hbox, w);
    }

    ggtk_dialog_pack_in_right_column( ggtk_dialog, hbox);

    ggtk_dialog_label_new( ggtk_dialog, button);
}

static void dialog_close( dialog_info_t *dialog)
{
    ggtk_dialog_info_t *dialog_info = (ggtk_dialog_info_t *)dialog;
    //printf( "dialog_close\n");
    if (dialog_info->window != NULL) {
        //printf( "before gtk_widget_destroy1\n");
        gtk_widget_destroy( dialog_info->window);
    }
}

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

#define GILDAS_PROPS_FILE ".gag.gtk"

void ggtk_create_props_file(void)
{
    char *path;
    FILE *file;

    path = g_build_filename(g_get_home_dir(), GILDAS_PROPS_FILE, NULL);
    if ((file = fopen(path, "w")) == NULL) {
        g_message("Problem creating properties file in home directory!");
    } else {
        fclose(file);
    }
    g_free(path);
}

#if GTK_CHECK_VERSION(2,8,0)
#define _g_file_set_contents g_file_set_contents
#else
gboolean _g_file_set_contents(const gchar *filename, const gchar *contents,
 int length, GError **error)
{
    FILE *fp = fopen(filename, "w");
    if (fp == NULL)
        return FALSE;
    if (length >= 0) {
        fwrite( contents, 1, length, fp);
    } else {
        fprintf( fp, contents);
    }
    fclose( fp);
    return TRUE;
}
#endif

void ggtk_save_window_props(GtkWindow *window)
{
    char *path;
    GKeyFile *key_file;
    GError *error;

    path = g_build_filename(g_get_home_dir(), GILDAS_PROPS_FILE, NULL);

    key_file = g_key_file_new();
    error = NULL;
    gboolean file_found = g_key_file_load_from_file(key_file, path,
     G_KEY_FILE_NONE, &error);

    if (!file_found) {
        ggtk_create_props_file();
        error = NULL;
        file_found = g_key_file_load_from_file(key_file, path, G_KEY_FILE_NONE,
         &error);
    }
    if(file_found || (error && error->code == 1/* file empty */)) {
        gint x;
        gint y;
        gint width;
        gint height;
        const gchar *key = gtk_window_get_title(window);

        gtk_window_get_position( window, &x, &y);
        gtk_window_get_size( window, &width, &height);

        g_key_file_set_integer(key_file, key, "x", x);
        g_key_file_set_integer(key_file, key, "y", y);
        g_key_file_set_integer(key_file, key, "width", width);
        g_key_file_set_integer(key_file, key, "height", height);

        gchar *keystore_contents;
        keystore_contents = g_key_file_to_data(key_file, NULL, NULL);
        _g_file_set_contents(path, keystore_contents, -1, NULL);
        g_free(keystore_contents);

    } else {
        /* else they must have deleted the file while the program was running
         * so simply save default values ... silly user
         */
        g_message("error (%d): %s\n", error ? error->code : -1, error ? error->message : "unknown");
    }

    /* free everything up */
    g_free(path);
    g_key_file_free(key_file);

}

void ggtk_load_window_props(GtkWindow *window)
{
    char *path;
    GKeyFile *key_file;
    GError *error = NULL;

    path = g_build_filename(g_get_home_dir(), GILDAS_PROPS_FILE, NULL);

    key_file = g_key_file_new();
    gboolean file_found = g_key_file_load_from_file(key_file, path,
     G_KEY_FILE_NONE, &error);
    if (file_found) {
        const gchar *key = gtk_window_get_title(window);

        /* this means that the properties file was found so load it */
        gint x_value = g_key_file_get_integer(key_file, key, "x", NULL);

        gint y_value = g_key_file_get_integer(key_file, key, "y", NULL);

        gint width_value = g_key_file_get_integer(key_file, key, "width",
         NULL);

        gint height_value = g_key_file_get_integer(key_file, key, "height",
         NULL);

        GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(window));
        GdkMonitor *monitor = gdk_display_get_primary_monitor(display);
        GdkRectangle geom = {0};
        if (monitor)
            gdk_monitor_get_geometry(monitor, &geom);

        gint screen_width = geom.width ? geom.width : 1024;
        gint screen_height = geom.height ? geom.height : 768;

        /* reposition the window but make sure we're not putting it off the
         * screen. If so, reset to default values. */
        if(x_value != 0 && y_value != 0) {
            if((x_value + width_value) > screen_width) {
                x_value = 0;
            }
            if((y_value + height_value) > screen_height) {
                y_value = 0;
            }
            
            gtk_window_move (window, x_value, y_value);
        }

        /* should really check to see if the app window is larger than the
           set resolution and if so, make it small enough to fit within the
           desktop display.
         */
        if(width_value != 0 && height_value != 0) {
            if(width_value > screen_width) {
                width_value = screen_width;
            }
            if(height_value > screen_height) {
                height_value = screen_height;
            }
            gtk_window_set_default_size(window, width_value, height_value);
        }
    }

    /* free everything up */
    g_free(path);
    g_key_file_free(key_file);
}

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

static void _close_dialog( ggtk_dialog_info_t *dialog, int tag)
{
    char return_command[COMMANDLENGTH];

    if (dialog->disable_close_dialog)
        return;
    if (tag) {
        // not on destroy
        ggtk_save_window_props(GTK_WINDOW(dialog->window));
    } else {
        tag = GGUI_ABORT;
    }
    if (tag == GGUI_ABORT)
        dialog->disable_close_dialog = 1;
    //printf( "_close_dialog( %d)\n", tag);
    if (tag == GGUI_OK)
        strcpy( return_command, ggtk_main_command);
    else
        return_command[0] = '\0';

    if (on_close_dialog( &ggtk_widget_api, (dialog_info_t *)dialog,
     return_command, tag) == -1)
        gdk_display_beep( gtk_widget_get_display(GTK_WIDGET(dialog->window)));
}

static void _popup_help(ggtk_dialog_info_t *dialog)
{
    if (dialog->help_window == NULL) {
        dialog->help_window = display_help( ggtk_helpfilename, NULL, NULL);
        g_object_set_data( G_OBJECT(dialog->help_window), "DIALOG_INFO",
         dialog);
    } else {
        gtk_widget_map( dialog->help_window);
    }
}

#ifndef _GGTK_USE_DIALOG
static void close_dialog_ok( GtkWidget *w, ggtk_dialog_info_t *dialog)
{
    _close_dialog( dialog, GGUI_OK);
}

static void close_dialog_abort( GtkWidget *w, ggtk_dialog_info_t *dialog)
{
    _close_dialog( dialog, GGUI_ABORT);
}

static void popup_helpshell( GtkWidget *w, ggtk_dialog_info_t *dialog)
{
    _popup_help( dialog);
}
#endif

static int _on_destroy_widget( void *widget)
{
    gtk_widget_destroy( (GtkWidget *)widget);
    // do not call again
    return FALSE;
}

static void destroy_widgets( void* dialog)
{
    ggtk_dialog_info_t *dialog_info = dialog;
    if (dialog_info->window != NULL) {
        //printf( "before gtk_widget_destroy2\n");
        dialog_info->disable_close_dialog = 1;
        g_idle_add(_on_destroy_widget, dialog_info->window);
    }
}

static void ggtk_update_variable( int widget_index, sic_widget_def_t *widget,
 void *display)
{
    sic_set_widget_def( widget_index, widget);
    dialog_widget_set_need_redraw( widget_index);
    gtv_push_modified_variable( &ggtk_widget_api, widget_index);
}

/* This callback quits the program */
static gboolean ggtk_delete_event( GtkWidget *widget, GdkEvent *event,
 ggtk_dialog_info_t *dialog)
{
    ggtk_save_window_props(GTK_WINDOW(dialog->window));
    /* return FALSE for emitting "destroy" */
    return FALSE;
}

/* This callback quits the program */
static void ggtk_destroy_event( GtkWidget *widget, ggtk_dialog_info_t *dialog)
{
    //printf( "ggtk_destroy_event\n");
    if (dialog->help_window != NULL)
        g_object_set_data( G_OBJECT(dialog->help_window), "DIALOG_INFO", 0);
    dialog->window = NULL;
    widget_info_close( close_moreoption_dialog);
    _close_dialog( dialog, 0);
}

void ggtk_menu_bar_append( GtkWidget *menu_bar, const char *caption, gboolean end, void *callback, void *data)
{
    GtkWidget *item;
    item = gtk_button_new_with_label( caption);
    if (end)
        gtk_box_pack_end( GTK_BOX(menu_bar), item, FALSE, FALSE, 0);
    else
        gtk_box_pack_start( GTK_BOX(menu_bar), item, FALSE, FALSE, 0);
    g_signal_connect( item,
        "clicked", G_CALLBACK(callback), data);
}

static void _on_response(GtkDialog *dialog, gint response_id, gpointer
 user_data)
{
    ggtk_dialog_info_t *dialog_info = (ggtk_dialog_info_t *)user_data;

    switch (response_id) {
    case GTK_RESPONSE_OK:
        _close_dialog( dialog_info, GGUI_OK);
        break;
    case GTK_RESPONSE_CLOSE:
        _close_dialog( dialog_info, GGUI_ABORT);
        break;
    case GTK_RESPONSE_HELP:
        _popup_help( dialog_info);
        break;
    }
}

static void add_menu_bar( GtkWidget *main_box, ggtk_dialog_info_t *dialog)
{
    char returned_command[COMMANDLENGTH];

    sic_get_widget_returned_command( returned_command);
#ifdef _GGTK_USE_DIALOG
    if (returned_command[0]) {
        gtk_dialog_add_button(GTK_DIALOG(main_box), "Go",
         GTK_RESPONSE_OK);
    } else {
        gtk_dialog_add_button(GTK_DIALOG(main_box), "_OK",
         GTK_RESPONSE_OK);
    }
    gtk_dialog_add_button(GTK_DIALOG(main_box), "_Close",
     GTK_RESPONSE_CLOSE);
#ifndef _GGTK_NO_INITIAL_FOCUS_HELP
    _first_focusable_widget =
#endif
    gtk_dialog_add_button(GTK_DIALOG(main_box), "_Help",
     GTK_RESPONSE_HELP);
    gtk_dialog_set_default_response(GTK_DIALOG(main_box), GTK_RESPONSE_OK);
    g_signal_connect(main_box, "response", G_CALLBACK(_on_response), dialog);
#else
    GtkWidget *menu_bar;

    /* Create menu bar */
    menu_bar = ggtk_hbutton_box_new( );

    /* Create buttons GO, ABORT and HELP */
    ggtk_menu_bar_append( menu_bar, "Go", FALSE, close_dialog_ok,
     (void *)dialog);
    ggtk_menu_bar_append( menu_bar, "Abort", FALSE, close_dialog_abort,
     (void *)dialog);
    ggtk_menu_bar_append( menu_bar, "Help", TRUE, popup_helpshell, dialog);

    gtk_box_pack_start( GTK_BOX(main_box), gtk_separator_new(GTK_ORIENTATION_HORIZONTAL), FALSE, FALSE,
     0);
    gtk_box_pack_start( GTK_BOX(main_box), menu_bar, FALSE, FALSE, 0);
#endif
}

void create_widgets( int argc, char **argv)
{
    GtkWidget *window;
    GtkWidget *main_box;
    GtkWidget *command_bar;
    GtkWidget *option_menu;
    GtkToolItem *option_button;
    ggtk_dialog_info_t *dialog;
    GtkWidget *dialog_box;
    void *iter;
    button_struct *b;

    widget_info_open( );

    on_run_dialog( ggtk_update_variable, NULL);

    /* Create a new window */
#ifdef _GGTK_USE_DIALOG
    window = gtk_dialog_new();
    /* disable keeping window on top : DOESN'T WORK FOR THE MOMENT */
    //gtk_window_set_transient_for( GTK_WINDOW(window), NULL);
    //gtk_window_set_modal( GTK_WINDOW(window), FALSE);
#else
    window = gtk_window_new( GTK_WINDOW_TOPLEVEL);
#endif

#ifdef _ADAPT_WINDOW_ON_EXPANDER
    gtk_window_set_resizable(window, FALSE);
#endif

    /* Set the window title */
    gtk_window_set_title( GTK_WINDOW(window), ggtk_window_title);

    /* Sets the border width of the window. */
    gtk_container_set_border_width( GTK_CONTAINER(window), 1);

#ifdef _GGTK_USE_DIALOG
    main_box = gtk_dialog_get_content_area(GTK_DIALOG(window));
#else
    main_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
#endif

    /* Create command bar */
    command_bar = NULL;
    option_menu = NULL;
    iter = parse_menu_button_begin( );
    while ((b = parse_menu_button_next( iter)) != NULL) {
        ggtk_button_info_t *button_info;
        gulong connect_id;

        button_info = ggtk_button_info_new( b);
        if (command_bar == NULL) {
            command_bar = gtk_toolbar_new( );
            gtk_toolbar_set_show_arrow( GTK_TOOLBAR(command_bar), TRUE);
            gtk_toolbar_set_style( GTK_TOOLBAR(command_bar), GTK_TOOLBAR_TEXT);
        }
        /* Add Buttons */
        if (b->group > 0) {
            option_menu = gtk_menu_new( );
            option_button = gtk_menu_tool_button_new( NULL, b->title);
            //gtk_tool_item_set_expand(option_button, TRUE);
            gtk_toolbar_insert( GTK_TOOLBAR(command_bar), option_button, -1);
            gtk_menu_tool_button_set_menu( GTK_MENU_TOOL_BUTTON(option_button),
             option_menu);
            connect_id = g_signal_connect( option_button, "clicked",
             G_CALLBACK(close_button_dialog), button_info);
            g_object_set_data( G_OBJECT(option_button), "CONNECT_ID", (gpointer)(gsize)connect_id);
        }
        if (option_menu != NULL) {
            GtkWidget *item;

            item = gtk_menu_item_new_with_label( b->title);
            gtk_widget_show( item);
            gtk_menu_shell_append( GTK_MENU_SHELL(option_menu), item);
            button_info->option_button = option_button;
            g_signal_connect( item, "activate",
             G_CALLBACK(click_option_menu), button_info);
        } else {
            GtkToolItem *item;

            item = gtk_tool_button_new( NULL, b->title);
            gtk_widget_set_can_focus( GTK_WIDGET(item), FALSE);
            gtk_toolbar_insert( GTK_TOOLBAR(command_bar), item, -1);
            //gtk_tool_item_set_homogeneous(item, TRUE);
            g_signal_connect( item, "clicked",
             G_CALLBACK(close_button_dialog), button_info);
        }
        if (b->group < 0) {
            option_menu = NULL;
        }
    }
    if (command_bar != NULL) {
#ifdef GGTK_USE_TOOLBAR_WITH_SCROLL
        GtkWidget *scroll_w;

        scroll_w = gtk_scrolled_window_new( NULL, NULL);
        gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scroll_w),
         GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);

        gtk_container_add( GTK_CONTAINER(scroll_w),
         command_bar);
        gtk_box_pack_start( GTK_BOX(main_box), scroll_w, FALSE, FALSE, 2);
#else
        gtk_box_pack_start( GTK_BOX(main_box), command_bar, FALSE, FALSE, 2);
#endif
    }

    _first_focusable_widget = NULL;
    dialog = ggtk_dialog_create( window, 0);
    if (dialog->container != NULL) {
        dialog_box = ggtk_dialog_make_scrollable( dialog);
        gtk_box_pack_start( GTK_BOX(main_box), dialog_box, TRUE, TRUE, 0);
    } else {
        dialog_box = NULL;
    }

    set_close_dialog_handler( destroy_widgets, dialog);

    /* Set a handler for delete_event that immediately
     * exits GTK. */
    g_signal_connect( window, "delete_event",
     G_CALLBACK(ggtk_delete_event), dialog);
    g_signal_connect( window, "destroy",
     G_CALLBACK(ggtk_destroy_event), dialog);

#ifdef _GGTK_USE_DIALOG
    add_menu_bar( window, dialog);
#else
    add_menu_bar( main_box, dialog);

    gtk_container_add( GTK_CONTAINER(window), main_box);
#endif

    ggtk_load_window_props( GTK_WINDOW(window));
    gtk_widget_show_all( window);
    if (_first_focusable_widget != NULL) {
        gtk_window_set_focus( GTK_WINDOW(window), _first_focusable_widget);
    }
    gtk_window_present( GTK_WINDOW(window));

    if (dialog_box != NULL) {
        _manage_scrolled_window_size( dialog);
    }

    sic_post_widget_created( );
}

static int _on_create_widgets( void *i)
{
    create_widgets(0, NULL);
    // do not call again
    return FALSE;
}

int run_dialog_args( int argc, char **argv)
{
    int nb_widgets;

    launch_gtv_main_loop( NULL);

    nb_widgets = sic_open_widget_board( );

    sic_get_widget_global_infos( ggtk_window_title, ggtk_helpfilename,
     ggtk_main_command);

    sic_close_widget_board( );

    //create_widgets( argc, argv);
    g_idle_add(_on_create_widgets, (gpointer)NULL);

    return 0;
}

int run_dialog( )
{
     return run_dialog_args( 0, NULL);
}

