/********************************************************************************************
    Clean OS Windows library module version 1.2.1.
    This module is part of the Clean Object I/O library, version 1.2.1,
    for the Windows platform.
********************************************************************************************/

/********************************************************************************************
    About this module:
    Routines related to menu handling.
********************************************************************************************/
#include "cCrossCallMenus_121.h"
#include "cCrossCall_121.h"
#include "util_121.h"


/*	Cross call procedure implementations.
    Eval<nr> corresponds with a CrossCallEntry generated by NewCrossCallEntry (nr,Eval<nr>).
*/
/*	Remove a shortkey from a framewindow shortkey table. */

static gboolean dummy_find_accel(GtkAccelKey *key, GClosure *closure, gpointer data)
{
        printf("dummy_find_accel\n");
    return gtk_true();
}

void EvalCcRqREMOVEMENUSHORTKEY (CrossCallInfo *pcci)	/* frameptr, cmd; no result. */
{
    GtkWidget *frame;
    GtkWidget *box;
    GtkWidget *menu_item;
    GtkAccelGroup *accel_group;

    printf("EvalCcRqREMOVEMENUSHORTKEY\n");
    frame = GTK_WIDGET(pcci->p1);
    menu_item = GTK_WIDGET(pcci->p2);

    accel_group = ((GtkAccelGroup*)gtk_accel_groups_from_object(G_OBJECT(frame))->data);

    for (;;)
    {
        GtkAccelKey *key = gtk_accel_group_find(accel_group, dummy_find_accel, NULL);
        if (!key) break;

        gtk_widget_remove_accelerator(menu_item,
                                      accel_group,
                                      key->accel_key,
                                      key->accel_mods);
    }

    MakeReturn0Cci (pcci);
}

void EvalCcRqMODIFYMENUITEM (CrossCallInfo *pcci)	/* hitem, hmenu, textptr; no result.	*/
{
    GtkWidget *menu, *menu_item, *label;
    gchar *title;

    printf("EvalCcRqMODIFYMENUITEM\n");
    title = createMnemonicString((gchar *) pcci->p3);

    menu = GTK_WIDGET(pcci->p2);
    menu_item = GTK_WIDGET(pcci->p1);
    label = gtk_bin_get_child(GTK_BIN(menu_item));
    gtk_label_set_text_with_mnemonic(GTK_LABEL(label), title);

    rfree(title);

    MakeReturn0Cci (pcci);
}

static int in_handler_flag = 0;

static void menuitem_activate_handler(GtkMenuItem *menu_item)
{
    printf("menuitem_activate_handler\n");
    if (in_handler_flag == 0)
    {
        in_handler_flag = 1;
        if (GTK_IS_CHECK_MENU_ITEM(menu_item))
            gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item), !(GTK_CHECK_MENU_ITEM(menu_item)->active));
        GdkEvent* event = gtk_get_current_event();
        if (!event || event->key.type != GDK_KEY_RELEASE) // We only look for key presses, otherwise every shortcut fires twice
            SendMessage2ToClean (CcWmCOMMAND, GTK_WIDGET(menu_item), GetModifiers ());
        in_handler_flag = 0;
    }
}

void EvalCcRqINSERTMENUITEM (CrossCallInfo *pcci)
{
    gchar *title;
    GtkWidget *menu, *menu_item, *label;
    GtkAccelGroup *accel_group;
    guint graystate, checkstate;

    printf("EvalCcRqINSERTMENUITEM\n");
    printf("Inserting item with position %d and name %s\n", pcci->p5, (char*)pcci->p3);

    printf("Checking graystate: ");
    if (pcci->p1)
    {
            graystate = 1; // MF_ENABLED
    } else {
            graystate = 0; // MF_GRAYED;
    }
    printf("%s\n", (graystate ? "enabled" : "grayed"));

    printf("Checking checkstate: ");
    if (pcci->p4)
    {
            checkstate = 1; // MF_CHECKED
    } else {
            checkstate = 0; // MF_UNCHECKED
    }
    printf("%s\n", (checkstate ? "checked" : "unchecked"));

    printf("Calling Make Mnemonic string with: %s\n", (gchar*)pcci->p3);
    title = createMnemonicString((gchar *) pcci->p3);
    printf("Got title: %s\n", title);

    menu = GTK_WIDGET(pcci->p2);

    printf("Creating new menu item\n");
    menu_item = gtk_menu_item_new_with_mnemonic(title);
    gtk_menu_shell_insert( GTK_MENU_SHELL (menu), menu_item, (gint) pcci->p5);

    gtk_signal_connect_object (GTK_OBJECT (menu_item), "activate",
        GTK_SIGNAL_FUNC (menuitem_activate_handler), menu_item);

    gtk_widget_show(menu_item);

    printf("About to free title: %s\n", title);
    rfree(title);
    printf("Freed title\n");

    printf("Creating return Cci\n");
    MakeReturn1Cci (pcci, (int64_t) menu_item);
}

