/** \file
 * \brief Menu Resources
 *
 * See Copyright Notice in "iup.h"
 */

#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#if GTK_CHECK_VERSION(3, 0, 0)
#include <gdk/gdkkeysyms-compat.h>
#endif

#ifdef HILDON
#include <hildon/hildon-window.h>
#endif

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <stdarg.h>

#include "iup.h"
#include "iupcbs.h"

#include "iup_object.h"
#include "iup_childtree.h"
#include "iup_attrib.h"
#include "iup_dialog.h"
#include "iup_str.h"
#include "iup_label.h"
#include "iup_drv.h"
#include "iup_drvfont.h"
#include "iup_image.h"
#include "iup_menu.h"

#include "iupgtk_drv.h"


typedef struct _ImenuPos
{
  int x, y;
  Ihandle* ih;
} ImenuPos;

static void gtkMenuPositionFunc(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, ImenuPos *menupos)
{
  char* value = iupAttribGet(menupos->ih, "POPUPALIGN");

  *x = menupos->x;
  *y = menupos->y;

  if (value)
  {
    GtkRequisition size;
    char value1[30], value2[30];
    iupStrToStrStr(value, value1, value2, ':');

#if GTK_CHECK_VERSION(3, 0, 0)
    gtk_widget_get_preferred_size(menupos->ih->handle, NULL, &size);
#else
    gtk_widget_size_request(menupos->ih->handle, &size);
#endif

    if (iupStrEqualNoCase(value1, "ARIGHT"))
      *x -= size.width;
    else if (iupStrEqualNoCase(value1, "ACENTER"))
      *x -= size.width/2;

    if (iupStrEqualNoCase(value2, "ABOTTOM"))
      *y -= size.height;
    else if (iupStrEqualNoCase(value2, "ACENTER"))
      *y -= size.height/2;
  }

  *push_in = FALSE;
  (void)menu;
}

int iupdrvMenuPopup(Ihandle* ih, int x, int y)
{
#if GTK_CHECK_VERSION(3, 22, 0)
  GdkRectangle rect;
  GdkWindow* window;
  GdkGravity rect_anchor = GDK_GRAVITY_NORTH_WEST;
  GdkGravity menu_anchor = GDK_GRAVITY_NORTH_WEST;
  char* value = iupAttribGet(ih, "POPUPALIGN");

  rect.x = x;
  rect.y = y;
  rect.width = 1;
  rect.height = 1;

  if (value)
  {
    char value1[30], value2[30];
    iupStrToStrStr(value, value1, value2, ':');

    if (iupStrEqualNoCase(value1, "ARIGHT"))
      menu_anchor = GDK_GRAVITY_NORTH_EAST;
    else if (iupStrEqualNoCase(value1, "ACENTER"))
      menu_anchor = GDK_GRAVITY_NORTH;

    if (iupStrEqualNoCase(value2, "ABOTTOM"))
    {
      if (menu_anchor == GDK_GRAVITY_NORTH_EAST)
        menu_anchor = GDK_GRAVITY_SOUTH_EAST;
      else if (menu_anchor == GDK_GRAVITY_NORTH)
        menu_anchor = GDK_GRAVITY_SOUTH;
      else
        menu_anchor = GDK_GRAVITY_SOUTH_WEST;
    }
    else if (iupStrEqualNoCase(value2, "ACENTER"))
    {
      if (menu_anchor == GDK_GRAVITY_NORTH_EAST)
        menu_anchor = GDK_GRAVITY_EAST;
      else if (menu_anchor == GDK_GRAVITY_NORTH)
        menu_anchor = GDK_GRAVITY_CENTER;
      else
        menu_anchor = GDK_GRAVITY_WEST;
    }
  }

  window = gdk_screen_get_root_window(gdk_screen_get_default());
  gtk_menu_popup_at_rect((GtkMenu*)ih->handle, window, &rect, rect_anchor, menu_anchor, NULL);
#else
  ImenuPos menupos;
  menupos.x = x;
  menupos.y = y;
  menupos.ih = ih;
  gtk_menu_popup((GtkMenu*)ih->handle, NULL, NULL, (GtkMenuPositionFunc)gtkMenuPositionFunc,
                 (gpointer)&menupos, 0, gtk_get_current_event_time());
#endif
  gtk_main();
  return IUP_NOERROR;
}

