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

/*
  Copyright (C) 2005 Francois Chazal <neptune3k@free.fr>
  Copyright (C) 2006-2007 Eike Hein <hein@kde.org>
*/


#include "main_window.h"
#include "main_window.moc"
#include "settings.h"
#include "general_settings.h"
#include "skin_settings.h"
#include "first_run_dialog.h"
#include "session.h"

#include <tqsignalmapper.h>
#include <tqwhatsthis.h>

#include <tdeaboutapplication.h>
#include <tdeabouttde.h>
#include <tdemessagebox.h>
#include <tdeconfigdialog.h>
#include <kiconloader.h>
#include <twin.h>
#include <dcopref.h>

MainWindow::MainWindow(TQWidget * parent, const char * name) :
        DCOPObject("DCOPInterface"),
        TDEMainWindow(parent, name, TQt::WStyle_Customize | TQt::WStyle_NoBorder),
        step(0)
{
    first_run_dialog = 0;
    about_app = 0;
    about_kde = 0;
    full_screen = false;
    is_shutting_down = false;
    background_changed = false;
    use_translucency = false;

    TDEConfig config(CONFIG_FILE);

    back_widget = new TQWidget(this);
    widgets_stack = new TQWidgetStack(this);

    // Register with DCOP.
    if (!kapp->dcopClient()->isRegistered())
    {
        kapp->dcopClient()->registerAs("dcopinterface");
        kapp->dcopClient()->setDefaultObject(objId());
    }

    // KRootPixmap::isAvailable() is unreliable, so we check
    // for kdesktop's presence ourselves to decide whether or
    // not to disable pseudo-translucency.
    if (Settings::translucency() && kapp->dcopClient()->isApplicationRegistered("kdesktop"))
        use_translucency = true;

    // Revert to default skin if selected skin can't be located.
    if (!locate("appdata", Settings::skin() + "/title.skin"))
        Settings::setSkin("default");

    // Initialize access key.
    global_key = new TDEGlobalAccel(this);
    global_key->insert("AccessKey", i18n("Open/Retract Yakuake"),
                       i18n("Slides the Yakuake window in and out"),
                       Key_F12, 0, this, TQ_SLOT(slotToggleState()));

    global_key->readSettings(&config);
    global_key->updateConnections();



    // Initialize shortcuts.
    TDEAction* action;

    TDEShortcut shortcut(TQt::CTRL+TQt::ALT+TQt::Key_N);
    shortcut.append(TDEShortcut(TQt::CTRL+TQt::SHIFT+TQt::Key_N));
    action = new TDEAction(i18n("New Session"), SmallIcon("tab_new"), shortcut,
                              this, TQ_SLOT(slotAddSession()),
                              actionCollection(), "add_tab");

    action = new TDEAction(i18n("Two Terminals, Horizontal"), SmallIcon("tab_new"),
                              0, this, TQ_SLOT(slotAddSessionTwoVertical()),
                              actionCollection(), "add_tab_twohorizontal");

    action = new TDEAction(i18n("Two Terminals, Vertical"), SmallIcon("tab_new"),
                              0, this, TQ_SLOT(slotAddSessionTwoHorizontal()),
                              actionCollection(), "add_tab_twovertical");

    action = new TDEAction(i18n("Four Terminals, Quad"), SmallIcon("tab_new"),
                              0, this, TQ_SLOT(slotAddSessionQuad()),
                              actionCollection(), "add_tab_quad");

    action = new TDEAction(i18n("Go to Next Terminal"), SmallIcon("go-next"),
                              "Ctrl+Shift+Up", this, TQ_SLOT(slotFocusNextSplit()),
                              actionCollection(), "focus_next_terminal");

    action = new TDEAction(i18n("Go to Previous Terminal"), SmallIcon("go-previous"),
                              "Ctrl+Shift+Down", this, TQ_SLOT(slotFocusPreviousSplit()),
                              actionCollection(), "focus_previous_terminal");

    action = new TDEAction(i18n("Paste"), SmallIcon("edit-paste"), SHIFT+Key_Insert,
                              this, TQ_SLOT(slotPasteClipboard()),
                              actionCollection(), "paste_clipboard");

    action = new TDEAction(i18n("Paste Selection"), SmallIcon("edit-paste"),
                              CTRL+SHIFT+Key_Insert, this, TQ_SLOT(slotPasteSelection()),
                              actionCollection(), "paste_selection");

    action = new TDEAction(i18n("Rename Session..."), SmallIcon("edit"),
                              "Alt+Ctrl+S", this, TQ_SLOT(slotInteractiveRename()),
                              actionCollection(), "edit_name");

    action = new TDEAction(i18n("Increase Width"), SmallIcon("zoom-in"),
                              "Alt+Shift+Right", this, TQ_SLOT(slotIncreaseSizeW()),
                              actionCollection(), "increasew");
    action = new TDEAction(i18n("Decrease Width"), SmallIcon("zoom-out"),
                              "Alt+Shift+Left", this, TQ_SLOT(slotDecreaseSizeW()),
                              actionCollection(), "decreasew");
    action = new TDEAction(i18n("Increase Height"), SmallIcon("zoom-in"),
                              "Alt+Shift+Down", this, TQ_SLOT(slotIncreaseSizeH()),
                              actionCollection(), "increaseh");
    action = new TDEAction(i18n("Decrease Height"), SmallIcon("zoom-out"),
                              "Alt+Shift+Up", this, TQ_SLOT(slotDecreaseSizeH()),
                              actionCollection(), "decreaseh");

    action = new TDEAction(i18n("Configure Global Shortcuts..."),
                              SmallIcon("configure_shortcuts"), 0,
                              this, TQ_SLOT(slotSetAccessKey()),
                              actionCollection(), "global_shortcuts");

    action = new TDEAction(i18n("Quit"), SmallIcon("system-log-out"), 0, this,
                              TQ_SLOT(close()), actionCollection(), "quit");

    KStdAction::keyBindings(this, TQ_SLOT(slotSetControlKeys()), actionCollection());
    KStdAction::preferences(this, TQ_SLOT(slotOpenSettingsDialog()), actionCollection());
    KStdAction::aboutApp(this, TQ_SLOT(slotOpenAboutApp()), actionCollection());
    KStdAction::aboutKDE(this, TQ_SLOT(slotOpenAboutKDE()), actionCollection());
    KStdAction::whatsThis(this, TQ_SLOT(whatsThis()), actionCollection());

    full_screen_action = KStdAction::fullScreen(this, TQ_SLOT(slotUpdateFullScreen()), actionCollection(), this);
    connect(full_screen_action, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(slotSetFullScreen(bool)));

    createMenu();
    createSessionMenu();
    createTitleBar();
    createTabsBar();

    action = new TDEAction(i18n("Go to Next Session"), SmallIcon("go-next"),
                              "Shift+Right", tab_bar, TQ_SLOT(slotSelectNextItem()),
                              actionCollection(), "next_tab");
    action = new TDEAction(i18n("Go to Previous Session"), SmallIcon("go-previous"),
                              "Shift+Left", tab_bar, TQ_SLOT(slotSelectPreviousItem()),
                              actionCollection(), "previous_tab");

    action = new TDEAction(i18n("Move Session Left"), SmallIcon("back"),
                              "Ctrl+Shift+Left", tab_bar, TQ_SLOT(slotMoveItemLeft()),
                              actionCollection(), "move_tab_left");

    action = new TDEAction(i18n("Move Session Right"), SmallIcon("forward"),
                              "Ctrl+Shift+Right", tab_bar, TQ_SLOT(slotMoveItemRight()),
                              actionCollection(), "move_tab_right");

    remove_tab_action = new TDEAction(i18n("Close Session"), SmallIcon("window-close"), 0,
                                    this, 0, actionCollection(), "remove_tab");
    connect(remove_tab_action, TQ_SIGNAL(activated(TDEAction::ActivationReason, TQt::ButtonState)),
        this, TQ_SLOT(slotHandleRemoveSession(TDEAction::ActivationReason, TQt::ButtonState)));

    split_horiz_action = new TDEAction(i18n("Split Terminal Horizontally"), SmallIcon("view_top_bottom"),
                                     CTRL+SHIFT+Key_T, this, 0, actionCollection(), "split_horizontally");
    connect(split_horiz_action, TQ_SIGNAL(activated(TDEAction::ActivationReason, TQt::ButtonState)),
        this, TQ_SLOT(slotHandleVerticalSplit(TDEAction::ActivationReason, TQt::ButtonState)));

    split_vert_action = new TDEAction(i18n("Split Terminal Vertically"), SmallIcon("view_left_right"),
                                    CTRL+SHIFT+Key_L, this, 0, actionCollection(), "split_vertically");
    connect(split_vert_action, TQ_SIGNAL(activated(TDEAction::ActivationReason, TQt::ButtonState)),
        this, TQ_SLOT(slotHandleHorizontalSplit(TDEAction::ActivationReason, TQt::ButtonState)));

    remove_term_action = new TDEAction(i18n("Close Terminal"), SmallIcon("view_remove"),
                                     CTRL+SHIFT+Key_R, this, 0, actionCollection(), "remove_terminal");
    connect(remove_term_action, TQ_SIGNAL(activated(TDEAction::ActivationReason, TQt::ButtonState)),
        this, TQ_SLOT(slotHandleRemoveTerminal(TDEAction::ActivationReason, TQt::ButtonState)));

    TQSignalMapper* tab_selection_mapper = new TQSignalMapper(this);
    connect(tab_selection_mapper, TQ_SIGNAL(mapped(int)), this, TQ_SLOT(slotSelectTabPosition(int)));

    for (uint i = 1; i <= 12; ++i)
    {
        TDEAction* tab_selection_action = new TDEAction(i18n("Switch to Session %1").arg(i), 0, 0,
            tab_selection_mapper, TQ_SLOT(map()), actionCollection(), TQString("go_to_tab_%1").arg(i).local8Bit());
        tab_selection_mapper->setMapping(tab_selection_action, i-1);
    }

    actionCollection()->readShortcutSettings("Shortcuts", &config);

    // Initialize settings.
    slotUpdateSettings();

    // Add first session.
    slotAddSession();

    connect(kapp, TQ_SIGNAL(aboutToQuit()), this, TQ_SLOT(slotAboutToQuit()));

    // No need for this if we're not going to use pseudo-translucency.
    if (use_translucency)
        connect(kapp, TQ_SIGNAL(backgroundChanged(int)), this, TQ_SLOT(slotUpdateBackgroundState()));

    connect(tab_bar, TQ_SIGNAL(addItem()), this, TQ_SLOT(slotAddSession()));
    connect(tab_bar, TQ_SIGNAL(removeItem()), this, TQ_SLOT(slotRemoveSession()));
    connect(tab_bar, TQ_SIGNAL(itemSelected(int)), this, TQ_SLOT(slotSelectSession(int)));
    connect(&desk_info, TQ_SIGNAL(workAreaChanged()), this, TQ_SLOT(slotUpdateSize()));

    connect(&poller, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotPollMouse()));

    // Startup notification popup.
    if (Settings::popup() && !Settings::firstrun())
        showPopup(i18n("Application successfully started!\nPress %1 to use it...").arg(global_key->shortcut("AccessKey").toString()));

    // First run dialog.
    if (Settings::firstrun())
    {
        TQTimer::singleShot(0, this, TQ_SLOT(slotToggleState()));
        TQTimer::singleShot(0, this, TQ_SLOT(slotOpenFirstRunDialog()));
    }
    else if (Settings::poll())
        toggleMousePoll(true);
}