/*  Cross call procedure implementations.
    Eval<nr> corresponds with a CrossCallEntry generated by NewCrossCallEntry (nr,Eval<nr>).
*/ 

/*  Add a shortkey to a framewindow shortkey table. */
void EvalCcRqADDMENUSHORTKEY (CrossCallInfo *pcci)  /* frameptr, cmd, key; no result. */
{
    GtkAccelGroup* accel_group;
    GObject* frame;
    GtkWidget* menu_item;
    guint key;

    printf("EvalCcRqADDMENUSHORTKEY\n");

    frame = G_OBJECT(pcci->p1);
    menu_item = GTK_WIDGET(pcci->p2);
    key = (guint) pcci->p3;

    printf("Creating accellerators\n");
    accel_group = (GtkAccelGroup*) gtk_accel_groups_from_object(frame)->data;

    printf("Accel groups: %p, %p\n", accel_group, gtk_accel_groups_from_object(frame)->next);

    gtk_widget_activate(menu_item);
    gtk_widget_add_accelerator(menu_item, "activate",
                               accel_group,
                               key,
                               GDK_CONTROL_MASK,
                               GTK_ACCEL_VISIBLE);

    MakeReturn0Cci (pcci);
}

static void find_item_callback(GtkWidget *menu_item, gpointer data)
{
    printf("find_item_callback\n");
    if (GTK_IS_MENU_ITEM(menu_item) && GTK_MENU_ITEM (menu_item)->submenu == ((GtkWidget *) data))
        *((GtkWidget **) data) = menu_item;
}

void EvalCcRqITEMENABLE (CrossCallInfo *pcci)	/* parent, HITEM, onoff; no result.  */
{
    GtkWidget *menu, *menu_item;
    printf("EvalCcRqITEMENABLE\n");
    
    menu      = GTK_WIDGET(pcci->p1);
    menu_item = GTK_WIDGET(pcci->p2);

    printf("Menu widget: %s\n", gtk_menu_get_title(GTK_MENU(menu)));
        printf("EvalCcRqITEMENABLE\n");
    gtk_widget_set_sensitive(menu_item, (gboolean) pcci->p3);

    MakeReturn0Cci (pcci);
}

/*  Destroy a menu 'physically' */
void EvalCcRqDESTROYMENU (CrossCallInfo *pcci)          /* HMENU; no result. */
{
    printf("EvalCcRqDESTROYMENU\n");

    /*
     * This is handled behind-the-scenes by GTK
     */
    MakeReturn0Cci (pcci);
}

/*	Remove a menu logically */
void EvalCcRqDELETEMENU (CrossCallInfo *pcci)			/* HMENU, HITEM; no result. */
{
    GtkWidget *menu, *menu_item;
    printf("EvalCcRqDELETEMENU\n");

    menu = GTK_WIDGET(pcci->p1);
    menu_item = GTK_WIDGET(pcci->p2);

    gtk_container_foreach(GTK_CONTAINER(menu), find_item_callback, (gpointer) &menu_item);
    if (menu_item != GTK_WIDGET(pcci->p2))
    {
        gtk_menu_item_remove_submenu(GTK_MENU_ITEM(menu_item));
        gtk_widget_destroy(menu_item);
    }

    MakeReturn0Cci (pcci);
}

void EvalCcRqREMOVEMENUITEM (CrossCallInfo *pcci)		/* menu, HITEM; no result. */
{
    GtkWidget *menu, *menu_item;
    printf("EvalCcRqREMOVEMENUITEM\n");

    menu = GTK_WIDGET(pcci->p1);
    menu_item = GTK_WIDGET(pcci->p2);

    gtk_menu_item_remove_submenu(GTK_MENU_ITEM(menu_item));
    gtk_widget_destroy(menu_item);

    MakeReturn0Cci (pcci);
}

