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
******************************************************************/
24
#include <QtGui/qdrawutil.h>
28
#include <QDesktopWidget>
29
#include <QDragEnterEvent>
30
#include <QDragLeaveEvent>
33
#include <QResizeEvent>
37
#include <QMouseEvent>
38
#include <QPaintEvent>
44
#include <kwindowsystem.h>
45
#include <ksharedpixmap.h>
46
#include <kpixmapeffect.h>
47
#include <kstringhandler.h>
48
#include <kiconloader.h>
49
#include <QtDBus/QtDBus>
52
#include "kickertip.h"
53
#include "kickerSettings.h"
54
#include "kshadowengine.h"
56
#include "pagerapplet.h"
57
#include "pagerbutton.h"
58
#include "pagerbutton.moc"
59
#include "pagersettings.h"
65
KSharedPixmap* KMiniPagerButton::s_commonSharedPixmap;
66
QPixmap* KMiniPagerButton::s_commonBgPixmap;
68
KMiniPagerButton::KMiniPagerButton(int desk, KMiniPager *parent, const char *name)
69
: QAbstractButton(parent, name, Qt::WNoAutoErase),
81
//setBackgroundOrigin(AncestorOrigin);
82
installEventFilter(KickerTip::self());
84
m_desktopName = KWindowSystem::desktopName(m_desktop);
86
connect(this, SIGNAL(clicked()), SLOT(slotClicked()));
87
connect(this, SIGNAL(toggled(bool)), SLOT(slotToggled(bool)));
88
connect(&m_dragSwitchTimer, SIGNAL(timeout()), this, SLOT(slotDragSwitch()));
90
m_dragSwitchTimer.setSingleShot(true);
92
if (m_pager->desktopPreview())
94
setMouseTracking(true);
99
KMiniPagerButton::~KMiniPagerButton()
101
delete m_sharedPixmap;
105
bool KMiniPagerButton::shouldPaintWindow( KWindowSystem::WindowInfo *info )
110
// if (info->mappingState != NET::Visible)
113
NET::WindowType type = info->windowType( NET::NormalMask | NET::DesktopMask
114
| NET::DockMask | NET::ToolbarMask | NET::MenuMask | NET::DialogMask
115
| NET::OverrideMask | NET::TopMenuMask | NET::UtilityMask | NET::SplashMask );
117
if (type == NET::Desktop || type == NET::Dock || type == NET::TopMenu)
120
if (!info->isOnDesktop(m_desktop))
123
if (info->state() & NET::SkipPager || info->state() & NET::Shaded )
126
if (info->win() == m_pager->winId())
129
if ( info->isMinimized() )
135
void KMiniPagerButton::resizeEvent(QResizeEvent *ev)
139
m_lineEdit->setGeometry(rect());
145
QAbstractButton::resizeEvent(ev);
148
void KMiniPagerButton::windowsChanged()
154
void KMiniPagerButton::backgroundChanged()
156
delete s_commonSharedPixmap;
157
s_commonSharedPixmap = 0;
158
delete s_commonBgPixmap;
159
s_commonBgPixmap = 0;
163
void KMiniPagerButton::loadBgPixmap()
165
if (m_pager->bgType() != PagerSettings::EnumBackgroundType::BgLive)
166
return; // not needed
170
QDBusInterface kdesktop("org.kde.kdesktop", "/Background", "org.kde.kdesktop.KBackground");
171
QDBusReply<bool> reply = kdesktop.call("isCommon");
179
if (s_commonBgPixmap)
180
{ // pixmap is already ready, just use it
181
backgroundLoaded( true );
184
else if (s_commonSharedPixmap)
185
{ // other button is already fetching the pixmap
186
connect(s_commonSharedPixmap, SIGNAL(done(bool)),
187
SLOT(backgroundLoaded(bool)));
192
kdesktop.call("setExport", 1);
196
if (!s_commonSharedPixmap)
198
s_commonSharedPixmap = new KSharedPixmap;
199
connect(s_commonSharedPixmap, SIGNAL(done(bool)),
200
SLOT(backgroundLoaded(bool)));
202
s_commonSharedPixmap->loadFromShared(QString("DESKTOP1"));
208
m_sharedPixmap = new KSharedPixmap;
209
connect(m_sharedPixmap, SIGNAL(done(bool)),
210
SLOT(backgroundLoaded(bool)));
212
m_sharedPixmap->loadFromShared(QString("DESKTOP%1").arg(m_desktop));
216
static QPixmap scalePixmap(const QPixmap &pixmap, int width, int height)
218
return pixmap.scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
221
QPixmap fastScalePixmap(const QPixmap &pixmap, int width, int height)
224
m.scale( (width / (double)pixmap.width()), (height / (double)pixmap.height()) );
225
return pixmap.transformed(m);
228
void KMiniPagerButton::backgroundLoaded( bool loaded )
234
m_bgPixmap = new QPixmap;
238
if (!s_commonBgPixmap)
240
s_commonBgPixmap = new QPixmap;
241
*s_commonBgPixmap = scalePixmap(s_commonSharedPixmap->pixmap(), width(), height());
242
s_commonSharedPixmap->deleteLater(); // let others get the signal too
243
s_commonSharedPixmap = 0;
245
*m_bgPixmap = *s_commonBgPixmap;
249
*m_bgPixmap = scalePixmap(m_sharedPixmap->pixmap(), width(), height());
250
delete m_sharedPixmap;
254
/* delete m_sharedPixmap;
261
kDebug() << "Error getting the background\n";
265
void KMiniPagerButton::paintEvent(QPaintEvent *)
269
bool on = isEnabled();
270
bool down = isChecked();
271
QPixmap buffer(w, h);
272
QBitmap mask(w, h, true);
273
QPainter bp(&buffer); //### copied attrs from this
278
bool liveBkgnd = m_pager->bgType() == PagerSettings::EnumBackgroundType::BgLive;
279
bool transparent = m_pager->bgType() == PagerSettings::EnumBackgroundType::BgTransparent;
284
if (m_bgPixmap && !m_bgPixmap->isNull())
288
QPixmap tmp = *m_bgPixmap;
289
KPixmapEffect::intensity(tmp, 0.33);
290
bp.drawPixmap(0, 0, tmp);
294
bp.drawPixmap(0, 0, *m_bgPixmap);
308
// transparent windows get an 1 pixel frame...
311
bp.setPen(palette().color( QPalette::Midlight ) );
315
bp.setPen(Plasma::blendColors(palette().color( QPalette::Mid ),
316
palette().color( QPalette::Midlight ) ) );
320
bp.setPen( palette().color( QPalette::Dark ) );
323
bp.drawRect( buffer.rect() );
324
mp.setPen( Qt::color1 );
325
mp.drawRect( buffer.rect() );
333
background = palette().brush(QPalette::Midlight);
337
background = Plasma::blendColors(palette().color( QPalette::Mid ),
338
palette().color( QPalette::Midlight ) );
342
background = palette().brush(QPalette::Mid);
345
bp.fillRect(buffer.rect(), background);
350
if (m_pager->desktopPreview())
352
KWindowSystem::WindowInfo *info = 0;
353
int dw = QApplication::desktop()->width();
354
int dh = QApplication::desktop()->height();
356
QList<WId> windows = KWindowSystem::stackingOrder();
357
QList<WId>::const_iterator itEnd = windows.constEnd();
358
for (QList<WId>::ConstIterator it = windows.constBegin(); it != itEnd; ++it)
360
info = m_pager->info(*it);
362
if (shouldPaintWindow(info))
364
QRect r = info->frameGeometry();
365
r = QRect(r.x() * width() / dw, 2 + r.y() * height() / dh,
366
r.width() * width() / dw, r.height() * height() / dh);
368
if (KWindowSystem::activeWindow() == info->win())
370
QBrush brush = palette().brush(QPalette::Highlight);
371
qDrawShadeRect(&bp, r, palette(), false, 1, 0, &brush);
375
QBrush brush = palette().brush(QPalette::Button);
379
brush.setColor(brush.color().light(120));
382
bp.fillRect(r, brush);
383
qDrawShadeRect(&bp, r, palette(), true, 1, 0);
388
mp.fillRect(r, Qt::color1);
391
if (m_pager->windowIcons() && r.width() > 15 && r.height() > 15)
393
QPixmap icon = KWindowSystem::icon(*it, 16, 16, true);
396
bp.drawPixmap(r.left() + ((r.width() - 16) / 2),
397
r.top() + ((r.height() - 16) / 2),
407
// draw a little border around the individual buttons
408
// makes it look a bit more finished.
411
bp.setPen(palette().midlight());
415
bp.setPen(palette().mid());
418
bp.drawRect(0, 0, w, h);
426
buffer.setMask(mask);
429
bp.eraseRect(rect());
430
bp.drawPixmap(0, 0, buffer);
433
if (m_pager->labelType() != PagerSettings::EnumLabelType::LabelNone)
435
QString label = (m_pager->labelType() == PagerSettings::EnumLabelType::LabelNumber) ?
436
QString::number(m_desktop) : m_desktopName;
438
QPixmap textPixmap(width(), height());
440
textPixmap.fill(QColor(0,0,0));
441
textPixmap.setMask(textPixmap.createHeuristicMask(true));
444
tp.begin(&textPixmap);
445
tp.setPen(Qt::white);
446
tp.setFont(font()); // get the font from the root painter
447
tp.drawText(0, 0, w, h, Qt::AlignCenter, label);
451
QImage img = m_pager->shadowEngine()->makeShadow(textPixmap,
452
liveBkgnd ? Qt::black
455
bp.drawImage(0, 0, img);
456
bp.drawText(0, 0, w, h, Qt::AlignCenter, label);
463
bp.drawPixmap(0, 0, buffer);
469
void KMiniPagerButton::mousePressEvent(QMouseEvent * e)
471
if (e->button() == Qt::RightButton)
473
// prevent LMB down -> RMB down -> LMB up sequence
474
if ((e->state() & Qt::MouseButtonMask ) == Qt::NoButton)
476
emit showMenu(e->globalPos(), m_desktop);
481
if (m_pager->desktopPreview())
483
m_pager->clickPos = e->pos();
486
QAbstractButton::mouseReleaseEvent(e);
489
void KMiniPagerButton::mouseReleaseEvent(QMouseEvent* e)
491
m_pager->clickPos = QPoint();
492
QAbstractButton::mouseReleaseEvent(e);
495
void KMiniPagerButton::mouseMoveEvent(QMouseEvent* e)
497
if (!m_pager->desktopPreview())
502
int dw = QApplication::desktop()->width();
503
int dh = QApplication::desktop()->height();
507
QPoint pos(m_pager->clickPos.isNull() ? mapFromGlobal(QCursor::pos()) : m_pager->clickPos);
508
QPoint p(pos.x() * dw / w, pos.y() * dh / h);
509
Task::TaskPtr wasWindow = m_currentWindow;
510
m_currentWindow = TaskManager::self()->findTask(m_desktop, p);
512
if (wasWindow != m_currentWindow)
514
KickerTip::Client::updateTip();
517
if (m_currentWindow && !m_pager->clickPos.isNull() &&
518
(m_pager->clickPos - e->pos()).manhattanLength() > KGlobalSettings::dndEventDelay())
520
QRect r = m_currentWindow->geometry();
522
// preview window height, window width
523
int ww = r.width() * w / dw;
524
int wh = r.height() * h / dh;
525
QPixmap windowImage(ww, wh);
526
QPainter bp(&windowImage); //### copied attributes from this
528
bp.setPen( palette().color( QPalette::Foreground ) );
529
bp.drawRect(0, 0, ww, wh);
530
bp.fillRect(1, 1, ww - 2, wh - 2, palette().color( QPalette::Background) );
533
tasklist.append(m_currentWindow);
534
TaskDrag* drag = new TaskDrag(tasklist, this);
535
QPoint offset(m_pager->clickPos.x() - (r.x() * w / dw),
536
m_pager->clickPos.y() - (r.y() * h / dh));
537
drag->setPixmap(windowImage);
538
drag->setHotSpot(offset);
546
m_pager->clickPos = QPoint();
550
void KMiniPagerButton::dragEnterEvent(QDragEnterEvent* e)
552
kDebug() << "received drag " << e->format();
553
if (TaskDrag::canDecode(e->mimeData()))
555
// if it's a task drag don't switch the desktop, just accept it
561
// if a dragitem is held for over a pager button for two seconds,
562
// activate corresponding desktop
563
m_dragSwitchTimer.start(1000);
564
QAbstractButton::dragEnterEvent( e );
568
void KMiniPagerButton::dropEvent(QDropEvent* e)
570
if (TaskDrag::canDecode(e->mimeData()))
573
Task::List tasks(TaskDrag::decode(e->mimeData()));
575
if (e->source() == this && tasks.count() == 1)
577
Task::TaskPtr task = tasks[0];
578
int dw = QApplication::desktop()->width();
579
int dh = QApplication::desktop()->height();
582
QRect location = task->geometry();
583
location.translate((e->pos().x() - m_pager->clickPos.x()) * dw / w,
584
(e->pos().y() - m_pager->clickPos.y()) * dh / h);
586
XMoveWindow(x11Display(), task->window(), location.x(), location.y());
587
if ((e->source() != this || !task->isOnAllDesktops()) &&
588
task->desktop() != m_desktop)
590
task->toDesktop(m_desktop);
595
Task::List::iterator itEnd = tasks.end();
596
for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
598
(*it)->toDesktop(m_desktop);
605
QAbstractButton::dropEvent( e );
608
void KMiniPagerButton::enabledChange( bool oldEnabled )
610
if (m_pager->bgType() == PagerSettings::EnumBackgroundType::BgLive)
615
QAbstractButton::enabledChange( oldEnabled );
618
void KMiniPagerButton::dragLeaveEvent( QDragLeaveEvent* e )
620
m_dragSwitchTimer.stop();
622
if (KWindowSystem::currentDesktop() != m_desktop)
627
QAbstractButton::dragLeaveEvent( e );
630
void KMiniPagerButton::slotDragSwitch()
632
emit buttonSelected(m_desktop);
635
void KMiniPagerButton::slotClicked()
637
emit buttonSelected(m_desktop);
640
void KMiniPagerButton::rename()
643
m_lineEdit = new QLineEdit( this );
644
connect( m_lineEdit, SIGNAL( returnPressed() ), m_lineEdit, SLOT( hide() ) );
645
m_lineEdit->installEventFilter( this );
647
m_lineEdit->setGeometry( rect() );
648
m_lineEdit->setText(m_desktopName);
650
m_lineEdit->setFocus();
651
m_lineEdit->selectAll();
652
m_pager->emitRequestFocus();
655
void KMiniPagerButton::slotToggled( bool b )
657
if ( !b && m_lineEdit )
663
bool KMiniPagerButton::eventFilter( QObject *o, QEvent * e)
665
if (o && o == m_lineEdit &&
666
(e->type() == QEvent::FocusOut || e->type() == QEvent::Hide))
668
KWindowSystem::setDesktopName( m_desktop, m_lineEdit->text() );
669
m_desktopName = m_lineEdit->text();
670
QTimer::singleShot( 0, m_lineEdit, SLOT( deleteLater() ) );
675
return QAbstractButton::eventFilter(o, e);
678
void KMiniPagerButton::updateTipData(KickerTip::Data &data)
680
Task::Dict tasks = TaskManager::self()->tasks();
681
Task::Dict::iterator taskEnd = tasks.end();
682
uint taskCounter = 0;
683
uint taskLimiter = 4;
686
for (Task::Dict::iterator it = tasks.begin(); it != taskEnd; ++it)
688
if (it.value()->desktop() == m_desktop || it.value()->isOnAllDesktops())
691
if (taskCounter > taskLimiter)
693
lastWindow = it.value()->visibleName();
697
if (it.value() == m_currentWindow)
699
data.subtext.append("<br>• <u>").append(it.value()->visibleName()).append("</u>");
703
data.subtext.append("<br>• ").append(it.value()->visibleName());
708
if (taskCounter > taskLimiter)
710
if (taskCounter - taskLimiter == 1)
712
data.subtext.append("<br>• ").append(lastWindow);
716
data.subtext.append("<br>• <i>")
717
.append(i18n("and %1 others",
718
taskCounter - taskLimiter))
725
data.subtext.prepend(i18np("One window:",
730
data.icon = DesktopIcon("window_list", K3Icon::SizeMedium);
731
data.message = m_desktopName;
732
data.direction = m_pager->popupDirection();