MainWindow::~MainWindow()
{
    if (!is_shutting_down) slotAboutToQuit();

    delete remove_tab_action;
    delete split_horiz_action;
    delete split_vert_action;
    delete remove_term_action;
    delete full_screen_action;
    delete screen_menu;
    delete width_menu;
    delete height_menu;
    delete session_menu;
    delete menu;
    delete about_app;
    delete about_kde;
}

void MainWindow::slotAboutToQuit()
{
    is_shutting_down = true;

    Settings::writeConfig();

    delete tab_bar;
    tab_bar = 0L;
    delete title_bar;
    title_bar = 0L;
    delete global_key;
    global_key = 0L;
    delete back_widget;
    back_widget = 0L;
    delete widgets_stack;
    widgets_stack = 0L;
}

bool MainWindow::queryClose()
{
    /* Ask before closing with multiple open sessions. */

    if (sessions_stack.size() > 1 && Settings::confirmquit())
    {
        if (focus_policy == false) focus_policy = true;

        int result = KMessageBox::warningYesNoCancel(
            this,
            i18n("You have multiple open sessions. These will be killed if you continue.\n\nAre you sure you want to quit?"),
            i18n("Really Quit?"),
            KStdGuiItem::quit(),
            KGuiItem(i18n("C&lose Session")));

        switch (result)
        {
            case KMessageBox::Yes:
                focus_policy = Settings::focus();
                KWin::activateWindow(winId());
                return true;
                break;
            case KMessageBox::No:
                focus_policy = Settings::focus();
                KWin::activateWindow(winId());
                slotRemoveSession();
                return false;
                break;

            default:
                focus_policy = Settings::focus();
                KWin::activateWindow(winId());
                return false;
                break;
        }
    }
    else
    {
        return true;
    }
}

