***************************************************************************/
#include "ktooltip.h"
-
-#include <QApplication>
-#include <QMap>
-#include <QPixmap>
-#include <QPainter>
-#include <QVariant>
-#include <QIcon>
+#include "ktooltipwindow_p.h"
+#include <QLabel>
+#include <QPoint>
#include <QWidget>
-#include <QToolTip>
-#include <QDebug>
-
-#ifdef Q_WS_X11
-# include <QX11Info>
-# include <X11/Xlib.h>
-# include <X11/extensions/Xrender.h>
-# include <X11/extensions/shape.h>
-#endif
-
-#include "ktooltip_p.h"
-
-
-// compile with XShape older than 1.0
-#ifndef ShapeInput
-const int ShapeInput = 2;
-#endif
-
-
-class KToolTipItemPrivate
-{
-public:
- QMap<int, QVariant> map;
- int type;
-};
-
-KToolTipItem::KToolTipItem(const QString &text, int type)
- : d(new KToolTipItemPrivate)
-{
- d->map[Qt::DisplayRole] = text;
- d->type = type;
-}
-
-KToolTipItem::KToolTipItem(const QIcon &icon, const QString &text, int type)
- : d(new KToolTipItemPrivate)
-{
- d->map[Qt::DecorationRole] = icon;
- d->map[Qt::DisplayRole] = text;
- d->type = type;
-}
-
-KToolTipItem::~KToolTipItem()
-{
- delete d;
-}
-
-int KToolTipItem::type() const
-{
- return d->type;
-}
-
-QString KToolTipItem::text() const
-{
- return data(Qt::DisplayRole).toString();
-}
-
-QIcon KToolTipItem::icon() const
-{
- return qvariant_cast<QIcon>(data(Qt::DecorationRole));
-}
-
-QVariant KToolTipItem::data(int role) const
-{
- return d->map.value(role);
-}
-
-void KToolTipItem::setData(int role, const QVariant &data)
-{
- d->map[role] = data;
- KToolTipManager::instance()->update();
-}
-
-
-
-// ----------------------------------------------------------------------------
-
-
-KStyleOptionToolTip::KStyleOptionToolTip()
- : fontMetrics(QApplication::font())
-{
-}
-
-
-// ----------------------------------------------------------------------------
-
-
-
-KToolTipDelegate::KToolTipDelegate() : QObject()
-{
-}
-
-KToolTipDelegate::~KToolTipDelegate()
-{
-}
-QSize KToolTipDelegate::sizeHint(const KStyleOptionToolTip *option, const KToolTipItem *item) const
-{
- QSize size;
- size.rwidth() = option->fontMetrics.width(item->text());
- size.rheight() = option->fontMetrics.lineSpacing();
-
- QIcon icon = item->icon();
- if (!icon.isNull()) {
- const QSize iconSize = icon.actualSize(option->decorationSize);
- size.rwidth() += iconSize.width() + 4;
- size.rheight() = qMax(size.height(), iconSize.height());
- }
-
- return size + QSize(20, 20);
-
-}
-
-void KToolTipDelegate::paint(QPainter *painter, const KStyleOptionToolTip *option,
- const KToolTipItem *item) const
-{
- bool haveAlpha = haveAlphaChannel();
- painter->setRenderHint(QPainter::Antialiasing);
-
- QPainterPath path;
- if (haveAlpha)
- path.addRoundRect(option->rect.adjusted(0, 0, -1, -1), 25);
- else
- path.addRect(option->rect.adjusted(0, 0, -1, -1));
-
- QColor color = option->palette.color(QPalette::ToolTipBase);
- QColor from = color.lighter(105);
- QColor to = color.darker(120);
-
- QLinearGradient gradient(0, 0, 0, 1);
- gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
- gradient.setColorAt(0, from);
- gradient.setColorAt(1, to);
-
- painter->translate(.5, .5);
- painter->setPen(QPen(Qt::black, 1));
- painter->setBrush(gradient);
- painter->drawPath(path);
- painter->translate(-.5, -.5);
-
- if (haveAlpha) {
- QLinearGradient mask(0, 0, 0, 1);
- gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
- gradient.setColorAt(0, QColor(0, 0, 0, 192));
- gradient.setColorAt(1, QColor(0, 0, 0, 72));
- painter->setCompositionMode(QPainter::CompositionMode_DestinationIn);
- painter->fillRect(option->rect, gradient);
- painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
- }
-
- QRect textRect = option->rect.adjusted(10, 10, -10, -10);
-
- QIcon icon = item->icon();
- if (!icon.isNull()) {
- const QSize iconSize = icon.actualSize(option->decorationSize);
- painter->drawPixmap(textRect.topLeft(), icon.pixmap(iconSize));
- textRect.adjust(iconSize.width() + 4, 0, 0, 0);
- }
- painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, item->text());
-}
-
-QRegion KToolTipDelegate::inputShape(const KStyleOptionToolTip *option) const
-{
- return QRegion(option->rect);
-}
-
-QRegion KToolTipDelegate::shapeMask(const KStyleOptionToolTip *option) const
-{
- return QRegion(option->rect);
-}
-
-bool KToolTipDelegate::haveAlphaChannel() const
-{
- return KToolTipManager::instance()->haveAlphaChannel();
-}
-
-
-
-// ----------------------------------------------------------------------------
-
-
-
-class KAbstractToolTipLabel
+class KToolTipManager
{
public:
- KAbstractToolTipLabel() {}
- virtual ~KAbstractToolTipLabel() {}
+ ~KToolTipManager();
- virtual void showTip(const QPoint &pos, const KToolTipItem *item) = 0;
- virtual void moveTip(const QPoint &pos) = 0;
- virtual void hideTip() = 0;
+ static KToolTipManager* instance();
-protected:
- KStyleOptionToolTip styleOption() const;
- KToolTipDelegate *delegate() const;
-};
-
-KStyleOptionToolTip KAbstractToolTipLabel::styleOption() const
-{
- KStyleOptionToolTip option;
- KToolTipManager::instance()->initStyleOption(&option);
- return option;
-}
-
-KToolTipDelegate *KAbstractToolTipLabel::delegate() const
-{
- return KToolTipManager::instance()->delegate();
-}
-
-
-// ----------------------------------------------------------------------------
-
-
-
-class QWidgetLabel : public QWidget, public KAbstractToolTipLabel
-{
-public:
- QWidgetLabel();
- void showTip(const QPoint &pos, const KToolTipItem *item);
- void moveTip(const QPoint &pos);
+ void showTip(const QPoint& pos, QWidget* content);
void hideTip();
private:
- void paintEvent(QPaintEvent*);
- QSize sizeHint() const;
+ KToolTipManager();
-private:
- const KToolTipItem *currentItem;
+ KToolTipWindow* m_window;
+ static KToolTipManager *s_instance;
};
-QWidgetLabel::QWidgetLabel() : QWidget(0, Qt::ToolTip)
-{
- if (KToolTipManager::instance()->haveAlphaChannel()) {
- setAttribute(Qt::WA_TranslucentBackground);
- }
-}
-
-void QWidgetLabel::showTip(const QPoint &pos, const KToolTipItem *item)
-{
- currentItem = item;
- move(pos);
- show();
-}
-
-void QWidgetLabel::hideTip()
-{
- hide();
- currentItem = 0;
-}
-
-void QWidgetLabel::moveTip(const QPoint &pos)
-{
- move(pos);
-}
-
-void QWidgetLabel::paintEvent(QPaintEvent*)
-{
- KStyleOptionToolTip option = styleOption();
- option.rect = rect();
-
- setMask(delegate()->shapeMask(&option));
-
- QPainter p(this);
- p.setFont(option.font);
- p.setPen(QPen(option.palette.brush(QPalette::Text), 0));
- delegate()->paint(&p, &option, currentItem);
-}
-
-QSize QWidgetLabel::sizeHint() const
-{
- if (!currentItem)
- return QSize();
-
- KStyleOptionToolTip option = styleOption();
- return delegate()->sizeHint(&option, currentItem);
-}
-
-
-
-// ----------------------------------------------------------------------------
-
-
-
-#ifdef Q_WS_X11
-
-// X11 specific label that displays the tip in an ARGB window.
-class ArgbLabel : public KAbstractToolTipLabel
-{
-public:
- ArgbLabel(Visual *visual, int depth);
- ~ArgbLabel();
-
- void showTip(const QPoint &pos, const KToolTipItem *item);
- void moveTip(const QPoint &pos);
- void hideTip();
-
-private:
- Window window;
- Colormap colormap;
- Picture picture;
- bool mapped;
-};
-
-ArgbLabel::ArgbLabel(Visual *visual, int depth)
-{
- Display *dpy = QX11Info::display();
- Window root = QX11Info::appRootWindow();
- colormap = XCreateColormap(dpy, QX11Info::appRootWindow(), visual, AllocNone);
-
- XSetWindowAttributes attr;
- attr.border_pixel = 0;
- attr.background_pixel = 0;
- attr.colormap = colormap;
- attr.override_redirect = True;
-
- window = XCreateWindow(dpy, root, 0, 0, 1, 1, 0, depth, InputOutput, visual,
- CWBorderPixel | CWBackPixel | CWColormap |
- CWOverrideRedirect, &attr);
-
- // ### TODO: Set the WM hints so KWin can identify this window as a
- // tooltip.
-
- XRenderPictFormat *format = XRenderFindVisualFormat(dpy, visual);
- picture = XRenderCreatePicture(dpy, window, format, 0, 0);
-
- mapped = false;
-}
-
-ArgbLabel::~ArgbLabel()
-{
- Display *dpy = QX11Info::display();
- XRenderFreePicture(dpy, picture);
- XDestroyWindow(dpy, window);
- XFreeColormap(dpy, colormap);
-}
-
-void ArgbLabel::showTip(const QPoint &pos, const KToolTipItem *item)
-{
- Display *dpy = QX11Info::display();
- KStyleOptionToolTip option = styleOption();
- const QSize size = delegate()->sizeHint(&option, item);
- option.rect = QRect(QPoint(), size);
-
- QPixmap pixmap(size);
- pixmap.fill(Qt::transparent);
-
- QPainter p(&pixmap);
- p.setFont(option.font);
- p.setPen(QPen(option.palette.brush(QPalette::Text), 0));
- delegate()->paint(&p, &option, item);
-
- // Resize, position and show the window.
- XMoveResizeWindow(dpy, window, pos.x(), pos.y(), size.width(), size.height());
-
- if (KToolTipManager::instance()->haveAlphaChannel()) {
- const QRegion region = delegate()->inputShape(&option);
- XShapeCombineRegion(dpy, window, ShapeInput, 0, 0, region.handle(), ShapeSet);
- } else {
- const QRegion region = delegate()->shapeMask(&option);
- XShapeCombineRegion(dpy, window, ShapeBounding, 0, 0, region.handle(), ShapeSet);
- }
-
- XMapWindow(dpy, window);
-
- // Blit the pixmap with the tip contents to the window.
- // Since the window is override-redirect and an ARGB32 window,
- // which always has an offscreen pixmap, there's no need to
- // wait for an Expose event, or to process those.
- XRenderComposite(dpy, PictOpSrc, pixmap.x11PictureHandle(), None,
- picture, 0, 0, 0, 0, 0, 0, size.width(), size.height());
-
- mapped = true;
-}
+KToolTipManager *KToolTipManager::s_instance = 0;
-void ArgbLabel::moveTip(const QPoint &pos)
+KToolTipManager::KToolTipManager() :
+ m_window(0)
{
- if (mapped)
- XMoveWindow(QX11Info::display(), window, pos.x(), pos.y());
}
-void ArgbLabel::hideTip()
+KToolTipManager::~KToolTipManager()
{
- if (mapped) {
- Display *dpy = QX11Info::display();
- XUnmapWindow(dpy, window);
- mapped = false;
- }
+ delete m_window;
+ m_window = 0;
}
-#endif // Q_WS_X11
-
-
-
-
-// ----------------------------------------------------------------------------
-
-
-
-
-KToolTipManager *KToolTipManager::s_instance = 0;
-
-KToolTipManager::KToolTipManager()
- : label(0), currentItem(0), m_delegate(0)
+KToolTipManager* KToolTipManager::instance()
{
-#ifdef Q_WS_X11
- Display *dpy = QX11Info::display();
- int screen = DefaultScreen(dpy);
- int depth = DefaultDepth(dpy, screen);
- Visual *visual = DefaultVisual(dpy, screen);
- net_wm_cm_s0 = XInternAtom(dpy, "_NET_WM_CM_S0", False);
- haveArgbVisual = false;
-
- int nvi;
- XVisualInfo templ;
- templ.screen = screen;
- templ.depth = 32;
- templ.c_class = TrueColor;
- XVisualInfo *xvi = XGetVisualInfo(dpy, VisualScreenMask | VisualDepthMask |
- VisualClassMask, &templ, &nvi);
-
- for (int i = 0; i < nvi; ++i)
- {
- XRenderPictFormat *format = XRenderFindVisualFormat(dpy, xvi[i].visual);
- if (format->type == PictTypeDirect && format->direct.alphaMask)
- {
- visual = xvi[i].visual;
- depth = xvi[i].depth;
- haveArgbVisual = true;
- break;
- }
+ if (s_instance == 0) {
+ s_instance = new KToolTipManager();
}
- if (haveArgbVisual)
- label = new ArgbLabel(visual, depth);
- else
-#endif
- label = new QWidgetLabel();
+ return s_instance;
}
-KToolTipManager::~KToolTipManager()
-{
- delete label;
- delete currentItem;
-}
-
-void KToolTipManager::showTip(const QPoint &pos, KToolTipItem *item)
+void KToolTipManager::showTip(const QPoint& pos, QWidget* content)
{
hideTip();
- label->showTip(pos, item);
- currentItem = item;
- m_tooltipPos = pos;
+ Q_ASSERT(m_window == 0);
+ m_window = new KToolTipWindow(content);
+ m_window->move(pos);
+ m_window->show();
}
void KToolTipManager::hideTip()
{
- label->hideTip();
- delete currentItem;
- currentItem = 0;
-}
-
-void KToolTipManager::initStyleOption(KStyleOptionToolTip *option) const
-{
- option->direction = QApplication::layoutDirection();
- option->fontMetrics = QFontMetrics(QToolTip::font());
- option->activeCorner = KStyleOptionToolTip::TopLeftCorner;
- option->palette = QToolTip::palette();
- option->font = QToolTip::font();
- option->rect = QRect();
- option->state = QStyle::State_None;
- option->decorationSize = QSize(32, 32);
-}
-
-bool KToolTipManager::haveAlphaChannel() const
-{
-#ifdef Q_WS_X11
- // ### This is a synchronous call - ideally we'd use a selection
- // watcher to avoid it.
- return haveArgbVisual &&
- XGetSelectionOwner(QX11Info::display(), net_wm_cm_s0) != None;
-#else
- return false;
-#endif
-}
-
-void KToolTipManager::setDelegate(KToolTipDelegate *delegate)
-{
- m_delegate = delegate;
-}
-
-void KToolTipManager::update()
-{
- if (currentItem == 0)
- return;
- label->showTip(m_tooltipPos, currentItem);
-}
-
-KToolTipDelegate *KToolTipManager::delegate() const
-{
- return m_delegate;
+ if (m_window != 0) {
+ m_window->hide();
+ delete m_window;
+ m_window = 0;
+ }
}
-
-
-// ----------------------------------------------------------------------------
-
-
-
namespace KToolTip
{
- void showText(const QPoint &pos, const QString &text, QWidget *widget, const QRect &rect)
+ void showText(const QPoint& pos, const QString& text)
{
- Q_UNUSED(widget)
- Q_UNUSED(rect)
- KToolTipItem *item = new KToolTipItem(text);
- KToolTipManager::instance()->showTip(pos, item);
+ QLabel* label = new QLabel(text);
+ label->setForegroundRole(QPalette::ToolTipText);
+ showTip(pos, label);
}
- void showText(const QPoint &pos, const QString &text, QWidget *widget)
+ void showTip(const QPoint& pos, QWidget* content)
{
- showText(pos, text, widget, QRect());
- }
-
- void showTip(const QPoint &pos, KToolTipItem *item)
- {
- KToolTipManager::instance()->showTip(pos, item);
+ KToolTipManager::instance()->showTip(pos, content);
}
void hideTip()
{
KToolTipManager::instance()->hideTip();
}
-
- void setToolTipDelegate(KToolTipDelegate *delegate)
- {
- KToolTipManager::instance()->setDelegate(delegate);
- }
}