void EvalCcRqINSERTSEPARATOR (CrossCallInfo *pcci)		/* hmenu, pos no result. */
{
    GtkWidget *menu, *menu_item;
    printf("EvalCcRqINSERTSEPARATOR\n");

    menu = GTK_WIDGET(pcci->p1);
    menu_item = gtk_menu_item_new();

    gtk_menu_insert(GTK_MENU(menu), menu_item, (gint) pcci->p2);
    gtk_widget_show_all(menu_item);

    MakeReturn1Cci (pcci, (int64_t) menu_item);
}

void EvalCcRqMODIFYMENU (CrossCallInfo *pcci)	/* hitem, hmenu, textptr; no result.	*/
{
    gint i;
    GtkWidget *menu, *menu_item, *label;
    gchar *title;

    printf("EvalCcRqMODIFYMENU\n");
    title = createMnemonicString((gchar *) pcci->p3);

    menu = GTK_WIDGET(pcci->p2);
    menu_item = GTK_WIDGET(pcci->p1);
    label = gtk_bin_get_child(GTK_BIN(menu_item));
    gtk_label_set_text_with_mnemonic(GTK_LABEL(label), title);

    rfree(title);

    MakeReturn0Cci (pcci);
}

/*	Insert a menu into the menu bar. */
void EvalCcRqINSERTMENU (CrossCallInfo *pcci)
{
    gint i;
    gchar *title;
    GtkWidget *parent_menu, *root_menu, *sub_menu;
    GtkAccelGroup *accel_group;
    printf("EvalCcRqINSERTMENU\n");

    title = createMnemonicString((gchar *) pcci->p3);
    parent_menu = GTK_WIDGET(pcci->p2);
    sub_menu = GTK_WIDGET(pcci->p4);

    if (GTK_IS_MENU_BAR(parent_menu))
    {
        printf("Adding to a menu bar.\n");
        GtkWidget *frame = gtk_widget_get_parent(gtk_widget_get_parent(parent_menu));
        accel_group = ((GtkAccelGroup*)gtk_accel_groups_from_object (G_OBJECT(frame))->data);
    }
    else
    {
        printf("We're not adding to a menu bar!?!\n");
        accel_group = gtk_menu_get_accel_group (GTK_MENU(parent_menu));
    }

    gtk_menu_set_accel_group (GTK_MENU(sub_menu), accel_group);

    root_menu = gtk_menu_item_new_with_mnemonic(title);
    gtk_widget_set_sensitive(root_menu, (gboolean) pcci->p1);
    gtk_widget_show_all (root_menu);

    gtk_menu_item_set_submenu (GTK_MENU_ITEM (root_menu), sub_menu);

    if (GTK_IS_MENU_BAR(parent_menu))
    {
        gtk_menu_shell_insert(GTK_MENU_SHELL(parent_menu), root_menu, (gint) pcci->p5);
    } else {
        gtk_menu_insert(GTK_MENU(parent_menu), root_menu, (gint) pcci->p5);
    }

    rfree(title);

    MakeReturn1Cci (pcci, (int64_t) sub_menu);
}

static void enable_menu_callback(GtkWidget *menu_item, gpointer data)
{
    printf("enable_menu_callback\n");
    gint *val = (gint*) data;
    printf("Checking: %d\n", *val);
    if (GTK_IS_MENU_ITEM(menu_item)
                    && (*val == 0))
    {
        gtk_widget_set_sensitive(menu_item, gtk_true());
    }
    else
    {
        *val = *val - 1;
    }
}

static void disable_menu_callback(GtkWidget *menu_item, gpointer data)
{
    printf("disable_menu_callback\n");
    gint *val = (gint*) data;
    
    printf("Checking: %d\n", *val);
    if (GTK_IS_MENU_ITEM(menu_item)
                    && (*val == 0))
    {
        gtk_widget_set_sensitive(menu_item, gtk_false());
    }
    else
    {
        *val = *val - 1;
    }
}

void EvalCcRqMENUENABLE (CrossCallInfo *pcci)	/* parent, zero based position of menu, onoff; no result. */
{
    GtkWidget *parent_menu, *sub_menu;
    printf("EvalCcRqMENUENABLE\n");
    gint index = pcci->p2;

    if (pcci->p1 && GTK_IS_CONTAINER(pcci->p1))
    {
        printf("We have a container. Checking the widget.\n");
        parent_menu = GTK_WIDGET(pcci->p1);
        gtk_container_foreach(GTK_CONTAINER(parent_menu), pcci->p3 ?
                        enable_menu_callback : disable_menu_callback,
                        (gpointer) (&index));
    }

    MakeReturn0Cci (pcci);
}

