/*
This source file is part of Scol
For the latest info, see http://www.scolring.org

Copyright (c) 2010 Stephane Bisaro, aka Iri <iri@irizone.net>

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt

For others informations, please contact us from http://www.scolring.org/
*/



#include "../include/scol_gtk_text.h"




/* ****************************************************************************
 *                                                                            *
 *  Miscelleanous                                                             *
 *                                                                            *
** ***************************************************************************/


/**
 * \brief _gtkTextLipsum : returns a "LOREM IPSUM" string for a given length
 * fun [I] S
 *
 * \param I : the length or nil for entire text
 * \return S : the LOREM IPSUM
 */
int SCOL_gtkTextLipsum (mmachine m)
{
    int mlen;
    int len;
    char *string;

    g_message ("SCOL_gtkTextLipsum : entering");

    mlen = MTOI (MMpull (m));

    if ((mlen == NIL) || (mlen <= 0))
        len = LIPSUM_SIZE;
    else
        len = mlen;

    string = (char *) g_malloc (sizeof (char) * (len + 1));

    if (len <= LIPSUM_SIZE)
    {
        strncpy (string, LIPSUM, len);
        string[len] = '\0';
        Mpushstrbloc (m, string);
        g_free (string);
        return 0;
    }
    while (len > 0)
    {
        if (len >= LIPSUM_SIZE)
        {
            strncat (string, LIPSUM, LIPSUM_SIZE);
            len -= LIPSUM_SIZE;
        }
        else
        {
            strncat (string, LIPSUM, len);
            len = 0;
        }
    }
    string[len] = '\0';
    Mpushstrbloc (m, string);
    g_free (string);
    return 0;
}








/* ****************************************************************************
 *                                                                            *
 *  TEXT VIEW -> GtkTextView                                                  *
 *                                                                            *
** ***************************************************************************/



/**
 * \brief _gtkTextNew : Create a new text object (->GtkTextView)
 *
 * fun [Chn ObjGtkWidget S] ObjGtkWidget
 *
 * \param S : string to insert (can be nil)
 * \param ObjGtkWidget : buffer object. Can be nil.
 * \param Chn : a channel
 * \return [ObjGtkWidget ObjGtkWidget] : a tuple : the new text object, the buffer text object (the same is the 2nd arg was not nil)
 */
int SCOL_gtkTextNew (mmachine m)
{
    int mchannel, mbuffer, mcontent;
    GtkWidget *buffer = NULL, *text = NULL;
    gchar *content = "";

    g_message ("SCOL_gtkTextNew : entering");

    mcontent = MMpull (m);
    mbuffer = MMpull (m);
    mchannel = MMget (m, 0);

    if (mchannel == NIL)
    {
        g_warning ("SCOL_gtkTextNew error : channel is nil");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }

    if (mbuffer != NIL)
        buffer = (GtkWidget*) MMfetch (m, MTOP (mbuffer), OBJ2DGTK_WIDGET_HANDLE);
    if (mcontent != NIL)
        content = SCOLUTF8 (MMstartstr (m, MTOP (mcontent)));

    text = gtk_text_view_new_with_buffer (GTK_TEXT_BUFFER (buffer));
    if (text == NULL)
    {
        MMpush (m, NIL);
        g_warning ("SCOL_gtkTextNew error : object not created");
        return 0;
    }
    if (mbuffer == NIL)
        buffer = (GtkWidget *) gtk_text_view_get_buffer (GTK_TEXT_VIEW (text));
    gtk_text_buffer_set_text (GTK_TEXT_BUFFER (buffer), content, -1);

    SCOL_gtk_memory_createObjectTAB (m, text, ObjGtkWidgetType, OBJ2DGTK_WIDGET_HANDLE);
    /*if (mbuffer == NIL)
    {
        MMpush (m, MMgetglobal (m, OFFSCCUR));
        SCOL_gtk_memory_createObjectTAB (m, buffer, ObjGtkWidgetType, OBJ2DGTK_WIDGET_HANDLE);
    }
    else
        MMpush (m, mbuffer);
    MMpush (m, ITOM (2));
    MBdeftab (m);*/
    return 0;
}

/**
 * \brief _gtkTextGetBuffer : Return the current buffer
 * fun [ObjGtkWidget] ObjGtkWidget
 *
 * \param ObjGtkWidget : any text object
 * \return ObjGtkWidget : the buffer object
 */
int SCOL_gtkTextGetBuffer (mmachine m)
{
    int mtext;
    int exist;
    GtkWidget *text, *buffer;

    g_message ("SCOL_gtkTextGetBuffer : entering");

    mtext = MMpull (m);
    if (mtext == NIL)
    {
        g_warning ("SCOL_gtkTextGetBuffer error : object is nil");
        MMpush (m, NIL);
        return 0;
    }
    text = (GtkWidget*) MMfetch (m, MTOP (mtext), OBJ2DGTK_WIDGET_HANDLE);
    buffer = (GtkWidget *) gtk_text_view_get_buffer (GTK_TEXT_VIEW (text));

    exist = OBJfindTH (m, ObjGtkWidgetType, (int) buffer);
    if (exist == -1)    /* buffer not already created because not found in the current machine. So we create it ! */
    {
        MMpush (m, MMgetglobal (m, OFFSCCUR));  /*  set the current channel */
        return SCOL_gtk_memory_createObjectTAB (m, buffer, ObjGtkWidgetType, OBJ2DGTK_WIDGET_HANDLE);
    }

    MMpush (m, MMfetch (m, exist, OFFOBJMAG));
    return 0;
}

/**
 * \brief _gtkTextSetBuffer : Sets a text buffer object as the buffer being displayed by a text object
 *
 * fun [ObjGtkWidget ObjGtkWidget] ObjGtkWidget
 *
 * \param ObjGtkWidget : a text object
 * \param ObjGtkWidget : a buffer text object
 * \return ObjGtkWidget : the same text object or nil if error
 */