IUP_SDK_API int iupdrvMenuGetMenuBarSize(Ihandle* ih)
{
  int ch;
  iupdrvFontGetCharSize(ih, NULL, &ch);
#ifdef WIN32
  return 3 + ch + 3;
#else
  return 4 + ch + 4;
#endif
}

/* GTK 3.10+ uses GtkMenuItem + GtkBox instead of deprecated GtkImageMenuItem */

#if GTK_CHECK_VERSION(3, 10, 0)

/* Check if menu item has our custom image box structure */
static int gtkItemHasImageBox(Ihandle* ih)
{
  GtkWidget* child = gtk_bin_get_child(GTK_BIN(ih->handle));
  return (child && GTK_IS_BOX(child));
}

/* Get the image widget from our box structure */
static GtkWidget* gtkItemGetImageWidget(Ihandle* ih)
{
  GtkWidget* child = gtk_bin_get_child(GTK_BIN(ih->handle));
  if (child && GTK_IS_BOX(child))
  {
    GList* children = gtk_container_get_children(GTK_CONTAINER(child));
    GList* l;
    GtkWidget* image = NULL;
    for (l = children; l; l = l->next)
    {
      if (GTK_IS_IMAGE(l->data))
      {
        image = (GtkWidget*)l->data;
        break;
      }
    }
    g_list_free(children);
    return image;
  }
  return NULL;
}

/* Get the label widget from menu item (handles both box and simple structures) */
static GtkWidget* gtkItemGetLabelWidget(Ihandle* ih)
{
  GtkWidget* child = gtk_bin_get_child(GTK_BIN(ih->handle));
  if (child && GTK_IS_BOX(child))
  {
    GList* children = gtk_container_get_children(GTK_CONTAINER(child));
    GList* l;
    GtkWidget* label = NULL;
    for (l = children; l; l = l->next)
    {
      if (GTK_IS_LABEL(l->data))
      {
        label = (GtkWidget*)l->data;
        break;
      }
    }
    g_list_free(children);
    return label;
  }
  else if (child && GTK_IS_LABEL(child))
    return child;
  return NULL;
}

/* Set/update/remove image in menu item with box structure */
static void gtkItemSetImageWidget(Ihandle* ih, GdkPixbuf* pixbuf)
{
  GtkWidget* child = gtk_bin_get_child(GTK_BIN(ih->handle));

  if (!pixbuf)
  {
    /* Remove image if present */
    if (child && GTK_IS_BOX(child))
    {
      GtkWidget* image = gtkItemGetImageWidget(ih);
      if (image)
        gtk_widget_destroy(image);
    }
    return;
  }

  if (child && GTK_IS_BOX(child))
  {
    /* Box exists, update or add image */
    GtkWidget* image = gtkItemGetImageWidget(ih);
    if (image)
    {
      gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
    }
    else
    {
      image = gtk_image_new_from_pixbuf(pixbuf);
      gtk_box_pack_start(GTK_BOX(child), image, FALSE, FALSE, 0);
      gtk_box_reorder_child(GTK_BOX(child), image, 0);
      gtk_widget_show(image);
    }
  }
  else if (child && GTK_IS_LABEL(child))
  {
    /* Convert from simple label to box structure */
    GtkWidget* box;
    GtkWidget* image;

    g_object_ref(child);
    gtk_container_remove(GTK_CONTAINER(ih->handle), child);

    box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
    image = gtk_image_new_from_pixbuf(pixbuf);

    gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0);
    gtk_box_pack_end(GTK_BOX(box), child, TRUE, TRUE, 0);
    g_object_unref(child);

    gtk_container_add(GTK_CONTAINER(ih->handle), box);
    gtk_widget_show_all(box);
  }
}

/* Create a menu item with box structure for image support */
static GtkWidget* gtkMenuItemNewWithImageSupport(void)
{
  GtkWidget* menu_item = gtk_menu_item_new();
  GtkWidget* box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
  GtkWidget* label = gtk_label_new("");

  gtk_label_set_use_underline(GTK_LABEL(label), TRUE);
  gtk_label_set_xalign(GTK_LABEL(label), 0.0);

  gtk_box_pack_end(GTK_BOX(box), label, TRUE, TRUE, 0);
  gtk_container_add(GTK_CONTAINER(menu_item), box);
  gtk_widget_show_all(box);

  return menu_item;
}

