/**
 * qtgtk.cpp
 *
 * Copyright (C)  2003  Zack Rusin <zack@kde.org>
 * Copyright (C)  2003  Daniel Molkentin <molkentin@kde.org>
 *
 * This library 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.1 of the License, or (at your option) any later version.
 *
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307  USA
 */

#include "qtgtk.h"
#include "gtkupdater.h"

#include <glib.h>
#include <gdk/gdkx.h>

#include <kuniqueapplication.h>
#include <kcmdlineargs.h>
#include <qsocketnotifier.h>
#include <qeventloop.h>
#include <qptrdict.h>

#include <X11/Xlib.h> /* ConnectionNumber */

extern "C" {

static gboolean gsource_integrator_prepare  ( GSource     *source,
                                              gint        *timeout );
static gboolean gsource_integrator_check    ( GSource     *source );
static gboolean gsource_integrator_dispatch ( GSource     *source,
                                              GSourceFunc  callback,
                                              gpointer     user_data );

static GSourceFuncs integrator_funcs = {
    gsource_integrator_prepare,
    gsource_integrator_check,
    gsource_integrator_dispatch,
    NULL,
    NULL,
    NULL
};

struct IntegratorSource {
    GSource source;

    GMainContext *context;
    QApplication *app;

    Integrate::GtkUpdater *updater;
    QSocketNotifier       *notifier;
    int inside;
};


static IntegratorSource*
create_integrator( GMainContext *context, IntegratorType type )
{

    GSource *source;
    IntegratorSource *ir_source;

    source = g_source_new( &integrator_funcs, sizeof(IntegratorSource) );

    ir_source = (IntegratorSource*)source;
    ir_source->context = context;
    ir_source->inside = false;

    ir_source->updater  = new Integrate::GtkUpdater( 0 );
    ir_source->notifier = new QSocketNotifier( ConnectionNumber( gdk_display ),
                                               QSocketNotifier::Read );
    //ir_source->notifier->setEnabled( false );
    QObject::connect( ir_source->notifier, SIGNAL(activated(int )),
                      ir_source->updater, SLOT(updateGtk()) );

    switch (type)
    {
        static char* argv[] = { const_cast<char*>( "qapp" ), 0 };
        static int argc = 1;
    case Qt:
        if ( !qApp ) {
            ir_source->app = new QApplication( argc, argv );
        } else
            ir_source->app = qApp;
        break;

    case KApp:
        if ( !kapp ) {
            KCmdLineArgs::init(argc, argv, g_get_prgname(), g_get_application_name(), "", "");
            ir_source->app = new KApplication( true, true );
        } else
            ir_source->app = kapp;
        break;

    case KUniqueApp:
        if ( !kapp ) {
            KCmdLineArgs::init(argc, argv, g_get_prgname(), g_get_application_name(), "", "");
            ir_source->app = new KUniqueApplication( true, true );
        } else
            ir_source->app = kapp;
        break;
    }
    return ir_source;
}

gboolean
gsource_integrator_prepare( GSource     *source,
                            gint        */*timeout*/ )
{
    IntegratorSource *ir_source = (IntegratorSource*)source;
    if ( ir_source->inside )
        return false;
    return true;
}

gboolean
gsource_integrator_check( GSource     *source )
{
    IntegratorSource *ir_source = (IntegratorSource*)source;
    if ( ir_source->inside )
        return false;
    return ir_source->app->eventLoop()->hasPendingEvents();
}

gboolean
gsource_integrator_dispatch( GSource     *source,
                             GSourceFunc  /*callback*/,
                             gpointer     /*user_data*/ )
{
    IntegratorSource *ir_source = (IntegratorSource*)source;
    ir_source->inside = true;
    //We're missing a lot of them if we only catch them here
    //ir_source->notifier->setEnabled( true );
    bool b = ir_source->app->eventLoop()->processEvents( QEventLoop::AllEvents );
    //ir_source->notifier->setEnabled( false );
    ir_source->inside = false;
    return b;
}


bool
qtgtk_init( GMainContext *context )
{
    return qtgtk_init_with_type( KApp, context );
}

bool
qtgtk_init_with_type( IntegratorType type, GMainContext *context )
{
    if ( !context )
        context = g_main_context_default();

    IntegratorSource *source =  create_integrator( context, type );
    g_source_attach( (GSource*)source, context );
    return TRUE;
}

}
