File indexing completed on 2024-04-28 05:47:26

0001 /*****************************************************************************
0002  *   Copyright 2007 - 2010 Craig Drummond <craig.p.drummond@gmail.com>       *
0003  *   Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com>                     *
0004  *                                                                           *
0005  *   This program is free software; you can redistribute it and/or modify    *
0006  *   it under the terms of the GNU Lesser General Public License as          *
0007  *   published by the Free Software Foundation; either version 2.1 of the    *
0008  *   License, or (at your option) version 3, or any later version accepted   *
0009  *   by the membership of KDE e.V. (or its successor approved by the         *
0010  *   membership of KDE e.V.), which shall act as a proxy defined in          *
0011  *   Section 6 of version 3 of the license.                                  *
0012  *                                                                           *
0013  *   This program is distributed in the hope that it will be useful,         *
0014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
0015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *
0016  *   Lesser General Public License for more details.                         *
0017  *                                                                           *
0018  *   You should have received a copy of the GNU Lesser General Public        *
0019  *   License along with this library. If not,                                *
0020  *   see <http://www.gnu.org/licenses/>.                                     *
0021  *****************************************************************************/
0022 
0023 #include "qtcurve_p.h"
0024 #include "utils.h"
0025 
0026 #include <QToolBar>
0027 #include <QToolButton>
0028 #include <QAbstractItemView>
0029 #include <QDialog>
0030 #include <QSplitter>
0031 #include <QMdiSubWindow>
0032 #include <QMainWindow>
0033 #include <QComboBox>
0034 #include <QTreeView>
0035 #include <QGroupBox>
0036 #include <QListView>
0037 #include <QCheckBox>
0038 #include <QRadioButton>
0039 #include <QTextEdit>
0040 #include <QDial>
0041 #include <QLabel>
0042 #include <QStackedLayout>
0043 #include <QMenuBar>
0044 #include <QMouseEvent>
0045 #include <QScrollBar>
0046 #include <QWizard>
0047 #include <QDialogButtonBox>
0048 #include <QPushButton>
0049 #include <QHeaderView>
0050 #include <QLineEdit>
0051 #include <QSpinBox>
0052 #include <QDir>
0053 #include <QSettings>
0054 #include <QPixmapCache>
0055 #include <QTextStream>
0056 
0057 #include "shadowhelper.h"
0058 #include <qtcurve-utils/x11qtc.h>
0059 #include <qtcurve-utils/qtutils.h>
0060 #include <sys/time.h>
0061 
0062 namespace QtCurve {
0063 
0064 bool
0065 blendOOMenuHighlight(const QPalette &pal, const QColor &highlight)
0066 {
0067     QColor text(pal.text().color());
0068     QColor hl(pal.highlightedText().color());
0069 
0070     return ((text.red() < 50) && (text.green() < 50) && (text.blue() < 50) &&
0071             (hl.red() > 127) && (hl.green() > 127) && (hl.blue() > 127) &&
0072             TOO_DARK(highlight));
0073 }
0074 
0075 bool isNoEtchWidget(const QWidget *widget)
0076 {
0077     if (theThemedApp == APP_KRUNNER) {
0078         return true;
0079     }
0080     if (theThemedApp == APP_PLASMA) {
0081         const QWidget *top = widget->window();
0082 
0083         return !top || (!qobject_cast<const QDialog*>(top) &&
0084                         !qobject_cast<const QMainWindow*>(top));
0085     }
0086 
0087     if (widget && widget->inherits("QWebView")) {
0088         return true;
0089     }
0090     // KHTML:  widget -> QWidget -> QWidget -> KHTMLView
0091     const QObject *w = (widget && widget->parent() &&
0092                         widget->parent()->parent() ?
0093                         widget->parent()->parent()->parent() : nullptr);
0094 
0095     return ((w && isA(w, "KHTMLView")) ||
0096             (widget && isInQAbstractItemView(widget->parentWidget())));
0097 }
0098 
0099 void
0100 setOpacityProp(QWidget *w, unsigned short opacity)
0101 {
0102     // DO NOT condition compile on QTC_ENABLE_X11.
0103     // There's no direct linkage on X11 and the following code will just do
0104     // nothing if X11 is not enabled (either at compile time or at run time).
0105     QTC_RET_IF_FAIL(qtcX11Enabled());
0106     if (WId wid = qtcGetWid(w->window())) {
0107         qtcX11SetOpacity(wid, opacity);
0108     }
0109 }
0110 
0111 void
0112 setBgndProp(QWidget *w, EAppearance app, bool haveBgndImage)
0113 {
0114     // DO NOT condition compile on QTC_ENABLE_X11.
0115     // There's no direct linkage on X11 and the following code will just do
0116     // nothing if X11 is not enabled (either at compile time or at run time).
0117     QTC_RET_IF_FAIL(qtcX11Enabled());
0118     if (WId wid = qtcGetWid(w->window())) {
0119         uint32_t prop = (((qtcIsFlatBgnd(app) ?
0120                            (haveBgndImage ? APPEARANCE_RAISED :
0121                             APPEARANCE_FLAT) : app) & 0xFF) |
0122                          (w->palette().window().color().rgb() &
0123                           0x00FFFFFF) << 8);
0124         qtcX11SetBgnd(wid, prop);
0125     }
0126 }
0127 
0128 void setSbProp(QWidget *w)
0129 {
0130     // DO NOT condition compile on QTC_ENABLE_X11.
0131     // There's no direct linkage on X11 and the following code will just do
0132     // nothing if X11 is not enabled (either at compile time or at run time).
0133     QTC_RET_IF_FAIL(qtcX11Enabled());
0134     if (WId wid = qtcGetWid(w->window())) {
0135         static const char *constStatusBarProperty = "qtcStatusBar";
0136         QVariant prop(w->property(constStatusBarProperty));
0137 
0138         if (!prop.isValid() || !prop.toBool()) {
0139             w->setProperty(constStatusBarProperty, true);
0140             qtcX11SetStatusBar(wid);
0141         }
0142     }
0143 }
0144 
0145 QWidget*
0146 scrollViewFrame(QWidget *widget)
0147 {
0148     QWidget *w = widget;
0149 
0150     for (int i = 0; i < 10 && w;i++, w = w->parentWidget()) {
0151         if ((qobject_cast<QFrame*>(w) &&
0152              ((QFrame*)w)->frameWidth() > 0) ||
0153             qobject_cast<QTabWidget*>(w)) {
0154             return w;
0155         }
0156     }
0157     return nullptr;
0158 }
0159 
0160 QToolBar*
0161 getToolBarChild(QWidget *w)
0162 {
0163     for (QObject *child: w->children()) {
0164         if (child->isWidgetType()) {
0165             if (qobject_cast<QToolBar*>(child))
0166                 return static_cast<QToolBar*>(child);
0167             QToolBar *tb = getToolBarChild((QWidget*)child);
0168             if (tb) {
0169                 return tb;
0170             }
0171         }
0172     }
0173 
0174     return nullptr;
0175 }
0176 
0177 void
0178 setStyleRecursive(QWidget *w, QStyle *s, int minSize)
0179 {
0180     w->setStyle(s);
0181     if (qobject_cast<QToolButton*>(w))
0182         w->setMinimumSize(1, minSize);
0183 
0184     for (QObject *child: w->children()) {
0185         if (child->isWidgetType()) {
0186             setStyleRecursive((QWidget*)child, s, minSize);
0187         }
0188     }
0189 }
0190 
0191 //
0192 // QtCurve's menu's have a 2 pixel border all around - but want the top,
0193 // and left edges to active the nearest menu item. Therefore, when we get a
0194 // mouse event in that region then adjsut its position...
0195 bool
0196 updateMenuBarEvent(QMouseEvent *event, QMenuBar *menu)
0197 {
0198     struct HackEvent: public QMouseEvent {
0199         bool
0200         adjust()
0201         {
0202             if (l.x() < 2 || l.y() < 2) {
0203                 l = QPointF(l.x() < 2 ? l.x() + 2 : l.x(),
0204                             l.y() < 2 ? l.y() + 2 : l.y());
0205                 s = QPointF(l.x() < 2 ? s.x() + 2 : s.x(),
0206                             l.y() < 2 ? s.y() + 2 : s.y());
0207                 return true;
0208             }
0209             return false;
0210         }
0211     };
0212 
0213     if (((HackEvent*)event)->adjust()) {
0214         static_cast<QObject*>(menu)->event(event);
0215         return true;
0216     }
0217     return false;
0218 }
0219 
0220 QRegion
0221 windowMask(const QRect &r, bool full)
0222 {
0223     int x, y, w, h;
0224     r.getRect(&x, &y, &w, &h);
0225 
0226     if (full) {
0227         QRegion region(x + 4, y + 0, w-4*2, h-0*2);
0228         region += QRegion(x + 0, y + 4, w-0*2, h-4*2);
0229         region += QRegion(x + 2, y + 1, w-2*2, h-1*2);
0230         region += QRegion(x + 1, y + 2, w-1*2, h-2*2);
0231         return region;
0232     } else {
0233         QRegion region(x+1, y+1, w-2, h-2);
0234         region += QRegion(x, y+2, w, h-4);
0235         region += QRegion(x+2, y, w-4, h);
0236         return region;
0237     }
0238 }
0239 
0240 const QWidget*
0241 getWidget(const QPainter *p)
0242 {
0243     if (p) {
0244         if (p->device()->devType() == QInternal::Widget) {
0245             return static_cast<const QWidget*>(p->device());
0246         }
0247 #if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
0248         // No-op on 5.13+.
0249         else {
0250             QPaintDevice *dev = QPainter::redirected(p->device());
0251             if (dev && dev->devType() == QInternal::Widget) {
0252                 return static_cast<const QWidget*>(dev);
0253             }
0254         }
0255 #endif
0256     }
0257     return nullptr;
0258 }
0259 
0260 const QImage*
0261 getImage(const QPainter *p)
0262 {
0263     return (p && p->device() && QInternal::Image==p->device()->devType() ?
0264             static_cast<const QImage*>(p->device()) : nullptr);
0265 }
0266 
0267 const QAbstractButton*
0268 getButton(const QWidget *w, const QPainter *p)
0269 {
0270     const QWidget *widget = w ? w : getWidget(p);
0271     return widget ? qobject_cast<const QAbstractButton*>(widget) : nullptr;
0272 }
0273 
0274 void
0275 drawDots(QPainter *p, const QRect &r, bool horiz, int nLines, int offset,
0276          const QColor *cols, int startOffset, int dark)
0277 {
0278     int space((nLines*2)+(nLines-1)),
0279         x(horiz ? r.x() : r.x()+((r.width()-space)>>1)),
0280         y(horiz ? r.y()+((r.height()-space)>>1) : r.y()),
0281         i, j,
0282         numDots((horiz ? (r.width()-(2*offset))/3 : (r.height()-(2*offset))/3)+1);
0283 
0284     p->setRenderHint(QPainter::Antialiasing, true);
0285     if (horiz) {
0286         if(startOffset && y+startOffset>0)
0287             y+=startOffset;
0288 
0289         p->setPen(cols[dark]);
0290         for(i=0; i<space; i+=3)
0291             for(j=0; j<numDots; j++)
0292                 drawAaPoint(p, x+offset+(3*j), y+i);
0293 
0294         p->setPen(cols[0]);
0295         for(i=1; i<space; i+=3)
0296             for(j=0; j<numDots; j++)
0297                 drawAaPoint(p, x+offset+1+(3*j), y+i);
0298     } else {
0299         if(startOffset && x+startOffset>0)
0300             x+=startOffset;
0301 
0302         p->setPen(cols[dark]);
0303         for(i=0; i<space; i+=3)
0304             for(j=0; j<numDots; j++)
0305                 drawAaPoint(p, x+i, y+offset+(3*j));
0306 
0307         p->setPen(cols[0]);
0308         for(i=1; i<space; i+=3)
0309             for(j=0; j<numDots; j++)
0310                 drawAaPoint(p, x+i, y+offset+1+(3*j));
0311     }
0312     QPAINTER_RENDERHINT_AA_MAYBE_OFF(p);
0313 }
0314 
0315 bool
0316 isInQAbstractItemView(const QObject *w)
0317 {
0318     int level = 8;
0319     while (w && --level > 0) {
0320         if (qobject_cast<const QAbstractItemView*>(w))
0321             return true;
0322         if (qobject_cast<const QDialog*>(w)
0323             /* || qobject_cast<const QMainWindow *>(w)*/)
0324             return false;
0325         w = w->parent();
0326     }
0327     return false;
0328 }
0329 
0330 const QToolBar*
0331 getToolBar(const QWidget *w)
0332 {
0333     return (w ? qobject_cast<const QToolBar*>(w) ?
0334             static_cast<const QToolBar*>(w) :
0335             getToolBar(w->parentWidget()) : nullptr);
0336 }
0337 
0338 void
0339 drawTbArrow(const QStyle *style, const QStyleOptionToolButton *toolbutton,
0340             const QRect &rect, QPainter *painter, const QWidget *widget)
0341 {
0342     QStyle::PrimitiveElement pe;
0343     switch (toolbutton->arrowType) {
0344     case Qt::LeftArrow:
0345         pe = QStyle::PE_IndicatorArrowLeft;
0346         break;
0347     case Qt::RightArrow:
0348         pe = QStyle::PE_IndicatorArrowRight;
0349         break;
0350     case Qt::UpArrow:
0351         pe = QStyle::PE_IndicatorArrowUp;
0352         break;
0353     case Qt::DownArrow:
0354         pe = QStyle::PE_IndicatorArrowDown;
0355         break;
0356     default:
0357         return;
0358     }
0359 
0360     QStyleOption arrowOpt;
0361     arrowOpt.rect = rect;
0362     arrowOpt.palette = toolbutton->palette;
0363     arrowOpt.state = toolbutton->state;
0364     style->drawPrimitive(pe, &arrowOpt, painter, widget);
0365 }
0366 
0367 void
0368 adjustToolbarButtons(const QWidget *widget, const QToolBar *toolbar,
0369                      int &leftAdjust, int &topAdjust, int &rightAdjust,
0370                      int &bottomAdjust, int &round)
0371 {
0372     const int constAdjust=6;
0373     const int d = 1;
0374     QRect geo(widget->geometry());
0375     if (toolbar->orientation() == Qt::Horizontal) {
0376         bool haveLeft =
0377             qobject_cast<QToolButton*>(toolbar->childAt(geo.x() -
0378                                                         d, geo.y()));
0379         bool haveRight =
0380             qobject_cast<QToolButton*>(toolbar->childAt(geo.right() +
0381                                                         d, geo.y()));
0382 
0383         if (haveLeft && haveRight) {
0384             leftAdjust = -constAdjust;
0385             rightAdjust = constAdjust;
0386             round = ROUNDED_NONE;
0387         } else if (haveLeft) {
0388             leftAdjust = -constAdjust;
0389             round = ROUNDED_RIGHT;
0390         } else if (haveRight) {
0391             rightAdjust = constAdjust;
0392             round = ROUNDED_LEFT;
0393         }
0394     } else {
0395         bool haveTop =
0396             qobject_cast<QToolButton*>(toolbar->childAt(geo.x(), geo.y() - d));
0397         bool haveBot =
0398             qobject_cast<QToolButton*>(toolbar->childAt(geo.x(),
0399                                                         geo.bottom() + d));
0400         if (haveTop && haveBot) {
0401             topAdjust = -constAdjust;
0402             bottomAdjust = constAdjust;
0403             round = ROUNDED_NONE;
0404         } else if (haveTop) {
0405             topAdjust = -constAdjust;
0406             round = ROUNDED_BOTTOM;
0407         } else if (haveBot) {
0408             bottomAdjust = constAdjust;
0409             round = ROUNDED_TOP;
0410         }
0411     }
0412 }
0413 
0414 bool
0415 isA(const QObject *w, const char *type)
0416 {
0417     return (w && (0 == strcmp(w->metaObject()->className(), type) ||
0418                   (w->parent() &&
0419                    0 == strcmp(w->parent()->metaObject()->className(), type))));
0420 }
0421 
0422 }