static void gtkItemUpdateImage(Ihandle* ih, const char* value, const char* image, const char* impress)
{
  GdkPixbuf* pixbuf;

  if (!impress || !iupStrBoolean(value))
    pixbuf = iupImageGetImage(image, ih, 0, NULL);
  else
    pixbuf = iupImageGetImage(impress, ih, 0, NULL);

  gtkItemSetImageWidget(ih, pixbuf);
}

#else /* GTK < 3.10 - use GtkImageMenuItem */

static void gtkItemUpdateImage(Ihandle* ih, const char* value, const char* image, const char* impress)
{
  GdkPixbuf* pixbuf;

  if (!impress || !iupStrBoolean(value))
    pixbuf = iupImageGetImage(image, ih, 0, NULL);
  else
    pixbuf = iupImageGetImage(impress, ih, 0, NULL);

  if (pixbuf)
  {
    GtkWidget* image_label = gtk_image_menu_item_get_image((GtkImageMenuItem*)ih->handle);
    if (!image_label)
    {
      image_label = gtk_image_new();
      gtk_image_menu_item_set_image((GtkImageMenuItem*)ih->handle, image_label);
    }

    if (pixbuf != gtk_image_get_pixbuf((GtkImage*)image_label))
      gtk_image_set_from_pixbuf((GtkImage*)image_label, pixbuf);
  }
  else
    gtk_image_menu_item_set_image((GtkImageMenuItem*)ih->handle, NULL);
}

#endif /* GTK_CHECK_VERSION(3, 10, 0) */


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


static void gtkMenuMap(GtkWidget *widget, Ihandle* ih)
{
  Icallback cb = IupGetCallback(ih, "OPEN_CB");
  if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "OPEN_CB");  /* check also in the Submenu */
  if (cb) cb(ih);

  (void)widget;
}

static void gtkMenuUnMap(GtkWidget *widget, Ihandle* ih)
{
  Icallback cb = IupGetCallback(ih, "MENUCLOSE_CB");
  if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "MENUCLOSE_CB");  /* check also in the Submenu */
  if (cb) cb(ih);

  (void)widget;
}

static void gtkPopupMenuUnMap(GtkWidget *widget, Ihandle* ih)
{
  gtkMenuUnMap(widget, ih);

  /* quit the popup loop */
  gtk_main_quit();
}

static void gtkItemSelect(GtkWidget *widget, Ihandle* ih)
{
  Icallback cb = IupGetCallback(ih, "HIGHLIGHT_CB");
  if (cb)
    cb(ih);

  cb = IupGetCallback(ih, "HELP_CB");
  if (cb)
    gtk_menu_set_active((GtkMenu*)ih->parent->handle, IupGetChildPos(ih->parent, ih));

  (void)widget;
}

static void gtkItemActivate(GtkWidget *widget, Ihandle* ih)
{
  Icallback cb;

  if (GTK_IS_CHECK_MENU_ITEM(ih->handle) && !iupAttribGetBoolean(ih, "AUTOTOGGLE") && !iupAttribGetBoolean(ih->parent, "RADIO"))
  {
    /* GTK by default will do autotoggle */
    g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkItemActivate), ih);
    gtk_check_menu_item_set_active((GtkCheckMenuItem*)ih->handle, !gtk_check_menu_item_get_active((GtkCheckMenuItem*)ih->handle));
    g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkItemActivate), ih);
  }

#if GTK_CHECK_VERSION(3, 10, 0)
  if (gtkItemHasImageBox(ih))
#else
  if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
#endif
  {
    if (iupAttribGetBoolean(ih, "AUTOTOGGLE"))
    {
      if (iupAttribGetBoolean(ih, "VALUE"))
        iupAttribSet(ih, "VALUE", "OFF");
      else
        iupAttribSet(ih, "VALUE", "ON");

      gtkItemUpdateImage(ih, iupAttribGet(ih, "VALUE"), iupAttribGet(ih, "IMAGE"), iupAttribGet(ih, "IMPRESS"));
    }
  }

  cb = IupGetCallback(ih, "ACTION");
  if (cb)
  {
    int result = cb(ih);
    if (result == IUP_CLOSE)
      IupExitLoop();
  }

  (void)widget;
}