int SCOL_gtkTextSetBuffer (mmachine m)
{
    int mtext, mbuffer;
    GtkWidget *text, *buffer;

    mbuffer = MMpull (m);
    mtext = MMpull (m);

    g_message ("SCOL_gtkTextSetBuffer : entering");

    if ((mtext == NIL) || (mbuffer == NIL))
    {
        g_warning ("SCOL_gtkTextSetBuffer error : argument is nil");
        MMpush (m, NIL);
        return 0;
    }
    text = (GtkWidget*) MMfetch (m, MTOP (mtext), OBJ2DGTK_WIDGET_HANDLE);
    buffer = (GtkWidget*) MMfetch (m, MTOP (mbuffer), OBJ2DGTK_WIDGET_HANDLE);
    gtk_text_view_set_buffer (GTK_TEXT_VIEW (text), GTK_TEXT_BUFFER (buffer));
    MMpush (m, mtext);
    return 0;
}

/**
 * \brief _gtkTextGetEditable : return if a text object is editable or not
 * fun [ObjGtkWidget] I
 * \param ObjGtkWidget : any text object
 * \return I : 1 if editable, else 0
 */
int SCOL_gtkTextGetEditable (mmachine m)
{
    int mtext;
    GtkWidget *text;

    g_message ("SCOL_gtkTextGetEditable : entering");

    mtext = MMpull (m);
    if (mtext == NIL)
    {
        g_warning ("SCOL_gtkTextGetEditable error : text object is nil");
        MMpush (m, NIL);
        return 0;
    }
    text = (GtkWidget*) MMfetch (m, MTOP (mtext), OBJ2DGTK_WIDGET_HANDLE);
    MMpush (m, ITOM (gtk_text_view_get_editable (GTK_TEXT_VIEW (text))));
    return 0;
}

/**
 * \brief _gtkTextSetEditable : return if a text object is editable or not
 * fun [ObjGtkWidget] I
 * \param ObjGtkWidget : any text object
 * \return I : 1 if editable, else 0
 */
int SCOL_gtkTextSetEditable (mmachine m)
{
    int mtext, mvalue;
    gboolean value = TRUE;
    GtkWidget *text;

    g_message ("SCOL_gtkTextSetEditable : entering");

    mvalue = MTOI (MMpull (m));
    mtext = MMpull (m);
    if (mtext == NIL)
    {
        g_warning ("SCOL_gtkTextSetEditable error : text object is nil");
        MMpush (m, NIL);
        return 0;
    }
    text = (GtkWidget*) MMfetch (m, MTOP (mtext), OBJ2DGTK_WIDGET_HANDLE);
    if (mvalue == 0)
        value = FALSE;
    gtk_text_view_set_editable (GTK_TEXT_VIEW (text), value);
    MMpush (m, mtext);
    return 0;
}

/**
 * \brief _gtkTextInsertWidget : insert a widget in a text object
 *
 * fun [ObjGtklWidget ObjGtklWidget I] ObjGtklWidget
 *
 * \param ObjGtklWidget : a text object
 * \param ObjGtklWidget : a widget
 * \param I : a position
 * \return ObjGtklWidget : the same text object or nil if error
 */
int SCOL_gtkTextInsertWidget (mmachine m)
{
    int mtext, mwidget, mpos;
    GtkWidget *text, *buffer, *widget;
    GtkTextIter pos;
    GtkTextChildAnchor *anchor;

    g_message ("SCOL_gtkTextInsertWidget : entering");

    mpos = MMpull (m);
    mwidget = MMpull (m);
    mtext = MMpull (m);
    if ((mtext == NIL) || (mwidget == NIL))
    {
        g_warning ("SCOL_gtkTextInsertWidget error : argument is nil");
        MMpush (m, NIL);
        return 0;
    }
    text = (GtkWidget*) MMfetch (m, MTOP (mtext), OBJ2DGTK_WIDGET_HANDLE);
    buffer = (GtkWidget*) gtk_text_view_get_buffer (GTK_TEXT_VIEW (text));
    widget = (GtkWidget*) MMfetch (m, MTOP (mwidget), OBJ2DGTK_WIDGET_HANDLE);
    if (mpos == NIL)
        mpos = 0;
    else if (MTOI (mpos) < 0)
        mpos = gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)) + MTOI (mpos);
    else
        mpos = MTOI (mpos);
    gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (buffer), &pos, mpos);

    anchor = gtk_text_buffer_create_child_anchor (GTK_TEXT_BUFFER (buffer), &pos);
    gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (text), widget, anchor);

    MMpush (m, mtext);
    return 0;
}

/**
 * \brief _gtkTextScroll : Scrolls text so that position is on the screen in the position indicated by xalign and yalign.
 *
 * fun [ObjGtkWidget I I I] I
 *
 * \param ObjGtkWidget : a valid text object
 * \param I : a position into the text
 * \param I : x alignment : 0 indicates the left, 100 indicates the right
 * \param I : y alignment : 0 indicates the top, 100 indicates the bottom
 * \return I : 1 if scroll is ok, else 0. If error, returns nil.
 */
int SCOL_gtkTextScroll (mmachine m)
{
    int mtext, mpos, malignx, maligny;
    GtkWidget *text, *buffer;
    GtkTextIter iter;
    gboolean b;
    gdouble alignx = 0.0, aligny = 0.0;

    g_message ("SCOL_gtkTextScroll : entering");

    maligny = MTOI (MMpull (m));
    malignx = MTOI (MMpull (m));
    mpos = MTOI (MMpull (m));
    mtext = MMpull (m);

    if (mtext == NIL)
    {
        g_warning ("SCOL_gtkTextScroll error : argument is nil");
        MMpush (m, NIL);
        return 0;
    }
    text = (GtkWidget*) MMfetch (m, MTOP (mtext), OBJ2DGTK_WIDGET_HANDLE);
    buffer = (GtkWidget*) gtk_text_view_get_buffer (GTK_TEXT_VIEW (text));
    if (malignx > 100)
        alignx = 1.0;
    else if (malignx > 0)
        alignx = malignx / 100.0;
    if (maligny > 100)
        aligny = 1.0;
    else if (maligny > 0)
        aligny = maligny / 100.0;
    if (mpos == NIL)
        mpos = 0;
    else if (mpos < 0)
        mpos = gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)) + mpos;
    gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (buffer), &iter, mpos);

    b = gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (text), &iter, 0.0, TRUE, alignx, aligny);
    MMpush (m, ITOM (b));
    return 0;
}

