/***************************************************************** 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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_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 layouted 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 layouted 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()->geometry().contains(r.topLeft()) && !TQApplication::desktop()->geometry().contains(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(colorGroup().midlight()); } else if (down) { bp->setPen(KickerLib::blendColors(colorGroup().mid(), colorGroup().midlight())); } else { bp->setPen(colorGroup().dark()); } bp->drawRect(0, 0, w, h); } else { TQBrush background; if (on) { background = colorGroup().brush(TQColorGroup::Midlight); } else if (down) { background = KickerLib::blendColors(colorGroup().mid(), colorGroup().midlight()); } else { background = colorGroup().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 windows = kwin->stackingOrder(); TQValueList::const_iterator itEnd = windows.constEnd(); for (TQValueList::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 = colorGroup().brush(TQColorGroup::Highlight); qDrawShadeRect(bp, r, colorGroup(), false, 1, 0, &brush); } else { TQBrush brush = colorGroup().brush(TQColorGroup::Button); if (on) { brush.setColor(brush.color().light(120)); } bp->fillRect(r, brush); qDrawShadeRect(bp, r, colorGroup(), 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(colorGroup().midlight()); } else { bp->setPen(colorGroup().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 ? colorGroup().midlight() : colorGroup().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), colorGroup().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->geometry(); // 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(colorGroup().foreground()); bp.drawRect(0, 0, ww, wh); bp.fillRect(1, 1, ww - 2, wh - 2, colorGroup().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 = "•"; } else { data.mimeFactory->setPixmap(TQString::number(taskCounter), winIcon); bullet = TQString("").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("
%1  ").arg(bullet)); data.subtext.append(name).append(""); } else { data.subtext.append(TQString("
%1  ").arg(bullet)); data.subtext.append(name); } } } if (taskCounter > taskLimiter) { if (taskCounter - taskLimiter == 1) { data.subtext.append("
• ").append(lastWindow); } else { data.subtext.append("
") .append(i18n("and 1 other", "and %n others", taskCounter - taskLimiter)) .append(""); } } 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(); }