static gboolean gtkMenuKeyPressEvent(GtkWidget *widget, GdkEventKey *evt, Ihandle *ih)
{
  if (evt->keyval == GDK_F1)
  {
    Ihandle* child;
    GtkWidget* active = gtk_menu_get_active((GtkMenu*)widget);
    for (child=ih->firstchild; child; child=child->brother)
    {
      if (child->handle == active)
        iupgtkShowHelp(NULL, NULL, child);
    }
  }

  (void)widget;
  (void)evt;
  return FALSE;
}


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


static int gtkMenuMapMethod(Ihandle* ih)
{
  if (iupMenuIsMenuBar(ih))
  {
    /* top level menu used for MENU attribute in IupDialog (a menu bar) */
#ifdef HILDON
    Ihandle *pih;
    ih->handle = gtk_menu_new();
    if (!ih->handle)
      return IUP_ERROR;

    pih = iupChildTreeGetNativeParent(ih);
    hildon_window_set_menu(HILDON_WINDOW(pih->handle), GTK_MENU(ih->handle));
#else
    ih->handle = gtk_menu_bar_new();
    if (!ih->handle)
      return IUP_ERROR;

    iupgtkAddToParent(ih);
#endif
  }
  else
  {
    ih->handle = gtk_menu_new();
    if (!ih->handle)
      return IUP_ERROR;

    if (ih->parent)
    {
      /* parent is a submenu */
      gtk_menu_item_set_submenu((GtkMenuItem*)ih->parent->handle, ih->handle);

      g_signal_connect(G_OBJECT(ih->handle), "map", G_CALLBACK(gtkMenuMap), ih);
      g_signal_connect(G_OBJECT(ih->handle), "unmap", G_CALLBACK(gtkMenuUnMap), ih);
    }
    else
    {
      /* top level menu used for IupPopup */
      g_signal_connect(G_OBJECT(ih->handle), "map", G_CALLBACK(gtkMenuMap), ih);
      g_signal_connect(G_OBJECT(ih->handle), "unmap", G_CALLBACK(gtkPopupMenuUnMap), ih);
    }
  }

  gtk_widget_add_events(ih->handle, GDK_KEY_PRESS_MASK);
  g_signal_connect(G_OBJECT(ih->handle), "key-press-event", G_CALLBACK(gtkMenuKeyPressEvent), ih);

  ih->serial = iupMenuGetChildId(ih); 
  gtk_widget_show(ih->handle);

  return IUP_NOERROR;
}

static void gtkMenuUnMapMethod(Ihandle* ih)
{
  if (iupMenuIsMenuBar(ih))
    ih->parent = NULL;

  iupdrvBaseUnMapMethod(ih);
}

void iupdrvMenuInitClass(Iclass* ic)
{
  /* Driver Dependent Class functions */
  ic->Map = gtkMenuMapMethod;
  ic->UnMap = gtkMenuUnMapMethod;

  /* Used by iupdrvMenuGetMenuBarSize */
  iupClassRegisterAttribute(ic, "FONT", NULL, NULL, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_DEFAULT);  /* inherited */

  iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, NULL, NULL, IUPAF_DEFAULT);
}


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

static int gtkItemSetTitleImageAttrib(Ihandle* ih, const char* value)
{
#if GTK_CHECK_VERSION(3, 10, 0)
  if (gtkItemHasImageBox(ih))
#else
  if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
#endif
  {
    gtkItemUpdateImage(ih, NULL, value, NULL);
    return 1;
  }
  else
    return 0;
}

static int gtkItemSetImageAttrib(Ihandle* ih, const char* value)
{
#if GTK_CHECK_VERSION(3, 10, 0)
  if (gtkItemHasImageBox(ih))
#else
  if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
#endif
  {
    gtkItemUpdateImage(ih, iupAttribGet(ih, "VALUE"), value, iupAttribGet(ih, "IMPRESS"));
    return 1;
  }
  else
    return 0;
}

static int gtkItemSetImpressAttrib(Ihandle* ih, const char* value)
{
#if GTK_CHECK_VERSION(3, 10, 0)
  if (gtkItemHasImageBox(ih))
#else
  if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
#endif
  {
    gtkItemUpdateImage(ih, iupAttribGet(ih, "VALUE"), iupAttribGet(ih, "IMAGE"), value);
    return 1;
  }
  else
    return 0;
}