/**
 * \brief _gtkTextSetBorderSize : set the width / heigth around the text in a text object
 *
 * fun [ObjGtkWidget [I I I I]] ObjGtkWidget
 *
 * \param ObjGtkWidget : a text object
 * \param [I I I I] : the size of (respectively) LEFT, TOP, RIGHT, BOTTOM
 * \return ObjGtkWidget : the same object or nil if error
 */
int SCOL_gtkTextSetBorderSize (mmachine m)
{
    int mtext, msizes;
    int size, i;
    GtkWidget *text;
    int tab[4] = {GTK_TEXT_WINDOW_LEFT, GTK_TEXT_WINDOW_TOP, GTK_TEXT_WINDOW_RIGHT, GTK_TEXT_WINDOW_BOTTOM};

    g_message ("SCOL_gtkTextSetBorderSize : entering");

    msizes = MMpull (m);
    mtext = MMpull (m);
    if (mtext == NIL)
    {
        g_warning ("SCOL_gtkTextSetBorderSize error : argument is nil");
        MMpush (m, NIL);
        return 0;
    }
    text = (GtkWidget*) MMfetch (m, MTOP (mtext), OBJ2DGTK_WIDGET_HANDLE);

    if (msizes == NIL)
    {
        for (i = 0; i < 4; i++)
            gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (text), tab[i], 0);
    }
    else
    {
        for (i = 0; i < 4; i++)
        {
            size = MTOI (MMfetch (m, msizes>>1, i));
            if (size == NIL)
                gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (text), tab[i], 0);
            else
                gtk_text_view_set_border_window_size (GTK_TEXT_VIEW (text), tab[i], size);
        }
    }
    MMpush (m, mtext);
    return 0;
}

/**
 * \brief _gtkTextSetWrap : set the wrap mode
 * fun [ObjGtkWidget I] ObjGtkWidget
 * \param ObjGtkWidget : a text object
 * \param I : a flag : SCOL_GTK_TEXT_WRAP_NONE, SCOL_GTK_TEXT_WRAP_CHAR, SCOL_GTK_TEXT_WRAP_WORD, SCOL_GTK_TEXT_WRAP_WORD_CHAR
 * \return ObjGtkWidget : the same objector nil if error
 */
int SCOL_gtkTextSetWrap (mmachine m)
{
    int mtext, mflag;
    GtkWrapMode mode;
    GtkWidget *text;

    g_message ("SCOL_gtkTextSetWrap : entering");

    mflag = MTOI (MMpull (m));
    mtext = MMpull (m);
    if (mtext == NIL)
    {
        g_warning ("SCOL_gtkTextSetWrap error : argument is nil");
        MMpush (m, NIL);
        return 0;
    }
    text = (GtkWidget*) MMfetch (m, MTOP (mtext), OBJ2DGTK_WIDGET_HANDLE);
    switch (mflag)
    {
        case (WRAP_CHAR) :
            mode = GTK_WRAP_CHAR;
            break;
        case (WRAP_WORD) :
            mode = GTK_WRAP_WORD;
            break;
        case (WRAP_WORD_CHAR) :
            mode = GTK_WRAP_WORD_CHAR;
            break;
        case (GTK_WRAP_NONE):
        default :
            mode = GTK_WRAP_NONE;
    }
    gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text), mode);
    MMpush (m, mtext);
    return 0;
}

/**
 * \brief _gtkTextGetWrap : returns the wrap mode
 *
 * fun [ObjGtkWidget] I
 *
 * \param ObjGtkWidget : any valid text object
 * \return I : the current mode or nil if error
 */
int SCOL_gtkTextGetWrap (mmachine m)
{
    int mtext;
    GtkWrapMode mode;
    GtkWidget *text;

    g_message ("SCOL_gtkTextGetWrap : entering");

    mtext = MMpull (m);
    if (mtext == NIL)
    {
        g_warning ("SCOL_gtkTextGetWrap error : argument is nil");
        MMpush (m, NIL);
        return 0;
    }
    text = (GtkWidget*) MMfetch (m, MTOP (mtext), OBJ2DGTK_WIDGET_HANDLE);
    mode = gtk_text_view_get_wrap_mode (GTK_TEXT_VIEW (text));
    switch (mode)
    {
        case (GTK_WRAP_CHAR):
            MMpush (m, ITOM (WRAP_CHAR));
            break;
        case (GTK_WRAP_WORD):
            MMpush (m, ITOM (WRAP_WORD));
            break;
        case (GTK_WRAP_WORD_CHAR):
            MMpush (m, ITOM (WRAP_WORD_CHAR));
            break;
        case (GTK_WRAP_NONE):
        default :
            MMpush (m, ITOM (WRAP_NONE));
    }
    return 0;
}

/**
 * \brief _gtkTextShowCursor : sets whether the text cursor is shown or not
 * fun [ObjGtkWidget I] ObjGtkWidget
 * \param ObjGtkWidget : a text object
 * \param I : 1, show; 0, hide
 * \return ObjGtkWidget : the same object or nil if error
 */
int SCOL_gtkTextShowCursor (mmachine m)
{
    int mtext, mflag;
    gboolean b = FALSE;
    GtkWidget *text;

    g_message ("SCOL_gtkTextShowCursor : entering");

    mflag = MTOI (MMpull (m));
    mtext = MMpull (m);
    if (mtext == NIL)
    {
        g_warning ("SCOL_gtkTextShowCursor error : argument is nil");
        MMpush (m, NIL);
        return 0;
    }
    text = (GtkWidget*) MMfetch (m, MTOP (mtext), OBJ2DGTK_WIDGET_HANDLE);
    if (mflag)
        b = TRUE;
    gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (text), b);
    MMpush (m, mtext);
    return 0;
}

/**
 * \brief _gtkTextSetOverwrite : sets the overwrite mode.
 * fun [ObjGtkWidget I] ObjGtkWidget
 * \param ObjGtkWidget : a text object
 * \param I : a falg : 1 to turn on (= inserted mode), 0 to turn off
 * \return ObjGtkWidget : the same object or nil if error
 */
