/* Modified by Michael de Hoog on 12/05/04:
Removed all of the C preprocessor pasting commands. */

#include "eiffel-gtk.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>		/* memcpy */
#include <limits.h>		/* gulong -> int conversion checks */

#ifndef GTK_HAVE_FEATURES_1_1_8
#error Must have at least GTK 1.1.8. 
#endif

static void marshal_func(GtkObject *object, 
			 gpointer        data,
			 guint           nparams,
			 GtkArg         *args,
			 GtkType        *arg_types,
			 GtkType         return_type);

static void destroy_signal_func(gpointer data); 
static void stash_params(struct stashed_data*, int, GtkArg *, GtkType *, GtkType); 

/* return a NULL pointer */
void *ext_null_pointer(void) {
  return NULL;
}

void ext_init(void) {
  gtk_init(&se_argc, &se_argv);
  gtk_signal_set_funcs(marshal_func, destroy_signal_func); 
}

void ext_widget_destroy(GtkObject *gtkobject) {
  gtk_widget_destroy(GTK_WIDGET(gtkobject));
}


/* gtk_eiffel_entry is a cecilized GTK_COMMAND.command_execution */ 
static void jump_to_eiffel(struct signal_data *data, 
			   struct stashed_data *params) {
  if (data->eiffel_target) { 
    gtk_eiffel_entry( data->eiffel_target, data->eiffel_data, params ); 
  }
}

void *ext_create_signal_data(void *command_object, char *eiffel_data) { 
  struct signal_data *data;

  data = (struct signal_data *)g_malloc(sizeof(struct signal_data));
  data->eiffel_target = command_object;
  data->eiffel_data = eiffel_data;

  return data; 
}

int ext_signal_connect(GtkObject *gtkobject, 
		       char *signal_name, 
		       void *command_object ,
		       char *eiffel_data) {

  return gtk_signal_connect(gtkobject, 
			    signal_name, 
			    NULL, 
			    ext_create_signal_data(command_object, eiffel_data)); 
}

int ext_signal_connect_after(GtkObject *gtkobject, 
			     char *signal_name, 
			     void *command_object ,
			     char *eiffel_data) {

  return gtk_signal_connect_after(gtkobject, 
				  signal_name, 
				  NULL, 
				  ext_create_signal_data(command_object, 
							 eiffel_data)); 
}

/* This function gets called every time there's a callback.  We use it
 * because we don't want to have to deal with all the different
 * callback formats. */

static void marshal_func(GtkObject      *object,
			 gpointer        data,
			 guint           nparams,
			 GtkArg         *args,
			 GtkType        *arg_types,
			 GtkType         return_type) { 

  struct stashed_data parms; 

  stash_params(&parms, nparams, args, arg_types, return_type); 
  jump_to_eiffel(data, &parms);
}

/* Free the data we allocated in ext_signal_connect. */ 

static void destroy_signal_func(gpointer data){
  g_free(data); 
}

static void stash_params(struct stashed_data *data, 
			 int nparams, 
			 GtkArg *args,
			 GtkType *arg_types, 
			 GtkType return_type) { 
#if 0
  int i; 

  if (nparams > 0) { 
    printf("stashing %d args ( types: ", nparams); 
    for (i=0; i<nparams; i++) { 
      printf("%d ", arg_types[i]); 
    }
    printf(")\n"); 
  }

#endif
  data->nparams=nparams;
  data->args=args;
  data->arg_types=arg_types;
  data->return_type=return_type;
  
  if (return_type == GTK_TYPE_NONE) { 
    data->return_arg=NULL;
  } else {
    if (data->args)
      data->return_arg=&data->args[nparams];
    else {
      printf("this is erroneous.\n");
      exit(-1);
    }
  }
}

GtkType ext_argument_type(struct stashed_data *data) { 
  return *data->arg_types;
}

GtkType ext_return_value_type(struct stashed_data *data) { 
  return data->return_type; 
}

int ext_num_params(struct stashed_data *data) { 
  return(data->nparams); 
}

void ext_set_return_value_boolean(struct stashed_data *data, int ret) {
  if (data && data->return_arg)
    *GTK_RETLOC_BOOL(*(data->return_arg))=ret;
}