static int gtkItemSetTitleAttrib(Ihandle* ih, const char* value)
{
  char *str;
  GtkWidget* label;

  if (!value)
  {
    str = "     ";
    value = str;
  }
  else
    str = iupMenuProcessTitle(ih, value);

#if GTK_CHECK_VERSION(3, 10, 0)
  label = gtkItemGetLabelWidget(ih);
#else
  label = gtk_bin_get_child((GtkBin*)ih->handle);
#endif

  if (label)
    iupgtkSetMnemonicTitle(ih, (GtkLabel*)label, str);

  if (str != value) free(str);
  return 1;
}

static int gtkItemSetValueAttrib(Ihandle* ih, const char* value)
{
  if (GTK_IS_CHECK_MENU_ITEM(ih->handle))
  {
    if (iupAttribGetBoolean(ih->parent, "RADIO"))
      value = "ON";

    g_signal_handlers_block_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkItemActivate), ih);
    gtk_check_menu_item_set_active((GtkCheckMenuItem*)ih->handle, iupStrBoolean(value));
    g_signal_handlers_unblock_by_func(G_OBJECT(ih->handle), G_CALLBACK(gtkItemActivate), ih);
    return 0;
  }
#if GTK_CHECK_VERSION(3, 10, 0)
  else if (gtkItemHasImageBox(ih))
#else
  else if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
#endif
  {
    gtkItemUpdateImage(ih, value, iupAttribGet(ih, "IMAGE"), iupAttribGet(ih, "IMPRESS"));
    return 1;
  }
  else
    return 0;
}

static char* gtkItemGetValueAttrib(Ihandle* ih)
{
  return iupStrReturnChecked(GTK_IS_CHECK_MENU_ITEM(ih->handle) && gtk_check_menu_item_get_active((GtkCheckMenuItem*)ih->handle));
}

static int gtkItemMapMethod(Ihandle* ih)
{
  int pos;

  if (!ih->parent)
    return IUP_ERROR;

#ifndef HILDON
  if (iupMenuIsMenuBar(ih->parent))
    ih->handle = gtk_menu_item_new_with_label("");
  else
#endif
  {
    if (iupAttribGet(ih, "IMAGE")||iupAttribGet(ih, "TITLEIMAGE"))
    {
#if GTK_CHECK_VERSION(3, 10, 0)
      ih->handle = gtkMenuItemNewWithImageSupport();
#else
      ih->handle = gtk_image_menu_item_new_with_label("");
#endif
    }
    else if (iupAttribGetBoolean(ih->parent, "RADIO"))
    {
      GtkRadioMenuItem* last_tg = (GtkRadioMenuItem*)iupAttribGet(ih->parent, "_IUPGTK_LASTRADIOITEM");
      if (last_tg)
        ih->handle = gtk_radio_menu_item_new_with_label_from_widget(last_tg, "");
      else
        ih->handle = gtk_radio_menu_item_new_with_label(NULL, "");
      iupAttribSet(ih->parent, "_IUPGTK_LASTRADIOITEM", (char*)ih->handle);
    }
    else
    {
      char* hidemark = iupAttribGetStr(ih, "HIDEMARK");
#if GTK_CHECK_VERSION(2, 14, 0)
      if (!hidemark)
      {
        /* change HIDEMARK default if VALUE is not defined, after GTK 2.14 */
        if (!iupAttribGet(ih, "VALUE"))
          hidemark = "YES";
      }
#endif

      if (iupStrBoolean(hidemark))
        ih->handle = gtk_menu_item_new_with_label("");
      else
        ih->handle = gtk_check_menu_item_new_with_label("");
    }
  }

  if (!ih->handle)
    return IUP_ERROR;

  ih->serial = iupMenuGetChildId(ih); 

  g_signal_connect(G_OBJECT(ih->handle), "select", G_CALLBACK(gtkItemSelect), ih);
  g_signal_connect(G_OBJECT(ih->handle), "activate", G_CALLBACK(gtkItemActivate), ih);

  pos = IupGetChildPos(ih->parent, ih);
  gtk_menu_shell_insert((GtkMenuShell*)ih->parent->handle, ih->handle, pos);
  gtk_widget_show(ih->handle);

  iupUpdateFontAttrib(ih);

  return IUP_NOERROR;
}