int SCOL_gtkTextSetOverwrite (mmachine m)
{
    int mtext, mflag;
    gboolean b = FALSE;
    GtkWidget *text;

    g_message ("SCOL_gtkTextSetOverwrite : entering");

    mflag = MTOI (MMpull (m));
    mtext = MMpull (m);
    if (mtext == NIL)
    {
        g_warning ("SCOL_gtkTextSetOverwrite error : argument is nil");
        MMpush (m, NIL);
        return 0;
    }
    text = (GtkWidget*) MMfetch (m, MTOP (mtext), OBJ2DGTK_WIDGET_HANDLE);
    if (mflag)
        b = TRUE;
    gtk_text_view_set_overwrite (GTK_TEXT_VIEW (text), b);
    MMpush (m, mtext);
    return 0;
}






/* ****************************************************************************
 *                                                                            *
 *  TEXT BUFFER -> GtkTextBuffer                                              *
 *                                                                            *
** ***************************************************************************/



/**
 * \brief _gtkTextBufferNew : Create a new text buffer object
 * fun [Chn ObjGtkWidget] ObjGtkWidget
 * \param Chn : a channel
 * \param ObjGtkWidget : a tags table, or nil (so, create a default tags table)
 * \return ObjGtkWidget : the new buffer object or nil if error
 */
int SCOL_gtkTextBufferNew (mmachine m)
{
    int mchannel, mtabletag;
    GtkWidget *buffer, *tabletag = NULL;

    g_message ("SCOL_gtkTextBufferNew : entering");

    mtabletag = MMpull (m);
    mchannel = MMget (m, 0);
    if (mchannel == NIL)
    {
        g_warning ("SCOL_gtkTextBufferNew error : channel is nil");
        MMpull (m);
        MMpush (m, NIL);
        return 0;
    }
    if (mtabletag != NIL)
        tabletag = (GtkWidget*) MMfetch (m, MTOP (mtabletag), OBJ2DGTK_WIDGET_HANDLE);

    buffer = (GtkWidget *) gtk_text_buffer_new (GTK_TEXT_TAG_TABLE (tabletag));
    gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (buffer), FALSE);
    return SCOL_gtk_memory_createObjectTAB (m, buffer, ObjGtkWidgetType, OBJ2DGTK_WIDGET_HANDLE);
}

/**
 * \brief _gtkTextBufferInsert insert a string in a text buffer
 *
 * fun [ObjGtkWidget S I] ObjGtkWidget
 *
 * \param ObjGtkWidget : a text buffer object already created
 * \param S : a string to insert
 * \param I : a position, where the string will be inserted
 * \return ObjGtkWidget : the same text buffer object or nil if error occurs
 */
int SCOL_gtkTextBufferInsert (mmachine m)
{
    int mbuffer, mstring, mstart;
    GtkWidget *buffer = NULL;
    GtkTextIter start;
    gchar *string;

    g_message ("SCOL_gtkTextBufferInsert : entering");

    mstart = MMpull (m);
    mstring = MMpull (m);
    mbuffer = MMpull (m);

    if ((mbuffer == NIL) || (mstring == NIL))
    {
        g_warning ("SCOL_gtkTextBufferInsert error : bad(s) argument(s)");
        MMpush (m, NIL);
        return 0;
    }

    buffer = (GtkWidget*) MMfetch (m, MTOP (mbuffer), OBJ2DGTK_WIDGET_HANDLE);
    string = SCOLUTF8 (MMstartstr (m, MTOP (mstring)));

    if (mstart == NIL)
        gtk_text_buffer_insert_at_cursor (GTK_TEXT_BUFFER (buffer), string, strlen (string));
    else
    {
        mstart = MTOI (mstart);
        if (mstart < -1)
            mstart = -1;
        gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (buffer), &start, (gint) mstart);
        gtk_text_buffer_insert (GTK_TEXT_BUFFER (buffer), &start, string, strlen (string));
    }
    g_free (string);
    MMpush (m, mbuffer);

    return 0;
}

/**
 * \brief _gtkTextBufferInsertCopy : copy a text between two positions from a buffer to another buffer
 *
 * fun [ObjGtkWidget I ObjGtkWidget I I] ObjGtkWidget
 *
 * \param ObjGtkWidget : a buffer (destination)
 * \param I : a position where the string will be inserted
 * \param ObjGtkWidget : another buffer (source)
 * \param I : a start position
 * \param I : a end position
 *\return : ObjGtkWidget : the same buffer (destination) or nil if error
 */
int SCOL_gtkTextBufferInsertCopy (mmachine m)
{
    int mbufferSrc, mbufferDest, mposStart, mposEnd, mposDest;
    GtkWidget *bufferSrc, *bufferDest;
    GtkTextIter start, end, dest;

    g_message ("SCOL_gtkTextBufferInsertCopy : entering");

    mposEnd = MMpull (m);
    mposStart = MMpull (m);
    mbufferSrc = MMpull (m);
    mposDest = MMpull (m);
    mbufferDest = MMpull (m);

    if (mbufferSrc == NIL)
    {
        g_warning ("SCOL_gtkTextBufferInsertCopy error : source buffer object is nil");
        MMpush (m, NIL);
        return 0;
    }

    bufferSrc = (GtkWidget*) MMfetch (m, MTOP (mbufferSrc), OBJ2DGTK_WIDGET_HANDLE);
    if (mposStart == NIL)
        gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (bufferSrc), &start, 0);
    else
        gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (bufferSrc), &start, (gint) MTOI (mposStart));
    if (mposEnd == NIL)
        gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (bufferSrc), &end, -1);
    else
        gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (bufferSrc), &end, (gint) MTOI (mposEnd));

    if (mbufferDest == NIL)
        bufferDest = (GtkWidget *) gtk_text_buffer_new (GTK_TEXT_TAG_TABLE (NULL));
    else
        bufferDest = (GtkWidget*) MMfetch (m, MTOP (mbufferDest), OBJ2DGTK_WIDGET_HANDLE);
    if (mposDest == NIL)
        gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (bufferDest), &dest, 0);
    else
        gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (bufferDest), &dest, (gint) MTOI (mposDest));

    gtk_text_buffer_insert_range (GTK_TEXT_BUFFER (bufferDest), &dest, &start, &end);

    if (mbufferDest == NIL)
        return SCOL_gtk_memory_createObjectTAB (m, bufferDest, ObjGtkWidgetType, OBJ2DGTK_WIDGET_HANDLE);
    return MMpush (m, mbufferDest);
}

