diff options
Diffstat (limited to 'kicker/taskmanager/taskmanager.cpp')
| -rw-r--r-- | kicker/taskmanager/taskmanager.cpp | 1521 | 
1 files changed, 1521 insertions, 0 deletions
| diff --git a/kicker/taskmanager/taskmanager.cpp b/kicker/taskmanager/taskmanager.cpp new file mode 100644 index 000000000..dd9364c0e --- /dev/null +++ b/kicker/taskmanager/taskmanager.cpp @@ -0,0 +1,1521 @@ +/***************************************************************** + +Copyright (c) 2000 Matthias Elter <elter@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qapplication.h> +#include <qcursor.h> +#include <qimage.h> +#include <qtimer.h> + +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kiconloader.h> +#include <klocale.h> +// #include <kpixmapio.h> +#include <kstaticdeleter.h> +#include <kwinmodule.h> +#include <kxerrorhandler.h> +#include <netwm.h> + +#include "taskmanager.h" +#include "taskmanager.moc" + +TaskManager* TaskManager::m_self = 0; +static KStaticDeleter<TaskManager> staticTaskManagerDeleter; +uint TaskManager::m_xCompositeEnabled = 0; + +TaskManager* TaskManager::the() +{ +    if (!m_self) +    { +        staticTaskManagerDeleter.setObject(m_self, new TaskManager()); +    } +    return m_self; +} + +TaskManager::TaskManager() +    : QObject(), +      _active(0), +      _startup_info(0), +      m_winModule(new KWinModule()), +      m_trackGeometry(false) +{ +    KGlobal::locale()->insertCatalogue("libtaskmanager"); +    connect(m_winModule, SIGNAL(windowAdded(WId)), +            this,        SLOT(windowAdded(WId))); +    connect(m_winModule, SIGNAL(windowRemoved(WId)), +            this,        SLOT(windowRemoved(WId))); +    connect(m_winModule, SIGNAL(activeWindowChanged(WId)), +            this,        SLOT(activeWindowChanged(WId))); +    connect(m_winModule, SIGNAL(currentDesktopChanged(int)), +            this,        SLOT(currentDesktopChanged(int))); +    connect(m_winModule, SIGNAL(windowChanged(WId,unsigned int)), +            this,        SLOT(windowChanged(WId,unsigned int))); + +    // register existing windows +    const QValueList<WId> windows = m_winModule->windows(); +    QValueList<WId>::ConstIterator end(windows.end()); +    for (QValueList<WId>::ConstIterator it = windows.begin(); it != end; ++it) +    { +        windowAdded(*it); +    } + +    // set active window +    WId win = m_winModule->activeWindow(); +    activeWindowChanged(win); +    configure_startup(); +} + +TaskManager::~TaskManager() +{ +    KGlobal::locale()->removeCatalogue("libtaskmanager"); +} + +void TaskManager::configure_startup() +{ +    KConfig c("klaunchrc", true); +    c.setGroup("FeedbackStyle"); +    if (!c.readBoolEntry("TaskbarButton", true)) +        return; +    _startup_info = new KStartupInfo( KStartupInfo::CleanOnCantDetect, this ); +    connect( _startup_info, +        SIGNAL( gotNewStartup( const KStartupInfoId&, const KStartupInfoData& )), +        SLOT( gotNewStartup( const KStartupInfoId&, const KStartupInfoData& ))); +    connect( _startup_info, +        SIGNAL( gotStartupChange( const KStartupInfoId&, const KStartupInfoData& )), +        SLOT( gotStartupChange( const KStartupInfoId&, const KStartupInfoData& ))); +    connect( _startup_info, +        SIGNAL( gotRemoveStartup( const KStartupInfoId&, const KStartupInfoData& )), +        SLOT( killStartup( const KStartupInfoId& ))); +    c.setGroup( "TaskbarButtonSettings" ); +    _startup_info->setTimeout( c.readUnsignedNumEntry( "Timeout", 30 )); +} + +#ifdef THUMBNAILING_POSSIBLE +void TaskManager::setXCompositeEnabled(bool state) +{ +    Display *dpy = QPaintDevice::x11AppDisplay(); + +    if (!state) +    { +        if (!--m_xCompositeEnabled) +        { +            // unredirecting windows +            for (int i = 0; i < ScreenCount(dpy); i++) +            { +                XCompositeUnredirectSubwindows(dpy, RootWindow(dpy, i), +                                                CompositeRedirectAutomatic); +            } +        } +        return; +    } + +    if (m_xCompositeEnabled) +    { +        // we don't unlearn riding bike ;) +        m_xCompositeEnabled++; +        return; +    } + +    // XComposite extension check +    int event_base, error_base; +    if (!XCompositeQueryExtension(dpy, &event_base, &error_base)) +    { +        return; +    } + +    int major = 0, minor = 99; // The highest version we support +    XCompositeQueryVersion(dpy, &major, &minor); + +    // We use XCompositeNameWindowPixmap(), i.e.  we need at least +    // version 0.2. +    if (major == 0 && minor < 2) +    { +        return; +    } + +    // XRender extension check +    if (!XRenderQueryExtension(dpy, &event_base, &error_base)) +    { +        return; +    } + +    major = 0, minor = 99; // The highest version we support +    XRenderQueryVersion(dpy, &major, &minor); + +    // We use SetPictureTransform() and SetPictureFilter(), i.e. we +    // need at least version 0.6. +    if (major == 0 && minor < 6) +    { +        return; +    } + +    // XFixes extension check +    if (!XFixesQueryExtension(dpy, &event_base, &error_base)) +    { +        return; +    } + +    major = 3, minor = 99; // The highest version we support +    XFixesQueryVersion(dpy, &major, &minor); + +    // We use Region objects, i.e. we need at least version 2.0. +    if (major < 2) +    { +        return; +    } + +    // if we get here, we've got usable extensions +    m_xCompositeEnabled++; + +    // redirecting windows to backing pixmaps +    for (int i = 0; i < ScreenCount(dpy); i++) +    { +        XCompositeRedirectSubwindows(dpy, RootWindow(dpy, i), +                                     CompositeRedirectAutomatic); +    } + +    Task::Dict::iterator itEnd = m_tasksByWId.end(); +    for (Task::Dict::iterator it = m_tasksByWId.begin(); it != itEnd; ++it) +    { +        it.data()->updateWindowPixmap(); +    } +} +#else // THUMBNAILING_POSSIBLE +void TaskManager::setXCompositeEnabled(bool) +{ +} +#endif // !THUMBNAILING_POSSIBLE + +Task::Ptr TaskManager::findTask(WId w) +{ +    // TODO: might be able to be made more efficient if +    // we check to see if w is a transient first? +    // profiling would say whether this is worth the effort + +    Task::Dict::iterator it = m_tasksByWId.begin(); +    Task::Dict::iterator itEnd = m_tasksByWId.end(); + +    for (; it != itEnd; ++it) +    { +        if (it.key() == w || it.data()->hasTransient(w)) +        { +            return it.data(); +        } +    } + +    return 0; +} + +Task::Ptr TaskManager::findTask(int desktop, const QPoint& p) +{ +    QValueList<WId> list = winModule()->stackingOrder(); + +    Task::Ptr task = 0; +    int currentIndex = -1; +    Task::Dict::iterator itEnd = m_tasksByWId.end(); +    for (Task::Dict::iterator it = m_tasksByWId.begin(); it != itEnd; ++it) +    { +        Task::Ptr t = it.data(); +        if (!t->isOnAllDesktops() && t->desktop() != desktop) +        { +            continue; +        } + +        if (t->isIconified() || t->isShaded()) +        { +            continue; +        } + +        if (t->geometry().contains(p)) +        { +            int index = list.findIndex(t->window()); +            if (index > currentIndex) +            { +                currentIndex = index; +                task = t; +            } +        } +    } + +    return task; +} + +void TaskManager::windowAdded(WId w ) +{ +    NETWinInfo info(qt_xdisplay(),  w, qt_xrootwin(), +                    NET::WMWindowType | NET::WMPid | NET::WMState); + +    // ignore NET::Tool and other special window types +    NET::WindowType wType = +        info.windowType( NET::NormalMask | NET::DesktopMask | NET::DockMask | +                         NET::ToolbarMask | NET::MenuMask | NET::DialogMask | +                         NET::OverrideMask | NET::TopMenuMask | +                         NET::UtilityMask | NET::SplashMask ); + +    if (wType != NET::Normal && +        wType != NET::Override && +        wType != NET::Unknown && +        wType != NET::Dialog && +        wType != NET::Utility) +    { +        return; +    } + +    // ignore windows that want to be ignored by the taskbar +    if ((info.state() & NET::SkipTaskbar) != 0) +    { +        _skiptaskbar_windows.push_front( w ); // remember them though +        return; +    } + +    Window transient_for_tmp; +    if (XGetTransientForHint( qt_xdisplay(), (Window) w, &transient_for_tmp )) +    { +        WId transient_for = (WId) transient_for_tmp; + +        // check if it's transient for a skiptaskbar window +        if( _skiptaskbar_windows.contains( transient_for )) +            return; + +        // lets see if this is a transient for an existing task +        if( transient_for != qt_xrootwin() +            && transient_for != 0 +            && wType != NET::Utility ) +        { +            Task::Ptr t = findTask(transient_for); +            if (t) +            { +                if (t->window() != w) +                { +                    t->addTransient(w, info); +                    // kdDebug() << "TM: Transient " << w << " added for Task: " << t->window() << endl; +                } +                return; +            } +        } +    } + +    Task::Ptr t = new Task(w, this); +    m_tasksByWId[w] = t; + +    // kdDebug() << "TM: Task added for WId: " << w << endl; + +    emit taskAdded(t); +} + +void TaskManager::windowRemoved(WId w) +{ +    _skiptaskbar_windows.remove(w); + +    // find task +    Task::Ptr t = findTask(w); +    if (!t) +    { +        return; +    } + +    if (t->window() == w) +    { +        m_tasksByWId.remove(w); +        emit taskRemoved(t); + +        if (t == _active) +        { +            _active = 0; +        } + +        //kdDebug() << "TM: Task for WId " << w << " removed." << endl; +    } +    else +    { +        t->removeTransient(w); +        //kdDebug() << "TM: Transient " << w << " for Task " << t->window() << " removed." << endl; +    } +} + +void TaskManager::windowChanged(WId w, unsigned int dirty) +{ +    if (dirty & NET::WMState) +    { +        NETWinInfo info (qt_xdisplay(),  w, qt_xrootwin(), +                         NET::WMState | NET::XAWMState); +        if (info.state() & NET::SkipTaskbar) +        { +            windowRemoved(w); +            _skiptaskbar_windows.push_front(w); +            return; +        } +        else +        { +            _skiptaskbar_windows.remove(w); +            if (info.mappingState() != NET::Withdrawn && !findTask(w)) +            { +                // skipTaskBar state was removed and the window is still +                // mapped, so add this window +                windowAdded( w ); +            } +        } +    } + +    // check if any state we are interested in is marked dirty +    if (!(dirty & (NET::WMVisibleName | NET::WMName | NET::WMIcon | +                  NET::WMState | NET::XAWMState | NET::WMDesktop) || +          (m_trackGeometry && dirty & NET::WMGeometry))) +    { +        return; +    } + +    // find task +    Task::Ptr t = findTask(w); +    if (!t) +    { +        return; +    } + +    //kdDebug() << "TaskManager::windowChanged " << w << " " << dirty << endl; + +    if (dirty & NET::WMState) +    { +        t->updateDemandsAttentionState(w); +    } + +    // refresh icon pixmap if necessary +    if (dirty & NET::WMIcon) +    { +        t->refreshIcon(); + +        // we're done with the icon processing, don't pass this on anymore +        dirty ^= NET::WMIcon; +    } + +    if (dirty) +    { +        // only refresh this stuff if we have other changes besides icons +        t->refresh(dirty); +    } + +    if (dirty & (NET::WMDesktop | NET::WMState | NET::XAWMState)) +    { +        // moved to different desktop or is on all or change in iconification/withdrawnnes +        emit windowChanged(t); + +        if (m_xCompositeEnabled && dirty & NET::WMState) +        { +            // update on restoring a minimized window +            updateWindowPixmap(w); +        } + +    } +    else if (dirty & NET::WMGeometry) +    { +        emit windowChangedGeometry(t); + +        if (m_xCompositeEnabled) +        { +            // update on size changes, not on task drags +            updateWindowPixmap(w); +        } + +    } +} + +void TaskManager::updateWindowPixmap(WId w) +{ +    if (!m_xCompositeEnabled) +    { +        return; +    } + +    Task::Ptr task = findTask(w); +    if (task) +    { +        task->updateWindowPixmap(); +    } +} + +void TaskManager::activeWindowChanged(WId w ) +{ +    //kdDebug() << "TaskManager::activeWindowChanged" << endl; + +    Task::Ptr t = findTask( w ); +    if (!t) { +        if (_active) { +            _active->setActive(false); +            _active = 0; +        } +    } +    else { +        if (_active) +            _active->setActive(false); + +        _active = t; +        _active->setActive(true); +    } +} + +void TaskManager::currentDesktopChanged(int desktop) +{ +    emit desktopChanged(desktop); +} + +void TaskManager::gotNewStartup( const KStartupInfoId& id, const KStartupInfoData& data ) +{ +    Startup::Ptr s = new Startup( id, data, this ); +    _startups.append(s); + +    emit startupAdded(s); +} + +void TaskManager::gotStartupChange( const KStartupInfoId& id, const KStartupInfoData& data ) +{ +    Startup::List::iterator itEnd = _startups.end(); +    for (Startup::List::iterator sIt = _startups.begin(); sIt != itEnd; ++sIt) +    { +        if ((*sIt)->id() == id) +        { +            (*sIt)->update(data); +            return; +        } +    } +} + +void TaskManager::killStartup( const KStartupInfoId& id ) +{ +    Startup::List::iterator sIt = _startups.begin(); +    Startup::List::iterator itEnd = _startups.end(); +    Startup::Ptr s = 0; +    for (; sIt != itEnd; ++sIt) +    { +        if ((*sIt)->id() == id) +        { +            s = *sIt; +            break; +        } +    } + +    if (!s) +    { +        return; +    } + +    _startups.erase(sIt); +    emit startupRemoved(s); +} + +void TaskManager::killStartup(Startup::Ptr s) +{ +    if (!s) +    { +        return; +    } + +    Startup::List::iterator sIt = _startups.begin(); +    Startup::List::iterator itEnd = _startups.end(); +    for (; sIt != itEnd; ++sIt) +    { +        if ((*sIt) == s) +        { +            _startups.erase(sIt); +            break; +        } +    } + +    emit startupRemoved(s); +} + +QString TaskManager::desktopName(int desk) const +{ +    return m_winModule->desktopName(desk); +} + +int TaskManager::numberOfDesktops() const +{ +    return m_winModule->numberOfDesktops(); +} + +bool TaskManager::isOnTop(const Task* task) +{ +    if (!task) +    { +        return false; +    } + +    QValueList<WId>::ConstIterator begin(m_winModule->stackingOrder().constBegin()); +    QValueList<WId>::ConstIterator it = m_winModule->stackingOrder().fromLast(); +    do +    { +        Task::Dict::iterator taskItEnd = m_tasksByWId.end(); +        for (Task::Dict::iterator taskIt = m_tasksByWId.begin(); +             taskIt != taskItEnd; ++taskIt) +        { +            Task::Ptr t = taskIt.data(); +            if ((*it) == t->window()) +            { +                if (t == task) +                { +                    return true; +                } + +                if (!t->isIconified() && +                    (t->isAlwaysOnTop() == task->isAlwaysOnTop())) +                { +                    return false; +                } + +                break; +            } +        } +    } while (it-- != begin); + +    return false; +} + +bool TaskManager::isOnScreen(int screen, const WId wid) +{ +    if (screen == -1) +    { +        return true; +    } + +    KWin::WindowInfo wi = KWin::windowInfo(wid, NET::WMKDEFrameStrut); + +    // for window decos that fudge a bit and claim to extend beyond the +    // edge of the screen, we just contract a bit. +    QRect window = wi.frameGeometry(); +    QRect desktop = QApplication::desktop()->screenGeometry(screen); +    desktop.addCoords(5, 5, -5, -5); +    return window.intersects(desktop); +} + +Task::Task(WId win, QObject *parent, const char *name) +  : QObject(parent, name), +    _active(false), +    _win(win), +    m_frameId(win), +    _info(KWin::windowInfo(_win, 0, NET::WM2AllowedActions)), +    _lastWidth(0), +    _lastHeight(0), +    _lastResize(false), +    _lastIcon(), +    _thumbSize(0.2), +    _thumb(), +    _grab() +{ +    // try to load icon via net_wm +    _pixmap = KWin::icon(_win, 16, 16, true); + +    // try to guess the icon from the classhint +    if(_pixmap.isNull()) +    { +        KGlobal::iconLoader()->loadIcon(className().lower(), +                                                    KIcon::Small, +                                                    KIcon::Small, +                                                    KIcon::DefaultState, +                                                    0, true); +    } + +    // load xapp icon +    if (_pixmap.isNull()) +    { +        _pixmap = SmallIcon("kcmx"); +    } + +#ifdef THUMBNAILING_POSSIBLE +    m_windowPixmap = 0; +    findWindowFrameId(); + +    if (TaskManager::xCompositeEnabled()) +    { +        updateWindowPixmap(); +    } +#endif // THUMBNAILING_POSSIBLE +} + +Task::~Task() +{ +#ifdef THUMBNAILING_POSSIBLE +    if (m_windowPixmap) +    { +        XFreePixmap(QPaintDevice::x11AppDisplay(), m_windowPixmap); +    } +#endif // THUMBNAILING_POSSIBLE +} + +// Task::findWindowFrameId() +// Code was copied from Kompose. +// Copyright (C) 2004 Hans Oischinger +// Permission granted on 2005-04-27. +void Task::findWindowFrameId() +{ +#ifdef THUMBNAILING_POSSIBLE +    Window target_win, parent, root; +    Window *children; +    uint nchildren; + +    target_win = _win; +    for (;;) +    { +        if (!XQueryTree(QPaintDevice::x11AppDisplay(), target_win, &root, +                        &parent, &children, &nchildren)) +        { +            break; +        } + +        if (children) +        { +            XFree(children); // it's a list, that's deallocated! +        } + +        if (!parent || parent == root) +        { +            break; +        } +        else +        { +            target_win = parent; +        } +    } + +    m_frameId = target_win; +#endif // THUMBNAILING_POSSIBLE +} + +void Task::refreshIcon() +{ +    // try to load icon via net_wm +    _pixmap = KWin::icon(_win, 16, 16, true); + +    // try to guess the icon from the classhint +    if(_pixmap.isNull()) +    { +        KGlobal::iconLoader()->loadIcon(className().lower(), +                                                    KIcon::Small, +                                                    KIcon::Small, +                                                    KIcon::DefaultState, +                                                    0, true); +    } + +    // load xapp icon +    if (_pixmap.isNull()) +    { +        _pixmap = SmallIcon("kcmx"); +    } + +    _lastIcon.resize(0,0); +    emit iconChanged(); +} + +void Task::refresh(unsigned int dirty) +{ +    QString name = visibleName(); +    _info = KWin::windowInfo(_win, 0, NET::WM2AllowedActions); + +    if (dirty != NET::WMName || name != visibleName()) +    { +        emit changed(dirty == NET::WMGeometry); +    } +} + +void Task::setActive(bool a) +{ +    _active = a; +    emit changed(false); +    if ( a ) +      emit activated(); +    else +      emit deactivated(); +} + +bool Task::isMaximized() const +{ +    return _info.valid() && (_info.state() & NET::Max); +} + +bool Task::isMinimized() const +{ +    return _info.valid() && _info.isMinimized(); +} + +bool Task::isIconified() const +{ +    return _info.valid() && _info.isMinimized(); +} + +bool Task::isAlwaysOnTop() const +{ +    return _info.valid() && (_info.state() & NET::StaysOnTop); +} + +bool Task::isKeptBelowOthers() const +{ +    return _info.valid() && (_info.state() & NET::KeepBelow); +} + +bool Task::isFullScreen() const +{ +    return _info.valid() && (_info.state() & NET::FullScreen); +} + +bool Task::isShaded() const +{ +    return _info.valid() && (_info.state() & NET::Shaded); +} + +bool Task::isOnCurrentDesktop() const +{ +    return _info.valid() && _info.isOnCurrentDesktop(); +} + +bool Task::isOnAllDesktops() const +{ +    return _info.valid() && _info.onAllDesktops(); +} + +bool Task::isActive() const +{ +    return _active; +} + +bool Task::isOnTop() const +{ +    return TaskManager::the()->isOnTop(this); +} + +bool Task::isModified() const +{ +  static QString modStr = QString::fromUtf8("[") + +                          i18n("modified") + +                          QString::fromUtf8("]"); +  int modStrPos = _info.visibleName().find(modStr); + +  return ( modStrPos != -1 ); +} + +bool Task::demandsAttention() const +{ +    return (_info.valid() && (_info.state() & NET::DemandsAttention)) || +           _transients_demanding_attention.count() > 0; +} + +bool Task::isOnScreen( int screen ) const +{ +    return TaskManager::isOnScreen( screen, _win ); +} + +void Task::updateDemandsAttentionState( WId w ) +{ +    if (window() != w) +    { +        // 'w' is a transient for this task +        NETWinInfo i( qt_xdisplay(), w, qt_xrootwin(), NET::WMState ); +        if(i.state() & NET::DemandsAttention) +        { +            if (!_transients_demanding_attention.contains(w)) +            { +                _transients_demanding_attention.append(w); +            } +        } +        else +        { +            _transients_demanding_attention.remove( w ); +        } +    } +} + +void Task::addTransient( WId w, const NETWinInfo& info ) +{ +    _transients.append(w); +    if (info.state() & NET::DemandsAttention) +    { +        _transients_demanding_attention.append(w); +        emit changed(false); +    } +} + +void Task::removeTransient(WId w) +{ +    _transients.remove(w); +    _transients_demanding_attention.remove(w); +} + +QString Task::className() +{ +    XClassHint hint; +    if(XGetClassHint(qt_xdisplay(), _win, &hint)) { +        QString nh( hint.res_name ); +        XFree( hint.res_name ); +        XFree( hint.res_class ); +        return nh; +    } +    return QString::null; +} + +QString Task::classClass() +{ +    XClassHint hint; +    if(XGetClassHint(qt_xdisplay(), _win, &hint)) { +        QString ch( hint.res_class ); +        XFree( hint.res_name ); +        XFree( hint.res_class ); +        return ch; +    } +    return QString::null; +} + +QPixmap Task::icon( int width, int height, bool allowResize ) +{ +  if ( (width == _lastWidth) +       && (height == _lastHeight) +       && (allowResize == _lastResize ) +       && (!_lastIcon.isNull()) ) +    return _lastIcon; + +  QPixmap newIcon = KWin::icon( _win, width, height, allowResize ); +  if ( !newIcon.isNull() ) { +    _lastIcon = newIcon; +    _lastWidth = width; +    _lastHeight = height; +    _lastResize = allowResize; +  } + +  return newIcon; +} + +QPixmap Task::bestIcon( int size, bool &isStaticIcon ) +{ +  QPixmap pixmap; +  isStaticIcon = false; + +  switch( size ) { +  case KIcon::SizeSmall: +    { +      pixmap = icon( 16, 16, true  ); + +      // Icon of last resort +      if( pixmap.isNull() ) { +        pixmap = KGlobal::iconLoader()->loadIcon( "go", +                                                  KIcon::NoGroup, +                                                  KIcon::SizeSmall ); +        isStaticIcon = true; +      } +    } +    break; +  case KIcon::SizeMedium: +    { +      // +      // Try 34x34 first for KDE 2.1 icons with shadows, if we don't +      // get one then try 32x32. +      // +      pixmap = icon( 34, 34, false  ); + +      if ( (( pixmap.width() != 34 ) || ( pixmap.height() != 34 )) && +           (( pixmap.width() != 32 ) || ( pixmap.height() != 32 )) ) +      { +        pixmap = icon( 32, 32, true  ); +      } + +      // Icon of last resort +      if( pixmap.isNull() ) { +        pixmap = KGlobal::iconLoader()->loadIcon( "go", +                            KIcon::NoGroup, +                            KIcon::SizeMedium ); +        isStaticIcon = true; +      } +    } +    break; +  case KIcon::SizeLarge: +    { +      // If there's a 48x48 icon in the hints then use it +      pixmap = icon( size, size, false  ); + +      // If not, try to get one from the classname +      if ( pixmap.isNull() || pixmap.width() != size || pixmap.height() != size ) { +        pixmap = KGlobal::iconLoader()->loadIcon( className(), +                            KIcon::NoGroup, +                            size, +                            KIcon::DefaultState, +                            0L, +                            true ); +        isStaticIcon = true; +      } + +      // If we still don't have an icon then scale the one in the hints +      if ( pixmap.isNull() || ( pixmap.width() != size ) || ( pixmap.height() != size ) ) { +        pixmap = icon( size, size, true  ); +        isStaticIcon = false; +      } + +      // Icon of last resort +      if( pixmap.isNull() ) { +        pixmap = KGlobal::iconLoader()->loadIcon( "go", +                                                  KIcon::NoGroup, +                                                  size ); +        isStaticIcon = true; +      } +    } +  } + +  return pixmap; +} + +bool Task::idMatch( const QString& id1, const QString& id2 ) +{ +  if ( id1.isEmpty() || id2.isEmpty() ) +    return false; + +  if ( id1.contains( id2 ) > 0 ) +    return true; + +  if ( id2.contains( id1 ) > 0 ) +    return true; + +  return false; +} + + +void Task::move() +{ +    bool on_current = _info.isOnCurrentDesktop(); + +    if (!on_current) +    { +        KWin::setCurrentDesktop(_info.desktop()); +        KWin::forceActiveWindow(_win); +    } + +    if (_info.isMinimized()) +    { +        KWin::deIconifyWindow(_win); +    } + +    QRect geom = _info.geometry(); +    QCursor::setPos(geom.center()); + +    NETRootInfo ri(qt_xdisplay(), NET::WMMoveResize); +    ri.moveResizeRequest(_win, geom.center().x(), +                         geom.center().y(), NET::Move); +} + +void Task::resize() +{ +    bool on_current = _info.isOnCurrentDesktop(); + +    if (!on_current) +    { +        KWin::setCurrentDesktop(_info.desktop()); +        KWin::forceActiveWindow(_win); +    } + +    if (_info.isMinimized()) +    { +        KWin::deIconifyWindow(_win); +    } + +    QRect geom = _info.geometry(); +    QCursor::setPos(geom.bottomRight()); + +    NETRootInfo ri(qt_xdisplay(), NET::WMMoveResize); +    ri.moveResizeRequest(_win, geom.bottomRight().x(), +                         geom.bottomRight().y(), NET::BottomRight); +} + +void Task::setMaximized(bool maximize) +{ +    KWin::WindowInfo info = KWin::windowInfo(_win, NET::WMState | NET::XAWMState | NET::WMDesktop); +    bool on_current = info.isOnCurrentDesktop(); + +    if (!on_current) +    { +        KWin::setCurrentDesktop(info.desktop()); +    } + +    if (info.isMinimized()) +    { +        KWin::deIconifyWindow(_win); +    } + +    NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), NET::WMState); + +    if (maximize) +    { +        ni.setState(NET::Max, NET::Max); +    } +    else +    { +        ni.setState(0, NET::Max); +    } + +    if (!on_current) +    { +        KWin::forceActiveWindow(_win); +    } +} + +void Task::toggleMaximized() +{ +    setMaximized(!isMaximized()); +} + +void Task::restore() +{ +    KWin::WindowInfo info = KWin::windowInfo(_win, NET::WMState | NET::XAWMState | NET::WMDesktop); +    bool on_current = info.isOnCurrentDesktop(); + +    if (!on_current) +    { +        KWin::setCurrentDesktop(info.desktop()); +    } + +    if( info.isMinimized()) +    { +        KWin::deIconifyWindow(_win); +    } + +    NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), NET::WMState); +    ni.setState(0, NET::Max); + +    if (!on_current) +    { +        KWin::forceActiveWindow( _win ); +    } +} + +void Task::setIconified(bool iconify) +{ +    if (iconify) +    { +        KWin::iconifyWindow(_win); +    } +    else +    { +        KWin::WindowInfo info = KWin::windowInfo(_win, NET::WMState | NET::XAWMState | NET::WMDesktop); +        bool on_current = info.isOnCurrentDesktop(); + +        if (!on_current) +        { +            KWin::setCurrentDesktop(info.desktop()); +        } + +        KWin::deIconifyWindow(_win); + +        if (!on_current) +        { +            KWin::forceActiveWindow(_win); +        } +    } +} + +void Task::toggleIconified() +{ +    setIconified(!isIconified()); +} + +void Task::close() +{ +    NETRootInfo ri( qt_xdisplay(),  NET::CloseWindow ); +    ri.closeWindowRequest( _win ); +} + +void Task::raise() +{ +//    kdDebug(1210) << "Task::raise(): " << name() << endl; +    KWin::raiseWindow( _win ); +} + +void Task::lower() +{ +//    kdDebug(1210) << "Task::lower(): " << name() << endl; +    KWin::lowerWindow( _win ); +} + +void Task::activate() +{ +//    kdDebug(1210) << "Task::activate():" << name() << endl; +    WId w = _win; +    if (_transients_demanding_attention.count() > 0) +    { +        w = _transients_demanding_attention.last(); +    } +    KWin::forceActiveWindow( w ); +} + +void Task::activateRaiseOrIconify() +{ +    if (!isActive() || isIconified()) +    { +        activate(); +    } +    else if (!isOnTop()) +    { +       raise(); +    } +    else +    { +       setIconified(true); +    } +} + +void Task::toDesktop(int desk) +{ +    NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), NET::WMDesktop); +    if (desk == 0) +    { +        if (_info.valid() && _info.onAllDesktops()) +        { +            ni.setDesktop(TaskManager::the()->winModule()->currentDesktop()); +            KWin::forceActiveWindow(_win); +        } +        else +        { +            ni.setDesktop(NETWinInfo::OnAllDesktops); +        } + +        return; +    } +    ni.setDesktop(desk); +    if(desk == TaskManager::the()->winModule()->currentDesktop()) +        KWin::forceActiveWindow(_win); +} + +void Task::toCurrentDesktop() +{ +    toDesktop(TaskManager::the()->winModule()->currentDesktop()); +} + +void Task::setAlwaysOnTop(bool stay) +{ +    NETWinInfo ni( qt_xdisplay(),  _win, qt_xrootwin(), NET::WMState); +    if(stay) +        ni.setState( NET::StaysOnTop, NET::StaysOnTop ); +    else +        ni.setState( 0, NET::StaysOnTop ); +} + +void Task::toggleAlwaysOnTop() +{ +    setAlwaysOnTop( !isAlwaysOnTop() ); +} + +void Task::setKeptBelowOthers(bool below) +{ +    NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), NET::WMState); + +    if (below) +    { +        ni.setState(NET::KeepBelow, NET::KeepBelow); +    } +    else +    { +        ni.setState(0, NET::KeepBelow); +    } +} + +void Task::toggleKeptBelowOthers() +{ +    setKeptBelowOthers(!isKeptBelowOthers()); +} + +void Task::setFullScreen(bool fullscreen) +{ +    NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), NET::WMState); + +    if (fullscreen) +    { +        ni.setState(NET::FullScreen, NET::FullScreen); +    } +    else +    { +        ni.setState(0, NET::FullScreen); +    } +} + +void Task::toggleFullScreen() +{ +    setFullScreen(!isFullScreen()); +} + +void Task::setShaded(bool shade) +{ +    NETWinInfo ni( qt_xdisplay(),  _win, qt_xrootwin(), NET::WMState); +    if(shade) +        ni.setState( NET::Shaded, NET::Shaded ); +    else +        ni.setState( 0, NET::Shaded ); +} + +void Task::toggleShaded() +{ +    setShaded( !isShaded() ); +} + +void Task::publishIconGeometry(QRect rect) +{ +    if (rect == m_iconGeometry) +    { +        return; +    } + +    m_iconGeometry = rect; +    NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), 0); +    NETRect r; + +    if (rect.isValid()) +    { +        r.pos.x = rect.x(); +        r.pos.y = rect.y(); +        r.size.width = rect.width(); +        r.size.height = rect.height(); +    } +    ni.setIconGeometry(r); +} + +void Task::updateThumbnail() +{ +    if ( !_info.valid() || +            !isOnCurrentDesktop() || +            !isActive() || +            !_grab.isNull() ) // We're already processing one... +    { +        return; +    } + +    // +    // We do this as a two stage process to remove the delay caused +    // by the thumbnail generation. This makes things much smoother +    // on slower machines. +    // +    QWidget *rootWin = qApp->desktop(); +    QRect geom = _info.geometry(); +    _grab = QPixmap::grabWindow(rootWin->winId(), +                                geom.x(), geom.y(), +                                geom.width(), geom.height()); + +    if (!_grab.isNull()) +    { +       QTimer::singleShot(200, this, SLOT(generateThumbnail())); +    } +} + +void Task::generateThumbnail() +{ +   if ( _grab.isNull() ) +      return; + +   QImage img = _grab.convertToImage(); + +   double width = img.width(); +   double height = img.height(); +   width = width * _thumbSize; +   height = height * _thumbSize; + +   img = img.smoothScale( qRound(width), qRound(height) ); +   _thumb = img; +   _grab.resize( 0, 0 ); // Makes grab a null image. + +   emit thumbnailChanged(); +} + +#ifdef THUMBNAILING_POSSIBLE +QPixmap Task::thumbnail(int maxDimension) +{ +    if (!TaskManager::xCompositeEnabled() || !m_windowPixmap) +    { +        return QPixmap(); +    } + +    Display *dpy = QPaintDevice::x11AppDisplay(); + +    XWindowAttributes winAttr; +    XGetWindowAttributes(dpy, m_frameId, &winAttr); +    XRenderPictFormat *format = XRenderFindVisualFormat(dpy, winAttr.visual); + +    XRenderPictureAttributes picAttr; +    picAttr.subwindow_mode = IncludeInferiors; // Don't clip child widgets + +    Picture picture = XRenderCreatePicture(dpy, m_windowPixmap, format, +                                           CPSubwindowMode, &picAttr); + +    // Get shaped windows handled correctly. +    XserverRegion region = XFixesCreateRegionFromWindow(dpy, m_frameId, +                                                        WindowRegionBounding); +    XFixesSetPictureClipRegion(dpy, picture, 0, 0, region); +    XFixesDestroyRegion(dpy, region); + +    double factor; +    if (winAttr.width > winAttr.height) +    { +        factor = (double)maxDimension / (double)winAttr.width; +    } +    else +    { +        factor = (double)maxDimension / (double)winAttr.height; +    } +    int thumbnailWidth = (int)(winAttr.width * factor); +    int thumbnailHeight = (int)(winAttr.height * factor); + +    QPixmap thumbnail(thumbnailWidth, thumbnailHeight); +    thumbnail.fill(QApplication::palette().active().background()); + +#if 0 // QImage::smoothScale() scaling +    QPixmap full(winAttr.width, winAttr.height); +    full.fill(QApplication::palette().active().background()); + +    bool hasAlpha = format->type == PictTypeDirect && format->direct.alphaMask; + +    XRenderComposite(dpy, +                     hasAlpha ? PictOpOver : PictOpSrc, +                     picture, // src +                     None, // mask +                     full.x11RenderHandle(), // dst +                     0, 0, // src offset +                     0, 0, // mask offset +                     0, 0, // dst offset +                     winAttr.width, winAttr.height); + +    KPixmapIO io; +    QImage image = io.convertToImage(full); +    thumbnail = io.convertToPixmap(image.smoothScale(thumbnailWidth, +                                                     thumbnailHeight)); +#else // XRENDER scaling +    // Scaling matrix +    XTransform transformation = {{ +        { XDoubleToFixed(1), XDoubleToFixed(0), XDoubleToFixed(     0) }, +        { XDoubleToFixed(0), XDoubleToFixed(1), XDoubleToFixed(     0) }, +        { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(factor) } +    }}; + +    XRenderSetPictureTransform(dpy, picture, &transformation); +    XRenderSetPictureFilter(dpy, picture, FilterBest, 0, 0); + +    XRenderComposite(QPaintDevice::x11AppDisplay(), +                     PictOpOver, // we're filtering, alpha values are probable +                     picture, // src +                     None, // mask +                     thumbnail.x11RenderHandle(), // dst +                     0, 0, // src offset +                     0, 0, // mask offset +                     0, 0, // dst offset +                     thumbnailWidth, thumbnailHeight); +#endif +    XRenderFreePicture(dpy, picture); + +    return thumbnail; +} +#else // THUMBNAILING_POSSIBLE +QPixmap Task::thumbnail(int /* maxDimension */) +{ +    return QPixmap(); +} +#endif // THUMBNAILING_POSSIBLE + +void Task::updateWindowPixmap() +{ +#ifdef THUMBNAILING_POSSIBLE +    if (!TaskManager::xCompositeEnabled() || !isOnCurrentDesktop() || +        isMinimized()) +    { +        return; +    } + +    Display *dpy = QPaintDevice::x11AppDisplay(); + +    if (m_windowPixmap) +    { +        XFreePixmap(dpy, m_windowPixmap); +    } + +    KXErrorHandler err; +    m_windowPixmap = XCompositeNameWindowPixmap(dpy, m_frameId); +    if( err.error( true )) +        m_windowPixmap = None; +#endif // THUMBNAILING_POSSIBLE +} + +Startup::Startup(const KStartupInfoId& id, const KStartupInfoData& data, +                 QObject * parent, const char *name) +    : QObject(parent, name), _id(id), _data(data) +{ +} + +Startup::~Startup() +{ +} + +void Startup::update(const KStartupInfoData& data) +{ +    _data.update(data); +    emit changed(); +} + +int TaskManager::currentDesktop() const +{ +    return m_winModule->currentDesktop(); +} + +TaskDrag::TaskDrag(const Task::List& tasks, QWidget* source, const char* name) +  : QStoredDrag("taskbar/task", source, name) +{ +    QByteArray data; +    QDataStream stream(data, IO_WriteOnly); + +    Task::List::const_iterator itEnd = tasks.constEnd(); +    for (Task::List::const_iterator it = tasks.constBegin(); it != itEnd; ++it) +    { +        stream << (*it)->window(); +    } + +    setEncodedData(data); +} + +TaskDrag::~TaskDrag() +{ +} + +bool TaskDrag::canDecode(const QMimeSource* e) +{ +    return e->provides("taskbar/task"); +} + +Task::List TaskDrag::decode( const QMimeSource* e ) +{ +    QByteArray data(e->encodedData("taskbar/task")); +    Task::List tasks; + +    if (data.size()) +    { +        QDataStream stream(data, IO_ReadOnly); +        while (!stream.atEnd()) +        { +            WId id; +            stream >> id; +            if (Task::Ptr task = TaskManager::the()->findTask(id)) +            { +                tasks.append(task); +            } +        } +    } + +    return tasks; +} + | 