void MainWindow::updateWindowMask()
{
    TQRegion mask = title_bar->getWidgetMask();

    mask.translate(0, mask_height);
    mask += TQRegion(0, 0, width(), mask_height);

    setMask(mask);
}

void MainWindow::showPopup(const TQString& text, int time)
{
    /* Show a passive popup with the given text. */

    popup.setView(i18n("Yakuake Notification"), text, TDEApplication::kApplication()->miniIcon());
    popup.setTimeout(time);
    popup.show();
}

void MainWindow::slotAddSession()
{
    slotAddSession(Session::Single);
}

void MainWindow::slotAddSessionTwoHorizontal()
{
    slotAddSession(Session::TwoHorizontal);
}

void MainWindow::slotAddSessionTwoVertical()
{
    slotAddSession(Session::TwoVertical);
}

void MainWindow::slotAddSessionQuad()
{
    slotAddSession(Session::Quad);
}

void MainWindow::slotAddSession(Session::SessionType type)
{
    Session* session = new Session(widgets_stack, type);
    connect(session, TQ_SIGNAL(destroyed(int)), this, TQ_SLOT(slotSessionDestroyed(int)));
    connect(session, TQ_SIGNAL(titleChanged(const TQString&)), this, TQ_SLOT(slotUpdateTitle(const TQString&)));

    widgets_stack->addWidget(session->widget());
    sessions_stack.insert(session->id(), session);

    selected_id = session->id();

    tab_bar->addItem(selected_id);
    widgets_stack->raiseWidget(session->widget());
    title_bar->setTitleText(session->title());
}

void MainWindow::slotRemoveSession()
{
    sessions_stack[selected_id]->deleteLater();
}

void MainWindow::slotRemoveSession(int session_id)
{
    if (!sessions_stack[session_id]) return;

    sessions_stack[session_id]->deleteLater();
}

void MainWindow::slotHandleRemoveSession(TDEAction::ActivationReason reason, TQt::ButtonState /* state */)
{
    if (reason == TDEAction::PopupMenuActivation
        && tab_bar->pressedPosition() != -1)
    {
        slotRemoveSession(tab_bar->sessionIdForTabPosition(tab_bar->pressedPosition()));
        tab_bar->resetPressedPosition();
    }
    else
        slotRemoveSession();
}

void MainWindow::slotRemoveTerminal()
{
    sessions_stack[selected_id]->removeTerminal();
}