/**
 * \brief _gtkTextBufferCount : returns the number of characters in a text buffer object
 *
 * fun [ObjGtkWidget] I
 *
 * \param ObjGtkWidget : any text buffer object
 * \return I : this number or nil if error
 */
int SCOL_gtkTextBufferCount (mmachine m)
{
    int mbuffer;
    GtkWidget *buffer;

    g_message ("SCOL_gtkTextBufferCount : entering");

    mbuffer = MMpull (m);
    if (mbuffer == NIL)
    {
        g_warning ("SCOL_gtkTextBufferCount error : object is nil");
        MMpush (m, NIL);
        return 0;
    }

    buffer = (GtkWidget*) MMfetch (m, MTOP (mbuffer), OBJ2DGTK_WIDGET_HANDLE);
    MMpush (m, ITOM (gtk_text_buffer_get_line_count (GTK_TEXT_BUFFER (buffer))));
    MMpush (m, ITOM (gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer))));
    MMpush (m, ITOM (2));
    MBdeftab (m);
    return 0;
}

/**
 * \brief _gtkTextBufferRem : removes the text between two positions in  a buffer text object
 *
 * fun [ObjGtkWidget I I] ObjGtkWidget
 *
 * \param ObjGtkWidget : any text buffer object
 * \param I : a position. If nil, the position will be at 0. If negative, it will be the position from the end
 * \param I : another position. If nil, the position will be the ned. If negative, it will be the first position + this value
 * \return ObjGtkWidget : the same object or nil if error
 */
int SCOL_gtkTextBufferRem (mmachine m)
{
    int mbuffer, mstart, mend;
    GtkWidget *buffer;
    GtkTextIter start, end;

    g_message ("SCOL_gtkTextBufferRem : entering");

    mend = MMpull (m);
    mstart = MMpull (m);
    mbuffer = MMpull (m);

    if (mbuffer == NIL)
    {
        g_warning ("SCOL_gtkTextBufferRem error : object is nil");
        MMpush (m, NIL);
        return 0;
    }
    mstart = MTOI (mstart);
    if (mstart == NIL)
        mstart = 0;
    else if (mstart < 0)
        mstart = gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer));
    mend = MTOI (mend);
    if (mend == NIL)
        mend = -1;  /* force a garder à -1 */
    else if (mend < 0)
        mend = mstart-mend;
    else if (mend < mstart)
        mend = mstart;

    buffer = (GtkWidget*) MMfetch (m, MTOP (mbuffer), OBJ2DGTK_WIDGET_HANDLE);
    gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (buffer), &start, mstart);
    gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (buffer), &end, mend);
    gtk_text_buffer_delete (GTK_TEXT_BUFFER (buffer), &start, &end);
    MMpush (m, mbuffer);
    return 0;
}

/**
 * \brief _gtkTextBufferSet : set a text to a text bufer. The old content is overwritten.
 *
 * fun [ObjGtkWidget S] ObjGtkWidget
 *
 * \param ObjGtkWidget : a text buffer object
 * \param S : a string
 * \return : the same object or nil if an error occirs
 */
int SCOL_gtkTextBufferSet (mmachine m)
{
    int mbuffer, mstring;
    GtkWidget *buffer;
    gchar *string = "";

    g_message ("SCOL_gtkTextBufferSet : entering");

    mstring = MMpull (m);
    mbuffer = MMpull (m);

    if (mbuffer == NIL)
    {
        g_warning ("SCOL_gtkTextBufferSet error : object is nil");
        MMpush (m, NIL);
        return 0;
    }
    buffer = (GtkWidget*) MMfetch (m, MTOP (mbuffer), OBJ2DGTK_WIDGET_HANDLE);

    if (mstring != NIL)
        string = SCOLUTF8 (MMstartstr (m, MTOP (mstring)));

    gtk_text_buffer_set_text (GTK_TEXT_BUFFER (buffer), string, -1);
    MMpush (m, mbuffer);
    g_free (string);
    return 0;
}

/**
 * \brief _gtkTextBufferSetFrom : set a text from a given position
 * fun [ObjGtkWidget S I] ObjGtkWidget
 *
 * \param ObjGtkWidget : any text buffer object
 * \param S : any string
 * \param I : a position
 *\return ObjGtkWidget : the same object or nil if error
 */
int SCOL_gtkTextBufferSetFrom (mmachine m)
{
    int mbuffer, mstring, mpos;
    GtkWidget *buffer;
    gchar *string = "";
    GtkTextIter start, end;

    g_message ("SCOL_gtkTextBufferSetFrom : entering");

    mpos = MMpull (m);
    mstring = MMpull (m);
    mbuffer = MMpull (m);

    if (mbuffer == NIL)
    {
        g_warning ("SCOL_gtkTextBufferSetFrom error : object is nil");
        MMpush (m, NIL);
        return 0;
    }
    buffer = (GtkWidget*) MMfetch (m, MTOP (mbuffer), OBJ2DGTK_WIDGET_HANDLE);

    if (mstring != NIL)
        string = SCOLUTF8 (MMstartstr (m, MTOP (mstring)));
    if (mpos == NIL)
        mpos = 0;
    else if (mpos < 0)
        mpos = gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)) + MTOI (mpos);
    else
        mpos = MTOI (mpos);

    gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (buffer), &start, mpos);
    gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (buffer), &end, -1);
    gtk_text_buffer_delete (GTK_TEXT_BUFFER (buffer), &start, &end);
    gtk_text_buffer_insert (GTK_TEXT_BUFFER (buffer), &start, string, strlen (string));
    g_free (string);
    MMpush (m, mbuffer);
    return 0;
}