void EvalCcRqDRAWMBAR (CrossCallInfo *pcci)		/* framePtr, clientPtr; no result. */
{
    printf("EvalCcRqDRAWMBAR\n");
    MakeReturn0Cci (pcci);
}

/*	Track pop up menu. */
void EvalCcRqTRACKPOPMENU (CrossCallInfo *pcci)	/* popupmenu,framePtr; BOOL result. */
{
    printf("EvalCcRqTRACKPOPMENU\n");
    if (GTK_IS_MENU(pcci->p1))
    {
        GtkWidget *popup_menu = GTK_WIDGET(pcci->p1);
        GtkWidget *frame = GTK_WIDGET(pcci->p2);

        GdkEvent *event = gtk_get_current_event();
        gtk_menu_popup(GTK_MENU(popup_menu),NULL,NULL,NULL,NULL,
                        (event->type == GDK_BUTTON_PRESS) ?
                        ((GdkEventButton *) event)->button : 0,
                        gdk_event_get_time(event));
    }

    MakeReturn1Cci (pcci,(int64_t)gtk_true());
}

void EvalCcRqCREATEPOPMENU (CrossCallInfo *pcci) /* no params; MENU result.   */
{
    /*
     * Establish a new meta-menu that will be used to hold the individual
     * menu entries later.
     *
     * This menu should be added to a menu bar.
     */
    printf("EvalCcRqCREATEPOPMENU\n");
    MakeReturn1Cci (pcci, (int64_t) gtk_menu_new());
}

void EvalCcRqCHECKMENUITEM (CrossCallInfo *pcci) /* menu, HITEM, on/off; no result.	*/
{
    printf("EvalCcRqCHECKMENUITEM\n");
    if (GTK_IS_MENU(pcci->p1))
    {
        GtkWidget *menu = GTK_WIDGET(pcci->p1);
        GtkWidget *menu_item = GTK_WIDGET(pcci->p2);

        if (GTK_IS_CHECK_MENU_ITEM(menu_item))
            gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menu_item),
                            (gboolean) pcci->p3);
    }

    MakeReturn0Cci (pcci);
}


/*	Install the cross call procedures in the gCrossCallProcedureTable of cCrossCall_121.
*/
OS InstallCrossCallMenus (OS ios)
{
    CrossCallProcedureTable newTable;

    printf("InstallCrossCallMenus\n");
    newTable = EmptyCrossCallProcedureTable ();
    AddCrossCallEntry (newTable, CcRqADDMENUSHORTKEY, EvalCcRqADDMENUSHORTKEY);
    AddCrossCallEntry (newTable, CcRqREMOVEMENUSHORTKEY, EvalCcRqREMOVEMENUSHORTKEY);
    AddCrossCallEntry (newTable, CcRqMODIFYMENUITEM,     EvalCcRqMODIFYMENUITEM);
    AddCrossCallEntry (newTable, CcRqINSERTMENUITEM,     EvalCcRqINSERTMENUITEM);
    AddCrossCallEntry (newTable, CcRqITEMENABLE,         EvalCcRqITEMENABLE);
    AddCrossCallEntry (newTable, CcRqDELETEMENU,         EvalCcRqDELETEMENU);
    AddCrossCallEntry (newTable, CcRqDESTROYMENU,        EvalCcRqDESTROYMENU);
    AddCrossCallEntry (newTable, CcRqREMOVEMENUITEM,     EvalCcRqREMOVEMENUITEM);
    AddCrossCallEntry (newTable, CcRqINSERTSEPARATOR,    EvalCcRqINSERTSEPARATOR);
    AddCrossCallEntry (newTable, CcRqMODIFYMENU,         EvalCcRqMODIFYMENU);
    AddCrossCallEntry (newTable, CcRqINSERTMENU,         EvalCcRqINSERTMENU);
    AddCrossCallEntry (newTable, CcRqMENUENABLE,         EvalCcRqMENUENABLE);
    AddCrossCallEntry (newTable, CcRqDRAWMBAR,           EvalCcRqDRAWMBAR);
    AddCrossCallEntry (newTable, CcRqTRACKPOPMENU,       EvalCcRqTRACKPOPMENU);
    AddCrossCallEntry (newTable, CcRqCREATEPOPMENU,      EvalCcRqCREATEPOPMENU);
    AddCrossCallEntry (newTable, CcRqCHECKMENUITEM,      EvalCcRqCHECKMENUITEM);
    AddCrossCallEntries (gCrossCallProcedureTable, newTable);

    return ios;
}