You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebase/kpager/desktop.cpp

689 lines
18 KiB

/**************************************************************************
desktop.cpp - KPager's desktop
Copyright (C) 2000 Antonio Larrosa Jimenez
Matthias Ettrich
Matthias Elter
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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Send comments and bug fixes to larrosa@kde.org
***************************************************************************/
#include "kpager.h"
#include <dcopobject.h>
#include <dcopclient.h>
#include <kdatastream.h>
#include <kapplication.h>
#include <kglobalsettings.h>
#include <kwinmodule.h>
#include <kwin.h>
#include <kconfig.h>
#include <kglobal.h>
#include <kdebug.h>
#include <ksharedpixmap.h>
#include <kpixmapio.h>
#include <kpopupmenu.h>
#include <netwm.h>
#include <qcstring.h>
#include <qpixmap.h>
#include <qpainter.h>
#include <qdrawutil.h>
#include <qpoint.h>
#include "desktop.h"
#include "config.h"
#include "windowdrag.h"
Desktop::Desktop( int desk, QString desktopName, QWidget *parent, const char *name): QWidget(parent,name)
{
m_desk = desk;
m_name = desktopName;
m_bgSmallPixmap=0L;
m_bgCommonSmallPixmap=0L;
m_bgPixmap = 0L;
m_bgDirty=true;
m_grabWindows=false;
setAcceptDrops(TRUE);
setBackgroundMode(NoBackground);
if (m_desk==1) Desktop::m_windowPixmaps.setAutoDelete(true);
KConfig *cfg= KGlobal::config();
m_transparentMode=static_cast<WindowTransparentMode>
(cfg->readNumEntry("windowTransparentMode", c_defWindowTransparentMode));
resize(67, 50);
}
Desktop::~Desktop()
{
delete m_bgPixmap;
delete m_bgSmallPixmap;
}
void Desktop::mouseMoveEvent( QMouseEvent *ev )
{
if ( !KPagerConfigDialog::m_windowDragging )
return;
if ( (ev->state() & LeftButton) == 0 )
return;
QPoint p( ev->pos() - pressPos );
if ( p.manhattanLength() >= qApp->startDragDistance() )
startDrag( pressPos );
}
void Desktop::mousePressEvent( QMouseEvent * ev)
{
bool showWindows= KPagerConfigDialog::m_showWindows;
if (ev->button()==LeftButton){
pressPos = ev->pos();
}
else if ((ev->button()==MidButton)&&(showWindows))
startDrag(ev->pos());
else if (ev->button()==RightButton) {
QPoint pos;
KWin::WindowInfo *info = windowAtPosition(ev->pos(), &pos);
if ( info && showWindows )
pager()->showPopupMenu(info->win(), mapToGlobal(ev->pos()));
else
pager()->showPopupMenu(0, mapToGlobal(ev->pos()));
}
}
void Desktop::mouseReleaseEvent( QMouseEvent *ev )
{
/** Note that mouseReleaseEvent is not called when releasing the mouse
to drop a window in this desktop */
if (ev->button()==LeftButton)
{
bool showWindows= KPagerConfigDialog::m_showWindows;
QPoint pos;
KWin::setCurrentDesktop(m_desk);
if (showWindows)
{
KWin::WindowInfo *info = windowAtPosition(ev->pos(), &pos);
if (info)
{
KWin::forceActiveWindow(info->win());
// if ( static_cast<WindowDrawMode>( KPagerConfigDialog::m_windowDrawMode ) == Pixmap )
// m_windowPixmapsDirty.replace(info->win,true);
}
}
}
}
KWin::WindowInfo *Desktop::windowAtPosition(const QPoint &p, QPoint *internalpos)
{
QRect r;
const QValueList<WId> &list(pager()->kwin()->stackingOrder());
if (list.count() <= 0)
return 0L;
for (QValueList<WId>::ConstIterator it = list.fromLast(); ; --it)
{
KWin::WindowInfo* info = pager()->info( *it );
if (shouldPaintWindow(info))
{
r=info->geometry();
convertRectS2P(r);
if (r.contains(p))
{
if (internalpos)
{
internalpos->setX(p.x()-r.x());
internalpos->setY(p.y()-r.y());
}
return info;
}
}
if (it == list.begin())
break;
}
return 0L;
}
void Desktop::convertRectS2P(QRect &r)
{
QRect tmp(r);
r.setRect(deskX()+tmp.x()*deskWidth()/kapp->desktop()->width(),
deskY()+tmp.y()*deskHeight()/kapp->desktop()->height(),
tmp.width()*deskWidth()/kapp->desktop()->width(),
tmp.height()*deskHeight()/kapp->desktop()->height());
}
void Desktop::convertCoordP2S(int &x, int &y)
{
x=(x-deskX())*(kapp->desktop()->width())/deskWidth();
y=(y-deskY())*(kapp->desktop()->height())/deskHeight();
}
QPixmap scalePixmap(const QPixmap &pixmap, int width, int height)
{
if (pixmap.width()>100)
{
KPixmapIO io;
QImage img(io.convertToImage(pixmap));
return io.convertToPixmap(img.smoothScale(width,height));
}
QImage img(pixmap.convertToImage().smoothScale(width,height));
QPixmap pix;
pix.convertFromImage(img);
return pix;
}
QPixmap fastScalePixmap(const QPixmap &pixmap, int width, int height)
{
QWMatrix m;
m.scale(width/(double)pixmap.width(),
height/(double)pixmap.height());
return pixmap.xForm(m);
}
void Desktop::loadBgPixmap(void)
{
// if (!m_bgDirty) return;
DCOPClient *client = kapp->dcopClient();
if (!client->isAttached())
client->attach();
QByteArray data, data2, replyData;
QCString replyType;
if (client->call("kdesktop", "KBackgroundIface", "isCommon()",
data, replyType, replyData))
{
QDataStream reply(replyData, IO_ReadOnly);
if (replyType == "bool") {
reply >> m_isCommon;
}
}
if ( m_isCommon && m_desk!=1 ) return;
/*
QDataStream args2( data2, IO_WriteOnly );
args2 << m_desk-1 << 0 << 0 << -1 << -1 << 200 << 150 ;
if (client->call("kdesktop", "KBackgroundIface",
"wallpaper(int,int,int,int,int,int,int)", data2, replyType, replyData))
{
QDataStream reply(replyData, IO_ReadOnly);
if (replyType == "QPixmap") {
QPixmap pixmap;
reply >> pixmap;
if (!pixmap.isNull())
{
kdDebug() << "getting small bg through dcop\n";
if (m_isCommon)
{
if (m_bgSmallPixmap) { delete m_bgSmallPixmap; m_bgSmallPixmap=0L; }
if (!m_bgCommonSmallPixmap) m_bgCommonSmallPixmap=new QPixmap(pixmap);
else *m_bgCommonSmallPixmap=pixmap;
}
else
{
if (m_bgCommonSmallPixmap)
{
delete m_bgCommonSmallPixmap;
m_bgCommonSmallPixmap=0L;
}
if (!m_bgSmallPixmap) m_bgSmallPixmap=new QPixmap(pixmap);
else *m_bgSmallPixmap=pixmap;
}
return;
}
}
}
kdDebug() << "getting whole bg through shpixmap\n";
*/
QDataStream args( data, IO_WriteOnly );
args << 1;
client->send( "kdesktop", "KBackgroundIface", "setExport(int)", data );
if (!m_bgPixmap)
{
m_bgPixmap = new KSharedPixmap;
connect(m_bgPixmap, SIGNAL(done(bool)), SLOT(backgroundLoaded(bool)));
}
m_bgPixmap->loadFromShared(QString("DESKTOP%1").arg(m_isCommon?1:m_desk));
}
void Desktop::paintWindow(QPainter &p, const KWin::WindowInfo *info, bool onDesktop)
{
switch (static_cast<WindowDrawMode>(KPagerConfigDialog::m_windowDrawMode ) )
{
case (Plain) : paintWindowPlain (p, info, onDesktop);break;
case (Icon) : paintWindowIcon (p, info, onDesktop);break;
case (Pixmap) : paintWindowPixmap(p, info, onDesktop);break;
}
}
QPixmap *Desktop::paintNewWindow(const KWin::WindowInfo *info)
{
QRect r = info->frameGeometry();
int dw = QApplication::desktop()->width();
int dh = QApplication::desktop()->height();
r = QRect( r.x() * width() / dw, 2 + r.y() * height() / dh,
r.width() * width() / dw, r.height() * height() / dh );
r.moveTopLeft(QPoint(0,0));
QPixmap *pixmap=new QPixmap(r.width(),r.height());
QPainter p;
p.begin(pixmap);
p.setFont(font());
p.fillRect( r, colorGroup().brush(QColorGroup::Dark));
paintWindow(p, info, false);
p.end();
return pixmap;
}
void Desktop::startDrag(const QPoint &p)
{
QPoint dragpos;
KWin::WindowInfo *info=windowAtPosition(p,&dragpos);
if ( (!info)/* || (info->state & NET::Max)*/ ) return;
QPixmap *pixmap=paintNewWindow(info);
int deltax=dragpos.x();
int deltay=dragpos.y();
PagerWindowDrag *wdrag= new PagerWindowDrag( info->win(), deltax, deltay,
m_desk, this);
wdrag->setPixmap( *pixmap, QPoint( deltax, deltay) );
delete pixmap;
wdrag->dragCopy();
}
void Desktop::dragEnterEvent(QDragEnterEvent *ev)
{
if (PagerWindowDrag::canDecode( ev )) ev->accept();
}
void Desktop::dragMoveEvent(QDragMoveEvent *)
{
// TODO Moving the window while dragging would be cool, wouldn't it ?
// Matthias: No, is way to slow on low end machines.
// Antonio:Ok, I'll make it configurable after 2.0 (it would add a string)
}
void Desktop::dropEvent(QDropEvent *ev)
{
WId win=0;
int deltax,deltay;
int origdesk;
if (!PagerWindowDrag::decode(ev,win,deltax,deltay,origdesk)) return;
int x=ev->pos().x()-deltax;
int y=ev->pos().y()-deltay;
/*
* x and y now contain the position (in local coordinates) which
* has the origin of the window
*/
convertCoordP2S(x,y);
// kdDebug() << "moving window " << win << "d from " << origdesk << " to " << m_desk << endl;
// NETWinInfo NETinfo( qt_xdisplay(), win, qt_xrootwin(), NET::Client | NET::WMDesktop);
if (m_desk==0)
{
/*
* The next line moves the window to the active desktop. This is done
* because in other case, kwm raises the window when it's in a semi
* changed state and doesn't work well with kpager. Let's see how well
* KWin behaves.
* if (activedesktop!=KWM::desktop(w))
* KWM::moveToDesktop(w,activedesktop);
*/
// KWin::setState(win, NET::Sticky);
KWin::setOnAllDesktops(win, true);
}
else
{
if (origdesk==0) KWin::setOnAllDesktops(win, false);
KWin::WindowInfo *info = pager()->info(win);
if (!info->onAllDesktops())
KWin::setOnDesktop(win, m_desk);
}
XMoveWindow(x11Display(), win, x, y );
}
bool Desktop::shouldPaintWindow( KWin::WindowInfo *info )
{
if (!info)
return false;
// if (info->mappingState != NET::Visible)
// return false;
NET::WindowType type = info->windowType( NET::NormalMask | NET::DesktopMask
| NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
| NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask );
if (type == NET::Desktop || type == NET::Dock
|| type == NET::TopMenu)
return false;
if (!info->isOnDesktop(m_desk))
return false;
if (info->state() & NET::SkipPager
|| info->state() & NET::Shaded )
return false;
if (info->win() == pager()->winId())
return false;
if ( info->isMinimized() )
return false;
return true;
}
void Desktop::paintFrame(bool active)
{
QPainter p(this);
if ( active )
p.setPen(yellow);
else
p.setPen(QColorGroup::Base);
p.drawRect(rect());
p.end();
}
void Desktop::paintEvent( QPaintEvent * )
{
QPixmap pixmap(width(),height());
QPainter p;
p.begin(&pixmap);
// p.setFont(font());
// p.fillRect(rect(), colorGroup().brush(QColorGroup::Dark));
// p.setPen(Qt::black);
// p.drawRect(rect());
if (KPagerConfigDialog::m_showBackground )
{
if ( ( !m_isCommon && !m_bgSmallPixmap )
|| (m_isCommon && !m_bgCommonSmallPixmap) )
loadBgPixmap();
if ( ( !m_isCommon && m_bgSmallPixmap && !m_bgSmallPixmap->isNull() )
|| ( m_isCommon &&
m_bgCommonSmallPixmap && !m_bgCommonSmallPixmap->isNull() ) )
{
QPixmap tmp;
if ( m_isCommon )
tmp=fastScalePixmap(*m_bgCommonSmallPixmap, width(),height());
else
tmp=fastScalePixmap(*m_bgSmallPixmap, width(),height());
p.drawPixmap(0,0,tmp);
}
else pixmap.fill(Qt::gray);
}
else
p.fillRect(rect(), colorGroup().brush(QColorGroup::Mid));
// set in/active pen
if (isCurrent())
p.setPen(yellow);
else
p.setPen(QColorGroup::Base);
// paint number & name
bool sname=KPagerConfigDialog::m_showName;
bool snumber=KPagerConfigDialog::m_showNumber;
if ( sname || snumber ) {
QString txt;
// set font
if (sname) {
QFont f(KGlobalSettings::generalFont().family(), 10, QFont::Bold);
p.setFont(f);
}
else {
QFont f(KGlobalSettings::generalFont().family(), 12, QFont::Bold);
p.setFont(f);
}
// draw text
if ( sname && snumber )
txt=QString("%1. %2").arg(m_desk).arg(pager()->kwin()->desktopName( m_desk ));
else if ( sname )
txt=pager()->kwin()->desktopName( m_desk );
else if ( snumber )
txt=QString::number( m_desk );
p.drawText(2, 0, width()-4, height(), AlignCenter, txt );
}
// paint windows
if ( KPagerConfigDialog::m_showWindows ) {
QValueList<WId>::ConstIterator it;
for ( it = pager()->kwin()->stackingOrder().begin();
it != pager()->kwin()->stackingOrder().end(); ++it ) {
KWin::WindowInfo* info = pager()->info( *it );
if (shouldPaintWindow(info))
paintWindow(p,info);
}
}
// paint border rectangle
p.drawRect(rect());
p.end();
// blit pixmap to widget
p.begin(this);
p.drawPixmap(0,0,pixmap);
p.end();
m_grabWindows=false;
}
void Desktop::paintWindowPlain(QPainter &p, const KWin::WindowInfo *info, bool onDesktop)
{
QRect r = info->frameGeometry();
int dw = QApplication::desktop()->width();
int dh = QApplication::desktop()->height();
r = QRect( r.x() * width() / dw, 2 + r.y() * height() / dh,
r.width() * width() / dw, r.height() * height() / dh );
if ( !onDesktop )
r.moveTopLeft(QPoint(0,0));
bool isActive=(pager()->kwin()->activeWindow() == info->win());
QBrush brush;
if ( isActive ) brush=colorGroup().brush( QColorGroup::Highlight );
else brush=colorGroup().brush( QColorGroup::Button );
if ( m_transparentMode==AllWindows
|| (m_transparentMode==MaximizedWindows && ( info->state() & NET::Max )) )
brush.setStyle(QBrush::Dense4Pattern);
if ( isActive )
{
qDrawShadeRect( &p, r, colorGroup(), false, 1, 0, &brush );
}
else
{
p.fillRect( r, brush );
qDrawShadeRect( &p, r, colorGroup(), true, 1, 0 );
}
}
void Desktop::paintWindowIcon(QPainter &p, const KWin::WindowInfo *info, bool onDesktop)
{
QRect r = info->frameGeometry();
int dw = QApplication::desktop()->width();
int dh = QApplication::desktop()->height();
r = QRect( r.x() * width() / dw, 2 + r.y() * height() / dh,
r.width() * width() / dw, r.height() * height() / dh );
QPixmap icon=KWin::icon( info->win(), int(r.width()*0.8),
int(r.height()*0.8), true);
NET::WindowType type = info->windowType( NET::NormalMask | NET::DesktopMask
| NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
| NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask );
if ( icon.isNull() || type!=NET::Override )
paintWindowPlain(p,info,onDesktop);
if ( !onDesktop )
r.moveTopLeft(QPoint(0,0));
p.drawPixmap( r.topLeft()+ QPoint(int(r.width()*0.1),int(r.height()*0.1)),
icon );
}
void Desktop::paintWindowPixmap(QPainter &p, const KWin::WindowInfo *info,
bool onDesktop)
{
const int knDefaultPixmapWd = 100;
const int knDefaultPixmapHg = 75;
QRect rSmall, r = info->frameGeometry();
int dw = QApplication::desktop()->width();
int dh = QApplication::desktop()->height();
rSmall = QRect( r.x() * width() / dw, 2 + r.y() * height() / dh,
r.width() * width() / dw, r.height() * height() / dh );
QPixmap *pixmap=m_windowPixmaps[info->win()];
bool isDirty=m_windowPixmapsDirty[info->win()];
if ( !pixmap || isDirty || m_grabWindows )
{
if ( isCurrent() )
{
QPixmap tmp=QPixmap::grabWindow(info->win(),
0,0,r.width(),r.height());
if (!tmp.isNull() && tmp.width() > 0 && tmp.height() > 0)
{
tmp.setOptimization(QPixmap::BestOptim);
int nWd, nHg;
if (rSmall.width() > knDefaultPixmapWd || rSmall.height() > knDefaultPixmapHg)
{
nWd = knDefaultPixmapWd;
nHg = knDefaultPixmapHg;
}
else
{
nWd = rSmall.width();
nHg = rSmall.height();
}
pixmap=new QPixmap(fastScalePixmap(tmp, nWd, nHg));
m_windowPixmaps.replace(info->win(),pixmap);
m_windowPixmapsDirty.replace(info->win(),false);
}
}
// It was impossible to get the pixmap, let's fallback to the icon mode.
if ( !pixmap || pixmap->isNull() )
{
paintWindowIcon(p, info, onDesktop);
return;
}
}
if ( !onDesktop )
rSmall.moveTopLeft(QPoint(0,0));
if (rSmall.width() != pixmap->width() || rSmall.height() != pixmap->height())
{
QPixmap pixmapSmall(fastScalePixmap(*pixmap,rSmall.width(),rSmall.height()));
p.drawPixmap( rSmall.topLeft(), pixmapSmall );
}
else
{
p.drawPixmap( rSmall.topLeft(), *pixmap);
}
}
KPager *Desktop::pager() const
{
return reinterpret_cast<KPager *>(parent());
}
bool Desktop::isCurrent() const
{
return pager()->kwin()->currentDesktop()==m_desk;
}
void Desktop::backgroundLoaded(bool b)
{
if (b)
{
if (m_isCommon)
{
if (m_bgSmallPixmap) { delete m_bgSmallPixmap; m_bgSmallPixmap=0L ; };
if (!m_bgCommonSmallPixmap) m_bgCommonSmallPixmap=new QPixmap;
*m_bgCommonSmallPixmap=scalePixmap(*m_bgPixmap,200,150);
}
else
{
if (m_bgCommonSmallPixmap) { delete m_bgCommonSmallPixmap;
m_bgCommonSmallPixmap=0L ; };
if (!m_bgSmallPixmap) m_bgSmallPixmap=new QPixmap;
*m_bgSmallPixmap=fastScalePixmap(*m_bgPixmap,200,150);
}
delete m_bgPixmap;
m_bgPixmap=0L;
if (m_isCommon) pager()->redrawDesktops();
else update();
} else kdDebug() << "Error getting the background\n";
}
QSize Desktop::sizeHint() const
{
return QSize(67,50);
}
QPixmap *Desktop::m_bgCommonSmallPixmap=0L;
bool Desktop::m_isCommon=false;
QIntDict<QPixmap> Desktop::m_windowPixmaps;
QMap<int,bool> Desktop::m_windowPixmapsDirty;
// Default Configuration -------------------------------------------------
const bool Desktop::c_defShowName=false;
const bool Desktop::c_defShowNumber=false;
const bool Desktop::c_defShowWindows=true;
const bool Desktop::c_defShowBackground=true;
const bool Desktop::c_defWindowDragging=true;
const Desktop::WindowDrawMode Desktop::c_defWindowDrawMode=Desktop::Icon;
const Desktop::WindowTransparentMode
Desktop::c_defWindowTransparentMode=Desktop::AllWindows;
#include "desktop.moc"