void ext_set_return_value_integer(struct stashed_data *data, int ret) {
  if (data && data->return_arg)
    *GTK_RETLOC_INT(*(data->return_arg))=ret; 
}

void ext_set_return_value_pointer(struct stashed_data *data, void *ret) {
  if (data && data->return_arg)
    *GTK_RETLOC_POINTER(*(data->return_arg))=ret;
}

int ext_shift_param_int(struct stashed_data *data) { 
  int ret; 

  if (data->nparams<=0) { 
    return -1;
  }

  data->nparams--; 

  if (data->arg_types[0] != GTK_TYPE_INT && 
      data->arg_types[0] != GTK_TYPE_UINT) { 
    fprintf(stderr, "Warning: stashed arg not of type integer\n"); 
  }

  ret=GTK_VALUE_INT(data->args[0]); 
  data->args++; 
  data->arg_types++; 
  return ret; 
}

void *ext_shift_param_pointer(struct stashed_data *data) { 
  void *ret; 

  if (data->nparams<=0) { 
    return NULL;
  }

  data->nparams--; 

#if 0
  /* For some reason some events return with type GTK_TYPE_POINTER
   * and others return with the GTK_TYPE_GDK_EVENT */
  if (data->arg_types[0] != GTK_TYPE_POINTER) { 
    fprintf(stderr, "Warning: stashed arg not of type pointer\n"); 
  }
#endif

  ret=GTK_VALUE_POINTER(data->args[0]); 
  data->args++; 
  data->arg_types++; 
  return ret; 
}

float ext_shift_param_float(struct stashed_data *data) { 
  float ret; 

  if (data->nparams<=0) { 
    return 0.0;
  }

  data->nparams--; 

  if (data->arg_types[0] != GTK_TYPE_FLOAT ) { 
    fprintf(stderr, "Warning: stashed arg not of type real\n"); 
  }

  ret=GTK_VALUE_FLOAT(data->args[0]); 
  data->args++; 
  data->arg_types++; 
  return ret; 
}

GtkType ext_object_type ( GtkObject *gtkobject ) { 
  return gtkobject->klass->type; 
}

#ifdef GTK_1_0
int ext_type_builtins(int i) { 
  return gtk_type_builtins[i];
}
#endif

GtkWidget* ext_dialog_vbox(GtkDialog *p) { 
  return p->vbox;
}

GtkWidget* ext_dialog_action_area(GtkDialog *p) { 
  return p->action_area;
}

void ext_widget_set_flags(GtkWidget *widget, int flags) {
  GTK_WIDGET_SET_FLAGS(widget, flags);
}  

void ext_widget_unset_flags(GtkWidget *widget, int flags) { 
  GTK_WIDGET_UNSET_FLAGS(widget, flags); 
}

int ext_widget_visible(GtkWidget *gtkwidget) {
  return GTK_WIDGET_VISIBLE(gtkwidget);
}

GSList *ext_radio_button_get_group(GtkRadioButton *radio_button) {
  return radio_button->group;
}

GtkWidget *ext_fileselection_ok_button(GtkObject *gtkobject) {
  return GTK_FILE_SELECTION(gtkobject)->ok_button;
}

GtkWidget *ext_fileselection_cancel_button(GtkObject *gtkobject) {
  return GTK_FILE_SELECTION(gtkobject)->cancel_button;
}

GtkWidget *ext_fileselection_help_button(GtkObject *gtkobject) {
  return GTK_FILE_SELECTION(gtkobject)->help_button;
}

GtkWidget *ext_fileselection_action_area(GtkObject *gtkobject) { 
  return GTK_FILE_SELECTION(gtkobject)->action_area;
}

GList *ext_list_selection(GtkObject *gtkobject) {
  return GTK_LIST(gtkobject)->selection;
}

guint ext_toggle_button_active(GtkObject *gtkobject) { 
  return (GTK_TOGGLE_BUTTON(gtkobject)->active);
}

gfloat ext_adjustment_lower (GtkObject *gtkobject) {
  return (GTK_ADJUSTMENT(gtkobject)->lower);
}

gfloat ext_adjustment_upper (GtkObject *gtkobject) {
  return (GTK_ADJUSTMENT(gtkobject)->upper);
}