void iupdrvItemInitClass(Iclass* ic)
{
  /* Driver Dependent Class functions */
  ic->Map = gtkItemMapMethod;
  ic->UnMap = iupdrvBaseUnMapMethod;

  /* Common */
  iupClassRegisterAttribute(ic, "FONT", NULL, iupdrvSetFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED);  /* inherited */

  /* Visual */
  iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
  iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);

  /* IupItem only */
  iupClassRegisterAttribute(ic, "VALUE", gtkItemGetValueAttrib, gtkItemSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "TITLE", NULL, gtkItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "TITLEIMAGE", NULL, gtkItemSetTitleImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkItemSetImageAttrib, NULL, NULL, IUPAF_IHANDLENAME|IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "IMPRESS", NULL, gtkItemSetImpressAttrib, NULL, NULL, IUPAF_IHANDLENAME|IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);

  /* IupItem GTK and Motif only */
  iupClassRegisterAttribute(ic, "HIDEMARK", NULL, NULL, NULL, NULL, IUPAF_DEFAULT);
}


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


static int gtkSubmenuSetImageAttrib(Ihandle* ih, const char* value)
{
#if GTK_CHECK_VERSION(3, 10, 0)
  if (gtkItemHasImageBox(ih))
#else
  if (GTK_IS_IMAGE_MENU_ITEM(ih->handle))
#endif
  {
    gtkItemUpdateImage(ih, NULL, value, NULL);
    return 1;
  }
  else
    return 0;
}

static int gtkSubmenuMapMethod(Ihandle* ih)
{
  int pos;

  if (!ih->parent)
    return IUP_ERROR;

#ifndef HILDON
  if (iupMenuIsMenuBar(ih->parent))
    ih->handle = gtk_menu_item_new_with_label("");
  else
#endif
  {
#if GTK_CHECK_VERSION(3, 10, 0)
    ih->handle = gtkMenuItemNewWithImageSupport();
#else
    ih->handle = gtk_image_menu_item_new_with_label("");
#endif
  }

  if (!ih->handle)
    return IUP_ERROR;

  ih->serial = iupMenuGetChildId(ih);

  pos = IupGetChildPos(ih->parent, ih);
  gtk_menu_shell_insert((GtkMenuShell*)ih->parent->handle, ih->handle, pos);
  gtk_widget_show(ih->handle);

  g_signal_connect(G_OBJECT(ih->handle), "select", G_CALLBACK(gtkItemSelect), ih);

  iupUpdateFontAttrib(ih);

  return IUP_NOERROR;
}

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

static int gtkSeparatorMapMethod(Ihandle* ih)
{
  int pos;

  if (!ih->parent)
    return IUP_ERROR;

  ih->handle = gtk_separator_menu_item_new();
  if (!ih->handle)
    return IUP_ERROR;

  ih->serial = iupMenuGetChildId(ih);

  pos = IupGetChildPos(ih->parent, ih);
  gtk_menu_shell_insert((GtkMenuShell*)ih->parent->handle, ih->handle, pos);
  gtk_widget_show(ih->handle);

  return IUP_NOERROR;
}

void iupdrvSeparatorInitClass(Iclass* ic)
{
  /* Driver Dependent Class functions */
  ic->Map = gtkSeparatorMapMethod;
  ic->UnMap = iupdrvBaseUnMapMethod;
}

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

static void gtkRecentItemActivate(GtkWidget *widget, Ihandle* menu)
{
  int index = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "_IUP_RECENT_INDEX"));
  Icallback recent_cb = (Icallback)iupAttribGet(menu, "_IUP_RECENT_CB");
  Ihandle* config = (Ihandle*)iupAttribGet(menu, "_IUP_CONFIG");

  if (recent_cb && config)
  {
    char attr_name[32];
    const char* filename;

    sprintf(attr_name, "_IUP_RECENT_FILE%d", index);
    filename = iupAttribGet(menu, attr_name);

    if (filename)
    {
      IupSetStrAttribute(config, "RECENTFILENAME", filename);
      IupSetStrAttribute(config, "TITLE", filename);
      config->parent = menu;

      recent_cb(config);

      config->parent = NULL;
      IupSetAttribute(config, "RECENTFILENAME", NULL);
      IupSetAttribute(config, "TITLE", NULL);
    }
  }
}