/**
 * \brief _gtkTextBufferGetFull : returns the content between two position from a text buffer
 *
 * fun [ObjGtkWidget I I I I] S
 *
 * \param ObjGtkWidget : any text buffer object
 * \param I : a first position
 * \param I : a second position
 * \param I : a flag : SCOL_GTK_TEXT_WITH_HIDDENCHAR to include any invisible characters, otherwise 0 or nil
 * \param I : a flag : SCOL_GTK_TEXT_WITH_OBJECT to include any embedded object otherwise 0 or nil
 * \return : S : the string, or nil if an error occurs
 */
int SCOL_gtkTextBufferGetFull (mmachine m)
{
    int mbuffer, mstart, mend, mflagChar, mflagObject;
    GtkWidget *buffer;
    gchar *string;
    GtkTextIter start, end;

    g_message ("SCOL_gtkTextBufferGetFull : entering");

    mflagObject = MTOI (MMpull (m));
    mflagChar = MTOI (MMpull (m));
    mend = MMpull (m);
    mstart = MMpull (m);
    mbuffer = MMpull (m);

    if (mbuffer == NIL)
    {
        g_warning ("SCOL_gtkTextBufferGetFull error : object is nil");
        MMpush (m, NIL);
        return 0;
    }
    buffer = (GtkWidget*) MMfetch (m, MTOP (mbuffer), OBJ2DGTK_WIDGET_HANDLE);
    if (mstart == NIL)
        mstart = 0;
    else if (MTOI (mstart) < 0)
        mstart = gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)) + MTOI (mstart);
    else
        mstart = MTOI (mstart);
    if (mend == NIL)
        mend = 0;
    else if (MTOI (mend) < 0)
        mend = gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)) + MTOI (mend);
    else
        mend = MTOI (mend);
    gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (buffer), &start, mstart);
    gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (buffer), &end, mend);

    if (mflagObject == TEXT_WITH_OBJECT)
        string = UTF8SCOL (gtk_text_buffer_get_slice (GTK_TEXT_BUFFER (buffer), &start, &end, mflagChar));
    else
        string = UTF8SCOL (gtk_text_buffer_get_text (GTK_TEXT_BUFFER (buffer), &start, &end, mflagChar));

    Mpushstrbloc (m, string);
    g_free (string);
    return 0;
}

/**
 * \brief _gtkTextBufferGet : Get the text
 * fun [ObjGtkWidget] S
 */
int SCOL_gtkTextBufferGet (mmachine m)
{
    int mbuffer;
    GtkWidget *buffer;
    gchar *string;
    GtkTextIter start, end;

    g_message ("SCOL_gtkTextBufferGet : entering");

    mbuffer = MMpull (m);

    if (mbuffer == NIL)
    {
        g_warning ("SCOL_gtkTextBufferGet error : object is nil");
        MMpush (m, NIL);
        return 0;
    }
    buffer = (GtkWidget*) MMfetch (m, MTOP (mbuffer), OBJ2DGTK_WIDGET_HANDLE);
    gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (buffer), &start, 0);
    gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (buffer), &end, -1);
    string = UTF8SCOL (gtk_text_buffer_get_text (GTK_TEXT_BUFFER (buffer), &start, &end, 0));
    Mpushstrbloc (m, string);
    g_free (string);
    return 0;
}

int SCOL_gtkTextBufferInsertPix (mmachine m)
{
    int mbuffer, mfilename, mpos, mwidth, mheight, mratio;
    GtkWidget *buffer;
    GtkTextIter pos;
    GdkPixbuf *pix = NULL;
    const gchar *filename;
    gboolean ratio = FALSE;

    g_message ("SCOL_gtkTextBufferInsertPix : entering");

    mratio = MTOI (MMpull (m));
    mheight = MMpull (m);
    mwidth = MMpull (m);
    mpos = MMpull (m);
    mfilename = MMpull (m);
    mbuffer = MMpull (m);
    if ((mbuffer == NIL) || (mfilename == NIL))
    {
        g_warning ("SCOL_gtkTextBufferInsertPix error : argument is nil");
        MMpush (m, NIL);
        return 0;
    }
    buffer = (GtkWidget*) MMfetch (m, MTOP (mbuffer), OBJ2DGTK_WIDGET_HANDLE);
    if (mpos == NIL)
        mpos = 0;
    else if (MTOI (mpos) < 0)
        mpos = gtk_text_buffer_get_char_count (GTK_TEXT_BUFFER (buffer)) + MTOI (mpos);
    else
        mpos = MTOI (mpos);
    if (mheight == NIL)
        mheight = -1;
    if (mwidth == NIL)
        mwidth = -1;
    if (mratio == 1)
        ratio = TRUE;

    gtk_text_buffer_get_iter_at_offset (GTK_TEXT_BUFFER (buffer), &pos, mpos);
    filename = MMstartstr (m, MTOP (mfilename));
    if (!(scol_gtk_pixbuf_load (&pix, filename, mwidth, mheight, ratio)))
        g_warning ("SCOL_gtkTextBufferInsertPix error : image couldn't load");
    gtk_text_buffer_insert_pixbuf (GTK_TEXT_BUFFER (buffer), &pos, pix);

    MMpush (m, mbuffer);
    return 0;
}

/**
 * \brief _gtkTextBufferIsModified : get or set if the text buffer has been modified since the last call (or its creation)
 * fun [ObjGtkWidget I] I
 *
 * \param ObjGtkWidget : text buffer object
 * \param I : to get the state, value must be nil. To set the state, value must be 1 (true, is modified) or 0 (false, isn't modified)
 * \return I : the current / new state
 */
int SCOL_gtkTextBufferIsModified (mmachine m)
{
    int mbuffer, mvalue;
    gboolean b = TRUE;
    GtkWidget *buffer;

    g_message ("SCOL_gtkTextBufferIsModified : entering");

    mvalue = MMpull (m);
    mbuffer = MMpull (m);
    if (mbuffer == NIL)
    {
        g_warning ("SCOL_gtkTextBufferIsModified error : object is nil");
        MMpush (m, NIL);
        return 0;
    }
    buffer = (GtkWidget*) MMfetch (m, MTOP (mbuffer), OBJ2DGTK_WIDGET_HANDLE);

    if (mvalue == NIL)
        MMpush (m, ITOM (gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (buffer))));
    else
    {
        if (MTOP (mvalue) != 1)
            b = FALSE;
        gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (buffer), b);
        MMpush (m, ITOM (b));
    }
    return 0;
}

