//
// C++ Implementation: komposeglobal
//
// Description:
//
//
// Author: Hans Oischinger <hans.oischinger@kde-mail.net>, (C) 2004
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include "komposeglobal.h"


#include "komposetaskmanager.h"
#include "komposeviewmanager.h"
#include "komposesettings.h"
#include "komposesystray.h"

#include <tqtimer.h>

#include <tdeapplication.h>
#include <tdepopupmenu.h>
#include <tdeaction.h>
#include <tdeactioncollection.h>
#include <tdelocale.h>
#include <kiconloader.h>
#include <tdeaccel.h>
#include <kkeydialog.h>
#include <tdeaboutapplication.h>
#include <ksharedpixmap.h>
#include <twinmodule.h>
#include <kdebug.h>
#include <dcopclient.h>
#include <dcopref.h>

#include <dcopclient.h>

// #include those AFTER TQt-includes!
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <Imlib2.h>

#ifdef COMPOSITE
#include <X11/Xatom.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xdamage.h>
#include <X11/extensions/Xrender.h>
#endif

static KomposeGlobal* globalInstance = 0;
Display *disp;

static TQString wallpaperForDesktop(int desktop)
{
  return DCOPRef("kdesktop", "KBackgroundIface").call("currentWallpaper", desktop);
}

/**
 * KomposeSettings is a singleton
 */
KomposeGlobal* KomposeGlobal::instance()
{
  if ( !globalInstance )
  {
    kdDebug() << "KomposeSettings::instance() - Creating Singleton instance" << endl;
    KomposeGlobal *settiglobalInstance = new KomposeGlobal();
  }
  return globalInstance;
}

KomposeGlobal::KomposeGlobal(TQObject *parent, const char *name)
    : TQObject(parent, name),
    aboutDialogOpen(0),
    hideSystray( false ),
    singleShot( false ),
    xcomposite(0),
    damageEvent(0)
{
  globalInstance = this;
  twin_module = new TWinModule(); //FIXME: only needed for sharedpixmap :(
  currentDesktop = twin_module->currentDesktop();

  desktopBgPixmap = new TDESharedPixmap;
  connect(desktopBgPixmap, TQ_SIGNAL(done(bool)), TQ_SLOT(slotDone(bool)));
  initSharedPixmaps();
  initCompositeExt();
  initImlib();

  connect( KomposeSettings::instance(), TQ_SIGNAL(settingsChanged()), this, TQ_SLOT(slotConfigChanged()) );
}

KomposeGlobal::~KomposeGlobal()
{
  delete systray;
  delete actionCollection;
  delete actConfigGlobalShortcuts;
  delete actPreferencesDialog;
  delete actShowVirtualDesktopView;
  delete actShowCurrentDesktopView;
  delete actShowWorldView;
  delete actAboutDlg;
  delete actQuit;
  delete desktopBgPixmap;
}

void KomposeGlobal::slotConfigChanged( )
{
  initCompositeExt();
}

/**
 * Gives us control about when the GUI should appear. Called from outside
 * Called from outside as KomposeGlobal is a singleton that can be instantiated at any time
 */
void KomposeGlobal::initGui()
{
  // Initialise the Singleton instances
  KomposeSettings::instance();
  KomposeViewManager::instance();
  KomposeTaskManager::instance();

  // Create DCop Client
  tdeApp->dcopClient()->setDefaultObject( "KomposeTaskMgrDcopIface" );

  initActions();

  if ( !hideSystray && !singleShot )
  {
    // Create systray
    systray = new KomposeSysTray();
    tdeApp->setMainWidget( systray );
    systray->currentDesktopChanged( currentDesktop );

    actionCollection->setWidget( systray );
    systray->show();
  }
  else
    kdDebug() << "KomposeGlobal::initGui() - Hiding systray icon" << endl;

  if ( singleShot )
  {
    kdDebug() << "KomposeGlobal::initGui() - SingleShot has been selected" << endl;
    KomposeViewManager::instance()->createView();
  }
}


/**
 * Initialise Kompose's global actions. Retrieve these via the getters in KomposeGlobal
 */