gfloat ext_adjustment_value (GtkObject *gtkobject) {
  return (GTK_ADJUSTMENT(gtkobject)->value);
}

gfloat ext_adjustment_step_increment (GtkObject *gtkobject) {
  return (GTK_ADJUSTMENT(gtkobject)->step_increment);
}

gfloat ext_adjustment_page_increment (GtkObject *gtkobject) {
  return (GTK_ADJUSTMENT(gtkobject)->page_increment);
}

gfloat ext_adjustment_page_size (GtkObject *gtkobject) {
  return (GTK_ADJUSTMENT(gtkobject)->page_size);
}

GdkColor *ext_style_fg (GtkStyle *gtkobject, int state) {
  return &gtkobject->fg[state];
}

GdkColor *ext_style_bg (GtkStyle *gtkobject, int state) {
  return &gtkobject->bg[state];
}

GdkColor *ext_style_light (GtkStyle *gtkobject, int state) {
  return &gtkobject->light[state];
}

GdkColor *ext_style_dark (GtkStyle *gtkobject, int state) {
  return &gtkobject->dark[state];
}

GdkColor *ext_style_mid (GtkStyle *gtkobject, int state) {
  return &gtkobject->mid[state];
}

GdkColor *ext_style_text (GtkStyle *gtkobject, int state) {
  return &gtkobject->text[state];
}

GdkColor *ext_style_base (GtkStyle *gtkobject, int state) {
  return &gtkobject->base[state];
}

GdkColor *ext_style_black(GtkStyle *gtkobject) { 
  return &gtkobject->black; 
     }

GdkColor *ext_style_white(GtkStyle *gtkobject) { 
  return &gtkobject->white; 
}

GdkGC *ext_fg_gc (GtkStyle *gtkobject, int state) {
  return gtkobject->fg_gc[state];
}

GdkGC *ext_bg_gc (GtkStyle *gtkobject, int state) {
  return gtkobject->bg_gc[state];
}

GdkGC *ext_light_gc (GtkStyle *gtkobject, int state) {
  return gtkobject->light_gc[state];
}

GdkGC *ext_dark_gc (GtkStyle *gtkobject, int state) {
  return gtkobject->dark_gc[state];
}

GdkGC *ext_mid_gc (GtkStyle *gtkobject, int state) {
  return gtkobject->mid_gc[state];
}

GdkGC *ext_text_gc (GtkStyle *gtkobject, int state) {
  return gtkobject->text_gc[state];
}

GdkGC *ext_base_gc (GtkStyle *gtkobject, int state) {
  return gtkobject->base_gc[state];
}

GdkGC *ext_black_gc(GtkStyle *gtkobject) { 
  return gtkobject->black_gc; 
}

GdkGC *ext_white_gc(GtkStyle *gtkobject) { 
  return gtkobject->white_gc; 
}

int ext_allocation_x(GtkAllocation *gtkobject) {
  return gtkobject->x;
}

int ext_allocation_y(GtkAllocation *gtkobject) {
  return gtkobject->y;
}

int ext_allocation_width(GtkAllocation *gtkobject) {
  return gtkobject->width;
}

int ext_allocation_height(GtkAllocation *gtkobject) {
  return gtkobject->height;
}

GtkAllocation *ext_allocation(GtkWidget *gtkobject) { 
  return &gtkobject->allocation;
}

void ext_point_new(int x, int y, GdkPoint *gdkobject) { 
  gdkobject->x=x;
  gdkobject->y=y;
}    

int
ext_point_x(GdkPoint *gdkobject) { 
  return gdkobject->x;
}

int
ext_point_y(GdkPoint *gdkobject) { 
  return gdkobject->y;
}

int
ext_sizeof_gdk_point(void) {
  return sizeof(GdkPoint);
}

void
ext_requisition_new(int width, int height, GtkRequisition *gtkobject) { 
  gtkobject->width=width;
  gtkobject->height=height;
}

int 
ext_sizeof_requisition(void) {
  return sizeof(GtkRequisition);
}

int ext_requisition_width(GtkRequisition *gtkobject) {
  return gtkobject->width;
}