/**
 * \brief _gtkTextBufferSelectionRem : delete the current selected text into a text buffer object
 * fun [ObjGtkWidget] ObjGtkWidget
 * \param ObjGtkWidget : a text buffer object
 * \return ObjGtkWidget : the same object or nil if an error occurs
 */
int SCOL_gtkTextBufferSelectionRem (mmachine m)
{
    int mbuffer;
    GtkWidget *buffer;

    g_message ("SCOL_gtkTextBufferSelectionRem : entering");

    mbuffer = MMpull (m);
    if (mbuffer == NIL)
    {
        g_warning ("SCOL_gtkTextBufferSelectionRem error : object is nil");
        MMpush (m, NIL);
        return 0;
    }
    buffer = (GtkWidget*) MMfetch (m, MTOP (mbuffer), OBJ2DGTK_WIDGET_HANDLE);
    gtk_text_buffer_delete_selection (GTK_TEXT_BUFFER (buffer), TRUE, TRUE);
    MMpush (m, mbuffer);
    return 0;
}




/* ****************************************************************************
 *                                                                            *
 *  TEXT TAGS TABLE -> GtkTextTagTable                                        *
 *                                                                            *
** ***************************************************************************/




/**
 * \brief _gtkTextBufferGetTagTable : returns the current tags table from a buffer.
 *
 * fun [ObjGtkWidget] ObjGtkWidget
 *
 * \param ObjGtkWidget : a buffer
 * \return ObjGtkWidget : the current tags table or nil if error.
 */
int SCOL_gtkTextBufferGetTagTable (mmachine m)
{
    int mbuffer;
    int exist;
    GtkWidget *buffer;
    GtkTextTagTable *table;

    g_message ("SCOL_gtkTextBufferGetTagTable : entering");

    mbuffer = MMpull (m);
    if (mbuffer == NIL)
    {
        g_warning ("SCOL_gtkTextBufferGetTagTable error : object is nil");
        MMpush (m, NIL);
        return 0;
    }

    buffer = (GtkWidget*) MMfetch (m, MTOP (mbuffer), OBJ2DGTK_WIDGET_HANDLE);
    table = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (buffer));

    exist = OBJfindTH (m, ObjGtkWidgetType, (int) table);
    if (exist == -1)    /* table not already created because not found in the current machine. So we create it ! */
    {
        MMpush (m, MMgetglobal (m, OFFSCCUR));  /*  set the current channel */
        return SCOL_gtk_memory_createObjectTAB (m, table, ObjGtkWidgetType, OBJ2DGTK_WIDGET_HANDLE);
    }
    MMpush (m, MMfetch (m, exist, OFFOBJMAG));
    return 0;
}




/* FLAGS */
int SCOL_GTK_TEXT_WITH_HIDDENCHAR (mmachine m) { MMpush (m, ITOM (TEXT_WITH_HIDDENCHAR)); return 0; }
int SCOL_GTK_TEXT_WITH_OBJECT (mmachine m) { MMpush (m, ITOM (TEXT_WITH_OBJECT)); return 0; }

int SCOL_GTK_TEXT_WRAP_NONE (mmachine m) { MMpush (m, ITOM (WRAP_NONE)); return 0; }
int SCOL_GTK_TEXT_WRAP_CHAR (mmachine m) { MMpush (m, ITOM (WRAP_CHAR)); return 0; }
int SCOL_GTK_TEXT_WRAP_WORD (mmachine m) { MMpush (m, ITOM (WRAP_WORD)); return 0; }
int SCOL_GTK_TEXT_WRAP_WORD_CHAR (mmachine m) { MMpush (m, ITOM (WRAP_WORD_CHAR)); return 0; }



/* API definitions : */

char* gtk_txt_name[GTK_TEXT_PKG_NB]=
{
    "SCOL_GTK_TEXT_WITH_HIDDENCHAR", "SCOL_GTK_TEXT_WITH_OBJECT",

    "SCOL_GTK_TEXT_WRAP_NONE", "SCOL_GTK_TEXT_WRAP_CHAR", "SCOL_GTK_TEXT_WRAP_WORD",
    "SCOL_GTK_TEXT_WRAP_WORD_CHAR",

    "_gtkTextLipsum",

    "_gtkTextNew",
    "_gtkTextGetBuffer",
    "_gtkTextSetBuffer",
    "_gtkTextGetEditable",
    "_gtkTextSetEditable",
    "_gtkTextInsertWidget",
    "_gtkTextScroll",
    "_gtkTextSetBorderSize",
    "_gtkTextSetWrap",
    "_gtkTextGetWrap",
    "_gtkTextShowCursor",
    "_gtkTextSetOverwrite",

    "_gtkTextBufferNew",
    "_gtkTextBufferInsert",
    "_gtkTextBufferInsertCopy",
    "_gtkTextBufferCount",
    "_gtkTextBufferRem",
    "_gtkTextBufferSet",
    "_gtkTextBufferSetFrom",
    "_gtkTextBufferGetFull",
    "_gtkTextBufferGet",
    "_gtkTextBufferInsertPix",
    "_gtkTextBufferIsModified",
    "_gtkTextBufferSelectionRem",

    "_gtkTextBufferGetTagTable"
};

int (*gtk_txt_fun[GTK_TEXT_PKG_NB])(mmachine m)=
{
    SCOL_GTK_TEXT_WITH_HIDDENCHAR, SCOL_GTK_TEXT_WITH_OBJECT,

    SCOL_GTK_TEXT_WRAP_NONE, SCOL_GTK_TEXT_WRAP_CHAR, SCOL_GTK_TEXT_WRAP_WORD,
    SCOL_GTK_TEXT_WRAP_WORD_CHAR,

    SCOL_gtkTextLipsum,

    SCOL_gtkTextNew,
    SCOL_gtkTextGetBuffer,
    SCOL_gtkTextSetBuffer,
    SCOL_gtkTextGetEditable,
    SCOL_gtkTextSetEditable,
    SCOL_gtkTextInsertWidget,
    SCOL_gtkTextScroll,
    SCOL_gtkTextSetBorderSize,
    SCOL_gtkTextSetWrap,
    SCOL_gtkTextGetWrap,
    SCOL_gtkTextShowCursor,
    SCOL_gtkTextSetOverwrite,

    SCOL_gtkTextBufferNew,
    SCOL_gtkTextBufferInsert,
    SCOL_gtkTextBufferInsertCopy,
    SCOL_gtkTextBufferCount,
    SCOL_gtkTextBufferRem,
    SCOL_gtkTextBufferSet,
    SCOL_gtkTextBufferSetFrom,
    SCOL_gtkTextBufferGetFull,
    SCOL_gtkTextBufferGet,
    SCOL_gtkTextBufferInsertPix,
    SCOL_gtkTextBufferIsModified,
    SCOL_gtkTextBufferSelectionRem,

    SCOL_gtkTextBufferGetTagTable
};