int iupdrvRecentMenuInit(Ihandle* menu, int max_recent, Icallback recent_cb)
{
  iupAttribSetInt(menu, "_IUP_RECENT_MAX", max_recent);
  iupAttribSet(menu, "_IUP_RECENT_CB", (char*)recent_cb);
  iupAttribSetInt(menu, "_IUP_RECENT_COUNT", 0);
  return 0;
}

int iupdrvRecentMenuUpdate(Ihandle* menu, const char** filenames, int count, Icallback recent_cb)
{
  GtkMenuShell* gtk_menu;
  GtkWidget* empty_item;
  int max_recent, existing, i;

  if (!menu || !menu->handle)
    return -1;

  gtk_menu = (GtkMenuShell*)menu->handle;
  max_recent = iupAttribGetInt(menu, "_IUP_RECENT_MAX");
  existing = iupAttribGetInt(menu, "_IUP_RECENT_COUNT");

  if (count > max_recent)
    count = max_recent;

  iupAttribSet(menu, "_IUP_RECENT_CB", (char*)recent_cb);

  empty_item = (GtkWidget*)iupAttribGet(menu, "_IUP_RECENT_EMPTY");
  if (count > 0 && empty_item)
  {
    gtk_container_remove(GTK_CONTAINER(gtk_menu), empty_item);
    iupAttribSet(menu, "_IUP_RECENT_EMPTY", NULL);
  }

  for (i = 0; i < count; i++)
  {
    GtkWidget* item;
    char attr_name[32];

    sprintf(attr_name, "_IUP_RECENT_ITEM%d", i);
    item = (GtkWidget*)iupAttribGet(menu, attr_name);

    if (item)
    {
      GtkWidget* label = gtk_bin_get_child(GTK_BIN(item));
      if (label)
        gtk_label_set_text(GTK_LABEL(label), filenames[i]);
    }
    else
    {
      item = gtk_menu_item_new_with_label(filenames[i]);
      g_object_set_data(G_OBJECT(item), "_IUP_RECENT_INDEX", GINT_TO_POINTER(i));
      g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(gtkRecentItemActivate), menu);
      gtk_menu_shell_insert(gtk_menu, item, i);
      gtk_widget_show(item);
      iupAttribSet(menu, attr_name, (char*)item);
    }

    sprintf(attr_name, "_IUP_RECENT_FILE%d", i);
    iupAttribSetStr(menu, attr_name, filenames[i]);
  }

  for (; i < existing; i++)
  {
    char attr_name[32];
    GtkWidget* item;

    sprintf(attr_name, "_IUP_RECENT_ITEM%d", i);
    item = (GtkWidget*)iupAttribGet(menu, attr_name);
    if (item)
    {
      gtk_container_remove(GTK_CONTAINER(gtk_menu), item);
      iupAttribSet(menu, attr_name, NULL);
    }

    sprintf(attr_name, "_IUP_RECENT_FILE%d", i);
    iupAttribSet(menu, attr_name, NULL);
  }

  if (count == 0 && !iupAttribGet(menu, "_IUP_RECENT_EMPTY"))
  {
    empty_item = gtk_menu_item_new_with_label("");
    gtk_widget_set_sensitive(empty_item, FALSE);
    gtk_menu_shell_append(gtk_menu, empty_item);
    gtk_widget_show(empty_item);
    iupAttribSet(menu, "_IUP_RECENT_EMPTY", (char*)empty_item);
  }

  iupAttribSetInt(menu, "_IUP_RECENT_COUNT", count);
  return 0;
}

void iupdrvSubmenuInitClass(Iclass* ic)
{
  /* Driver Dependent Class functions */
  ic->Map = gtkSubmenuMapMethod;
  ic->UnMap = iupdrvBaseUnMapMethod;

  /* Common */
  iupClassRegisterAttribute(ic, "FONT", NULL, iupdrvSetFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED);  /* inherited */

  /* Visual */
  iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT);
  iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT);

  /* IupSubmenu only */
  iupClassRegisterAttribute(ic, "TITLE", NULL, gtkItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
  iupClassRegisterAttribute(ic, "IMAGE", NULL, gtkSubmenuSetImageAttrib, NULL, NULL, IUPAF_IHANDLENAME|IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT);
}