void MainWindow::slotRemoveTerminal(int session_id)
{
    if (!sessions_stack[session_id]) return;

    sessions_stack[session_id]->removeTerminal();
}

void MainWindow::slotRemoveTerminal(int session_id, int terminal_id)
{
    if (!sessions_stack[session_id]) return;

    sessions_stack[session_id]->removeTerminal(terminal_id);
}

void MainWindow::slotRenameSession(int session_id, const TQString& name)
{
    tab_bar->renameItem(session_id, name);
}

void MainWindow::slotInteractiveRename()
{
    /* Open inline edit for the current item and show tab bar if necessary. */

    if (!Settings::tabs() && tab_bar->isHidden())
    {
        Settings::setTabs(true);
        tab_bar->show();
    }

    tab_bar->interactiveRename();
}

int MainWindow::selectedSession()
{
    return selected_id;
}

int MainWindow::selectedTerminal()
{
    return sessions_stack[selected_id]->activeTerminalId();
}

const TQString MainWindow::sessionIdList()
{
    TQValueList<int>::iterator it;
    TQValueList<int> key_list = sessions_stack.keys();
    TQStringList id_list;

    for (it = key_list.begin(); it != key_list.end(); ++it)
        id_list << TQString::number((*it));

    return id_list.join(",");
}

const TQString MainWindow::terminalIdList(int session_id)
{
    if (!sessions_stack[session_id]) return 0;

    return sessions_stack[session_id]->terminalIdList();
}

int MainWindow::tabPositionForSessionId(int session_id)
{
    return tab_bar->tabPositionForSessionId(session_id);
}

int MainWindow::sessionIdForTabPosition(int position)
{
    return tab_bar->sessionIdForTabPosition(position);
}

void MainWindow::slotSelectSession(int session_id)
{
    if (selected_id == session_id) return;
    if (!sessions_stack[session_id]) return;
    if (!sessions_stack[session_id]->widget()) return;

    selected_id = session_id;

    Session* session = sessions_stack[session_id];

    tab_bar->selectItem(session_id);
    widgets_stack->raiseWidget(session->widget());
    session->widget()->setFocus();
    title_bar->setTitleText(session->title());
}

void MainWindow::slotSelectTabPosition(int position)
{
    tab_bar->selectPosition(position);
}

const TQString MainWindow::slotSessionName()
{
    return tab_bar->itemName(selected_id);
}

const TQString MainWindow::slotSessionName(int session_id)
{
    if (!sessions_stack[session_id]) return 0;

    return tab_bar->itemName(session_id);
}

const TQString MainWindow::slotSessionTitle()
{
    return sessions_stack[selected_id]->title();
}

const TQString MainWindow::slotSessionTitle(int session_id)
{
    if (!sessions_stack[session_id]) return 0;

    return sessions_stack[session_id]->title();
}

const TQString MainWindow::slotSessionTitle(int session_id, int terminal_id)
{
    if (!sessions_stack[session_id]) return 0;

    return sessions_stack[session_id]->title(terminal_id);
}

void MainWindow::slotSetSessionTitleText(const TQString& title)
{
    sessions_stack[selected_id]->setTitle(title);
}

void MainWindow::slotSetSessionTitleText(int session_id, const TQString& title)
{
    if (!sessions_stack[session_id]) return;

    sessions_stack[session_id]->setTitle(title);
}

void MainWindow::slotSetSessionTitleText(int session_id, int terminal_id, const TQString& title)
{
    if (!sessions_stack[session_id]) return;

    sessions_stack[session_id]->setTitle(terminal_id, title);
}

void MainWindow::slotPasteClipboard()
{
    sessions_stack[selected_id]->pasteClipboard();
}

void MainWindow::slotPasteClipboard(int session_id)
{
    if (!sessions_stack[session_id]) return;

    sessions_stack[session_id]->pasteClipboard();
}

void MainWindow::slotPasteClipboard(int session_id, int terminal_id)
{
    if (!sessions_stack[session_id]) return;

    sessions_stack[session_id]->pasteClipboard(terminal_id);
}

void MainWindow::slotPasteSelection()
{
    sessions_stack[selected_id]->pasteSelection();
}

void MainWindow::slotPasteSelection(int session_id)
{
    if (!sessions_stack[session_id]) return;

    sessions_stack[session_id]->pasteSelection();
}

void MainWindow::slotPasteSelection(int session_id, int terminal_id)
{
    if (!sessions_stack[session_id]) return;

    sessions_stack[session_id]->pasteSelection(terminal_id);
}

void MainWindow::slotRunCommandInSession(const TQString& command)
{
    sessions_stack[selected_id]->runCommand(command);
}

void MainWindow::slotRunCommandInSession(int session_id, const TQString& command)
{
    if (!sessions_stack[session_id]) return;

    sessions_stack[session_id]->runCommand(command);
}

void MainWindow::slotRunCommandInSession(int session_id, int terminal_id, const TQString& command)
{
    if (!sessions_stack[session_id]) return;

    sessions_stack[session_id]->runCommand(terminal_id, command);
}

void MainWindow::slotSplitHorizontally()
{
    sessions_stack[selected_id]->splitHorizontally();
}

