1 /*****************************************************************************
2  *   Copyright 2007 - 2010 Craig Drummond <craig.p.drummond@gmail.com>       *
3  *   Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com>                     *
4  *                                                                           *
5  *   This program is free software; you can redistribute it and/or modify    *
6  *   it under the terms of the GNU Lesser General Public License as          *
7  *   published by the Free Software Foundation; either version 2.1 of the    *
8  *   License, or (at your option) version 3, or any later version accepted   *
9  *   by the membership of KDE e.V. (or its successor approved by the         *
10  *   membership of KDE e.V.), which shall act as a proxy defined in          *
11  *   Section 6 of version 3 of the license.                                  *
12  *                                                                           *
13  *   This program is distributed in the hope that it will be useful,         *
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *
16  *   Lesser General Public License for more details.                         *
17  *                                                                           *
18  *   You should have received a copy of the GNU Lesser General Public        *
19  *   License along with this library. If not,                                *
20  *   see <http://www.gnu.org/licenses/>.                                     *
21  *****************************************************************************/
22 
23 #include "qtcurve_p.h"
24 #include "utils.h"
25 
26 #include <QToolBar>
27 #include <QToolButton>
28 #include <QAbstractItemView>
29 #include <QDialog>
30 #include <QSplitter>
31 #include <QMdiSubWindow>
32 #include <QMainWindow>
33 #include <QComboBox>
34 #include <QTreeView>
35 #include <QGroupBox>
36 #include <QListView>
37 #include <QCheckBox>
38 #include <QRadioButton>
39 #include <QTextEdit>
40 #include <QDial>
41 #include <QLabel>
42 #include <QStackedLayout>
43 #include <QMenuBar>
44 #include <QMouseEvent>
45 #include <QScrollBar>
46 #include <QWizard>
47 #include <QDialogButtonBox>
48 #include <QPushButton>
49 #include <QHeaderView>
50 #include <QLineEdit>
51 #include <QSpinBox>
52 #include <QDir>
53 #include <QSettings>
54 #include <QPixmapCache>
55 #include <QTextStream>
56 
57 #include "shadowhelper.h"
58 #include <qtcurve-utils/x11qtc.h>
59 #include <qtcurve-utils/qtutils.h>
60 #include <sys/time.h>
61 
62 namespace QtCurve {
63 
64 static const char *constBoldProperty = "qtc-set-bold";
65 
66 bool
blendOOMenuHighlight(const QPalette & pal,const QColor & highlight)67 blendOOMenuHighlight(const QPalette &pal, const QColor &highlight)
68 {
69     QColor text(pal.text().color());
70     QColor hl(pal.highlightedText().color());
71 
72     return ((text.red() < 50) && (text.green() < 50) && (text.blue() < 50) &&
73             (hl.red() > 127) && (hl.green() > 127) && (hl.blue() > 127) &&
74             TOO_DARK(highlight));
75 }
76 
isNoEtchWidget(const QWidget * widget)77 bool isNoEtchWidget(const QWidget *widget)
78 {
79     if (theThemedApp == APP_KRUNNER) {
80         return true;
81     }
82     if (theThemedApp == APP_PLASMA) {
83         const QWidget *top = widget->window();
84 
85         return !top || (!qobject_cast<const QDialog*>(top) &&
86                         !qobject_cast<const QMainWindow*>(top));
87     }
88 
89     if (widget && widget->inherits("QWebView")) {
90         return true;
91     }
92     // KHTML:  widget -> QWidget -> QWidget -> KHTMLView
93     const QObject *w = (widget && widget->parent() &&
94                         widget->parent()->parent() ?
95                         widget->parent()->parent()->parent() : nullptr);
96 
97     return ((w && isA(w, "KHTMLView")) ||
98             (widget && isInQAbstractItemView(widget->parentWidget())));
99 }
100 
101 void
setOpacityProp(QWidget * w,unsigned short opacity)102 setOpacityProp(QWidget *w, unsigned short opacity)
103 {
104     // DO NOT condition compile on QTC_ENABLE_X11.
105     // There's no direct linkage on X11 and the following code will just do
106     // nothing if X11 is not enabled (either at compile time or at run time).
107     QTC_RET_IF_FAIL(qtcX11Enabled());
108     if (WId wid = qtcGetWid(w->window())) {
109         qtcX11SetOpacity(wid, opacity);
110     }
111 }
112 
113 void
setBgndProp(QWidget * w,EAppearance app,bool haveBgndImage)114 setBgndProp(QWidget *w, EAppearance app, bool haveBgndImage)
115 {
116     // DO NOT condition compile on QTC_ENABLE_X11.
117     // There's no direct linkage on X11 and the following code will just do
118     // nothing if X11 is not enabled (either at compile time or at run time).
119     QTC_RET_IF_FAIL(qtcX11Enabled());
120     if (WId wid = qtcGetWid(w->window())) {
121         uint32_t prop = (((qtcIsFlatBgnd(app) ?
122                            (haveBgndImage ? APPEARANCE_RAISED :
123                             APPEARANCE_FLAT) : app) & 0xFF) |
124                          (w->palette().background().color().rgb() &
125                           0x00FFFFFF) << 8);
126         qtcX11SetBgnd(wid, prop);
127     }
128 }
129 
setSbProp(QWidget * w)130 void setSbProp(QWidget *w)
131 {
132     // DO NOT condition compile on QTC_ENABLE_X11.
133     // There's no direct linkage on X11 and the following code will just do
134     // nothing if X11 is not enabled (either at compile time or at run time).
135     QTC_RET_IF_FAIL(qtcX11Enabled());
136     if (WId wid = qtcGetWid(w->window())) {
137         static const char *constStatusBarProperty = "qtcStatusBar";
138         QVariant prop(w->property(constStatusBarProperty));
139 
140         if (!prop.isValid() || !prop.toBool()) {
141             w->setProperty(constStatusBarProperty, true);
142             qtcX11SetStatusBar(wid);
143         }
144     }
145 }
146 
147 void
setBold(QWidget * widget)148 setBold(QWidget *widget)
149 {
150     QVariant prop(widget->property(constBoldProperty));
151     if (!prop.isValid() || !prop.toBool()) {
152         QFont font(widget->font());
153         if (!font.bold()) {
154             font.setBold(true);
155             widget->setFont(font);
156             widget->setProperty(constBoldProperty, true);
157         }
158     }
159 }
160 
161 void
unSetBold(QWidget * widget)162 unSetBold(QWidget *widget)
163 {
164     QVariant prop(widget->property(constBoldProperty));
165     if (prop.isValid() && prop.toBool()) {
166         QFont font(widget->font());
167         font.setBold(false);
168         widget->setFont(font);
169         widget->setProperty(constBoldProperty, false);
170     }
171 }
172 
173 QWidget*
scrollViewFrame(QWidget * widget)174 scrollViewFrame(QWidget *widget)
175 {
176     QWidget *w = widget;
177 
178     for (int i = 0; i < 10 && w;i++, w = w->parentWidget()) {
179         if ((qobject_cast<QFrame*>(w) &&
180              ((QFrame*)w)->frameWidth() > 0) ||
181             qobject_cast<QTabWidget*>(w)) {
182             return w;
183         }
184     }
185     return nullptr;
186 }
187 
188 QToolBar*
getToolBarChild(QWidget * w)189 getToolBarChild(QWidget *w)
190 {
191     for (QObject *child: w->children()) {
192         if (child->isWidgetType()) {
193             if (qobject_cast<QToolBar*>(child))
194                 return static_cast<QToolBar*>(child);
195             QToolBar *tb = getToolBarChild((QWidget*)child);
196             if (tb) {
197                 return tb;
198             }
199         }
200     }
201 
202     return nullptr;
203 }
204 
205 void
setStyleRecursive(QWidget * w,QStyle * s,int minSize)206 setStyleRecursive(QWidget *w, QStyle *s, int minSize)
207 {
208     w->setStyle(s);
209     if (qobject_cast<QToolButton*>(w))
210         w->setMinimumSize(1, minSize);
211 
212     for (QObject *child: w->children()) {
213         if (child->isWidgetType()) {
214             setStyleRecursive((QWidget*)child, s, minSize);
215         }
216     }
217 }
218 
219 //
220 // QtCurve's menu's have a 2 pixel border all around - but want the top,
221 // and left edges to active the nearest menu item. Therefore, when we get a
222 // mouse event in that region then adjsut its position...
223 bool
updateMenuBarEvent(QMouseEvent * event,QMenuBar * menu)224 updateMenuBarEvent(QMouseEvent *event, QMenuBar *menu)
225 {
226     struct HackEvent: public QMouseEvent {
227         bool
228         adjust()
229         {
230             if (l.x() < 2 || l.y() < 2) {
231                 l = QPointF(l.x() < 2 ? l.x() + 2 : l.x(),
232                             l.y() < 2 ? l.y() + 2 : l.y());
233                 s = QPointF(l.x() < 2 ? s.x() + 2 : s.x(),
234                             l.y() < 2 ? s.y() + 2 : s.y());
235                 return true;
236             }
237             return false;
238         }
239     };
240 
241     if (((HackEvent*)event)->adjust()) {
242         static_cast<QObject*>(menu)->event(event);
243         return true;
244     }
245     return false;
246 }
247 
248 QRegion
windowMask(const QRect & r,bool full)249 windowMask(const QRect &r, bool full)
250 {
251     int x, y, w, h;
252     r.getRect(&x, &y, &w, &h);
253 
254     if (full) {
255         QRegion region(x + 4, y + 0, w-4*2, h-0*2);
256         region += QRegion(x + 0, y + 4, w-0*2, h-4*2);
257         region += QRegion(x + 2, y + 1, w-2*2, h-1*2);
258         region += QRegion(x + 1, y + 2, w-1*2, h-2*2);
259         return region;
260     } else {
261         QRegion region(x+1, y+1, w-2, h-2);
262         region += QRegion(x, y+2, w, h-4);
263         region += QRegion(x+2, y, w-4, h);
264         return region;
265     }
266 }
267 
268 const QWidget*
getWidget(const QPainter * p)269 getWidget(const QPainter *p)
270 {
271     if(p) {
272         if (QInternal::Widget==p->device()->devType()) {
273             return static_cast<const QWidget *>(p->device());
274         } else {
275             QPaintDevice *dev = QPainter::redirected(p->device());
276             if (dev && QInternal::Widget==dev->devType()) {
277                 return static_cast<const QWidget *>(dev);
278             }
279         }
280     }
281     return nullptr;
282 }
283 
284 const QImage*
getImage(const QPainter * p)285 getImage(const QPainter *p)
286 {
287     return (p && p->device() && QInternal::Image==p->device()->devType() ?
288             static_cast<const QImage*>(p->device()) : nullptr);
289 }
290 
291 const QAbstractButton*
getButton(const QWidget * w,const QPainter * p)292 getButton(const QWidget *w, const QPainter *p)
293 {
294     const QWidget *widget = w ? w : getWidget(p);
295     return widget ? qobject_cast<const QAbstractButton*>(widget) : nullptr;
296 }
297 
298 void
drawDots(QPainter * p,const QRect & r,bool horiz,int nLines,int offset,const QColor * cols,int startOffset,int dark)299 drawDots(QPainter *p, const QRect &r, bool horiz, int nLines, int offset,
300          const QColor *cols, int startOffset, int dark)
301 {
302     int space((nLines*2)+(nLines-1)),
303         x(horiz ? r.x() : r.x()+((r.width()-space)>>1)),
304         y(horiz ? r.y()+((r.height()-space)>>1) : r.y()),
305         i, j,
306         numDots((horiz ? (r.width()-(2*offset))/3 : (r.height()-(2*offset))/3)+1);
307 
308     p->setRenderHint(QPainter::Antialiasing, true);
309     if (horiz) {
310         if(startOffset && y+startOffset>0)
311             y+=startOffset;
312 
313         p->setPen(cols[dark]);
314         for(i=0; i<space; i+=3)
315             for(j=0; j<numDots; j++)
316                 drawAaPoint(p, x+offset+(3*j), y+i);
317 
318         p->setPen(cols[0]);
319         for(i=1; i<space; i+=3)
320             for(j=0; j<numDots; j++)
321                 drawAaPoint(p, x+offset+1+(3*j), y+i);
322     } else {
323         if(startOffset && x+startOffset>0)
324             x+=startOffset;
325 
326         p->setPen(cols[dark]);
327         for(i=0; i<space; i+=3)
328             for(j=0; j<numDots; j++)
329                 drawAaPoint(p, x+i, y+offset+(3*j));
330 
331         p->setPen(cols[0]);
332         for(i=1; i<space; i+=3)
333             for(j=0; j<numDots; j++)
334                 drawAaPoint(p, x+i, y+offset+1+(3*j));
335     }
336     QPAINTER_RENDERHINT_AA_MAYBE_OFF(p);
337 }
338 
339 bool
isInQAbstractItemView(const QObject * w)340 isInQAbstractItemView(const QObject *w)
341 {
342     int level = 8;
343     while (w && --level > 0) {
344         if (qobject_cast<const QAbstractItemView*>(w))
345             return true;
346         if (qobject_cast<const QDialog*>(w)
347             /* || qobject_cast<const QMainWindow *>(w)*/)
348             return false;
349         w = w->parent();
350     }
351     return false;
352 }
353 
354 const QToolBar*
getToolBar(const QWidget * w)355 getToolBar(const QWidget *w)
356 {
357     return (w ? qobject_cast<const QToolBar*>(w) ?
358             static_cast<const QToolBar*>(w) :
359             getToolBar(w->parentWidget()) : nullptr);
360 }
361 
362 void
drawTbArrow(const QStyle * style,const QStyleOptionToolButton * toolbutton,const QRect & rect,QPainter * painter,const QWidget * widget)363 drawTbArrow(const QStyle *style, const QStyleOptionToolButton *toolbutton,
364             const QRect &rect, QPainter *painter, const QWidget *widget)
365 {
366     QStyle::PrimitiveElement pe;
367     switch (toolbutton->arrowType) {
368     case Qt::LeftArrow:
369         pe = QStyle::PE_IndicatorArrowLeft;
370         break;
371     case Qt::RightArrow:
372         pe = QStyle::PE_IndicatorArrowRight;
373         break;
374     case Qt::UpArrow:
375         pe = QStyle::PE_IndicatorArrowUp;
376         break;
377     case Qt::DownArrow:
378         pe = QStyle::PE_IndicatorArrowDown;
379         break;
380     default:
381         return;
382     }
383 
384     QStyleOption arrowOpt;
385     arrowOpt.rect = rect;
386     arrowOpt.palette = toolbutton->palette;
387     arrowOpt.state = toolbutton->state;
388     style->drawPrimitive(pe, &arrowOpt, painter, widget);
389 }
390 
391 void
adjustToolbarButtons(const QWidget * widget,const QToolBar * toolbar,int & leftAdjust,int & topAdjust,int & rightAdjust,int & bottomAdjust,int & round)392 adjustToolbarButtons(const QWidget *widget, const QToolBar *toolbar,
393                      int &leftAdjust, int &topAdjust, int &rightAdjust,
394                      int &bottomAdjust, int &round)
395 {
396     const int constAdjust=6;
397     const int d = 1;
398     QRect geo(widget->geometry());
399     if (toolbar->orientation() == Qt::Horizontal) {
400         bool haveLeft =
401             qobject_cast<QToolButton*>(toolbar->childAt(geo.x() -
402                                                         d, geo.y()));
403         bool haveRight =
404             qobject_cast<QToolButton*>(toolbar->childAt(geo.right() +
405                                                         d, geo.y()));
406 
407         if (haveLeft && haveRight) {
408             leftAdjust = -constAdjust;
409             rightAdjust = constAdjust;
410             round = ROUNDED_NONE;
411         } else if (haveLeft) {
412             leftAdjust = -constAdjust;
413             round = ROUNDED_RIGHT;
414         } else if (haveRight) {
415             rightAdjust = constAdjust;
416             round = ROUNDED_LEFT;
417         }
418     } else {
419         bool haveTop =
420             qobject_cast<QToolButton*>(toolbar->childAt(geo.x(), geo.y() - d));
421         bool haveBot =
422             qobject_cast<QToolButton*>(toolbar->childAt(geo.x(),
423                                                         geo.bottom() + d));
424         if (haveTop && haveBot) {
425             topAdjust = -constAdjust;
426             bottomAdjust = constAdjust;
427             round = ROUNDED_NONE;
428         } else if (haveTop) {
429             topAdjust = -constAdjust;
430             round = ROUNDED_BOTTOM;
431         } else if (haveBot) {
432             bottomAdjust = constAdjust;
433             round = ROUNDED_TOP;
434         }
435     }
436 }
437 
438 bool
isA(const QObject * w,const char * type)439 isA(const QObject *w, const char *type)
440 {
441     return (w && (0 == strcmp(w->metaObject()->className(), type) ||
442                   (w->parent() &&
443                    0 == strcmp(w->parent()->metaObject()->className(), type))));
444 }
445 
446 }
447