int ext_requisition_height(GtkRequisition *gtkobject) {
  return gtkobject->height;
}

GdkWindow *ext_gdk_window_from_widget(GtkWidget *gtkobject) { 
  return gtkobject->window;
}

GtkObject *ext_list_item(GList *list, int index) {
  GList *sublist;
  sublist = g_list_nth(list, index);
  return sublist->data;
}

GList *ext_list_append(GList *list, gpointer data) {
  GList *new_list;
  new_list = g_list_append(list, data);
  return new_list;
}

GtkObject *ext_slist_item(GSList *list, int index) {
  GSList *sublist;
  sublist = g_slist_nth(list, index);
  return sublist->data;
}

GSList *ext_slist_append(GSList *list, gpointer data) {
  GSList *new_slist;
  new_slist = g_slist_append(list, data);
  return new_slist;
}

/* We're accepting patches, if you're interested. */ 
void ext_event_button_build (GdkEventButton *p, 
			     GdkEventType *type, 
			     GdkWindow **window,
			     gint8 *send_event,
			     guint32 *time,
			     gdouble *x,
			     gdouble *y,
			     gdouble *pressure, 
			     gdouble *xtilt,
			     gdouble *ytilt,
			     guint *state,
			     guint *button,
			     GdkInputSource *source,
			     guint32 *deviceid,
			     gdouble *x_root, 
			     gdouble *y_root) { 

  *type=p->type; 
  *window=p->window; 
  *send_event=p->send_event;
  *time=p->time;
  *x=p->x;
  *y=p->y;
  *pressure=p->pressure;
  *xtilt=p->xtilt;
  *ytilt=p->ytilt;
  *state=p->state;
  *button=p->button;
  *source=p->source;
  *deviceid=p->deviceid;
  *x_root=p->x_root;
  *y_root=p->y_root;
}

GdkEventType ext_gdk_event_type(GdkEvent *p) { 
  return (p->any.type); 
}

void ext_event_build(GdkEvent *event, 
		     GdkEventType *event_type,
		     GdkWindow **window, 
		     int *send_event) { 

  *event_type=event->any.type; 
  *window=event->any.window; 
  *send_event=event->any.send_event;
}

int ext_event_is_button (GdkEvent *p) { 
  int ret; 
  ret=(p->type == GDK_BUTTON_PRESS);
  return(ret);
}

GtkWidget *ext_color_selection_dialog_colorsel(GtkColorSelectionDialog *gtkobject) {
  return gtkobject->colorsel;
}

GtkWidget *ext_color_selection_dialog_main_vbox(GtkColorSelectionDialog *gtkobject) {
  return gtkobject->main_vbox;
}

GtkWidget *ext_color_selection_dialog_ok_button(GtkColorSelectionDialog *gtkobject) {
  return gtkobject->ok_button;
}

GtkWidget *ext_color_selection_dialog_reset_button(GtkColorSelectionDialog *gtkobject) {
  return gtkobject->reset_button;
}

GtkWidget *ext_color_selection_dialog_cancel_button(GtkColorSelectionDialog *gtkobject) {
  return gtkobject->cancel_button;
}

GtkWidget *ext_color_selection_dialog_help_button(GtkColorSelectionDialog *gtkobject) {
  return gtkobject->help_button;
}

int ext_color_red(GdkColor *color) {
  return color->red;
}

int ext_color_green(GdkColor *color) {
  return color->green;
}

int ext_color_blue(GdkColor *color) {
  return color->blue;
}

GtkWidget *ext_font_selection_dialog_fontsel(GtkFontSelectionDialog *gtkobject) {
  return gtkobject->fontsel;
}

GtkWidget *ext_font_selection_dialog_main_vbox(GtkFontSelectionDialog *gtkobject) {
  return gtkobject->main_vbox;
}

GtkWidget *ext_font_selection_dialog_action_area(GtkFontSelectionDialog *gtkobject) {
  return gtkobject->action_area;
}

GtkWidget *ext_font_selection_dialog_ok_button(GtkFontSelectionDialog *gtkobject) {
  return gtkobject->ok_button;
}

GtkWidget *ext_font_selection_dialog_apply_button(GtkFontSelectionDialog *gtkobject) {
  return gtkobject->apply_button;
}