void KomposeGlobal::initActions()
{
  actionCollection = new TDEActionCollection( (TQWidget*)0 );

  // Actions
  actQuit = KStdAction::quit( tdeApp, TQ_SLOT(quit()), actionCollection );
  actShowWorldView = new TDEAction(i18n("Komposé (ungrouped)"), "kompose_ungrouped",
                                 0,
                                 KomposeViewManager::instance(), TQ_SLOT(createWorldView()),
                                 actionCollection, "showWorldView");
  actShowVirtualDesktopView = new TDEAction(i18n("Komposé (grouped by virtual desktops)"), "kompose_grouped_by_virtual_desktop",
                                          0,
                                          KomposeViewManager::instance(), TQ_SLOT(createVirtualDesktopView()),
                                          actionCollection, "showVirtualDesktopView");
  actShowCurrentDesktopView = new TDEAction(i18n("Komposé (current virtual desktop)"), "kompose_current_virtual_desktop",
                                          0,
                                          KomposeViewManager::instance(), TQ_SLOT(createCurrentDesktopView()),
                                          actionCollection, "showCurrentDesktopView");

  actPreferencesDialog      = KStdAction::preferences( KomposeSettings::instance(), TQ_SLOT(showPreferencesDlg()), actionCollection );

  actConfigGlobalShortcuts  = KStdAction::keyBindings(this, TQ_SLOT(showGlobalShortcutsSettingsDialog()),
                              actionCollection, "options_configure_global_keybinding");
  actConfigGlobalShortcuts->setText(i18n("Configure &Global Shortcuts..."));
  actAboutDlg      = new TDEAction(i18n("About Komposé"), "kompose",
                                 0,
                                 this, TQ_SLOT(showAboutDlg()),
                                 actionCollection, "showAboutDlg");
}

void KomposeGlobal::initSharedPixmaps()
{
  // Whenever the background pixmap changes we'll have to reload it:
  //connect(twin_module, TQ_SIGNAL(windowChanged(WId, unsigned int)), TQ_SLOT(desktopChanged(WId, unsigned int)));
  connect(twin_module, TQ_SIGNAL(currentDesktopChanged(int)), TQ_SLOT(slotDesktopChanged(int)));
  connect(tdeApp, TQ_SIGNAL(backgroundChanged(int)), TQ_SLOT(slotBackgroundChanged(int)));

  enablePixmapExports();
  // When Kompose is started by session management the bg shared pixmap may not be available yet
  if (!desktopBgPixmap->isAvailable( pixmapName(1) ))
  {
    tqWarning("KomposeGlobal::initSharedPixmaps() - Pixmap not available");
    //enablePixmapExports();
    TQTimer::singleShot( 1000, this, TQ_SLOT( initSharedPixmaps() ) );
    //initSharedPixmaps();
    //return;
  }

  kdDebug() << "KomposeGlobal::initSharedPixmaps()" << endl;
  refreshSharedPixmaps();
}

void KomposeGlobal::slotDesktopChanged(int desktop)
{
  systray->currentDesktopChanged( desktop );
  if (desktop != -2)
  {
    // -2 is for manual loading, everything else enables the following checks:
    if (wallpaperForDesktop(currentDesktop) == wallpaperForDesktop(desktop) &&
        !wallpaperForDesktop(currentDesktop).isNull())
      return;

    if ( !(pixmapName(currentDesktop) != pixmapName(desktop)) )
      return;
  }

  currentDesktop = twin_module->currentDesktop();
  refreshSharedPixmaps();
}

void KomposeGlobal::slotBackgroundChanged(int)
{
  refreshSharedPixmaps();
}

void KomposeGlobal::refreshSharedPixmaps()
{
  desktopBgPixmap->loadFromShared( pixmapName(currentDesktop) );
}

TQString KomposeGlobal::pixmapName(int desk)
{
  // To simplify things we take the background of the first desktop
  TQString pattern = TQString("DESKTOP%1");
  int screen_number = DefaultScreen(tqt_xdisplay());
  if (screen_number)
  {
    pattern = TQString("SCREEN%1-DESKTOP").arg(screen_number) + "%1";
  }
  return pattern.arg( desk );
}