void MainWindow::slotSplitHorizontally(int session_id)
{
    if (!sessions_stack[session_id]) return;

    sessions_stack[session_id]->splitHorizontally();
}

void MainWindow::slotSplitHorizontally(int session_id, int terminal_id)
{
    if (!sessions_stack[session_id]) return;

    sessions_stack[session_id]->splitHorizontally(terminal_id);
}

void MainWindow::slotSplitVertically()
{
    sessions_stack[selected_id]->splitVertically();
}

void MainWindow::slotSplitVertically(int session_id)
{
    if (!sessions_stack[session_id]) return;

    sessions_stack[session_id]->splitVertically();
}

void MainWindow::slotSplitVertically(int session_id, int terminal_id)
{
    if (!sessions_stack[session_id]) return;

    sessions_stack[session_id]->splitVertically(terminal_id);
}


void MainWindow::slotFocusNextSplit()
{
    sessions_stack[selected_id]->focusNextSplit();
}

void MainWindow::slotFocusPreviousSplit()
{
    sessions_stack[selected_id]->focusPreviousSplit();
}

void MainWindow::windowActivationChange(bool old_active)
{
    /* Retract the window when focus changes. */

    if (!focus_policy && old_active && step)
        slotToggleState();
}

void MainWindow::slotHandleHorizontalSplit(TDEAction::ActivationReason reason, TQt::ButtonState /* state */)
{
    if (reason == TDEAction::PopupMenuActivation
        && tab_bar->pressedPosition() != -1)
    {
        slotSplitHorizontally(tab_bar->sessionIdForTabPosition(tab_bar->pressedPosition()));
        tab_bar->resetPressedPosition();
    }
    else
        slotSplitHorizontally();
}

void MainWindow::slotHandleVerticalSplit(TDEAction::ActivationReason reason, TQt::ButtonState /* state */)
{
    if (reason == TDEAction::PopupMenuActivation
        && tab_bar->pressedPosition() != -1)
    {
        slotSplitVertically(tab_bar->sessionIdForTabPosition(tab_bar->pressedPosition()));
        tab_bar->resetPressedPosition();
    }
    else
        slotSplitVertically();
}


void MainWindow::slotHandleRemoveTerminal(TDEAction::ActivationReason reason, TQt::ButtonState /* state */)
{
    if (reason == TDEAction::PopupMenuActivation
        && tab_bar->pressedPosition() != -1)
    {
        slotRemoveTerminal(tab_bar->sessionIdForTabPosition(tab_bar->pressedPosition()));
        tab_bar->resetPressedPosition();
    }
    else
        slotRemoveTerminal();
}

void MainWindow::initWindowProps()
{
    /* Initializes the window properties. */

    if (Settings::focus() && !Settings::keepabove())
    {
        KWin::clearState(winId(), NET::KeepAbove);
        KWin::setState(winId(), NET::Sticky | NET::SkipTaskbar | NET::SkipPager);
    }
    else
        KWin::setState(winId(), NET::KeepAbove | NET::Sticky | NET::SkipTaskbar | NET::SkipPager);

    KWin::setOnAllDesktops(winId(), true);
}

int MainWindow::getMouseScreen()
{
    /* Gets the screen where the mouse pointer is located. */

    return TQApplication::desktop()->screenNumber(TQCursor::pos());
}

TQRect MainWindow::getDesktopGeometry()
{
    /* Computes the desktop geometry. */

    if (full_screen)
    {
        if (!Settings::screen())
            return TQApplication::desktop()->screenGeometry(getMouseScreen());
        else
            return TQApplication::desktop()->screenGeometry(Settings::screen()-1);
    }

    TQRect result;
    result = desk_info.workArea();

    TDEConfigGroup group(TDEGlobal::config(), "Windows");

    if (TQApplication::desktop()->isVirtualDesktop() &&
            group.readBoolEntry("XineramaEnabled", true) &&
            group.readBoolEntry("XineramaPlacementEnabled", true))
    {
        if (!Settings::screen())
            return result.intersect(TQApplication::desktop()->screenGeometry(getMouseScreen()));
        else
            return result.intersect(TQApplication::desktop()->screenGeometry(Settings::screen()-1));
    }

    return result;
}

void MainWindow::createTabsBar()
{
    /* Creates the tabs frame. */

    tab_bar = new TabBar(this, "Session tab bar", use_translucency, Settings::skin());
    connect(this, TQ_SIGNAL(updateBackground()), tab_bar, TQ_SIGNAL(updateBackground()));

    tab_bar->setSessionMenu(session_menu);

    tab_bar->resize(width(), tab_bar->height());
}

void MainWindow::createTitleBar()
{
    /* Creates the title frame. */

    title_bar = new TitleBar(this, "Application title bar", Settings::skin());
    title_bar->setConfigurationMenu(menu);

    title_bar->resize(width(), title_bar->height());
}

void MainWindow::createMenu()
{
    /* Creates the main menu. */

    menu = new TDEPopupMenu();

    menu->insertTitle(i18n("Help"));

    actionCollection()->action(KStdAction::stdName(KStdAction::WhatsThis))->plug(menu);
    actionCollection()->action(KStdAction::stdName(KStdAction::AboutApp))->plug(menu);
    actionCollection()->action(KStdAction::stdName(KStdAction::AboutKDE))->plug(menu);

    menu->insertTitle(i18n("Quick Options"));

    actionCollection()->action(KStdAction::stdName(KStdAction::FullScreen))->plug(menu);

    screen_menu = new TDEPopupMenu(menu);

    if (TQApplication::desktop()->numScreens() > 1)
    {
        menu->insertItem(i18n("Open on screen"), screen_menu);
        connect(screen_menu, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotSetScreen(int)));
    }

    width_menu = new TDEPopupMenu(menu);
    menu->insertItem(i18n("Width"), width_menu);
    connect(width_menu, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotSetWidth(int)));

    height_menu = new TDEPopupMenu(menu);
    menu->insertItem(i18n("Height"), height_menu);
    connect(height_menu, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotSetHeight(int)));

    menu->insertItem(i18n("Keep open on focus change"), this, TQ_SLOT(slotSetFocusPolicy()), 0, Focus);

    menu->insertTitle(i18n("Settings"));

    actionCollection()->action("global_shortcuts")->plug(menu);
    actionCollection()->action(KStdAction::stdName(KStdAction::KeyBindings))->plug(menu);
    actionCollection()->action(KStdAction::stdName(KStdAction::Preferences))->plug(menu);
}

void MainWindow::updateWidthMenu()
{
    width_menu->clear();
    for (int i = 10; i <= 100; i += 10) width_menu->insertItem(TQString::number(i) + '%', i);
    width_menu->setItemChecked(Settings::width(), true);
}

void MainWindow::updateHeightMenu()
{
    height_menu->clear();
    for (int i = 10; i <= 100; i += 10) height_menu->insertItem(TQString::number(i) + '%', i);
    height_menu->setItemChecked(Settings::height(), true);
}

void MainWindow::updateScreenMenu()
{
    screen_menu->clear();
    screen_menu->insertItem(i18n("At mouse location"), 0);
    screen_menu->insertSeparator();
    for (int i = 1; i <= TQApplication::desktop()->numScreens(); i++)
        screen_menu->insertItem(i18n("Screen %1").arg(TQString::number(i)), i);
    screen_menu->setItemChecked(Settings::screen(), true);
}

void MainWindow::createSessionMenu()
{
    session_menu = new TDEPopupMenu();

    actionCollection()->action("add_tab")->plug(session_menu);
    actionCollection()->action("add_tab_twohorizontal")->plug(session_menu);
    actionCollection()->action("add_tab_twovertical")->plug(session_menu);
    actionCollection()->action("add_tab_quad")->plug(session_menu);
}

void MainWindow::slotUpdateTitle(const TQString& title)
{
    title_bar->setTitleText(title);
}


void MainWindow::slotIncreaseSizeW()
{
    /* Increase the window's width. */

    if (Settings::width() < 100)
    {
        Settings::setWidth(Settings::width() + 10);
        updateWidthMenu();
        slotUpdateSize();
    }
}

void MainWindow::slotDecreaseSizeW()
{
    /* Decrease the window's width. */

    if (Settings::width() > 10)
    {
        Settings::setWidth(Settings::width() - 10);
        updateWidthMenu();
        slotUpdateSize();
    }
}

void MainWindow::slotIncreaseSizeH()
{
    /* Increase the window's height. */

    if (Settings::height() < 100)
    {
        Settings::setHeight(Settings::height() + 10);
        updateHeightMenu();
        slotUpdateSize();
    }
}

void MainWindow::slotDecreaseSizeH()
{
    /* Decrease the window's height. */

    if (Settings::height() > 10)
    {
        Settings::setHeight(Settings::height() - 10);
        updateHeightMenu();
        slotUpdateSize();
    }
}

void MainWindow::slotSessionDestroyed(int id)
{
    if (is_shutting_down) return;

    sessions_stack.remove(id);

    if (tab_bar->removeItem(id) == -1)
        slotAddSession();
}

void MainWindow::slotToggleState()
{
    /* Toggles the window's open/closed state. */

    static int state = 1;

    if (timer.isActive())
        return;

    KWinModule twin(this);

    if (state)
    {
        // Open.

        initWindowProps();

        slotUpdateSize();

        show();

        KWin::forceActiveWindow(winId());
        connect(&timer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotIncreaseHeight()));
                initWindowProps();
        timer.start(10, false);
        state = !state;
    }
    else
    {
        // Close.

        if (!this->isActiveWindow() && focus_policy && Settings::focusontoggle())
        {
            KWin::forceActiveWindow(winId());
            return;
        }
        else if (full_screen)
            this->setWindowState( this->windowState() & ~TQt::WindowFullScreen);

        connect(&timer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotDecreaseHeight()));
        timer.start(10, false);
        state = !state;
    }
}

void MainWindow::slotIncreaseHeight()
{
    /* Increases the window's height. */

    int steps = (Settings::steps() == 0) ? 1 : Settings::steps();

    mask_height = (step++ * max_height) / steps;

    if (step >= steps)
    {
        step = steps;
        timer.stop();
        disconnect(&timer, TQ_SIGNAL(timeout()), 0, 0);

        mask_height = max_height;

        if (background_changed)
        {
            emit updateBackground();
            background_changed = false;
        }

        if (Settings::poll()) toggleMousePoll(false);
    }

    updateWindowMask();
    title_bar->move(0, mask_height);
}

void MainWindow::slotDecreaseHeight()
{
    /* Decreases the window's height. */

    int steps = (Settings::steps() == 0) ? 1 : Settings::steps();

    mask_height = (--step * max_height) / steps;

    if (step <= 0)
    {
        step = 0;
        timer.stop();
        disconnect(&timer, TQ_SIGNAL(timeout()), 0, 0);

        hide();

        if (Settings::poll()) toggleMousePoll(true);

    }

    updateWindowMask();
    title_bar->move(0, mask_height);
}

void MainWindow::slotInitSkin()
{
    TDEConfig config(locate("appdata", Settings::skin() + "/title.skin"));

    config.setGroup("Border");

    margin = config.readNumEntry("width", 0);

    back_widget->setBackgroundColor(TQColor(config.readNumEntry("red", 0),
                                           config.readNumEntry("green", 0),
                                           config.readNumEntry("blue", 0)));
}

void MainWindow::slotUpdateSize()
{
    if (full_screen) full_screen_action->activate();
    slotUpdateSize(Settings::width(), Settings::height(), Settings::location());
}

void MainWindow::slotUpdateSize(int new_width, int new_height, int new_location)
{
    /* Updates the window size. */

    int tmp_height;
    TQRect desk_area;

    // Xinerama aware work area.
    desk_area = getDesktopGeometry();
    max_height = desk_area.height() * new_height / 100;

    // Update the size of the components.
    setGeometry(desk_area.x() + desk_area.width() * new_location * (100 - new_width) / 10000,
                desk_area.y(), desk_area.width() * new_width / 100, max_height);

    max_height -= title_bar->height();
    title_bar->setGeometry(0, max_height, width(), title_bar->height());

    tmp_height = max_height;

    if (Settings::tabs())
    {
        tmp_height -= tab_bar->height();
        tab_bar->setGeometry(margin, tmp_height, width() - 2 * margin, tab_bar->height());
    }

    widgets_stack->setGeometry(margin, 0, width() - 2 * margin, tmp_height);

    back_widget->setGeometry(0, 0, width(), height());

    // Update the window mask.
    mask_height = (isVisible()) ? max_height : 0;
    updateWindowMask();
}

void MainWindow::moveEvent(TQMoveEvent* e)
{
    // If the screen setting isn't to appear on the screen the
    // mouse cursor is on, detect whether the screen number has
    // changed on this move event and update the internal set-
    // ting. Makes it play nice with the move-window-to-screen
    // twin shortcuts found in Lubos' Xinerama Improvements patch-
    // set.

    if (Settings::screen()
        && TQApplication::desktop()->screenNumber(this) != (Settings::screen()-1))
    {
        Settings::setScreen(TQApplication::desktop()->screenNumber(this)+1);

        updateScreenMenu();

        slotUpdateSize();
    }

    TDEMainWindow::moveEvent(e);
}

void MainWindow::slotSetFullScreen(bool state)
{
     if (state)
     {
        full_screen = true;
        slotUpdateSize(100, 100, Settings::location());
     }
     else
     {
        full_screen = false;
        slotUpdateSize();
     }
}

void MainWindow::slotUpdateFullScreen()
{
    if (full_screen_action->isChecked())
        showFullScreen();
    else
        this->setWindowState( this->windowState() & ~TQt::WindowFullScreen);
}

void MainWindow::slotSetFocusPolicy()
{
    slotSetFocusPolicy(!focus_policy);
}

void MainWindow::slotSetFocusPolicy(bool focus)
{
    Settings::setFocus(focus);
    focus_policy = Settings::focus();
    menu->setItemChecked(Focus, Settings::focus());
    title_bar->setFocusButtonEnabled(Settings::focus());
}

void MainWindow::slotSetWidth(int width)
{
    Settings::setWidth(width);
    slotUpdateSettings();
}

void MainWindow::slotSetHeight(int height)
{
    Settings::setHeight(height);
    slotUpdateSettings();
}

void MainWindow::slotSetScreen(int screen)
{
    Settings::setScreen(screen);
    slotUpdateSettings();
}

void MainWindow::slotSetAccessKey()
{
    if (full_screen) full_screen_action->activate();

    if (focus_policy == false) focus_policy = true;

    TDEConfig config(CONFIG_FILE);

    KKeyDialog::configure(global_key);

    global_key->updateConnections();
    global_key->writeSettings(&config);

    slotDialogFinished();
}

void MainWindow::slotSetControlKeys()
{
    if (full_screen) full_screen_action->activate();

    if (focus_policy == false) focus_policy = true;

    TDEConfig config(CONFIG_FILE);

    KKeyDialog::configure(actionCollection());

    actionCollection()->writeShortcutSettings("Shortcuts", &config);

    slotDialogFinished();
}

void MainWindow::slotUpdateBackgroundState()
{
    background_changed = true;
}

void MainWindow::slotUpdateSettings()
{
    slotInitSkin();

    title_bar->reloadSkin(Settings::skin());
    tab_bar->reloadSkin(Settings::skin());

    step = (isVisible()) ? Settings::steps() : 0;

    focus_policy = Settings::focus();

    if (Settings::tabs())
        tab_bar->show();
    else
        tab_bar->hide();

    slotUpdateSize();

    initWindowProps();

    menu->setItemChecked(Focus, Settings::focus());
    title_bar->setFocusButtonEnabled(Settings::focus());

    updateWidthMenu();
    updateHeightMenu();
    updateScreenMenu();
}

