1
/*****************************************************************
3
Copyright (c) 1996-2000 the kicker authors. See file AUTHORS.
5
Permission is hereby granted, free of charge, to any person obtaining a copy
6
of this software and associated documentation files (the "Software"), to deal
7
in the Software without restriction, including without limitation the rights
8
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
copies of the Software, and to permit persons to whom the Software is
10
furnished to do so, subject to the following conditions:
12
The above copyright notice and this permission notice shall be included in
13
all copies or substantial portions of the Software.
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
******************************************************************/
27
#include <qdrawutil.h>
28
#include <qlineedit.h>
30
#include <qpopupmenu.h>
31
#include <qstylesheet.h>
34
#include <dcopclient.h>
36
#include <kwinmodule.h>
37
#include <ksharedpixmap.h>
38
#include <kpixmapio.h>
39
#include <kpixmapeffect.h>
40
#include <kstringhandler.h>
41
#include <kiconloader.h>
44
#include "kickertip.h"
45
#include "kickerSettings.h"
46
#include "kshadowengine.h"
47
#include "paneldrag.h"
49
#include "pagerapplet.h"
50
#include "pagerbutton.h"
51
#include "pagerbutton.moc"
52
#include "pagersettings.h"
58
KSharedPixmap* KMiniPagerButton::s_commonSharedPixmap;
59
KPixmap* KMiniPagerButton::s_commonBgPixmap;
61
KMiniPagerButton::KMiniPagerButton(int desk, bool useViewPorts, const QPoint& viewport,
62
KMiniPager *parent, const char *name)
63
: QButton(parent, name),
66
m_useViewports(useViewPorts),
75
setToggleButton(true);
77
setWFlags(WNoAutoErase);
79
setBackgroundOrigin(AncestorOrigin);
80
installEventFilter(KickerTip::the());
82
m_desktopName = m_pager->kwin()->desktopName(m_desktop);
84
connect(this, SIGNAL(clicked()), SLOT(slotClicked()));
85
connect(this, SIGNAL(toggled(bool)), SLOT(slotToggled(bool)));
86
connect(&m_dragSwitchTimer, SIGNAL(timeout()), this, SLOT(slotDragSwitch()));
87
connect(&m_updateCompressor, SIGNAL(timeout()), this, SLOT(update()));
89
if (m_pager->desktopPreview())
91
setMouseTracking(true);
96
KMiniPagerButton::~KMiniPagerButton()
98
delete m_sharedPixmap;
102
QRect KMiniPagerButton::mapGeometryToViewport(const KWin::WindowInfo& info) const
105
return info.frameGeometry();
107
// ### fix vertically layouted viewports
108
QRect _r(info.frameGeometry());
109
QPoint vx(m_pager->kwin()->currentViewport(m_pager->kwin()->currentDesktop()));
111
_r.moveBy( - (m_desktop - vx.x()) * QApplication::desktop()->width(),
114
if ((info.state() & NET::Sticky))
116
_r.moveTopLeft(QPoint(_r.x() % QApplication::desktop()->width(),
117
_r.y() % QApplication::desktop()->height()));
124
QPoint KMiniPagerButton::mapPointToViewport(const QPoint& _p) const
126
if (!m_useViewports) return _p;
128
QPoint vx(m_pager->kwin()->currentViewport(m_pager->kwin()->currentDesktop()));
130
// ### fix vertically layouted viewports
132
p.setX(p.x() + (m_desktop - vx.x()) * QApplication::desktop()->width());
136
bool KMiniPagerButton::shouldPaintWindow( KWin::WindowInfo *info ) const
141
// if (info->mappingState != NET::Visible)
144
NET::WindowType type = info->windowType( NET::NormalMask | NET::DesktopMask
145
| NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
146
| NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask );
148
if (type == NET::Desktop || type == NET::Dock || type == NET::TopMenu)
151
if (!m_useViewports && !info->isOnDesktop(m_desktop))
154
if (m_useViewports) {
155
QRect r = mapGeometryToViewport(*info);
157
if (!info->hasState(NET::Sticky) &&
158
!QApplication::desktop()->geometry().contains(r.topLeft()) &&
159
!QApplication::desktop()->geometry().contains(r.topRight()))
163
if (info->state() & NET::SkipPager || info->state() & NET::Shaded )
166
if (info->win() == m_pager->winId())
169
if ( info->isMinimized() )
175
void KMiniPagerButton::resizeEvent(QResizeEvent *ev)
179
m_lineEdit->setGeometry(rect());
185
QButton::resizeEvent(ev);
188
void KMiniPagerButton::windowsChanged()
192
if (!m_updateCompressor.isActive())
194
m_updateCompressor.start(50, true);
198
void KMiniPagerButton::backgroundChanged()
200
delete s_commonSharedPixmap;
201
s_commonSharedPixmap = 0;
202
delete s_commonBgPixmap;
203
s_commonBgPixmap = 0;
207
void KMiniPagerButton::loadBgPixmap()
209
if (m_pager->bgType() != PagerSettings::EnumBackgroundType::BgLive)
210
return; // not needed
212
DCOPClient *client = kapp->dcopClient();
213
if (!client->isAttached())
218
QCString kdesktop_name;
219
int screen_number = DefaultScreen(qt_xdisplay());
220
if (screen_number == 0)
221
kdesktop_name = "kdesktop";
223
kdesktop_name.sprintf("kdesktop-screen-%d", screen_number);
225
QByteArray data, replyData;
227
if (client->call(kdesktop_name, "KBackgroundIface", "isCommon()",
228
data, replyType, replyData))
230
if (replyType == "bool")
232
QDataStream reply(replyData, IO_ReadOnly);
239
if (s_commonBgPixmap)
240
{ // pixmap is already ready, just use it
241
backgroundLoaded( true );
244
else if (s_commonSharedPixmap)
245
{ // other button is already fetching the pixmap
246
connect(s_commonSharedPixmap, SIGNAL(done(bool)),
247
SLOT(backgroundLoaded(bool)));
252
QDataStream args( data, IO_WriteOnly );
254
client->send(kdesktop_name, "KBackgroundIface", "setExport(int)", data);
258
if (!s_commonSharedPixmap)
260
s_commonSharedPixmap = new KSharedPixmap;
261
connect(s_commonSharedPixmap, SIGNAL(done(bool)),
262
SLOT(backgroundLoaded(bool)));
264
s_commonSharedPixmap->loadFromShared(QString("DESKTOP1"));
270
m_sharedPixmap = new KSharedPixmap;
271
connect(m_sharedPixmap, SIGNAL(done(bool)),
272
SLOT(backgroundLoaded(bool)));
274
m_sharedPixmap->loadFromShared(QString("DESKTOP%1").arg(m_desktop));
278
static QPixmap scalePixmap(const QPixmap &pixmap, int width, int height)
280
if (pixmap.width()>100)
283
QImage img( io.convertToImage( pixmap ) );
284
return io.convertToPixmap( img.smoothScale( width, height ) );
287
QImage img( pixmap.convertToImage().smoothScale( width, height ) );
289
pix.convertFromImage( img );
294
void KMiniPagerButton::backgroundLoaded( bool loaded )
300
m_bgPixmap = new KPixmap;
304
if (!s_commonBgPixmap)
306
s_commonBgPixmap = new KPixmap;
307
*s_commonBgPixmap = scalePixmap(*s_commonSharedPixmap, width(), height());
308
s_commonSharedPixmap->deleteLater(); // let others get the signal too
309
s_commonSharedPixmap = 0;
311
*m_bgPixmap = *s_commonBgPixmap;
315
*m_bgPixmap = scalePixmap(*m_sharedPixmap, width(), height());
316
delete m_sharedPixmap;
324
kdWarning() << "Error getting the background\n";
328
void KMiniPagerButton::enterEvent(QEvent *)
334
void KMiniPagerButton::leaveEvent(QEvent *)
340
void KMiniPagerButton::drawButton(QPainter *bp)
345
bool down = isDown();
349
bool liveBkgnd = m_pager->bgType() == PagerSettings::EnumBackgroundType::BgLive;
350
bool transparent = m_pager->bgType() == PagerSettings::EnumBackgroundType::BgTransparent;
354
if (backgroundPixmap())
356
QPoint pt = backgroundOffset();
357
bp->drawTiledPixmap(0, 0, width(), height(), *backgroundPixmap(), pt.x(), pt.y());
361
bp->fillRect(0, 0, width(), height(), paletteBackgroundColor());
365
// desktop background
369
if (m_bgPixmap && !m_bgPixmap->isNull())
373
KPixmap tmp = *m_bgPixmap;
374
KPixmapEffect::intensity(tmp, 0.33);
375
bp->drawPixmap(0, 0, tmp);
379
bp->drawPixmap(0, 0, *m_bgPixmap);
392
// transparent windows get an 1 pixel frame...
395
bp->setPen(colorGroup().midlight());
399
bp->setPen(KickerLib::blendColors(colorGroup().mid(),
400
colorGroup().midlight()));
404
bp->setPen(colorGroup().dark());
407
bp->drawRect(0, 0, w, h);
415
background = colorGroup().brush(QColorGroup::Midlight);
419
background = KickerLib::blendColors(colorGroup().mid(),
420
colorGroup().midlight());
424
background = colorGroup().brush(QColorGroup::Mid);
427
bp->fillRect(0, 0, w, h, background);
432
if (m_pager->desktopPreview())
434
KWinModule* kwin = m_pager->kwin();
435
KWin::WindowInfo *info = 0;
436
int dw = QApplication::desktop()->width();
437
int dh = QApplication::desktop()->height();
439
QValueList<WId> windows = kwin->stackingOrder();
440
QValueList<WId>::const_iterator itEnd = windows.constEnd();
441
for (QValueList<WId>::ConstIterator it = windows.constBegin(); it != itEnd; ++it)
443
info = m_pager->info(*it);
445
if (shouldPaintWindow(info))
447
QRect r = mapGeometryToViewport(*info);
448
r = QRect(r.x() * width() / dw, 2 + r.y() * height() / dh,
449
r.width() * width() / dw, r.height() * height() / dh);
451
if (kwin->activeWindow() == info->win())
453
QBrush brush = colorGroup().brush(QColorGroup::Highlight);
454
qDrawShadeRect(bp, r, colorGroup(), false, 1, 0, &brush);
458
QBrush brush = colorGroup().brush(QColorGroup::Button);
462
brush.setColor(brush.color().light(120));
465
bp->fillRect(r, brush);
466
qDrawShadeRect(bp, r, colorGroup(), true, 1, 0);
469
if (m_pager->windowIcons() && r.width() > 15 && r.height() > 15)
471
QPixmap icon = KWin::icon(*it, 16, 16, true);
474
bp->drawPixmap(r.left() + ((r.width() - 16) / 2),
475
r.top() + ((r.height() - 16) / 2),
485
// draw a little border around the individual buttons
486
// makes it look a bit more finished.
489
bp->setPen(colorGroup().midlight());
493
bp->setPen(colorGroup().mid());
496
bp->drawRect(0, 0, w, h);
499
if (m_pager->labelType() != PagerSettings::EnumLabelType::LabelNone)
501
QString label = (m_pager->labelType() == PagerSettings::EnumLabelType::LabelNumber) ?
502
QString::number(m_desktop) : m_desktopName;
504
if (transparent || liveBkgnd)
506
bp->setPen(on ? colorGroup().midlight() : colorGroup().buttonText());
507
m_pager->shadowEngine()->drawText(*bp, QRect(0, 0, w, h), AlignCenter, label, size());
510
bp->drawText(0, 0, w, h, AlignCenter, label);
514
KickerLib::drawBlendedRect(bp, QRect(1, 1, width() - 2, height() - 2), colorGroup().foreground());
517
void KMiniPagerButton::mousePressEvent(QMouseEvent * e)
519
if (e->button() == RightButton)
521
// prevent LMB down -> RMB down -> LMB up sequence
522
if ((e->state() & MouseButtonMask ) == NoButton)
524
emit showMenu(e->globalPos(), m_desktop);
529
if (m_pager->desktopPreview())
531
m_pager->clickPos = e->pos();
534
QButton::mousePressEvent(e);
537
void KMiniPagerButton::mouseReleaseEvent(QMouseEvent* e)
539
m_pager->clickPos = QPoint();
540
QButton::mouseReleaseEvent(e);
543
void KMiniPagerButton::mouseMoveEvent(QMouseEvent* e)
545
if (!m_pager->desktopPreview())
550
int dw = QApplication::desktop()->width();
551
int dh = QApplication::desktop()->height();
555
QPoint pos(m_pager->clickPos.isNull() ? mapFromGlobal(QCursor::pos()) : m_pager->clickPos);
556
QPoint p = mapPointToViewport(QPoint(pos.x() * dw / w, pos.y() * dh / h));
558
Task::Ptr wasWindow = m_currentWindow;
559
m_currentWindow = TaskManager::the()->findTask(m_useViewports ? 1 : m_desktop, p);
561
if (wasWindow != m_currentWindow)
563
KickerTip::Client::updateKickerTip();
566
if (m_currentWindow && !m_pager->clickPos.isNull() &&
567
(m_pager->clickPos - e->pos()).manhattanLength() > KGlobalSettings::dndEventDelay())
569
QRect r = m_currentWindow->geometry();
571
// preview window height, window width
572
int ww = r.width() * w / dw;
573
int wh = r.height() * h / dh;
574
QPixmap windowImage(ww, wh);
575
QPainter bp(&windowImage, this);
577
bp.setPen(colorGroup().foreground());
578
bp.drawRect(0, 0, ww, wh);
579
bp.fillRect(1, 1, ww - 2, wh - 2, colorGroup().background());
582
tasklist.append(m_currentWindow);
583
TaskDrag* drag = new TaskDrag(tasklist, this);
584
QPoint offset(m_pager->clickPos.x() - (r.x() * w / dw),
585
m_pager->clickPos.y() - (r.y() * h / dh));
586
drag->setPixmap(windowImage, offset);
594
m_pager->clickPos = QPoint();
598
void KMiniPagerButton::dragEnterEvent(QDragEnterEvent* e)
600
if (PanelDrag::canDecode(e))
602
// ignore container drags
605
else if (TaskDrag::canDecode(e))
607
// if it's a task drag don't switch the desktop, just accept it
613
// if a dragitem is held for over a pager button for two seconds,
614
// activate corresponding desktop
615
m_dragSwitchTimer.start(1000, true);
616
QButton::dragEnterEvent(e);
620
void KMiniPagerButton::dropEvent(QDropEvent* e)
622
if (TaskDrag::canDecode(e))
625
Task::List tasks(TaskDrag::decode(e));
627
if ((m_useViewports || e->source() == this) && tasks.count() == 1)
629
Task::Ptr task = tasks[0];
630
int dw = QApplication::desktop()->width();
631
int dh = QApplication::desktop()->height();
634
QRect location = mapGeometryToViewport(task->info());
635
QPoint pos = mapPointToViewport(e->pos());
636
int deltaX = pos.x() - m_pager->clickPos.x();
637
int deltaY = pos.y() - m_pager->clickPos.y();
645
deltaX = deltaX * dw / w;
654
deltaY = deltaY * dh / h;
657
location.moveBy(deltaX, deltaY);
659
XMoveWindow(x11Display(), task->window(), location.x(), location.y());
660
if ((e->source() != this || !task->isOnAllDesktops()) &&
661
task->desktop() != m_desktop)
663
task->toDesktop(m_desktop);
668
Task::List::iterator itEnd = tasks.end();
669
for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
671
(*it)->toDesktop(m_desktop);
678
QButton::dropEvent( e );
681
void KMiniPagerButton::enabledChange( bool oldEnabled )
683
if (m_pager->bgType() == PagerSettings::EnumBackgroundType::BgLive)
688
QButton::enabledChange(oldEnabled);
691
void KMiniPagerButton::dragLeaveEvent( QDragLeaveEvent* e )
693
m_dragSwitchTimer.stop();
695
if (m_pager->kwin()->currentDesktop() != m_desktop)
700
QButton::dragLeaveEvent( e );
703
void KMiniPagerButton::slotDragSwitch()
705
emit buttonSelected(m_desktop);
708
void KMiniPagerButton::slotClicked()
710
emit buttonSelected(m_desktop);
713
void KMiniPagerButton::rename()
716
m_lineEdit = new QLineEdit( this );
717
connect( m_lineEdit, SIGNAL( returnPressed() ), m_lineEdit, SLOT( hide() ) );
718
m_lineEdit->installEventFilter( this );
720
m_lineEdit->setGeometry( rect() );
721
m_lineEdit->setText(m_desktopName);
723
m_lineEdit->setFocus();
724
m_lineEdit->selectAll();
725
m_pager->emitRequestFocus();
728
void KMiniPagerButton::slotToggled( bool b )
730
if ( !b && m_lineEdit )
736
bool KMiniPagerButton::eventFilter( QObject *o, QEvent * e)
738
if (o && o == m_lineEdit &&
739
(e->type() == QEvent::FocusOut || e->type() == QEvent::Hide))
741
m_pager->kwin()->setDesktopName( m_desktop, m_lineEdit->text() );
742
m_desktopName = m_lineEdit->text();
743
QTimer::singleShot( 0, m_lineEdit, SLOT( deleteLater() ) );
748
return QButton::eventFilter(o, e);
751
void KMiniPagerButton::updateKickerTip(KickerTip::Data &data)
753
Task::Dict tasks = TaskManager::the()->tasks();
754
Task::Dict::iterator taskEnd = tasks.end();
755
uint taskCounter = 0;
756
uint taskLimiter = 4;
759
for (Task::Dict::iterator it = tasks.begin(); it != taskEnd; ++it)
761
if (it.data()->desktop() == m_desktop || it.data()->isOnAllDesktops())
764
if (taskCounter > taskLimiter)
766
lastWindow = it.data()->visibleName();
770
QPixmap winIcon = it.data()->pixmap();
773
if (winIcon.isNull())
779
data.mimeFactory->setPixmap(QString::number(taskCounter), winIcon);
780
bullet = QString("<img src=\"%1\" width=\"%2\" height=\"%3\">").arg(taskCounter).arg(16).arg(16);
783
QString name = KStringHandler::cPixelSqueeze(it.data()->visibleName(), fontMetrics(), 400);
784
name = QStyleSheet::escape(name);
785
if (it.data() == m_currentWindow)
787
data.subtext.append(QString("<br>%1 <u>").arg(bullet));
788
data.subtext.append(name).append("</u>");
792
data.subtext.append(QString("<br>%1 ").arg(bullet));
793
data.subtext.append(name);
798
if (taskCounter > taskLimiter)
800
if (taskCounter - taskLimiter == 1)
802
data.subtext.append("<br>• ").append(lastWindow);
806
data.subtext.append("<br>• <i>")
807
.append(i18n("and 1 other", "and %n others", taskCounter - taskLimiter))
814
data.subtext.prepend(i18n("One window:",
819
data.duration = 4000;
820
data.icon = DesktopIcon("window_list", KIcon::SizeMedium);
821
data.message = QStyleSheet::escape(m_desktopName);
822
data.direction = m_pager->popupDirection();