void KomposeGlobal::slotDone(bool success)
{
  if (!success)
  {
    kdDebug() << "KomposeGlobal::slotDone() - loading of desktop background failed.\n" << endl;
    //TQTimer::singleShot( 1000, this, TQ_SLOT( initSharedPixmaps() ) );
  }
}

void KomposeGlobal::enablePixmapExports()
{
#ifdef TQ_WS_X11
  kdDebug() << "KomposeGlobal::enablePixmapExports()" << endl;
  DCOPClient *client = tdeApp->dcopClient();
  if (!client->isAttached())
    client->attach();
  TQByteArray data;
  TQDataStream args( data, IO_WriteOnly );
  args << 1;

  TQCString appname( "kdesktop" );
  int screen_number = DefaultScreen(tqt_xdisplay());
  if ( screen_number )
    appname.sprintf("kdesktop-screen-%d", screen_number );

  client->send( appname, "KBackgroundIface", "setExport(int)", data );
#endif
}

/**
 * Show Global Shortcuts Dialog for Kompose
 */
void KomposeGlobal::showGlobalShortcutsSettingsDialog()
{
  KKeyDialog::configure( KomposeSettings::instance()->getGlobalAccel() );
  KomposeSettings::instance()->writeConfig();
}

/**
 * Show About Dialog for Kompose
 */
void KomposeGlobal::showAboutDlg()
{
  aboutDialogOpen = true;
  TDEAboutApplication* kabout = new TDEAboutApplication();
  kabout->exec();
  delete kabout;
  aboutDialogOpen = false;
}

/**
 * Initialise Imlib2.
 * Should only be called by the KomposeGlobal constructor
 */
void KomposeGlobal::initImlib()
{
  Display *disp;
  Visual *vis;
  Colormap cm;
  //int screen;
  disp = TQPaintDevice::x11AppDisplay();
  vis   = DefaultVisual(disp, DefaultScreen(disp));
  cm    = DefaultColormap(disp, DefaultScreen(disp));
  //     context = imlib_context_new();

  //     imlib_context_push(d->context);
  imlib_set_cache_size(0);
  imlib_set_color_usage(128);
  imlib_context_set_dither(1);
  imlib_context_set_display(disp);
  imlib_context_set_visual(vis);
  imlib_context_set_colormap(cm);
  kdDebug() << "KomposeGlobal::initImlib() - Imlib2 support enabled." << endl;
}

/**
 * Detect and initialise the XComposite extension.
 * Should only be called by the KomposeGlobal constructor
 */
void KomposeGlobal::initCompositeExt()
{
  if ( !(!xcomposite && KomposeSettings::instance()->getUseComposite()) )
    return;

  xcomposite = false;
#ifdef COMPOSITE
  // Check for XComposite
  Display *dpy = TQPaintDevice::x11AppDisplay();

  int event_base, error_base;
  if ( XCompositeQueryExtension( dpy, &event_base, &error_base ) )
  {
    // If we get here the server supports the extension
    xcomposite = true;

    // XComposite version check
    int major = 1, minor = 1; // The highest version we support
    XCompositeQueryVersion( dpy, &major, &minor );
    // major and minor will now contain the version the server supports.
    if (!(major > 0 || minor >= 2))
    {
      kdDebug() << "KomposeGlobal::initCompositeExt() - XComposite doesn't allow NamePixmap requests! - Disabling XComposite support" << endl;
      // TODO: create a namewindowpixbool to make it work with composite 0.1
      xcomposite = false;
    }

    // XRender version check
    int renderEvent, renderError;
    if (!XRenderQueryExtension (dpy, &renderEvent, &renderError))
    {
      kdDebug() << "KomposeGlobal::initCompositeExt() - XRender not available! - Disabling XComposite support" << endl;
    }

    //XDamage version check
    //int damageEvent, damageError; // The event base is important here
    if (!XDamageQueryExtension( dpy, &damageEvent, &damageError ))
    {
      kdDebug() << "KomposeGlobal::initCompositeExt() - XDamage is not available! - Disabling XComposite support" << endl;
      xcomposite = false;
    }

  }
  else
    xcomposite = false;
#endif

  if ( xcomposite )
    kdDebug() << "KomposeGlobal::initCompositeExt() - XComposite extension found and enabled." << endl;
}


#include "komposeglobal.moc"
