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/kicker/applets/minipager/pagerbutton.cpp

837 lines
23 KiB

/*****************************************************************
Copyright (c) 1996-2000 the kicker authors. See file AUTHORS.
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 <stdlib.h>
#include <tqcursor.h>
#include <tqdrawutil.h>
#include <tqlineedit.h>
#include <tqpainter.h>
#include <tqpopupmenu.h>
#include <tqstylesheet.h>
#include <netwm.h>
#include <dcopclient.h>
#include <kwinmodule.h>
#include <ksharedpixmap.h>
#include <kpixmapio.h>
#include <kpixmapeffect.h>
#include <kstringhandler.h>
#include <kiconloader.h>
#include "global.h"
#include "kickertip.h"
#include "kickerSettings.h"
#include "kshadowengine.h"
#include "paneldrag.h"
#include "pagerapplet.h"
#include "pagerbutton.h"
#include "pagerbutton.moc"
#include "pagersettings.h"
#ifdef FocusOut
#undef FocusOut
#endif
KSharedPixmap* KMiniPagerButton::s_commonSharedPixmap;
KPixmap* KMiniPagerButton::s_commonBgPixmap;
KMiniPagerButton::KMiniPagerButton(int desk, bool useViewPorts, const TQPoint& viewport,
KMiniPager *parent, const char *name)
: TQButton(parent, name),
m_pager(parent),
m_desktop(desk),
m_useViewports(useViewPorts),
m_viewport(viewport),
m_lineEdit(0),
m_sharedPixmap(0),
m_bgPixmap(0),
m_isCommon(false),
m_currentWindow(0),
m_updateCompressor(0, "KMiniPagerButton::updateCompressor"),
m_dragSwitchTimer(0, "KMiniPagerButton::dragSwitchTimer"),
m_inside(false)
{
setToggleButton(true);
setAcceptDrops(true);
setWFlags(WNoAutoErase);
setBackgroundOrigin(AncestorOrigin);
installEventFilter(KickerTip::the());
m_desktopName = m_pager->kwin()->desktopName(m_desktop);
connect(this, TQT_SIGNAL(clicked()), TQT_SLOT(slotClicked()));
connect(this, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotToggled(bool)));
connect(&m_dragSwitchTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotDragSwitch()));
connect(&m_updateCompressor, TQT_SIGNAL(timeout()), this, TQT_SLOT(update()));
if (m_pager->desktopPreview())
{
setMouseTracking(true);
}
loadBgPixmap();
}
KMiniPagerButton::~KMiniPagerButton()
{
delete m_sharedPixmap;
delete m_bgPixmap;
}
TQRect KMiniPagerButton::mapGeometryToViewport(const KWin::WindowInfo& info) const
{
if (!m_useViewports)
return info.frameGeometry();
// ### fix vertically tqlayouted viewports
TQRect _r(info.frameGeometry());
TQPoint vx(m_pager->kwin()->currentViewport(m_pager->kwin()->currentDesktop()));
_r.moveBy( - (m_desktop - vx.x()) * TQApplication::desktop()->width(),
0);
if ((info.state() & NET::Sticky))
{
_r.moveTopLeft(TQPoint(_r.x() % TQApplication::desktop()->width(),
_r.y() % TQApplication::desktop()->height()));
}
return _r;
}
TQPoint KMiniPagerButton::mapPointToViewport(const TQPoint& _p) const
{
if (!m_useViewports) return _p;
TQPoint vx(m_pager->kwin()->currentViewport(m_pager->kwin()->currentDesktop()));
// ### fix vertically tqlayouted viewports
TQPoint p(_p);
p.setX(p.x() + (m_desktop - vx.x()) * TQApplication::desktop()->width());
return p;
}
bool KMiniPagerButton::shouldPaintWindow( KWin::WindowInfo *info ) const
{
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 (!m_useViewports && !info->isOnDesktop(m_desktop))
return false;
if (m_useViewports) {
TQRect r = mapGeometryToViewport(*info);
if (!info->hasState(NET::Sticky) &&
!TQApplication::desktop()->tqgeometry().tqcontains(r.topLeft()) &&
!TQApplication::desktop()->tqgeometry().tqcontains(r.topRight()))
return false;
}
if (info->state() & NET::SkipPager || info->state() & NET::Shaded )
return false;
if (info->win() == m_pager->winId())
return false;
if ( info->isMinimized() )
return false;
return true;
}
void KMiniPagerButton::resizeEvent(TQResizeEvent *ev)
{
if (m_lineEdit)
{
m_lineEdit->setGeometry(rect());
}
delete m_bgPixmap;
m_bgPixmap = 0;
TQButton::resizeEvent(ev);
}
void KMiniPagerButton::windowsChanged()
{
m_currentWindow = 0;
if (!m_updateCompressor.isActive())
{
m_updateCompressor.start(50, true);
}
}
void KMiniPagerButton::backgroundChanged()
{
delete s_commonSharedPixmap;
s_commonSharedPixmap = 0;
delete s_commonBgPixmap;
s_commonBgPixmap = 0;
loadBgPixmap();
}
void KMiniPagerButton::loadBgPixmap()
{
bool retval;
if (m_pager->bgType() != PagerSettings::EnumBackgroundType::BgLive)
return; // not needed
DCOPClient *client = kapp->dcopClient();
if (!client->isAttached())
{
client->attach();
}
TQCString kdesktop_name;
int screen_number = DefaultScreen(qt_xdisplay());
if (screen_number == 0)
kdesktop_name = "kdesktop";
else
kdesktop_name.sprintf("kdesktop-screen-%d", screen_number);
TQByteArray data, replyData;
TQCString replyType;
if (client->call(kdesktop_name, "KBackgroundIface", "isCommon()",
data, replyType, replyData))
{
if (replyType == "bool")
{
TQDataStream reply(replyData, IO_ReadOnly);
reply >> m_isCommon;
}
}
if (m_isCommon)
{
if (s_commonBgPixmap)
{ // pixmap is already ready, just use it
backgroundLoaded( true );
return;
}
else if (s_commonSharedPixmap)
{ // other button is already fetching the pixmap
connect(s_commonSharedPixmap, TQT_SIGNAL(done(bool)),
TQT_SLOT(backgroundLoaded(bool)));
return;
}
}
if (m_isCommon)
{
if (!s_commonSharedPixmap)
{
s_commonSharedPixmap = new KSharedPixmap;
connect(s_commonSharedPixmap, TQT_SIGNAL(done(bool)),
TQT_SLOT(backgroundLoaded(bool)));
}
retval = s_commonSharedPixmap->loadFromShared(TQString("DESKTOP1"));
if (retval == false) {
TQDataStream args( data, IO_WriteOnly );
args << 1; // Argument is 1 (true)
client->send(kdesktop_name, "KBackgroundIface", "setExport(int)", data);
retval = s_commonSharedPixmap->loadFromShared(TQString("DESKTOP1"));
}
}
else
{
if (!m_sharedPixmap)
{
m_sharedPixmap = new KSharedPixmap;
connect(m_sharedPixmap, TQT_SIGNAL(done(bool)),
TQT_SLOT(backgroundLoaded(bool)));
}
retval = m_sharedPixmap->loadFromShared(TQString("DESKTOP%1").arg(m_desktop));
if (retval == false) {
TQDataStream args( data, IO_WriteOnly );
args << 1;
client->send(kdesktop_name, "KBackgroundIface", "setExport(int)", data);
retval = m_sharedPixmap->loadFromShared(TQString("DESKTOP%1").arg(m_desktop));
}
}
}
static TQPixmap scalePixmap(const TQPixmap &pixmap, int width, int height)
{
if (pixmap.width()>100)
{
KPixmapIO io;
TQImage img( io.convertToImage( pixmap ) );
return io.convertToPixmap( img.smoothScale( width, height ) );
}
TQImage img( pixmap.convertToImage().smoothScale( width, height ) );
TQPixmap pix;
pix.convertFromImage( img );
return pix;
}
void KMiniPagerButton::backgroundLoaded( bool loaded )
{
if (loaded)
{
if (!m_bgPixmap)
{
m_bgPixmap = new KPixmap;
}
if (m_isCommon)
{
if (!s_commonBgPixmap)
{
s_commonBgPixmap = new KPixmap;
*s_commonBgPixmap = scalePixmap(*s_commonSharedPixmap, width(), height());
s_commonSharedPixmap->deleteLater(); // let others get the signal too
s_commonSharedPixmap = 0;
}
*m_bgPixmap = *s_commonBgPixmap;
}
else
{
*m_bgPixmap = scalePixmap(*m_sharedPixmap, width(), height());
delete m_sharedPixmap;
m_sharedPixmap = 0L;
}
update();
}
else
{
kdWarning() << "Error getting the background\n";
}
}
void KMiniPagerButton::enterEvent(TQEvent *)
{
m_inside = true;
update();
}
void KMiniPagerButton::leaveEvent(TQEvent *)
{
m_inside = false;
update();
}
void KMiniPagerButton::drawButton(TQPainter *bp)
{
int w = width();
int h = height();
bool on = isOn();
bool down = isDown();
TQBrush background;
bool liveBkgnd = m_pager->bgType() == PagerSettings::EnumBackgroundType::BgLive;
bool transparent = m_pager->bgType() == PagerSettings::EnumBackgroundType::BgTransparent;
// background
if (backgroundPixmap())
{
TQPoint pt = backgroundOffset();
bp->drawTiledPixmap(0, 0, width(), height(), *backgroundPixmap(), pt.x(), pt.y());
}
else
{
bp->fillRect(0, 0, width(), height(), paletteBackgroundColor());
}
// desktop background
if (liveBkgnd)
{
if (m_bgPixmap && !m_bgPixmap->isNull())
{
if (on)
{
KPixmap tmp = *m_bgPixmap;
KPixmapEffect::intensity(tmp, 0.33);
bp->drawPixmap(0, 0, tmp);
}
else
{
bp->drawPixmap(0, 0, *m_bgPixmap);
}
}
else
{
liveBkgnd = false;
}
}
if (!liveBkgnd)
{
if (transparent)
{
// transparent windows get an 1 pixel frame...
if (on)
{
bp->setPen(tqcolorGroup().midlight());
}
else if (down)
{
bp->setPen(KickerLib::blendColors(tqcolorGroup().mid(),
tqcolorGroup().midlight()));
}
else
{
bp->setPen(tqcolorGroup().dark());
}
bp->drawRect(0, 0, w, h);
}
else
{
TQBrush background;
if (on)
{
background = tqcolorGroup().brush(TQColorGroup::Midlight);
}
else if (down)
{
background = KickerLib::blendColors(tqcolorGroup().mid(),
tqcolorGroup().midlight());
}
else
{
background = tqcolorGroup().brush(TQColorGroup::Mid);
}
bp->fillRect(0, 0, w, h, background);
}
}
// window preview...
if (m_pager->desktopPreview())
{
KWinModule* kwin = m_pager->kwin();
KWin::WindowInfo *info = 0;
int dw = TQApplication::desktop()->width();
int dh = TQApplication::desktop()->height();
TQValueList<WId> windows = kwin->stackingOrder();
TQValueList<WId>::const_iterator itEnd = windows.constEnd();
for (TQValueList<WId>::ConstIterator it = windows.constBegin(); it != itEnd; ++it)
{
info = m_pager->info(*it);
if (shouldPaintWindow(info))
{
TQRect r = mapGeometryToViewport(*info);
r = TQRect(r.x() * width() / dw, 2 + r.y() * height() / dh,
r.width() * width() / dw, r.height() * height() / dh);
if (kwin->activeWindow() == info->win())
{
TQBrush brush = tqcolorGroup().brush(TQColorGroup::Highlight);
qDrawShadeRect(bp, r, tqcolorGroup(), false, 1, 0, &brush);
}
else
{
TQBrush brush = tqcolorGroup().brush(TQColorGroup::Button);
if (on)
{
brush.setColor(brush.color().light(120));
}
bp->fillRect(r, brush);
qDrawShadeRect(bp, r, tqcolorGroup(), true, 1, 0);
}
if (m_pager->windowIcons() && r.width() > 15 && r.height() > 15)
{
TQPixmap icon = KWin::icon(*it, 16, 16, true);
if (!icon.isNull())
{
bp->drawPixmap(r.left() + ((r.width() - 16) / 2),
r.top() + ((r.height() - 16) / 2),
icon);
}
}
}
}
}
if (liveBkgnd)
{
// draw a little border around the individual buttons
// makes it look a bit more finished.
if (on)
{
bp->setPen(tqcolorGroup().midlight());
}
else
{
bp->setPen(tqcolorGroup().mid());
}
bp->drawRect(0, 0, w, h);
}
if (m_pager->labelType() != PagerSettings::EnumLabelType::LabelNone)
{
TQString label = (m_pager->labelType() == PagerSettings::EnumLabelType::LabelNumber) ?
TQString::number(m_desktop) : m_desktopName;
if (transparent || liveBkgnd)
{
bp->setPen(on ? tqcolorGroup().midlight() : tqcolorGroup().buttonText());
m_pager->shadowEngine()->drawText(*bp, TQRect(0, 0, w, h), AlignCenter, label, size());
}
else
bp->drawText(0, 0, w, h, AlignCenter, label);
}
if (m_inside)
KickerLib::drawBlendedRect(bp, TQRect(1, 1, width() - 2, height() - 2), tqcolorGroup().foreground());
}
void KMiniPagerButton::mousePressEvent(TQMouseEvent * e)
{
if (e->button() == RightButton)
{
// prevent LMB down -> RMB down -> LMB up sequence
if ((e->state() & MouseButtonMask ) == NoButton)
{
emit showMenu(e->globalPos(), m_desktop);
return;
}
}
if (m_pager->desktopPreview())
{
m_pager->clickPos = e->pos();
}
TQButton::mousePressEvent(e);
}
void KMiniPagerButton::mouseReleaseEvent(TQMouseEvent* e)
{
m_pager->clickPos = TQPoint();
TQButton::mouseReleaseEvent(e);
}
void KMiniPagerButton::mouseMoveEvent(TQMouseEvent* e)
{
if (!m_pager->desktopPreview())
{
return;
}
int dw = TQApplication::desktop()->width();
int dh = TQApplication::desktop()->height();
int w = width();
int h = height();
TQPoint pos(m_pager->clickPos.isNull() ? mapFromGlobal(TQCursor::pos()) : m_pager->clickPos);
TQPoint p = mapPointToViewport(TQPoint(pos.x() * dw / w, pos.y() * dh / h));
Task::Ptr wasWindow = m_currentWindow;
m_currentWindow = TaskManager::the()->findTask(m_useViewports ? 1 : m_desktop, p);
if (wasWindow != m_currentWindow)
{
KickerTip::Client::updateKickerTip();
}
if (m_currentWindow && !m_pager->clickPos.isNull() &&
(m_pager->clickPos - e->pos()).manhattanLength() > KGlobalSettings::dndEventDelay())
{
TQRect r = m_currentWindow->tqgeometry();
// preview window height, window width
int ww = r.width() * w / dw;
int wh = r.height() * h / dh;
TQPixmap windowImage(ww, wh);
TQPainter bp(&windowImage, this);
bp.setPen(tqcolorGroup().foreground());
bp.drawRect(0, 0, ww, wh);
bp.fillRect(1, 1, ww - 2, wh - 2, tqcolorGroup().background());
Task::List tasklist;
tasklist.append(m_currentWindow);
TaskDrag* drag = new TaskDrag(tasklist, this);
TQPoint offset(m_pager->clickPos.x() - (r.x() * w / dw),
m_pager->clickPos.y() - (r.y() * h / dh));
drag->setPixmap(windowImage, offset);
drag->dragMove();
if (isDown())
{
setDown(false);
}
m_pager->clickPos = TQPoint();
}
}
void KMiniPagerButton::dragEnterEvent(TQDragEnterEvent* e)
{
if (PanelDrag::canDecode(e))
{
// ignore container drags
return;
}
else if (TaskDrag::canDecode(e))
{
// if it's a task drag don't switch the desktop, just accept it
e->accept();
setDown(true);
}
else
{
// if a dragitem is held for over a pager button for two seconds,
// activate corresponding desktop
m_dragSwitchTimer.start(1000, true);
TQButton::dragEnterEvent(e);
}
}
void KMiniPagerButton::dropEvent(TQDropEvent* e)
{
if (TaskDrag::canDecode(e))
{
e->accept();
Task::List tasks(TaskDrag::decode(e));
if ((m_useViewports || e->source() == this) && tasks.count() == 1)
{
Task::Ptr task = tasks[0];
int dw = TQApplication::desktop()->width();
int dh = TQApplication::desktop()->height();
int w = width();
int h = height();
TQRect location = mapGeometryToViewport(task->info());
TQPoint pos = mapPointToViewport(e->pos());
int deltaX = pos.x() - m_pager->clickPos.x();
int deltaY = pos.y() - m_pager->clickPos.y();
if (abs(deltaX) < 3)
{
deltaX = 0;
}
else
{
deltaX = deltaX * dw / w;
}
if (abs(deltaY) < 3)
{
deltaY = 0;
}
else
{
deltaY = deltaY * dh / h;
}
location.moveBy(deltaX, deltaY);
XMoveWindow(x11Display(), task->window(), location.x(), location.y());
if ((e->source() != this || !task->isOnAllDesktops()) &&
task->desktop() != m_desktop)
{
task->toDesktop(m_desktop);
}
}
else
{
Task::List::iterator itEnd = tasks.end();
for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
{
(*it)->toDesktop(m_desktop);
}
}
setDown(false);
}
TQButton::dropEvent( e );
}
void KMiniPagerButton::enabledChange( bool oldEnabled )
{
if (m_pager->bgType() == PagerSettings::EnumBackgroundType::BgLive)
{
m_pager->refresh();
}
TQButton::enabledChange(oldEnabled);
}
void KMiniPagerButton::dragLeaveEvent( TQDragLeaveEvent* e )
{
m_dragSwitchTimer.stop();
if (m_pager->kwin()->currentDesktop() != m_desktop)
{
setDown(false);
}
TQButton::dragLeaveEvent( e );
}
void KMiniPagerButton::slotDragSwitch()
{
emit buttonSelected(m_desktop);
}
void KMiniPagerButton::slotClicked()
{
emit buttonSelected(m_desktop);
}
void KMiniPagerButton::rename()
{
if ( !m_lineEdit ) {
m_lineEdit = new TQLineEdit( this );
connect( m_lineEdit, TQT_SIGNAL( returnPressed() ), m_lineEdit, TQT_SLOT( hide() ) );
m_lineEdit->installEventFilter( this );
}
m_lineEdit->setGeometry( rect() );
m_lineEdit->setText(m_desktopName);
m_lineEdit->show();
m_lineEdit->setFocus();
m_lineEdit->selectAll();
m_pager->emitRequestFocus();
}
void KMiniPagerButton::slotToggled( bool b )
{
if ( !b && m_lineEdit )
{
m_lineEdit->hide();
}
}
bool KMiniPagerButton::eventFilter( TQObject *o, TQEvent * e)
{
if (o && o == m_lineEdit &&
(e->type() == TQEvent::FocusOut || e->type() == TQEvent::Hide))
{
m_pager->kwin()->setDesktopName( m_desktop, m_lineEdit->text() );
m_desktopName = m_lineEdit->text();
TQTimer::singleShot( 0, m_lineEdit, TQT_SLOT( deleteLater() ) );
m_lineEdit = 0;
return true;
}
return TQButton::eventFilter(o, e);
}
void KMiniPagerButton::updateKickerTip(KickerTip::Data &data)
{
Task::Dict tasks = TaskManager::the()->tasks();
Task::Dict::iterator taskEnd = tasks.end();
uint taskCounter = 0;
uint taskLimiter = 4;
TQString lastWindow;
for (Task::Dict::iterator it = tasks.begin(); it != taskEnd; ++it)
{
if (it.data()->desktop() == m_desktop || it.data()->isOnAllDesktops())
{
taskCounter++;
if (taskCounter > taskLimiter)
{
lastWindow = it.data()->visibleName();
continue;
}
TQPixmap winIcon = it.data()->pixmap();
TQString bullet;
if (winIcon.isNull())
{
bullet = "&bull;";
}
else
{
data.mimeFactory->setPixmap(TQString::number(taskCounter), winIcon);
bullet = TQString("<img src=\"%1\" width=\"%2\" height=\"%3\">").arg(taskCounter).arg(16).arg(16);
}
TQString name = KStringHandler::cPixelSqueeze(it.data()->visibleName(), fontMetrics(), 400);
name = TQStyleSheet::escape(name);
if (it.data() == m_currentWindow)
{
data.subtext.append(TQString("<br>%1&nbsp; <u>").arg(bullet));
data.subtext.append(name).append("</u>");
}
else
{
data.subtext.append(TQString("<br>%1&nbsp; ").arg(bullet));
data.subtext.append(name);
}
}
}
if (taskCounter > taskLimiter)
{
if (taskCounter - taskLimiter == 1)
{
data.subtext.append("<br>&bull; ").append(lastWindow);
}
else
{
data.subtext.append("<br>&bull; <i>")
.append(i18n("and 1 other", "and %n others", taskCounter - taskLimiter))
.append("</i>");
}
}
if (taskCounter > 0)
{
data.subtext.prepend(i18n("One window:",
"%n windows:",
taskCounter));
}
data.duration = 4000;
data.icon = DesktopIcon("window_list", KIcon::SizeMedium);
data.message = TQStyleSheet::escape(m_desktopName);
data.direction = m_pager->popupDirection();
}