GtkWidget *ext_font_selection_dialog_cancel_button(GtkFontSelectionDialog *gtkobject) {
  return gtkobject->cancel_button;
}

GtkWidget *ext_gamma_curve_table(GtkGammaCurve *gtkobject) {
  return gtkobject->table;
}

GtkWidget *ext_gamma_curve_curve(GtkGammaCurve *gtkobject) {
  return gtkobject->curve;
}

GtkWidget *ext_gamma_curve_spline(GtkGammaCurve *gtkobject) {
  return gtkobject->button[0];
}

GtkWidget *ext_gamma_curve_linear(GtkGammaCurve *gtkobject) {
  return gtkobject->button[1];
}

GtkWidget *ext_gamma_curve_free(GtkGammaCurve *gtkobject) {
  return gtkobject->button[2];
}

GtkWidget *ext_gamma_curve_gamma(GtkGammaCurve *gtkobject) {
  return gtkobject->button[3];
}

GtkWidget *ext_gamma_curve_reset(GtkGammaCurve *gtkobject) {
  return gtkobject->button[4];
}

GdkWindow *ext_handle_box_bin_window(GtkHandleBox *box) {
  return box->bin_window;
}

GdkWindow *ext_handle_box_float_window(GtkHandleBox *box) {
  return box->float_window;
}

GtkWidget *ext_input_dialog_axis_list(GtkInputDialog *dialog) {
  return dialog->axis_list;
}

GtkWidget *ext_input_dialog_axis_listbox(GtkInputDialog *dialog) {
  return dialog->axis_listbox;
}

GtkWidget *ext_input_dialog_mode_optionmenu(GtkInputDialog *dialog) {
  return dialog->mode_optionmenu;
}

GtkWidget *ext_input_dialog_close_button(GtkInputDialog *dialog) {
  return dialog->close_button;
}

GtkWidget *ext_input_dialog_save_button(GtkInputDialog *dialog) {
  return dialog->save_button;
}

GtkWidget *ext_input_dialog_keys_list(GtkInputDialog *dialog) {
  return dialog->keys_list;
}

GtkWidget *ext_input_dialog_keys_listbox(GtkInputDialog *dialog) {
  return dialog->keys_listbox;
}

int ext_input_dialog_current_device (GtkInputDialog *dialog) { 
  return dialog->current_device; 
     }

int ext_flag_find_value ( int type, char *name ) { 
  GtkFlagValue *ret; 
  ret = gtk_type_flags_find_value ( type, name ) ; 
  return ret->value; 
}

int ext_enum_find_value ( int type, char *name ) { 
  GtkEnumValue *ret; 
  ret = gtk_type_enum_find_value ( type, name ); 
  return ret->value;
}

GtkWidget *ext_notebook_page_child(GtkNotebookPage *page) {
  return page->child;
}

GtkWidget *ext_notebook_page_tab_label(GtkNotebookPage *page) {
  return page->tab_label;
}

GtkWidget *ext_notebook_page_menu_label(GtkNotebookPage *page) {
  return page->menu_label;
}

int ext_notebook_page_default_menu(GtkNotebookPage *page) {
  return page->default_menu;
}

int ext_notebook_page_default_tab(GtkNotebookPage *page) {
  return page->default_tab;
}

GList *ext_notebook_children (GtkNotebook *notebook) { 
  return notebook->children;
     }

int ext_notebook_tab_pos (GtkNotebook *notebook) { 
  return notebook->tab_pos;
}

GtkNotebookPage *ext_notebook_cur_page ( GtkNotebook *notebook ) { 
  return notebook->cur_page; 
}

int
ext_motion_notify_event ( GtkWidget *widget, GdkEventMotion *event) { 
  return GTK_WIDGET_CLASS(GTK_OBJECT(widget)->klass)->motion_notify_event(widget, (GdkEventMotion*)event); 
}

void
ext_make_segment(int x1, int y1, int x2, int y2, 
		 GdkSegment *segment) 
{ 
  segment->x1=x1;
  segment->y1=y1;
  segment->x2=x2;
  segment->y2=y2;
}

int
ext_sizeof_gdk_segment(void) {
  return sizeof(GdkSegment); 
}

