• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

libplasma

tooltip.cpp

Go to the documentation of this file.
00001 /*
00002  *   Copyright 2007 by Dan Meltzer <hydrogen@notyetimplemented.com>
00003  *
00004  *   This program is free software; you can redistribute it and/or modify
00005  *   it under the terms of the GNU Library General Public License as
00006  *   published by the Free Software Foundation; either version 2, or
00007  *   (at your option) any later version.
00008 
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details
00014  *
00015  *   You should have received a copy of the GNU Library General Public
00016  *   License along with this program; if not, write to the
00017  *   Free Software Foundation, Inc.,
00018  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00019  */
00020 #include "tooltip_p.h"
00021 
00022 #include <QBitmap>
00023 #include <QHBoxLayout>
00024 #include <QLabel>
00025 #include <QMouseEvent>
00026 #include <QPixmap>
00027 #include <QTimer>
00028 #include <QGraphicsView>
00029 #ifdef Q_WS_X11
00030 #include <QX11Info>
00031 #endif
00032 
00033 #include <KDebug>
00034 #include <KGlobal>
00035 #include <KWindowSystem>
00036 #include <plasma/theme.h>
00037 #include <plasma/panelsvg.h>
00038 
00039 #ifdef Q_WS_X11
00040 #include <X11/Xlib.h>
00041 #include <fixx11h.h>
00042 #endif
00043 
00044 #include "plasma/plasma.h"
00045 
00046 namespace Plasma {
00047 
00048 class ToolTipPrivate
00049 {
00050     public:
00051         ToolTipPrivate()
00052         : label(0)
00053         , imageLabel(0)
00054         , preview(0)
00055         , windowToPreview(0)
00056         , currentWidget(0)
00057         , isShown(false)
00058         , delayedHide(false)
00059         , showTimer(0)
00060         , hideTimer(0)
00061     { }
00062 
00063     QLabel *label;
00064     QLabel *imageLabel;
00065     WindowPreview *preview;
00066     WId windowToPreview;
00067     Plasma::Widget *currentWidget;
00068     bool isShown;
00069     bool delayedHide;
00070     QTimer *showTimer;
00071     QTimer *hideTimer;
00072 
00073     PanelSvg *background;
00074 
00075 };
00076 
00077 class ToolTipSingleton
00078 {
00079     public:
00080         ToolTip self;
00081 };
00082 K_GLOBAL_STATIC( ToolTipSingleton, privateInstance )
00083 
00084 ToolTip *ToolTip::self()
00085 {
00086     return &privateInstance->self;
00087 }
00088 
00089 void ToolTip::show(Plasma::Widget *widget)
00090 {
00091     d->hideTimer->stop();
00092     d->delayedHide = false;
00093     if (d->isShown && d->currentWidget) {
00094         // we let know widget which had tooltip up to now that it's tooltip
00095         // is not longer displayed
00096         d->currentWidget->updateToolTip(false);
00097     }
00098     d->currentWidget = widget;
00099     d->showTimer->stop();
00100 
00101     if (d->isShown) {
00102         // small delay to prevent unnecessary showing when the mouse is moving quickly across items
00103         // which can be too much for less powerful CPUs to keep up with
00104         d->showTimer->start(200);
00105     } else {
00106         d->showTimer->start(500);
00107     }
00108 }
00109 
00110 void ToolTip::delayedHide()
00111 {
00112     d->showTimer->stop();  // stop the timer to show the tooltip
00113     d->delayedHide = true;
00114     d->hideTimer->start(250);
00115 }
00116 
00117 void ToolTip::hide()
00118 {
00119     d->currentWidget = 0;
00120     d->showTimer->stop();  //Mouse out, stop the timer to show the tooltip
00121     d->delayedHide = false;
00122     setVisible(false);
00123     d->hideTimer->start(250);  //250 ms delay before we are officially "gone" to allow for the time to move between widgets
00124 }
00125 
00126 Plasma::Widget *ToolTip::currentWidget() const
00127 {
00128     return d->currentWidget;
00129 }
00130 
00131 //PRIVATE FUNCTIONS
00132 void ToolTip::showToolTip()
00133 {
00134     if (!d->currentWidget || !d->currentWidget->toolTip()) {
00135         return;
00136     }
00137 
00138     QGraphicsView *v = d->currentWidget->view();
00139     if (v && v->mouseGrabber()) {
00140         return;
00141     }
00142 
00143     d->currentWidget->updateToolTip(true);
00144     setData(*d->currentWidget->toolTip());
00145 
00146     if( d->windowToPreview != 0 ) {
00147         // show/hide the preview area
00148         d->preview->show();
00149     } else {
00150         d->preview->hide();
00151     }
00152     layout()->activate();
00153 
00154     resize(sizeHint());
00155     move(d->currentWidget->popupPosition(size()));
00156 
00157     if (isVisible()) {
00158         d->preview->setInfo();
00159     } else {
00160         setVisible(true);
00161     }
00162 
00163     d->isShown = true;  //ToolTip is visible
00164 }
00165 
00166 void ToolTip::resetShownState()
00167 {
00168     if (!isVisible() || //One might have moused out and back in again
00169         d->delayedHide) {
00170         d->delayedHide = false;
00171         d->isShown = false;
00172         setVisible(false);
00173         if (d->currentWidget) {
00174             d->currentWidget->updateToolTip(false);
00175         }
00176         d->currentWidget = 0;
00177     }
00178 }
00179 
00180 void ToolTip::showEvent(QShowEvent *e)
00181 {
00182     QWidget::showEvent(e);
00183     d->preview->setInfo();
00184 }
00185 
00186 void ToolTip::mouseReleaseEvent(QMouseEvent* event)
00187 {
00188     if (rect().contains(event->pos())) {
00189         hide();
00190     }
00191 }
00192 
00193 ToolTip::ToolTip()
00194     : QWidget(0)
00195     , d( new ToolTipPrivate )
00196 {
00197     setWindowFlags(Qt::ToolTip);
00198     QGridLayout *l = new QGridLayout;
00199     d->preview = new WindowPreview;
00200     d->label = new QLabel;
00201     d->label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
00202     d->label->setWordWrap(true);
00203     d->imageLabel = new QLabel;
00204     d->imageLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
00205 
00206     d->background = new PanelSvg("widgets/tooltip", this);
00207     d->background->setBorderFlags(PanelSvg::DrawAllBorders);
00208 
00209     connect(d->background, SIGNAL(repaintNeeded()), this, SLOT(update()));
00210 
00211     l->addWidget(d->preview, 0, 0, 1, 2);
00212     l->addWidget(d->imageLabel, 1, 0);
00213     l->addWidget(d->label, 1, 1);
00214     setLayout(l);
00215 
00216     d->showTimer = new QTimer(this);
00217     d->showTimer->setSingleShot(true);
00218     d->hideTimer = new QTimer(this);
00219     d->hideTimer->setSingleShot(true);
00220 
00221     connect(d->showTimer, SIGNAL(timeout()), SLOT(showToolTip()));
00222     connect(d->hideTimer, SIGNAL(timeout()), SLOT(resetShownState()));
00223 
00224     connect(Plasma::Theme::self(), SIGNAL(themeChanged()), this, SLOT(themeUpdated()));
00225     themeUpdated();
00226 }
00227 
00228 ToolTip::~ToolTip()
00229 {
00230     delete d;
00231 }
00232 
00233 void ToolTip::setData(Plasma::Widget *widget, const Plasma::ToolTipData &data)
00234 {
00235     if (d->currentWidget && d->currentWidget == widget) {
00236         setData(data);
00237     }
00238 }
00239 
00240 void ToolTip::setData(const Plasma::ToolTipData &data)
00241 {
00242     //reset our size
00243     d->label->setText("<qt><b>" + data.mainText + "</b><br>" + data.subText + "</qt>");
00244     d->imageLabel->setPixmap(data.image);
00245     d->windowToPreview = data.windowToPreview;
00246     d->preview->setWindowId( d->windowToPreview );
00247 
00248     if (isVisible()) {
00249         resize(sizeHint());
00250 
00251         if (d->currentWidget) {
00252             move(d->currentWidget->popupPosition(size()));
00253         }
00254     }
00255 }
00256 
00257 void ToolTip::themeUpdated()
00258 {
00259     const int topHeight = d->background->marginSize(Plasma::TopMargin);
00260     const int leftWidth = d->background->marginSize(Plasma::LeftMargin);
00261     const int rightWidth = d->background->marginSize(Plasma::RightMargin);
00262     const int bottomHeight = d->background->marginSize(Plasma::BottomMargin);
00263     setContentsMargins(leftWidth, topHeight, rightWidth, bottomHeight);
00264 
00265     // Make the tooltip use Plasma's colorscheme
00266     QPalette plasmaPalette = QPalette();
00267     plasmaPalette.setColor(QPalette::Window, Plasma::Theme::self()->backgroundColor());
00268     plasmaPalette.setColor(QPalette::WindowText, Plasma::Theme::self()->textColor());
00269     setAutoFillBackground(true);
00270     setPalette(plasmaPalette);
00271 }
00272 
00273 // A widget which reserves area for window preview and sets hints on the toplevel
00274 // tooltip widget that tells KWin to render the preview in this area. This depends
00275 // on KWin's TaskbarThumbnail compositing effect (which is here detected).
00276 
00277 void WindowPreview::setWindowId(WId w)
00278 {
00279     if (!previewsAvailable()) {
00280         id = 0;
00281         return;
00282     }
00283     id = w;
00284     readWindowSize();
00285 }
00286 
00287 bool WindowPreview::previewsAvailable() const
00288 {
00289     if (!KWindowSystem::compositingActive()) {
00290         return false;
00291     }
00292 #ifdef Q_WS_X11
00293     // hackish way to find out if KWin has the effect enabled,
00294     // TODO provide proper support
00295     Display* dpy = QX11Info::display();
00296     Atom atom = XInternAtom(dpy, "_KDE_WINDOW_PREVIEW", False);
00297     int cnt;
00298     Atom* list = XListProperties(dpy, DefaultRootWindow( dpy ), &cnt);
00299     if (list != NULL) {
00300         bool ret = ( qFind(list, list + cnt, atom) != list + cnt );
00301         XFree(list);
00302         return ret;
00303     }
00304 #endif
00305     return false;
00306 }
00307 
00308 QSize WindowPreview::sizeHint() const
00309 {
00310     if (id == 0) {
00311         return QSize();
00312     }
00313     if (!windowSize.isValid()) {
00314         readWindowSize();
00315     }
00316     QSize s = windowSize;
00317     s.scale(200, 150, Qt::KeepAspectRatio);
00318     return s;
00319 }
00320 
00321 void WindowPreview::readWindowSize() const
00322 {
00323 #ifdef Q_WS_X11
00324     Window r;
00325     int x, y;
00326     unsigned int w, h, b, d;
00327     if (XGetGeometry(QX11Info::display(), id, &r, &x, &y, &w, &h, &b, &d)) {
00328         windowSize = QSize( w, h );
00329     } else {
00330         windowSize = QSize();
00331     }
00332 #else
00333     windowSize = QSize();
00334 #endif
00335 }
00336 
00337 void WindowPreview::setInfo()
00338 {
00339 #ifdef Q_WS_X11
00340     Display *dpy = QX11Info::display();
00341     Atom atom = XInternAtom(dpy, "_KDE_WINDOW_PREVIEW", False);
00342     if (id == 0) {
00343         XDeleteProperty(dpy, parentWidget()->winId(), atom);
00344         return;
00345     }
00346     if (!windowSize.isValid()) {
00347         readWindowSize();
00348     }
00349     if (!windowSize.isValid()) {
00350         XDeleteProperty(dpy, parentWidget()->winId(), atom);
00351         return;
00352     }
00353     Q_ASSERT( parentWidget()->isWindow()); // parent must be toplevel
00354     long data[] = { 1, 5, id, x(), y(), width(), height() };
00355     XChangeProperty(dpy, parentWidget()->winId(), atom, atom, 32, PropModeReplace,
00356         reinterpret_cast< unsigned char* >( data ), sizeof( data ) / sizeof( data[ 0 ] ));
00357 #endif
00358 }
00359 
00360 void ToolTip::resizeEvent(QResizeEvent *e)
00361 {
00362     QWidget::resizeEvent(e);
00363     d->background->resize(size());
00364 
00365     setMask(d->background->mask());
00366 }
00367 
00368 void ToolTip::paintEvent(QPaintEvent *e)
00369 {
00370     QPainter painter(this);
00371     painter.setRenderHint(QPainter::Antialiasing);
00372     painter.setClipRect(e->rect());
00373     painter.setCompositionMode(QPainter::CompositionMode_Source );
00374     painter.fillRect(rect(), Qt::transparent);
00375 
00376     d->background->paint(&painter, rect());
00377 }
00378 
00379 }
00380 #include "tooltip_p.moc"

libplasma

Skip menu "libplasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal