/*****************************************************************
 KWin - the KDE window manager
 This file is part of the KDE project.

Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>

You can Freely distribute this program under the GNU General Public
License. See the file "COPYING" for the exact licensing terms.
******************************************************************/

#include "options.h"

#ifndef KCMRULES

#include <tqpalette.h>
#include <tqpixmap.h>
#include <tdeapplication.h>
#include <tdeconfig.h>
#include <tdeglobal.h>
#include <tdeglobalsettings.h>
#include <tqtooltip.h>

#include "client.h"

#endif

namespace KWinInternal
{

#ifndef KCMRULES

Options::Options()
    :   active_borders( 0 ),
        active_border_delay(0)
    {
    d = new KDecorationOptionsPrivate;
    d->defaultKWinSettings();
    updateSettings();
    }

Options::~Options()
    {
    delete d;
    }

unsigned long Options::updateSettings()
    {
    TDEConfig *config = TDEGlobal::config();
    unsigned long changed = 0;
    changed |= d->updateKWinSettings( config ); // read decoration settings

    config->setGroup( "Windows" );
    moveMode   = stringToMoveResizeMode(config->readEntry("MoveMode",   "Opaque"));
    resizeMode = stringToMoveResizeMode(config->readEntry("ResizeMode", "Opaque"));
    tilingMode = stringToMoveResizeMode(config->readEntry("TilingMode", "Opaque"));
    show_geometry_tip = config->readBoolEntry("GeometryTip", false);
    reset_maximized_window_geometry = config->readBoolEntry("ResetMaximizedWindowGeometry", false);
    tabboxOutline = config->readBoolEntry("TabboxOutline", true);

    TQString val;

    val = config->readEntry ("FocusPolicy", "ClickToFocus");
    focusPolicy = ClickToFocus; // what a default :-)
    if ( val == "FocusFollowsMouse" )
        focusPolicy = FocusFollowsMouse;
    else if ( val == "FocusUnderMouse" )
        focusPolicy = FocusUnderMouse;
    else if ( val == "FocusStrictlyUnderMouse" )
        focusPolicy = FocusStrictlyUnderMouse;

    val = config->readEntry ("AltTabStyle", "KDE");
    altTabStyle = KDE; // what a default :-)
    if ( val == "CDE" )
        altTabStyle = CDE;

    separateScreenFocus = config->readBoolEntry( "SeparateScreenFocus", false );
    activeMouseScreen = config->readBoolEntry( "ActiveMouseScreen", focusPolicy != ClickToFocus );

    rollOverDesktops = config->readBoolEntry("RollOverDesktops", true);

//    focusStealingPreventionLevel = config->readNumEntry( "FocusStealingPreventionLevel", 2 );
    // TODO use low level for now
    focusStealingPreventionLevel = config->readNumEntry( "FocusStealingPreventionLevel", 1 );
    focusStealingPreventionLevel = KMAX( 0, KMIN( 4, focusStealingPreventionLevel ));
    if( !focusPolicyIsReasonable()) // #48786, comments #7 and later
        focusStealingPreventionLevel = 0;

    TDEConfig *gc = new TDEConfig("kdeglobals", false, false);
    gc->setGroup("Windows");
    xineramaEnabled = gc->readBoolEntry ("XineramaEnabled", true );
    xineramaPlacementEnabled = gc->readBoolEntry ("XineramaPlacementEnabled", true);
    xineramaMovementEnabled = gc->readBoolEntry ("XineramaMovementEnabled", true);
    xineramaMaximizeEnabled = gc->readBoolEntry ("XineramaMaximizeEnabled", true);
    xineramaFullscreenEnabled = gc->readBoolEntry ("XineramaFullscreenEnabled", true);
    delete gc;

    placement = Placement::policyFromString( config->readEntry("Placement"), true );
    xineramaPlacementScreen = KCLAMP( config->readNumEntry( "XineramaPlacementScreen", -1 ),
        -1, tqApp->desktop()->numScreens() - 1 );

    animateShade = config->readBoolEntry("AnimateShade", true );
    animateMinimize = config->readBoolEntry("AnimateMinimize", true );
    animateMinimizeSpeed = config->readNumEntry("AnimateMinimizeSpeed", 5 );

    if( focusPolicy == ClickToFocus )
        {
        autoRaise = false;
        autoRaiseInterval = 0;
        delayFocus = false;
        delayFocusInterval = 0;
        }
    else
        {
        autoRaise = config->readBoolEntry("AutoRaise", false );
        autoRaiseInterval = config->readNumEntry("AutoRaiseInterval", 0 );
        delayFocus = config->readBoolEntry("DelayFocus", false );
        delayFocusInterval = config->readNumEntry("DelayFocusInterval", 0 );
        }

    shadeHover = config->readBoolEntry("ShadeHover", false );
    shadeHoverInterval = config->readNumEntry("ShadeHoverInterval", 250 );

    // important: autoRaise implies ClickRaise
    clickRaise = autoRaise || config->readBoolEntry("ClickRaise", true );

    borderSnapZone = config->readNumEntry("BorderSnapZone", 10);
    windowSnapZone = config->readNumEntry("WindowSnapZone", 10);
    snapOnlyWhenOverlapping=config->readBoolEntry("SnapOnlyWhenOverlapping",false);

    // active borders: compatibility with old option names (Electric*)
    active_borders = config->readNumEntry("ActiveBorders", -1);
    if (active_borders == -1) {
        active_borders = config->readNumEntry("ElectricBorders", 0);
    }
    active_border_delay = config->readNumEntry("ActiveBorderDelay", -1);
    if (active_border_delay == -1) {
        active_border_delay = config->readNumEntry("ElectricBorderDelay", 150);
    }
    active_border_distance = config->readNumEntry("ActiveBorderDistance", 10);

    OpTitlebarDblClick = windowOperation( config->readEntry("TitlebarDoubleClickCommand", "Shade"), true );
    d->OpMaxButtonLeftClick = windowOperation( config->readEntry("MaximizeButtonLeftClickCommand", "Maximize"), true );
    d->OpMaxButtonMiddleClick = windowOperation( config->readEntry("MaximizeButtonMiddleClickCommand", "Maximize (vertical only)"), true );
    d->OpMaxButtonRightClick = windowOperation( config->readEntry("MaximizeButtonRightClickCommand", "Maximize (horizontal only)"), true );

    ignorePositionClasses = config->readListEntry("IgnorePositionClasses");
    ignoreFocusStealingClasses = config->readListEntry("IgnoreFocusStealingClasses");
    // Qt3.2 and older had resource class all lowercase, but Qt3.3 has it capitalized
    // therefore Client::resourceClass() forces lowercase, force here lowercase as well
    for( TQStringList::Iterator it = ignorePositionClasses.begin();
         it != ignorePositionClasses.end();
         ++it )
        (*it) = (*it).lower();
    for( TQStringList::Iterator it = ignoreFocusStealingClasses.begin();
         it != ignoreFocusStealingClasses.end();
         ++it )
        (*it) = (*it).lower();

    killPingTimeout = config->readNumEntry( "KillPingTimeout", 5000 );
    hideUtilityWindowsForInactive = config->readBoolEntry( "HideUtilityWindowsForInactive", true );
    showDesktopIsMinimizeAll = config->readBoolEntry( "ShowDesktopIsMinimizeAll", false );

    // Mouse bindings
    config->setGroup( "MouseBindings");
    CmdActiveTitlebar1 = mouseCommand(config->readEntry("CommandActiveTitlebar1","Raise"), true );
    CmdActiveTitlebar2 = mouseCommand(config->readEntry("CommandActiveTitlebar2","Lower"), true );
    CmdActiveTitlebar3 = mouseCommand(config->readEntry("CommandActiveTitlebar3","Operations menu"), true );
    CmdInactiveTitlebar1 = mouseCommand(config->readEntry("CommandInactiveTitlebar1","Activate and raise"), true );
    CmdInactiveTitlebar2 = mouseCommand(config->readEntry("CommandInactiveTitlebar2","Activate and lower"), true );
    CmdInactiveTitlebar3 = mouseCommand(config->readEntry("CommandInactiveTitlebar3","Operations menu"), true );
    CmdTitlebarWheel = mouseWheelCommand(config->readEntry("CommandTitlebarWheel","Nothing"));
    CmdTitlebarRevWheel = config->readBoolEntry("CommandTitlebarReverseWheel", false);
    CmdWindow1 = mouseCommand(config->readEntry("CommandWindow1","Activate, raise and pass click"), false );
    CmdWindow2 = mouseCommand(config->readEntry("CommandWindow2","Activate and pass click"), false );
    CmdWindow3 = mouseCommand(config->readEntry("CommandWindow3","Activate and pass click"), false );
    CmdAllModKey = (config->readEntry("CommandAllKey","Alt") == "Meta") ? TQt::Key_Meta : TQt::Key_Alt;
    CmdAll1 = mouseCommand(config->readEntry("CommandAll1","Move"), false );
    CmdAll2 = mouseCommand(config->readEntry("CommandAll2","Toggle raise and lower"), false );
    CmdAll3 = mouseCommand(config->readEntry("CommandAll3","Resize"), false );
    CmdAllWheel = mouseWheelCommand(config->readEntry("CommandAllWheel","Nothing"));
    CmdAllRevWheel = config->readBoolEntry("CommandAllReverseWheel", false);

    //translucency settings
    config->setGroup( "Notification Messages" );
    useTranslucency = config->readBoolEntry("UseTranslucency", false);
    config->setGroup( "Translucency");
    translucentActiveWindows = config->readBoolEntry("TranslucentActiveWindows", false);
    activeWindowOpacity = uint((config->readNumEntry("ActiveWindowOpacity", 100)/100.0)*0xFFFFFFFF);
    translucentInactiveWindows = config->readBoolEntry("TranslucentInactiveWindows", false);
    inactiveWindowOpacity = uint((config->readNumEntry("InactiveWindowOpacity", 75)/100.0)*0xFFFFFFFF);
    translucentMovingWindows = config->readBoolEntry("TranslucentMovingWindows", false);
    movingWindowOpacity = uint((config->readNumEntry("MovingWindowOpacity", 50)/100.0)*0xFFFFFFFF);
    translucentDocks = config->readBoolEntry("TranslucentDocks", false);
    dockOpacity = uint((config->readNumEntry("DockOpacity", 80)/100.0)*0xFFFFFFFF);
    keepAboveAsActive = config->readBoolEntry("TreatKeepAboveAsActive", true);
    //TODO: remove this variable
    useTitleMenuSlider = true;
    activeWindowShadowSize = config->readNumEntry("ActiveWindowShadowSize",  2*100);
    inactiveWindowShadowSize = config->readNumEntry("InactiveWindowShadowSize",  1*100);
    dockShadowSize = config->readNumEntry("DockShadowSize", 0*100);
    menuShadowSize = config->readNumEntry("MenuShadowSize", 1*100);
    removeShadowsOnMove = config->readBoolEntry("RemoveShadowsOnMove", false);
    removeShadowsOnResize = config->readBoolEntry("RemoveShadowsOnResize", false);
    onlyDecoTranslucent = config->readBoolEntry("OnlyDecoTranslucent",false);
    resetKompmgr = config->readBoolEntry("ResetKompmgr", false);
    if (resetKompmgr)
        config->writeEntry("ResetKompmgr",false);

     // window drop shadows
    config->setGroup("Style");
    shadow_colour = config->readColorEntry("ShadowColour", &TQt::black);
    shadow_docks = config->readBoolEntry("ShadowDocks", false);
    shadow_menus = config->readBoolEntry("ShadowMenus", false);
    shadow_overrides = config->readBoolEntry("ShadowOverrides", false);
    shadow_topMenus = config->readBoolEntry("ShadowTopMenus", false);
    shadow_inactive_colour = config->readColorEntry("InactiveShadowColour", &TQt::black);
    shadow_inactive_enabled = config->readBoolEntry("InactiveShadowEnabled", false);
    shadow_inactive_opacity = config->readDoubleNumEntry("InactiveShadowOpacity", 0.70);
    shadow_inactive_thickness = config->readNumEntry("InactiveShadowThickness", 5);
    shadow_inactive_x_offset = config->readNumEntry("InactiveShadowXOffset", 0);
    shadow_inactive_y_offset = config->readNumEntry("InactiveShadowYOffset", 5);
    shadow_enabled = config->readBoolEntry("ShadowEnabled", false);
    shadow_opacity = config->readDoubleNumEntry("ShadowOpacity", 0.70);
    shadow_thickness = config->readNumEntry("ShadowThickness", 10);
    shadow_x_offset = config->readNumEntry("ShadowXOffset", 0);
    shadow_y_offset = config->readNumEntry("ShadowYOffset", 10);


    // Read button tooltip animation effect from kdeglobals
    // Since we want to allow users to enable window decoration tooltips
    // and not tdestyle tooltips and vise-versa, we don't read the
    // "EffectNoTooltip" setting from kdeglobals.
    TDEConfig globalConfig("kdeglobals");
    globalConfig.setGroup("KDE");
    topmenus = globalConfig.readBoolEntry( "macStyle", false );

    TDEConfig kdesktopcfg( "kdesktoprc", true );
    kdesktopcfg.setGroup( "Menubar" );
    desktop_topmenu = kdesktopcfg.readBoolEntry( "ShowMenubar", false );
    if( desktop_topmenu )
        topmenus = true;

    TQToolTip::setGloballyEnabled( d->show_tooltips );

    return changed;
    }


// restricted should be true for operations that the user may not be able to repeat
// if the window is moved out of the workspace (e.g. if the user moves a window
// by the titlebar, and moves it too high beneath Kicker at the top edge, they
// may not be able to move it back, unless they know about Alt+LMB)
Options::WindowOperation Options::windowOperation(const TQString &name, bool restricted )
    {
    if (name == "Move")
        return restricted ? MoveOp : UnrestrictedMoveOp;
    else if (name == "Resize")
        return restricted ? ResizeOp : UnrestrictedResizeOp;
    else if (name == "Maximize")
        return MaximizeOp;
    else if (name == "Minimize")
        return MinimizeOp;
    else if (name == "Close")
        return CloseOp;
    else if (name == "OnAllDesktops")
        return OnAllDesktopsOp;
    else if (name == "Shade")
        return ShadeOp;
    else if (name == "Operations")
        return OperationsOp;
    else if (name == "Maximize (vertical only)")
        return VMaximizeOp;
    else if (name == "Maximize (horizontal only)")
        return HMaximizeOp;
    else if (name == "Lower")
        return LowerOp;
    else if (name == "Shadow")
        return ShadowOp;
    return NoOp;
    }

Options::MouseCommand Options::mouseCommand(const TQString &name, bool restricted )
    {
    TQString lowerName = name.lower();
    if (lowerName == "raise") return MouseRaise;
    if (lowerName == "lower") return MouseLower;
    if (lowerName == "operations menu") return MouseOperationsMenu;
    if (lowerName == "toggle raise and lower") return MouseToggleRaiseAndLower;
    if (lowerName == "activate and raise") return MouseActivateAndRaise;
    if (lowerName == "activate and lower") return MouseActivateAndLower;
    if (lowerName == "activate") return MouseActivate;
    if (lowerName == "activate, raise and pass click") return MouseActivateRaiseAndPassClick;
    if (lowerName == "activate and pass click") return MouseActivateAndPassClick;
    if (lowerName == "activate, raise and move")
        return restricted ? MouseActivateRaiseAndMove : MouseActivateRaiseAndUnrestrictedMove;
    if (lowerName == "move") return restricted ? MouseMove : MouseUnrestrictedMove;
    if (lowerName == "resize") return restricted ? MouseResize : MouseUnrestrictedResize;
    if (lowerName == "shade") return MouseShade;
    if (lowerName == "minimize") return MouseMinimize;
    if (lowerName == "nothing") return MouseNothing;
    return MouseNothing;
    }

Options::MouseWheelCommand Options::mouseWheelCommand(const TQString &name)
    {
    TQString lowerName = name.lower();
    if (lowerName == "raise/lower") return MouseWheelRaiseLower;
    if (lowerName == "shade/unshade") return MouseWheelShadeUnshade;
    if (lowerName == "maximize/restore") return MouseWheelMaximizeRestore;
    if (lowerName == "above/below") return MouseWheelAboveBelow;
    if (lowerName == "previous/next desktop") return MouseWheelPreviousNextDesktop;
    if (lowerName == "change opacity") return MouseWheelChangeOpacity;
    return MouseWheelNothing;
    }

bool Options::showGeometryTip()
    {
    return show_geometry_tip;
    }

bool Options::resetMaximizedWindowGeometry()
    {
    return reset_maximized_window_geometry;
    }

TQColor &Options::shadowColour(bool active)
    {
    return active ? shadow_colour : shadow_inactive_colour;
    }

bool Options::shadowWindowType(NET::WindowType t)
    {
    bool retval;

    switch (t)
        {
        case NET::Dialog:
        case NET::Normal:
            retval = true;
            break;
        case NET::Desktop:
        case NET::Menu:
            retval = shadow_menus;
            break;
        case NET::Toolbar:
            retval = false;
            break;
        case NET::Dock:
            retval = shadow_docks;
            break;
        case NET::Override:
            retval = shadow_overrides;
            break;
        case NET::TopMenu:
            retval = shadow_topMenus;
            break;
        default:
            retval = false;
            break;
        }

    return retval;
    }

bool Options::shadowEnabled(bool active)
    {
    return active ? shadow_enabled :
        (shadow_enabled && shadow_inactive_enabled);
    }

double Options::shadowOpacity(bool active)
    {
    return active ? shadow_opacity : shadow_inactive_opacity;
    }

int Options::shadowThickness(bool active)
    {
    return active ? shadow_thickness : shadow_inactive_thickness;
    }

int Options::shadowXOffset(bool active)
    {
    return active ? shadow_x_offset : shadow_inactive_x_offset;
    }

int Options::shadowYOffset(bool active)
    {
    return active ? shadow_y_offset : shadow_inactive_y_offset;
    }

int Options::activeBorders()
    {
    return active_borders;
    }

int Options::activeBorderDelay()
    {
    return active_border_delay;
    }

int Options::borderActivationDistance()
    {
    return active_border_distance;
    }

bool Options::checkIgnoreFocusStealing( const Client* c )
    {
    return ignoreFocusStealingClasses.contains(TQString::fromLatin1(c->resourceClass()));
    }

Options::MouseCommand Options::wheelToMouseCommand( MouseWheelCommand com, int delta, bool revDir )
    {
    if (revDir)
    {
      delta = -delta;
    }
    switch( com )
        {
        case MouseWheelRaiseLower:
            return delta > 0 ? MouseRaise : MouseLower;
        case MouseWheelShadeUnshade:
            return delta > 0 ? MouseSetShade : MouseUnsetShade;
        case MouseWheelMaximizeRestore:
            return delta > 0 ? MouseMaximize : MouseRestore;
        case MouseWheelAboveBelow:
            return delta > 0 ? MouseAbove : MouseBelow;
        case MouseWheelPreviousNextDesktop:
            return delta > 0 ? MousePreviousDesktop : MouseNextDesktop;
        case MouseWheelChangeOpacity:
            return delta > 0 ? MouseOpacityMore : MouseOpacityLess;
        default:
            return MouseNothing;
        }
    }
#endif

Options::MoveResizeMode Options::stringToMoveResizeMode( const TQString& s )
    {
    return s == "Opaque" ? Opaque : Transparent;
    }

const char* Options::moveResizeModeToString( MoveResizeMode mode )
    {
    return mode == Opaque ? "Opaque" : "Transparent";
    }

} // namespace
