/****************************************************************************
**
** $Id: xserver.cpp,v 1.6.2.1 2003/03/13 00:05:22 rnolden Exp $
**
** Copyright (C) 1999 Calderasystems, Inc
** All rights reserved.
**
** This file is part of the Caldera OpenLinux Installer.
** Original Implementation: 1999 by Troll Tech AS
**
** This file may be distributed under the terms of the Q Public License
** as defined by Troll Tech AS of Norway and appearing in the file
** LICENSE included in the packaging of this file.
**
*****************************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <signal.h>
#include <assert.h>

#include <qfile.h>

#include <kstandarddirs.h>
#include <kdebug.h>

#include "xserver.h"

LXServer *LXServer::_instance = 0;

LXServer::LXServer( const QString &configFile )
{
    KStandardDirs *dirs = new KStandardDirs;
    QString lwmPath = QFile::encodeName( dirs->findExe( "twm" ) );
    delete dirs;

    // fallback
    if ( lwmPath.isEmpty() )
    {
        lwmPath = QString::fromLatin1( "/usr/bin/lwm" );
        if ( !QFile::exists( lwmPath ) )
        {
            //fprintf( stderr, "ERROR: cannot find lwm binary. make sure you have the lizard-lwm package installed.\n" );
            // ### i18n
            fprintf( stderr, "ERROR: cannot find twm binary. Please check your X installation.\n" );
            ::exit( 1 );
        }
    }


    r = FALSE;

    // make xlib go to to the same server
    setenv( "DISPLAY", "127.0.0.1:8", 1 );

    xpid = fork();
    if ( xpid == 0 ) {
        int res;
#if 1
        int i = getdtablesize();
        while( i >= 0 ) {
            close( i );
            i--;
        }
        open( "/dev/null", O_RDWR );
        dup( 0 );
        dup( 0 );
        dup( 0 );
#endif

        res = execl("/usr/X11R6/bin/XFree86", "/usr/X11R6/bin/XFree86", ":8",
                        "-bestRefresh", "-dpi", "75", "-xf86config",
        QFile::encodeName( configFile ).data(), "-ac", 0);

        // Do not remove this. There is a compiler bug on ia64, which
        // otherwise removes the execl line.

        kdDebug() << "Should not happen, X Server did not start, res was " << res << "\n";

        exit( 0 );
    }

    while( !r ) {
        // make a nice socket for the X server probe
        int datafd = socket( AF_INET, SOCK_STREAM, 0 );
        if ( datafd < 0 )
                return;
        int on = 1;
        if (setsockopt( datafd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))<0)
                return;
        struct sockaddr_in probe;
        probe.sin_family = AF_INET;
        probe.sin_addr.s_addr = htonl( 0x7f000001 );
        probe.sin_port = htons( 6008 );

        // then try to connect until an attempt succeeds
        r = connect( datafd, (struct sockaddr *)&probe, sizeof(probe) ) >= 0;
        if ( !r ) {
            close( datafd );
            sleep( 1 );
        }
    }

    // succeeded.  keep the connection open, so the X server won't
    // exit.  start a window manager.
    if ( (lwmpid = fork()) == 0 ) {
#if 1
        int i = getdtablesize();
        while( i >= 0 ) {
            close( i );
            i--;
        }
        open( "/dev/null", O_RDWR );
        dup( 1 );
        dup( 2 );
#endif
        ::sleep( 1 );
        ::nice( 8 );
        // execl( "/opt/kde2/bin/kwin", "/opt/kde2/bin/kwin", "-style", "windows", 0 );
        //execl( lwmPath.latin1(), lwmPath.latin1(), "-style", "windows", 0 );
        execl( lwmPath.latin1(), lwmPath.latin1(), 0 );
        exit( 0 );
    }

    r = TRUE;

    return;
}


LXServer::~LXServer()
{
    ::kill( lwmpid, 9 );
    ::waitpid( lwmpid, NULL, 0 );

    ::kill( xpid, 15 );
    ::waitpid( xpid, NULL, 0 );
}


bool LXServer::runServer( const QString &configFile )
{
  if (!_instance)
    _instance = new LXServer( configFile );

  return _instance->r;
}


void LXServer::stopServer()
{
  if (_instance)
    {
      delete _instance;
      _instance = 0;
    }
}

/*
 * vim:et
 */