int gtk_txt_narg[GTK_TEXT_PKG_NB]=
{
    0, 0,

    0, 0, 0,
    0,

    1,      /* SCOL_gtkTextLipsum */

    3,       /* SCOL_gtkTextNew */
    1,       /* SCOL_gtkTextGetBuffer */
    2,      /* SCOL_gtkTextSetBuffer */
    1,      /* SCOL_gtkTextGetEditable */
    2,      /* SCOL_gtkTextSetEditable */
    3,      /* SCOL_gtkTextInsertWidget */
    4,      /* SCOL_gtkTextScroll */
    2,      /* SCOL_gtkTextSetBorderSize */
    2,      /* SCOL_gtkTextSetWrap */
    1,      /* SCOL_gtkTextGetWrap */
    2,      /* SCOL_gtkTextShowCursor */
    2,      /* SCOL_gtkTextSetOverwrite */

    2,       /* SCOL_gtkTextBufferNew */
    3,       /* SCOL_gtkTextBufferInsert */
    5,       /* SCOL_gtkTextBufferInsertCopy */
    1,       /* SCOL_gtkTextBufferCount */
    3,       /* SCOL_gtkTextBufferRem */
    2,      /* SCOL_gtkTextBufferSet */
    3,      /* SCOL_gtkTextBufferSetFrom */
    5,      /* SCOL_gtkTextBufferGetFull */
    1,      /* SCOL_gtkTextBufferGet */
    6,      /* SCOL_gtkTextBufferInsertPix */
    2,      /* SCOL_gtkTextBufferIsModified */
    1,      /* SCOL_gtkTextBufferSelectionRem */

    1       /* SCOL_gtkTextBufferGetTagTable */
};

char* gtk_txt_type[GTK_TEXT_PKG_NB]=
{
    "fun [] I", "fun [] I",

    "fun [] I", "fun [] I", "fun [] I",
    "fun [] I",

    "fun [I] S",                                                  /* SCOL_gtkTextLipsum */

    "fun [Chn ObjGtkWidget S] ObjGtkWidget",                         /* SCOL_gtkTextNew */
    "fun [ObjGtkWidget] ObjGtkWidget",                               /* SCOL_gtkTextGetBuffer */
    "fun [ObjGtkWidget ObjGtkWidget] ObjGtkWidget",                 /* SCOL_gtkTextSetBuffer */
    "fun [ObjGtkWidget] I",                                          /* SCOL_gtkTextGetEditable */
    "fun [ObjGtkWidget I] ObjGtkWidget",                             /* SCOL_gtkTextSetEditable */
    "fun [ObjGtkWidget ObjGtkWidget I] ObjGtkWidget",               /* SCOL_gtkTextInsertWidget */
    "fun [ObjGtkWidget I I I] I",                                   /* SCOL_gtkTextScroll */
    "fun [ObjGtkWidget [I I I I]] ObjGtkWidget",                    /* SCOL_gtkTextSetBorderSize */
    "fun [ObjGtkWidget I] ObjGtkWidget",                            /* SCOL_gtkTextSetWrap */
    "fun [ObjGtkWidget] I",                                         /* SCOL_gtkTextGetWrap */
    "fun [ObjGtkWidget I] ObjGtkWidget",                            /* SCOL_gtkTextShowCursor */
    "fun [ObjGtkWidget I] ObjGtkWidget",                            /* SCOL_gtkTextSetOverwrite */

    "fun [Chn ObjGtkWidget] ObjGtkWidget",                           /* SCOL_gtkTextBufferNew */
    "fun [ObjGtkWidget S I] ObjGtkWidget",                           /* SCOL_gtkTextBufferInsert */
    "fun [ObjGtkWidget I ObjGtkWidget I I] ObjGtkWidget",            /* SCOL_gtkTextBufferInsertCopy */
    "fun [ObjGtkWidget] [I I]",                                      /* SCOL_gtkTextBufferCount */
    "fun [ObjGtkWidget I I] ObjGtkWidget",                           /* SCOL_gtkTextBufferRem */
    "fun [ObjGtkWidget S] ObjGtkWidget",                            /* SCOL_gtkTextBufferSet */
    "fun [ObjGtkWidget S I] ObjGtkWidget",                          /* SCOL_gtkTextBufferSetFrom */
    "fun [ObjGtkWidget I I I I] S",                                 /* SCOL_gtkTextBufferGetFull */
    "fun [ObjGtkWidget] S",                                         /* SCOL_gtkTextBufferGet */
    "fun [ObjGtkWidget P I I I I] ObjGtkWidget",                    /* SCOL_gtkTextBufferInsertPix */
    "fun [ObjGtkWidget I] I",                                       /* SCOL_gtkTextBufferIsModified */
    "fun [ObjGtkWidget] ObjGtkWidget",                                         /* SCOL_gtkTextBufferSelectionRem */

    "fun [ObjGtkWidget] ObjGtkWidget"                               /* SCOL_gtkTextBufferGetTagTable */
};

int SCOLloadGTKtext (mmachine m)
{
    int k;

    MMechostr (0, "SCOLloadGTKtext : entering\n");

    k = PKhardpak (m, "GTK2DtextEngine", GTK_TEXT_PKG_NB, gtk_txt_name, gtk_txt_fun, gtk_txt_narg, gtk_txt_type);
    return k;
}