void MainWindow::slotOpenSettingsDialog()
{
    if (full_screen) full_screen_action->activate();

    if (focus_policy == false)
        focus_policy = true;

    if (TDEConfigDialog::showDialog("settings"))
        return;

    TDEConfigDialog* settings_dialog = new TDEConfigDialog(this, "settings", Settings::self());

    GeneralSettings* general_settings = new GeneralSettings(settings_dialog, "General");
    settings_dialog->addPage(general_settings, i18n("General"), "package_settings");
    connect(general_settings, TQ_SIGNAL(updateSize(int, int, int)), this, TQ_SLOT(slotUpdateSize(int, int, int)));

    SkinSettings* skin_settings = new SkinSettings(settings_dialog, "Skins", use_translucency);
    settings_dialog->addPage(skin_settings, i18n("Skins"), "style");
    connect(skin_settings, TQ_SIGNAL(settingsChanged()), settings_dialog, TQ_SIGNAL(settingsChanged()));
    connect(settings_dialog, TQ_SIGNAL(closeClicked()), skin_settings, TQ_SLOT(slotResetSelection()));
    connect(settings_dialog, TQ_SIGNAL(cancelClicked()), skin_settings, TQ_SLOT(slotResetSelection()));

    connect(settings_dialog, TQ_SIGNAL(settingsChanged()), this, TQ_SLOT(slotUpdateSettings()));
    connect(settings_dialog, TQ_SIGNAL(hidden()), this, TQ_SLOT(slotDialogFinished()));

    settings_dialog->show();
}

void MainWindow::slotOpenFirstRunDialog()
{
    if (!first_run_dialog)
    {
        first_run_dialog = new KDialogBase(this,
            "First Run Dialog", true, i18n("First Run"),
            KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true);
        connect(first_run_dialog, TQ_SIGNAL(okClicked()), this, TQ_SLOT(slotFirstRunDialogOK()));
        connect(first_run_dialog, TQ_SIGNAL(cancelClicked()), this, TQ_SLOT(slotFirstRunDialogCancel()));
        connect(first_run_dialog, TQ_SIGNAL(closeClicked()), this, TQ_SLOT(slotFirstRunDialogCancel()));
        connect(first_run_dialog, TQ_SIGNAL(hidden()), this, TQ_SLOT(slotDialogFinished()));

        FirstRunDialog* first_run_dialog_page = new FirstRunDialog(first_run_dialog);
        first_run_dialog_page->setMinimumSize(first_run_dialog_page->sizeHint());
        first_run_dialog_page->setShortcut(global_key->shortcut("AccessKey"));

        first_run_dialog->setMainWidget(first_run_dialog_page);
        first_run_dialog->adjustSize();
        first_run_dialog->disableResize();
    }

    if (focus_policy == false)
        focus_policy = true;

    first_run_dialog->show();
}

void MainWindow::slotFirstRunDialogOK()
{
    if (!first_run_dialog)
        return;

    FirstRunDialog* first_run_dialog_page =
        static_cast<FirstRunDialog*>(first_run_dialog->mainWidget());

    if (!first_run_dialog_page)
        return;


    if (first_run_dialog_page->shortcut() != global_key->shortcut("AccessKey"))
    {
        TDEConfig config(CONFIG_FILE);
        global_key->setShortcut("AccessKey", first_run_dialog_page->shortcut());
        global_key->updateConnections();
        global_key->writeSettings(&config);
    }

    Settings::setFirstrun(false);
    Settings::writeConfig();
}

void MainWindow::slotFirstRunDialogCancel()
{
    Settings::setFirstrun(false);
    Settings::writeConfig();
}

void MainWindow::slotOpenAboutApp()
{
    if (!about_app)
    {
        about_app = new TDEAboutApplication(this, "About Yakuake");
        connect(about_app, TQ_SIGNAL(hidden()), this, TQ_SLOT(slotDialogFinished()));
    }

    if (full_screen) full_screen_action->activate();

    if (focus_policy == false)
        focus_policy = true;

    about_app->show();
}

void MainWindow::slotOpenAboutKDE()
{
    if (!about_kde)
    {
        about_kde = new TDEAboutKDE(this, "About KDE");
        connect(about_kde, TQ_SIGNAL(hidden()), this, TQ_SLOT(slotDialogFinished()));
    }

    if (full_screen) full_screen_action->activate();

    if (focus_policy == false)
        focus_policy = true;

    about_kde->show();
}

void MainWindow::slotDialogFinished()
{
    slotUpdateSize();

    focus_policy = Settings::focus();

    KWin::activateWindow(winId());
}

void MainWindow::slotPollMouse()
{
    TQPoint pos = TQCursor::pos();

    if (pos.y() == 0)
    {
        if (Settings::screen() == 0) 
            slotToggleState(); // no need to check x since yakuake should open where the mouse pointer is
        else if (pos.x() >= getDesktopGeometry().x() && pos.x() <= (getDesktopGeometry().x() + getDesktopGeometry().width()))
            slotToggleState();
    }
}

void MainWindow::toggleMousePoll(bool poll)
{
    if (poll)
        poller.start(Settings::pollinterval());
    else
        poller.stop();
}