void
ext_make_target_entry(char *target, int flags, int info, 
		      GtkTargetEntry *storage) 
{
  storage->target=target;
  storage->flags=flags;
  storage->info=info;
}

/* Grrr.  The GTK+ interface to the dnd routines sucks. */
GtkTargetEntry *
ext_target_entry_to_array(GtkTargetEntry **entry, 
			  int n_entries) { 
  
  int i; 
  GtkTargetEntry *retval;
  retval = (GtkTargetEntry *)(g_malloc(n_entries * sizeof(GtkTargetEntry))); 
  for (i=0; i< n_entries; i++) { 
    memcpy(&retval[i], entry[i], sizeof(GtkTargetEntry)); 
  }
  return(retval); 
}

int ext_sizeof_target_entry(void) {
  return sizeof(GtkTargetEntry);
}

GdkDragProtocol ext_drag_context_protocol (GdkDragContext *p) {
  return p->protocol;
}

gboolean ext_drag_context_is_source (GdkDragContext *p) {
  return p->is_source;
}

GdkWindow* ext_drag_context_source_window (GdkDragContext *p) {
  return p->source_window;
}

GdkWindow* ext_drag_context_dest_window (GdkDragContext *p) {
  return p->dest_window;
}

GdkDragAction ext_drag_context_actions (GdkDragContext *p) {
  return p->actions;
}

GdkDragAction ext_drag_context_suggested_action (GdkDragContext *p) {
  return p->suggested_action;
}

GdkDragAction ext_drag_context_action (GdkDragContext *p) {
  return p->action;
}

guint32 ext_drag_context_start_time (GdkDragContext *p) {
  return p->start_time;
}

gint ext_selection_data_format (GtkSelectionData *p) {
  return p->format;
}

gint ext_selection_data_length (GtkSelectionData *p) {
  return p->length;
}

char* ext_selection_data_data (GtkSelectionData *p) {
  return p->data;
}

/* Problem: GdkAtom is gulong, which is 8 bytes on an Alpha. 
 * We cannot represent this type in Eiffel. So we use an int
 * and check to make sure it's not too big. */ 

int ext_selection_data_selection (GtkSelectionData *p) {
  if (p->selection > INT_MAX)
    g_warning("GdkAtom greater than INT_MAX");
  return p->selection;
}

int ext_selection_data_target (GtkSelectionData *p) {
  if (p->target > INT_MAX)
    g_warning("GdkAtom greater than INT_MAX");
  return p->target;
}

int ext_selection_data_type (GtkSelectionData *p) {
  if (p->type > INT_MAX)
    g_warning("GdkAtom greater than INT_MAX");
  return p->type;
}

void
ext_drag_source_set(GtkWidget *widget, 
			 GdkModifierType start_button_mask, 
			 GtkTargetEntry **targets, 
			 gint n_targets, 
			 GdkDragAction actions) { 

  GtkTargetEntry *targets_array; 

  targets_array=ext_target_entry_to_array(targets, n_targets); 

  gtk_drag_source_set(widget, 
		      start_button_mask, 
		      targets_array, 
		      n_targets, 
		      actions); 
  g_free(targets_array); 

     }

void
ext_drag_dest_set(GtkWidget *widget, 
		  GtkDestDefaults flags, 
		  GtkTargetEntry **targets, 
		  gint n_targets,
		  GdkDragAction actions) { 
  GtkTargetEntry *targets_array; 

  targets_array=ext_target_entry_to_array(targets, n_targets); 
  
  gtk_drag_dest_set(widget, 
		    flags, 
		    targets_array, 
		    n_targets,
		    actions); 
  g_free(targets_array); 

}

guint ext_version_major_version() {
  return gtk_major_version;
}

guint ext_version_minor_version() {
  return gtk_minor_version;
}

guint ext_version_micro_version() {
  return gtk_micro_version;
}

guint ext_version_binary_age() {
  return gtk_binary_age;
}

guint ext_version_interface_age() {
  return gtk_interface_age;
}

GdkWindow *ext_plug_socket_window(GtkPlug *plug) { 
  return plug->socket_window; 
}

gint ext_plug_same_app(GtkPlug *plug) {
  return plug->same_app;
}

