File indexing completed on 2024-04-14 05:39:55

0001 /*****************************************************************************
0002  *   Copyright 2003 - 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 "config.h"
0024 
0025 #include "drawing.h"
0026 
0027 #include "qt_settings.h"
0028 #include "helpers.h"
0029 #include "pixcache.h"
0030 #include "entry.h"
0031 #include "tab.h"
0032 #include "animation.h"
0033 
0034 #include <qtcurve-utils/gtkprops.h>
0035 #include <qtcurve-utils/color.h>
0036 #include <qtcurve-utils/log.h>
0037 
0038 #include <common/config_file.h>
0039 
0040 namespace QtCurve {
0041 
0042 #if GTK_CHECK_VERSION(2, 90, 0)
0043 static cairo_region_t*
0044 windowMask(int x, int y, int w, int h, bool full)
0045 {
0046     QtcRect rects[4];
0047     int numRects = 4;
0048 
0049     if (full) {
0050         rects[0] = qtcRect(x + 4, y + 0, w - 4 * 2, h);
0051         rects[1] = qtcRect(x + 0, y + 4, w, h - 4 * 2);
0052         rects[2] = qtcRect(x + 2, y + 1, w - 2 * 2, h - 2);
0053         rects[3] = qtcRect(x + 1, y + 2, w - 2, h - 2 * 2);
0054     } else {
0055         rects[0] = qtcRect(x + 1, y + 1, w - 2, h - 2);
0056         rects[1] = qtcRect(x, y + 2, w, h - 4);
0057         rects[2] = qtcRect(x + 2, y, w - 4, h);
0058         numRects = 3;
0059     }
0060     return cairo_region_create_rectangles(rects, numRects);
0061 }
0062 #endif
0063 
0064 void
0065 drawBgnd(cairo_t *cr, const GdkColor *col, GtkWidget *widget,
0066          const QtcRect *area, int x, int y, int width, int height)
0067 {
0068     Cairo::rect(cr, area, x, y, width, height,
0069                 qtcDefault(getParentBgCol(widget), col));
0070 }
0071 
0072 void
0073 drawAreaModColor(cairo_t *cr, const QtcRect *area, const GdkColor *orig,
0074                  double mod, int x, int y, int width, int height)
0075 {
0076     const GdkColor modified = shadeColor(orig, mod);
0077     Cairo::rect(cr, area, x, y, width, height, &modified);
0078 }
0079 
0080 void
0081 drawBevelGradient(cairo_t *cr, const QtcRect *area, int x, int y,
0082                   int width, int height, const GdkColor *base, bool horiz,
0083                   bool sel, EAppearance bevApp, EWidget w, double alpha)
0084 {
0085     /* EAppearance app = ((APPEARANCE_BEVELLED != bevApp || widgetIsButton(w) || */
0086     /*                     WIDGET_LISTVIEW_HEADER == w) ? bevApp : */
0087     /*                    APPEARANCE_GRADIENT); */
0088 
0089     if (qtcIsFlat(bevApp)) {
0090         if (noneOf(w, WIDGET_TAB_TOP, WIDGET_TAB_BOT) ||
0091             !qtcIsCustomBgnd(opts) || opts.tabBgnd || !sel) {
0092             Cairo::rect(cr, area, x, y, width, height, base, alpha);
0093         }
0094     } else {
0095         cairo_pattern_t *pt =
0096             cairo_pattern_create_linear(x, y, horiz ? x : x + width - 1,
0097                                         horiz ? y + height - 1 : y);
0098         bool topTab = w == WIDGET_TAB_TOP;
0099         bool botTab = w == WIDGET_TAB_BOT;
0100         bool selected = (topTab || botTab) ? false : sel;
0101         EAppearance app = (selected ? opts.sunkenAppearance :
0102                            WIDGET_LISTVIEW_HEADER == w &&
0103                            APPEARANCE_BEVELLED == bevApp ?
0104                            APPEARANCE_LV_BEVELLED :
0105                            APPEARANCE_BEVELLED != bevApp ||
0106                            widgetIsButton(w) ||
0107                            WIDGET_LISTVIEW_HEADER == w ? bevApp :
0108                            APPEARANCE_GRADIENT);
0109         const Gradient *grad = qtcGetGradient(app, &opts);
0110         Cairo::Saver saver(cr);
0111         Cairo::clipRect(cr, area);
0112 
0113         for (int i = 0;i < grad->numStops;i++) {
0114             GdkColor col;
0115             double pos = botTab ? 1.0 - grad->stops[i].pos : grad->stops[i].pos;
0116 
0117             if ((topTab || botTab) && i == grad->numStops - 1) {
0118                 if (sel && opts.tabBgnd == 0 && !isMozilla()) {
0119                     alpha = 0.0;
0120                 }
0121                 col = *base;
0122             } else {
0123                 double val = (botTab && opts.invertBotTab ?
0124                               INVERT_SHADE(grad->stops[i].val) :
0125                               grad->stops[i].val);
0126                 qtcShade(base, &col, botTab && opts.invertBotTab ?
0127                          qtcMax(val, 0.9) : val, opts.shading);
0128             }
0129 
0130             Cairo::patternAddColorStop(pt, pos, &col,
0131                                        oneOf(w, WIDGET_TOOLTIP,
0132                                              WIDGET_LISTVIEW_HEADER) ?
0133                                        alpha : alpha * grad->stops[i].alpha);
0134         }
0135 
0136         if (app == APPEARANCE_AGUA && !(topTab || botTab) &&
0137             (horiz ? height : width) > AGUA_MAX) {
0138             GdkColor col;
0139             double pos = AGUA_MAX / ((horiz ? height : width) * 2.0);
0140 
0141             qtcShade(base, &col, AGUA_MID_SHADE, opts.shading);
0142             Cairo::patternAddColorStop(pt, pos, &col, alpha);
0143             /* *grad->stops[i].alpha); */
0144             Cairo::patternAddColorStop(pt, 1.0 - pos, &col, alpha);
0145             /* *grad->stops[i].alpha); */
0146         }
0147 
0148         cairo_set_source(cr, pt);
0149         cairo_rectangle(cr, x, y, width, height);
0150         cairo_fill(cr);
0151         cairo_pattern_destroy(pt);
0152     }
0153 }
0154 
0155 void
0156 drawBorder(cairo_t *cr, GtkStyle *style, GtkStateType state,
0157            const QtcRect *area, int x, int y, int width, int height,
0158            const GdkColor *c_colors, ECornerBits round, EBorder borderProfile,
0159            EWidget widget, int flags, int borderVal)
0160 {
0161     if (opts.round == ROUND_NONE && widget != WIDGET_RADIO_BUTTON) {
0162         round = ROUNDED_NONE;
0163     }
0164     double radius = qtcGetRadius(&opts, width, height, widget, RADIUS_EXTERNAL);
0165     double xd = x + 0.5;
0166     double yd = y + 0.5;
0167     /* EAppearance app = qtcWidgetApp(widget, &opts); */
0168     bool enabled = state != GTK_STATE_INSENSITIVE;
0169     bool useText = (enabled && widget == WIDGET_DEF_BUTTON &&
0170                     opts.defBtnIndicator == IND_FONT_COLOR);
0171     /* CPD USED TO INDICATE FOCUS! */
0172     // TODO: what exactly is this
0173     bool hasFocus = (enabled && c_colors == qtcPalette.focus);
0174     bool hasMouseOver = (enabled && qtcPalette.mouseover &&
0175                          c_colors == qtcPalette.mouseover &&
0176                          opts.unifyCombo && opts.unifySpin);
0177     const GdkColor *colors = c_colors ? c_colors : qtcPalette.background;
0178     int useBorderVal = (!enabled && widgetIsButton(widget) ?
0179                         QTC_STD_BORDER :
0180                         qtcPalette.mouseover == colors && IS_SLIDER(widget) ?
0181                         SLIDER_MO_BORDER_VAL : borderVal);
0182     const GdkColor *border_col = (useText ? &style->text[GTK_STATE_NORMAL] :
0183                                   &colors[useBorderVal]);
0184     width--;
0185     height--;
0186     Cairo::Saver saver(cr);
0187     Cairo::clipRect(cr, area);
0188 
0189     if (oneOf(widget, WIDGET_TAB_BOT, WIDGET_TAB_TOP)) {
0190         colors = qtcPalette.background;
0191     }
0192     if (!(opts.thin&THIN_FRAMES)) {
0193         switch (borderProfile) {
0194         case BORDER_FLAT:
0195             break;
0196         case BORDER_RAISED:
0197         case BORDER_SUNKEN:
0198         case BORDER_LIGHT: {
0199             double radiusi = qtcGetRadius(&opts, width - 2, height - 2,
0200                                           widget, RADIUS_INTERNAL);
0201             double xdi = xd + 1;
0202             double ydi = yd + 1;
0203             double alpha = ((hasMouseOver || hasFocus) &&
0204                             oneOf(widget, WIDGET_ENTRY, WIDGET_SPIN,
0205                                   WIDGET_COMBO_BUTTON) ? ENTRY_INNER_ALPHA :
0206                             BORDER_BLEND_ALPHA(widget));
0207             int widthi = width - 2;
0208             int heighti = height - 2;
0209 
0210             if ((state != GTK_STATE_INSENSITIVE ||
0211                  borderProfile == BORDER_SUNKEN) /* && */
0212                 /* (oneOf(borderProfile, BORDER_RAISED, BORDER_LIGHT) || */
0213                 /*  app != APPEARANCE_FLAT) */) {
0214                 const GdkColor *col =
0215                     &colors[oneOf(borderProfile, BORDER_RAISED, BORDER_LIGHT) ?
0216                             0 : FRAME_DARK_SHADOW];
0217                 if (flags & DF_BLEND) {
0218                     if (oneOf(widget, WIDGET_SPIN, WIDGET_COMBO_BUTTON,
0219                               WIDGET_SCROLLVIEW)) {
0220                         Cairo::setColor(cr, &style->base[state]);
0221                         Cairo::pathTopLeft(cr, xdi, ydi, widthi, heighti,
0222                                            radiusi, round);
0223                         cairo_stroke(cr);
0224                     }
0225                     Cairo::setColor(cr, col, alpha);
0226                 } else {
0227                     Cairo::setColor(cr, col);
0228                 }
0229             } else {
0230                 Cairo::setColor(cr, &style->bg[state]);
0231             }
0232 
0233             Cairo::pathTopLeft(cr, xdi, ydi, widthi, heighti, radiusi, round);
0234             cairo_stroke(cr);
0235             if (widget != WIDGET_CHECKBOX) {
0236                 if(!hasFocus && !hasMouseOver &&
0237                    borderProfile != BORDER_LIGHT) {
0238                     if (widget == WIDGET_SCROLLVIEW) {
0239                         /* Because of list view headers, need to draw dark
0240                          * line on right! */
0241                         Cairo::Saver saver(cr);
0242                         Cairo::setColor(cr, &style->base[state]);
0243                         Cairo::pathBottomRight(cr, xdi, ydi, widthi, heighti,
0244                                                radiusi, round);
0245                         cairo_stroke(cr);
0246                     } else if (oneOf(widget, WIDGET_SCROLLVIEW, WIDGET_ENTRY)) {
0247                         Cairo::setColor(cr, &style->base[state]);
0248                     } else if (state != GTK_STATE_INSENSITIVE &&
0249                                (borderProfile == BORDER_SUNKEN ||
0250                                 /* app != APPEARANCE_FLAT ||*/
0251                                 oneOf(widget, WIDGET_TAB_TOP,
0252                                       WIDGET_TAB_BOT))) {
0253                         const GdkColor *col =
0254                             &colors[borderProfile == BORDER_RAISED ?
0255                                     FRAME_DARK_SHADOW : 0];
0256                         if (flags & DF_BLEND) {
0257                             Cairo::setColor(cr, col,
0258                                              borderProfile == BORDER_SUNKEN ?
0259                                              0.0 : alpha);
0260                         } else {
0261                             Cairo::setColor(cr, col);
0262                         }
0263                     } else {
0264                         Cairo::setColor(cr, &style->bg[state]);
0265                     }
0266                 }
0267 
0268                 Cairo::pathBottomRight(cr, xdi, ydi, widthi, heighti,
0269                                        radiusi, round);
0270                 cairo_stroke(cr);
0271             }
0272         }
0273         }
0274     }
0275 
0276     if (borderProfile == BORDER_SUNKEN &&
0277         (widget == WIDGET_FRAME ||
0278          (oneOf(widget, WIDGET_ENTRY, WIDGET_SCROLLVIEW) &&
0279           !opts.etchEntry && !hasFocus && !hasMouseOver))) {
0280         Cairo::setColor(cr, border_col,
0281                          /*enabled ? */1.0/* : LOWER_BORDER_ALPHA*/);
0282         Cairo::pathTopLeft(cr, xd, yd, width, height, radius, round);
0283         cairo_stroke(cr);
0284         Cairo::setColor(cr, border_col, LOWER_BORDER_ALPHA);
0285         Cairo::pathBottomRight(cr, xd, yd, width, height, radius, round);
0286         cairo_stroke(cr);
0287     } else {
0288         Cairo::setColor(cr, border_col);
0289         Cairo::pathWhole(cr, xd, yd, width, height, radius, round);
0290         cairo_stroke(cr);
0291     }
0292 }
0293 
0294 void
0295 drawGlow(cairo_t *cr, const QtcRect *area, int x, int y, int w, int h,
0296          ECornerBits round, EWidget widget, const GdkColor *colors)
0297 {
0298     if (qtcPalette.mouseover || qtcPalette.defbtn || colors) {
0299         double xd = x + 0.5;
0300         double yd = y + 0.5;
0301         double radius = qtcGetRadius(&opts, w, h, widget, RADIUS_ETCH);
0302         bool def = (widget == WIDGET_DEF_BUTTON &&
0303                     opts.defBtnIndicator == IND_GLOW);
0304         bool defShade =
0305             (def && (!qtcPalette.defbtn ||
0306                      (qtcPalette.mouseover &&
0307                       EQUAL_COLOR(qtcPalette.defbtn[ORIGINAL_SHADE],
0308                                   qtcPalette.mouseover[ORIGINAL_SHADE]))));
0309         const GdkColor *col =
0310             (colors ? &colors[GLOW_MO] : (def && qtcPalette.defbtn) ||
0311              !qtcPalette.mouseover ? &qtcPalette.defbtn[GLOW_DEFBTN] :
0312              &qtcPalette.mouseover[GLOW_MO]);
0313 
0314         Cairo::Saver saver(cr);
0315         Cairo::clipRect(cr, area);
0316         Cairo::setColor(cr, col, GLOW_ALPHA(defShade));
0317         Cairo::pathWhole(cr, xd, yd, w - 1, h - 1, radius, round);
0318         cairo_stroke(cr);
0319     }
0320 }
0321 
0322 void
0323 drawEtch(cairo_t *cr, const QtcRect *area, GtkWidget *widget, int x, int y,
0324          int w, int h, bool raised, ECornerBits round, EWidget wid)
0325 {
0326     double xd = x + 0.5;
0327     double yd = y + 0.5;
0328     double radius = qtcGetRadius(&opts, w, h, wid, RADIUS_ETCH);
0329     const QtcRect *a = area;
0330     QtcRect b;
0331 
0332     if (wid == WIDGET_TOOLBAR_BUTTON && opts.tbarBtnEffect == EFFECT_ETCH)
0333         raised = false;
0334 
0335     if (wid == WIDGET_COMBO_BUTTON && qtSettings.app == GTK_APP_OPEN_OFFICE &&
0336         widget && isFixedWidget(gtk_widget_get_parent(widget))) {
0337         b = qtcRect(x + 2, y, w - 4, h);
0338         a = &b;
0339     }
0340     Cairo::Saver saver(cr);
0341     Cairo::clipRect(cr, a);
0342 
0343     cairo_set_source_rgba(cr, 0.0, 0.0, 0.0,
0344                           USE_CUSTOM_ALPHAS(opts) ?
0345                           opts.customAlphas[ALPHA_ETCH_DARK] : ETCH_TOP_ALPHA);
0346     if (!raised && wid != WIDGET_SLIDER) {
0347         Cairo::pathTopLeft(cr, xd, yd, w - 1, h - 1, radius, round);
0348         cairo_stroke(cr);
0349         if (wid == WIDGET_SLIDER_TROUGH && opts.thinSbarGroove &&
0350             widget && GTK_IS_SCROLLBAR(widget)) {
0351             cairo_set_source_rgba(cr, 1.0, 1.0, 1.0,
0352                                   USE_CUSTOM_ALPHAS(opts) ?
0353                                   opts.customAlphas[ALPHA_ETCH_LIGHT] :
0354                                   ETCH_BOTTOM_ALPHA);
0355         } else {
0356             setLowerEtchCol(cr, widget);
0357         }
0358     }
0359     Cairo::pathBottomRight(cr, xd, yd, w - 1, h - 1, radius, round);
0360     cairo_stroke(cr);
0361 }
0362 
0363 void
0364 qtcClipPath(cairo_t *cr, int x, int y, int w, int h, EWidget widget,
0365             ERadius rad, ECornerBits round)
0366 {
0367     Cairo::clipWhole(cr, x + 0.5, y + 0.5, w - 1, h - 1,
0368                      qtcGetRadius(&opts, w, h, widget, rad), round);
0369 }
0370 
0371 QTC_ALWAYS_INLINE static inline void
0372 addStripes(cairo_t *cr, int x, int y, int w, int h, bool horizontal)
0373 {
0374     Cairo::stripes(cr, x, y, w, h, horizontal, STRIPE_WIDTH);
0375 }
0376 
0377 void
0378 drawLightBevel(cairo_t *cr, GtkStyle *style, GtkStateType state,
0379                const QtcRect *area, int x, int y, int width, int height,
0380                const GdkColor *base, const GdkColor *colors, ECornerBits round,
0381                EWidget widget, EBorder borderProfile, int flags, GtkWidget *wid)
0382 {
0383     EAppearance app = qtcWidgetApp(APPEARANCE_NONE != opts.tbarBtnAppearance &&
0384                                    (WIDGET_TOOLBAR_BUTTON == widget ||
0385                                     (widgetIsButton(widget) &&
0386                                      isOnToolbar(wid, nullptr, 0))) ?
0387                                    WIDGET_TOOLBAR_BUTTON : widget, &opts);
0388     bool sunken = flags & DF_SUNKEN;
0389     bool doColouredMouseOver =
0390         (opts.coloredMouseOver && qtcPalette.mouseover &&
0391          WIDGET_SPIN != widget && WIDGET_SPIN_DOWN != widget &&
0392          WIDGET_SPIN_UP != widget && WIDGET_COMBO_BUTTON != widget &&
0393          WIDGET_SB_BUTTON != widget && (!SLIDER(widget) ||
0394                                         !opts.colorSliderMouseOver) &&
0395          WIDGET_UNCOLOURED_MO_BUTTON != widget && GTK_STATE_PRELIGHT == state &&
0396          (!sunken || IS_TOGGLE_BUTTON(widget) ||
0397           (WIDGET_TOOLBAR_BUTTON == widget && opts.coloredTbarMo)));
0398     bool plastikMouseOver = (doColouredMouseOver &&
0399                              opts.coloredMouseOver == MO_PLASTIK);
0400     bool colouredMouseOver =
0401         (doColouredMouseOver && oneOf(opts.coloredMouseOver, MO_COLORED,
0402                                       MO_COLORED_THICK));
0403     bool flatWidget = (widget == WIDGET_PROGRESSBAR && !opts.borderProgress);
0404     bool lightBorder = !flatWidget && DRAW_LIGHT_BORDER(sunken, widget, app);
0405     bool draw3dfull = (!flatWidget && !lightBorder &&
0406                        DRAW_3D_FULL_BORDER(sunken, app));
0407     bool draw3d =
0408         (!flatWidget && (draw3dfull ||
0409                          (!lightBorder && DRAW_3D_BORDER(sunken, app))));
0410     bool drawShine = DRAW_SHINE(sunken, app);
0411     bool bevelledButton = widgetIsButton(widget) && app == APPEARANCE_BEVELLED;
0412     bool doEtch =
0413         (flags & DF_DO_BORDER &&
0414          (ETCH_WIDGET(widget) || (WIDGET_COMBO_BUTTON == widget &&
0415                                   opts.etchEntry)) &&
0416          opts.buttonEffect != EFFECT_NONE);
0417     bool glowFocus =
0418         (doEtch && USE_GLOW_FOCUS(GTK_STATE_PRELIGHT == state) && wid &&
0419          ((flags&DF_HAS_FOCUS) || gtk_widget_has_focus(wid)) &&
0420          GTK_STATE_INSENSITIVE != state && !isComboBoxEntryButton(wid) &&
0421          ((WIDGET_RADIO_BUTTON != widget && WIDGET_CHECKBOX != widget) ||
0422           GTK_STATE_ACTIVE != state));
0423     bool glowFocusSunkenToggle =
0424         (sunken && (glowFocus || (doColouredMouseOver &&
0425                                   MO_GLOW == opts.coloredMouseOver)) &&
0426          wid && GTK_IS_TOGGLE_BUTTON(wid));
0427     bool horiz = !(flags & DF_VERT);
0428     int xe = x, ye = y;
0429     int we = width, he = height;
0430     int origWidth = width, origHeight = height;
0431     double xd = x + 0.5, yd = y + 0.5;
0432     if (CIRCULAR_SLIDER(widget))
0433         horiz = true;
0434 
0435     if (WIDGET_TROUGH == widget && !opts.borderSbarGroove &&
0436         flags & DF_DO_BORDER) {
0437         flags -= DF_DO_BORDER;
0438     }
0439 
0440     if (WIDGET_COMBO_BUTTON == widget && doEtch) {
0441         if (ROUNDED_RIGHT == round) {
0442             x--;
0443             xd -= 1;
0444             width++;
0445         } else if(ROUNDED_LEFT == round) {
0446             width++;
0447         }
0448     }
0449 
0450     if (doEtch) {
0451         xd += 1;
0452         x++;
0453         yd += 1;
0454         y++;
0455         width -= 2;
0456         height -= 2;
0457         xe = x;
0458         ye = y;
0459         we = width;
0460         he = height;
0461     }
0462 
0463     if (width > 0 && height > 0) {
0464         Cairo::Saver saver(cr);
0465         if (!(flags & DF_DO_BORDER)) {
0466             Cairo::clipWhole(cr, x, y, width, height,
0467                              qtcGetRadius(&opts, width, height, widget,
0468                                           RADIUS_EXTERNAL), round);
0469         } else {
0470             qtcClipPath(cr, x, y, width, height, widget,
0471                         RADIUS_EXTERNAL, round);
0472         }
0473         drawBevelGradient(cr, area, x, y, width, height, base, horiz,
0474                           sunken && !IS_TROUGH(widget), app, widget);
0475         if (plastikMouseOver) {
0476             if (SLIDER(widget)) {
0477                 int len = sbSliderMOLen(opts, horiz ? width : height);
0478                 int so = lightBorder ? SLIDER_MO_PLASTIK_BORDER : 1;
0479                 int eo = len + so;
0480                 int col = SLIDER_MO_SHADE;
0481 
0482                 if (horiz) {
0483                     drawBevelGradient(cr, area, x + so, y, len, height,
0484                                       &qtcPalette.mouseover[col], horiz,
0485                                       sunken, app, widget);
0486                     drawBevelGradient(cr, area, x + width - eo, y, len,
0487                                       height, &qtcPalette.mouseover[col],
0488                                       horiz, sunken, app, widget);
0489                 } else {
0490                     drawBevelGradient(cr, area, x, y + so, width, len,
0491                                       &qtcPalette.mouseover[col], horiz,
0492                                       sunken, app, widget);
0493                     drawBevelGradient(cr, area, x, y + height - eo,
0494                                       width, len, &qtcPalette.mouseover[col],
0495                                       horiz, sunken, app, widget);
0496                 }
0497             } else {
0498                 int mh = height;
0499                 const GdkColor *col =
0500                     &qtcPalette.mouseover[MO_PLASTIK_DARK(widget)];
0501                 bool horizontal =
0502                     ((horiz && !(WIDGET_SB_BUTTON == widget ||
0503                                  SLIDER(widget))) ||
0504                      (!horiz && (WIDGET_SB_BUTTON == widget ||
0505                                  SLIDER(widget))));
0506                 bool thin =
0507                     (oneOf(widget, WIDGET_SB_BUTTON, WIDGET_SPIN_UP,
0508                            WIDGET_SPIN_DOWN) ||
0509                      (horiz ? height : width) < 16);
0510 
0511                 if (EFFECT_NONE != opts.buttonEffect &&
0512                     WIDGET_SPIN_UP == widget && horiz) {
0513                     mh--;
0514                 }
0515                 cairo_new_path(cr);
0516                 Cairo::setColor(cr, col);
0517                 if (horizontal) {
0518                     cairo_move_to(cr, x + 1, yd + 1);
0519                     cairo_line_to(cr, x + width -1, yd + 1);
0520                     cairo_move_to(cr, x + 1, yd + mh - 2);
0521                     cairo_line_to(cr, x + width - 1, yd + mh - 2);
0522                 } else {
0523                     cairo_move_to(cr, xd + 1, y + 1);
0524                     cairo_line_to(cr, xd + 1, y + mh - 1);
0525                     cairo_move_to(cr, xd + width - 2, y + 1);
0526                     cairo_line_to(cr, xd + width - 2, y + mh - 1);
0527                 }
0528                 cairo_stroke(cr);
0529                 if (!thin) {
0530                     col = &qtcPalette.mouseover[MO_PLASTIK_LIGHT(widget)];
0531                     cairo_new_path(cr);
0532                     Cairo::setColor(cr, col);
0533                     if (horizontal) {
0534                         cairo_move_to(cr, x + 1, yd + 2);
0535                         cairo_line_to(cr, x + width - 1, yd + 2);
0536                         cairo_move_to(cr, x + 1, yd + mh - 3);
0537                         cairo_line_to(cr, x + width - 1, yd + mh - 3);
0538                     } else {
0539                         cairo_move_to(cr, xd + 2, y + 1);
0540                         cairo_line_to(cr, xd + 2, y + mh - 1);
0541                         cairo_move_to(cr, xd + width - 3, y + 1);
0542                         cairo_line_to(cr, xd + width - 3, y + mh - 1);
0543                     }
0544                     cairo_stroke(cr);
0545                 }
0546             }
0547         }
0548 
0549         if (drawShine) {
0550             bool mo = state == GTK_STATE_PRELIGHT && opts.highlightFactor;
0551             int xa = x;
0552             int ya = y;
0553             int wa = width;
0554             int ha = height;
0555             if (widget == WIDGET_RADIO_BUTTON || CIRCULAR_SLIDER(widget)) {
0556                 double topSize = ha * 0.4;
0557                 double topWidthAdjust = 3.5;
0558                 double topGradRectX = xa + topWidthAdjust;
0559                 double topGradRectY = ya;
0560                 double topGradRectW = wa - topWidthAdjust * 2 - 1;
0561                 double topGradRectH = topSize - 1;
0562                 cairo_pattern_t *pt =
0563                     cairo_pattern_create_linear(topGradRectX, topGradRectY,
0564                                                 topGradRectX,
0565                                                 topGradRectY + topGradRectH);
0566 
0567                 Cairo::Saver saver(cr);
0568                 Cairo::clipWhole(cr, topGradRectX + 0.5, topGradRectY + 0.5,
0569                                  topGradRectW, topGradRectH,
0570                                  topGradRectW / 2.0, ROUNDED_ALL);
0571 
0572                 cairo_pattern_add_color_stop_rgba(
0573                     pt, 0.0, 1.0, 1.0, 1.0,
0574                     mo ? (opts.highlightFactor > 0 ? 0.8 : 0.7) : 0.75);
0575                 cairo_pattern_add_color_stop_rgba(
0576                     pt, CAIRO_GRAD_END, 1.0, 1.0, 1.0,
0577                     /*mo ? (opts.highlightFactor>0 ? 0.3 : 0.1) :*/ 0.2);
0578 
0579                 cairo_set_source(cr, pt);
0580                 cairo_rectangle(cr, topGradRectX, topGradRectY, topGradRectW,
0581                                 topGradRectH);
0582                 cairo_fill(cr);
0583                 cairo_pattern_destroy(pt);
0584             } else {
0585                 double size = qtcMin((horiz ? ha : wa) / 2.0, 16);
0586                 double rad = size / 2.0;
0587                 cairo_pattern_t *pt = nullptr;
0588                 int mod = 4;
0589 
0590                 if (horiz) {
0591                     if (!(ROUNDED_LEFT & round)) {
0592                         xa -= 8;
0593                         wa += 8;
0594                     }
0595                     if (!(ROUNDED_RIGHT & round)) {
0596                         wa += 8;
0597                     }
0598                 } else {
0599                     if (!(ROUNDED_TOP & round)) {
0600                         ya -= 8;
0601                         ha += 8;
0602                     }
0603                     if (!(ROUNDED_BOTTOM & round)) {
0604                         ha += 8;
0605                     }
0606                 }
0607                 pt = cairo_pattern_create_linear(
0608                     xa, ya, xa + (horiz ? 0.0 : size),
0609                     ya + (horiz ? size : 0.0));
0610 
0611                 if (qtcGetWidgetRound(&opts, origWidth, origHeight,
0612                                       widget) < ROUND_MAX ||
0613                     (!isMaxRoundWidget(widget) && !IS_SLIDER(widget))) {
0614                     rad /= 2.0;
0615                     mod /= 2;
0616                 }
0617 
0618                 Cairo::Saver saver(cr);
0619                 if (horiz) {
0620                     Cairo::clipWhole(cr, xa + mod + 0.5, ya + 0.5,
0621                                      wa - mod * 2 - 1, size - 1, rad, round);
0622                 } else {
0623                     Cairo::clipWhole(cr, xa + 0.5, ya + mod + 0.5, size - 1,
0624                                      ha - mod * 2 - 1, rad, round);
0625                 }
0626 
0627                 cairo_pattern_add_color_stop_rgba(
0628                     pt, 0.0, 1.0, 1.0, 1.0,
0629                     mo ? (opts.highlightFactor > 0 ? 0.95 : 0.85) : 0.9);
0630                 cairo_pattern_add_color_stop_rgba(
0631                     pt, CAIRO_GRAD_END, 1.0, 1.0, 1.0,
0632                     mo ? (opts.highlightFactor > 0 ? 0.3 : 0.1) : 0.2);
0633 
0634                 cairo_set_source(cr, pt);
0635                 cairo_rectangle(cr, xa, ya, horiz ? wa : size,
0636                                 horiz ? size : ha);
0637                 cairo_fill(cr);
0638                 cairo_pattern_destroy(pt);
0639             }
0640         }
0641     }
0642     xd += 1;
0643     x++;
0644     yd += 1;
0645     y++;
0646     width -= 2;
0647     height -= 2;
0648 
0649     cairo_save(cr);
0650     if (plastikMouseOver /* && !sunken */) {
0651         bool thin = (oneOf(widget, WIDGET_SB_BUTTON, WIDGET_SPIN) ||
0652                      (horiz ? height : width) < 16);
0653         bool horizontal =
0654             (SLIDER(widget) ? !horiz : (horiz && WIDGET_SB_BUTTON != widget) ||
0655              (!horiz && WIDGET_SB_BUTTON == widget));
0656         int len = (SLIDER(widget) ?
0657                    sbSliderMOLen(opts, horiz ? width : height) :
0658                    (thin ? 1 : 2));
0659         QtcRect rect;
0660         if (horizontal) {
0661             rect = qtcRect(x, y + len, width, height - len * 2);
0662         } else {
0663             rect = qtcRect(x + len, y, width - len * 2, height);
0664         }
0665         Cairo::clipRect(cr, &rect);
0666     } else {
0667         Cairo::clipRect(cr, area);
0668     }
0669 
0670     if (!colouredMouseOver && lightBorder) {
0671         const GdkColor *col = &colors[LIGHT_BORDER(app)];
0672 
0673         cairo_new_path(cr);
0674         Cairo::setColor(cr, col);
0675         Cairo::pathWhole(cr, xd, yd, width - 1, height - 1,
0676                          qtcGetRadius(&opts, width, height, widget,
0677                                       RADIUS_INTERNAL), round);
0678         cairo_stroke(cr);
0679     }  else if (colouredMouseOver ||
0680                 (!sunken && (draw3d || flags & DF_DRAW_INSIDE))) {
0681         int dark = /*bevelledButton ? */2/* : 4*/;
0682         const GdkColor *col1 =
0683             (colouredMouseOver ?
0684              &qtcPalette.mouseover[MO_STD_LIGHT(widget, sunken)] :
0685              &colors[sunken ? dark : 0]);
0686 
0687         cairo_new_path(cr);
0688         Cairo::setColor(cr, col1);
0689         Cairo::pathTopLeft(cr, xd, yd, width - 1, height - 1,
0690                            qtcGetRadius(&opts, width, height, widget,
0691                                         RADIUS_INTERNAL), round);
0692         cairo_stroke(cr);
0693         if (colouredMouseOver || bevelledButton || draw3dfull) {
0694             const GdkColor *col2 = colouredMouseOver ?
0695                 &qtcPalette.mouseover[MO_STD_DARK(widget)] :
0696                 &colors[sunken ? 0 : dark];
0697 
0698             cairo_new_path(cr);
0699             Cairo::setColor(cr, col2);
0700             Cairo::pathBottomRight(cr, xd, yd, width - 1, height - 1,
0701                                    qtcGetRadius(&opts, width, height, widget,
0702                                                 RADIUS_INTERNAL), round);
0703             cairo_stroke(cr);
0704         }
0705     }
0706 
0707     cairo_restore(cr);
0708 
0709     if ((doEtch || glowFocus) && !(flags & DF_HIDE_EFFECT)) {
0710         if ((!sunken || glowFocusSunkenToggle) &&
0711             GTK_STATE_INSENSITIVE != state && !(opts.thin&THIN_FRAMES) &&
0712             ((noneOf(widget, WIDGET_OTHER, WIDGET_SLIDER_TROUGH,
0713                      WIDGET_COMBO_BUTTON) &&
0714               opts.coloredMouseOver == MO_GLOW &&
0715               state == GTK_STATE_PRELIGHT) || glowFocus ||
0716              (widget == WIDGET_DEF_BUTTON &&
0717               opts.defBtnIndicator == IND_GLOW))) {
0718             drawGlow(cr, area, xe - 1, ye - 1, we + 2, he + 2, round,
0719                      (widget == WIDGET_DEF_BUTTON &&
0720                       state == GTK_STATE_PRELIGHT ? WIDGET_STD_BUTTON : widget),
0721                      glowFocus ? qtcPalette.focus : nullptr);
0722         } else {
0723             drawEtch(cr, area, wid,
0724                      xe - (WIDGET_COMBO_BUTTON == widget ?
0725                            (ROUNDED_RIGHT==round ? 3 : 1) : 1), ye - 1,
0726                      we + (WIDGET_COMBO_BUTTON == widget ?
0727                            (ROUNDED_RIGHT == round ? 4 : 5) : 2), he + 2,
0728                      EFFECT_SHADOW == opts.buttonEffect &&
0729                      WIDGET_COMBO_BUTTON != widget && widgetIsButton(widget) &&
0730                      !sunken, round, widget);
0731         }
0732     }
0733 
0734     xd -= 1;
0735     x--;
0736     yd -= 1;
0737     y--;
0738     width += 2;
0739     height += 2;
0740     if (flags & DF_DO_BORDER && width > 2 && height > 2) {
0741         const GdkColor *borderCols =
0742             (glowFocus && (!sunken || glowFocusSunkenToggle) ?
0743              qtcPalette.focus : oneOf(widget, WIDGET_COMBO,
0744                                       WIDGET_COMBO_BUTTON) &&
0745              qtcPalette.combobtn == colors ?
0746              state == GTK_STATE_PRELIGHT && opts.coloredMouseOver == MO_GLOW &&
0747              !sunken ? qtcPalette.mouseover :
0748              qtcPalette.button[PAL_ACTIVE] : colors);
0749 
0750         cairo_new_path(cr);
0751         /* Yuck! this is a mess!!!! */
0752         // Copied from KDE4 version...
0753         if (!sunken && state != GTK_STATE_INSENSITIVE && !glowFocus &&
0754             ((((doEtch && noneOf(widget, WIDGET_OTHER,
0755                                  WIDGET_SLIDER_TROUGH)) || SLIDER(widget) ||
0756                oneOf(widget, WIDGET_COMBO, WIDGET_MENU_BUTTON)) &&
0757               (opts.coloredMouseOver == MO_GLOW
0758                /* || opts.colorMenubarMouseOver == MO_COLORED */) &&
0759               state == GTK_STATE_PRELIGHT) ||
0760              (doEtch && widget == WIDGET_DEF_BUTTON &&
0761               opts.defBtnIndicator == IND_GLOW))) {
0762 
0763 // Previous Gtk2...
0764 //         if(!sunken && (doEtch || SLIDER(widget)) &&
0765 //             ( (WIDGET_OTHER!=widget && WIDGET_SLIDER_TROUGH!=widget && WIDGET_COMBO_BUTTON!=widget &&
0766 //                 MO_GLOW==opts.coloredMouseOver && GTK_STATE_PRELIGHT==state) ||
0767 //               (WIDGET_DEF_BUTTON==widget && IND_GLOW==opts.defBtnIndicator)))
0768             drawBorder(cr, style, state, area, x, y, width, height,
0769                        widget == WIDGET_DEF_BUTTON &&
0770                        opts.defBtnIndicator == IND_GLOW &&
0771                        (state != GTK_STATE_PRELIGHT || !qtcPalette.mouseover) ?
0772                        qtcPalette.defbtn : qtcPalette.mouseover,
0773                        round, borderProfile, widget, flags);
0774         } else {
0775             drawBorder(cr, style, state, area, x, y, width, height,
0776                        colouredMouseOver &&
0777                        opts.coloredMouseOver == MO_COLORED_THICK ?
0778                        qtcPalette.mouseover : borderCols,
0779                        round, borderProfile, widget, flags);
0780         }
0781     }
0782 
0783     if (WIDGET_SB_SLIDER == widget && opts.stripedSbar) {
0784         Cairo::Saver saver(cr);
0785         Cairo::clipWhole(cr, x, y, width, height,
0786                          qtcGetRadius(&opts, width, height, WIDGET_SB_SLIDER,
0787                                       RADIUS_INTERNAL), round);
0788         addStripes(cr, x + 1, y + 1, width - 2, height - 2, horiz);
0789     }
0790 }
0791 
0792 void
0793 drawFadedLine(cairo_t *cr, int x, int y, int width, int height,
0794               const GdkColor *col, const QtcRect *area, const QtcRect *gap,
0795               bool fadeStart, bool fadeEnd, bool horiz, double alpha)
0796 {
0797     Cairo::fadedLine(cr, x, y, width, height, area, gap,
0798                      fadeStart && opts.fadeLines,
0799                      fadeEnd && opts.fadeLines, FADE_SIZE, horiz, col, alpha);
0800 }
0801 
0802 void
0803 drawHighlight(cairo_t *cr, int x, int y, int width, int height,
0804               const QtcRect *area, bool horiz, bool inc)
0805 {
0806     drawFadedLine(cr, x, y, width, height,
0807                   &qtcPalette.mouseover[ORIGINAL_SHADE], area, nullptr,
0808                   true, true, horiz, inc ? 0.5 : 1.0);
0809     drawFadedLine(cr, x + (horiz ? 0 : 1), y + (horiz ? 1 : 0), width, height,
0810                   &qtcPalette.mouseover[ORIGINAL_SHADE], area, nullptr,
0811                   true, true, horiz, inc ? 1.0 : 0.5);
0812 }
0813 
0814 void setLineCol(cairo_t *cr, cairo_pattern_t *pt, const GdkColor *col)
0815 {
0816     if (pt) {
0817         Cairo::patternAddColorStop(pt, 0, col, 0.0);
0818         Cairo::patternAddColorStop(pt, 0.4, col);
0819         Cairo::patternAddColorStop(pt, 0.6, col);
0820         Cairo::patternAddColorStop(pt, CAIRO_GRAD_END, col, 0.0);
0821         cairo_set_source(cr, pt);
0822     } else {
0823         Cairo::setColor(cr, col);
0824     }
0825 }
0826 
0827 void
0828 drawLines(cairo_t *cr, double rx, double ry, int rwidth, int rheight,
0829           bool horiz, int nLines, int offset, const GdkColor *cols,
0830           const QtcRect *area, int dark, ELine type)
0831 {
0832     if (horiz) {
0833         ry += 0.5;
0834         rwidth += 1;
0835     } else {
0836         rx += 0.5;
0837         rheight += 1;
0838     }
0839     int space = nLines * 2 + (type != LINE_DASHES ? nLines - 1 : 0);
0840     int step = type != LINE_DASHES ? 3 : 2;
0841     int etchedDisp = type == LINE_SUNKEN ? 1 : 0;
0842     double x = horiz ? rx : rx + (rwidth - space) / 2;
0843     double y = horiz ? ry + (rheight - space) / 2 : ry;
0844     double x2 = rx + rwidth - 1;
0845     double y2 = ry + rheight - 1;
0846     const GdkColor *col1 = &cols[dark];
0847     const GdkColor *col2 = &cols[0];
0848     cairo_pattern_t *pt1 =
0849         ((opts.fadeLines && (horiz ? rwidth : rheight) > (16 + etchedDisp)) ?
0850          cairo_pattern_create_linear(rx, ry, horiz ? x2 : rx + 1,
0851                                      horiz ? ry + 1 : y2) : nullptr);
0852     cairo_pattern_t *pt2 =
0853         ((pt1 && type != LINE_FLAT) ?
0854          cairo_pattern_create_linear(rx, ry, horiz ? x2 : rx + 1,
0855                                      horiz ? ry + 1 : y2) : nullptr);
0856     Cairo::Saver saver(cr);
0857     Cairo::clipRect(cr, area);
0858     setLineCol(cr, pt1, col1);
0859     if (horiz) {
0860         for (int i = 0;i < space;i += step) {
0861             cairo_move_to(cr, x + offset, y + i);
0862             cairo_line_to(cr, x2 - offset, y + i);
0863         }
0864         cairo_stroke(cr);
0865         if (type != LINE_FLAT) {
0866             setLineCol(cr, pt2, col2);
0867             x += etchedDisp;
0868             x2 += etchedDisp;
0869             for (int i = 1;i < space;i += step) {
0870                 cairo_move_to(cr, x + offset, y + i);
0871                 cairo_line_to(cr, x2 - offset, y + i);
0872             }
0873             cairo_stroke(cr);
0874         }
0875     } else {
0876         for (int i = 0;i < space;i += step) {
0877             cairo_move_to(cr, x + i, y + offset);
0878             cairo_line_to(cr, x + i, y2 - offset);
0879         }
0880         cairo_stroke(cr);
0881         if (type != LINE_FLAT) {
0882             setLineCol(cr, pt2, col2);
0883             y += etchedDisp;
0884             y2 += etchedDisp;
0885             for (int i = 1;i < space;i += step) {
0886                 cairo_move_to(cr, x + i, y + offset);
0887                 cairo_line_to(cr, x + i, y2 - offset);
0888             }
0889             cairo_stroke(cr);
0890         }
0891     }
0892     if (pt1) {
0893         cairo_pattern_destroy(pt1);
0894     }
0895     if (pt2) {
0896         cairo_pattern_destroy(pt2);
0897     }
0898 }
0899 
0900 void
0901 drawEntryCorners(cairo_t *cr, const QtcRect *area, int round, int x, int y,
0902                  int width, int height, const GdkColor *col, double a)
0903 {
0904     Cairo::Saver saver(cr);
0905     Cairo::clipRect(cr, area);
0906     Cairo::setColor(cr, col, a);
0907     cairo_rectangle(cr, x + 0.5, y + 0.5, width - 1, height - 1);
0908     if (opts.buttonEffect != EFFECT_NONE && opts.etchEntry) {
0909         cairo_rectangle(cr, x + 1.5, y + 1.5, width - 2, height - 3);
0910     }
0911     if (opts.round > ROUND_FULL) {
0912         if (round & CORNER_TL) {
0913             cairo_rectangle(cr, x + 2.5, y + 2.5, 1, 1);
0914         }
0915         if (round & CORNER_BL) {
0916             cairo_rectangle(cr, x + 2.5, y + height - 3.5, 1, 1);
0917         }
0918         if (round & CORNER_TR) {
0919             cairo_rectangle(cr, x + width - 2.5, y + 2.5, 1, 1);
0920         }
0921         if (round & CORNER_BR) {
0922             cairo_rectangle(cr, x + width - 2.5, y + height - 3.5, 1, 1);
0923         }
0924     }
0925     cairo_set_line_width(cr, opts.round > ROUND_FULL &&
0926                          qtSettings.app != GTK_APP_OPEN_OFFICE ? 2 : 1);
0927     cairo_stroke(cr);
0928 }
0929 
0930 void
0931 drawBgndRing(cairo_t *cr, int x, int y, int size, int size2, bool isWindow)
0932 {
0933     double width = (size - size2) / 2.0;
0934     double width2 = width / 2.0;
0935     double radius = (size2 + width) / 2.0;
0936 
0937     cairo_set_source_rgba(cr, 1.0, 1.0, 1.0,
0938                           RINGS_INNER_ALPHA(isWindow ? opts.bgndImage.type :
0939                                             opts.menuBgndImage.type));
0940     cairo_set_line_width(cr, width);
0941     cairo_arc(cr, x + radius + width2 + 0.5, y + radius + width2 + 0.5, radius,
0942               0, 2 * M_PI);
0943     cairo_stroke(cr);
0944 
0945     if ((isWindow ? opts.bgndImage.type :
0946          opts.menuBgndImage.type) == IMG_BORDERED_RINGS) {
0947         cairo_set_line_width(cr, 1);
0948         cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, RINGS_OUTER_ALPHA);
0949         cairo_arc(cr, x + radius + width2 + 0.5, y + radius + width2 + 0.5,
0950                   size / 2.0, 0, 2 * M_PI);
0951         if (size2) {
0952             cairo_stroke(cr);
0953             cairo_arc(cr, x + radius + width2 + 0.5, y + radius + width2 + 0.5,
0954                       size2 / 2.0, 0, 2 * M_PI);
0955         }
0956         cairo_stroke(cr);
0957     }
0958 }
0959 
0960 void
0961 drawBgndRings(cairo_t *cr, int x, int y, int width, int height, bool isWindow)
0962 {
0963     static cairo_surface_t *bgndImage = nullptr;
0964     static cairo_surface_t *menuBgndImage = nullptr;
0965 
0966     bool useWindow = (isWindow ||
0967                       (opts.bgndImage.type == opts.menuBgndImage.type &&
0968                        (opts.bgndImage.type != IMG_FILE ||
0969                         (opts.bgndImage.height == opts.menuBgndImage.height &&
0970                          opts.bgndImage.width == opts.menuBgndImage.width &&
0971                          opts.bgndImage.pixmap.file ==
0972                          opts.menuBgndImage.pixmap.file))));
0973     QtCImage *img = useWindow ? &opts.bgndImage : &opts.menuBgndImage;
0974     int imgWidth = img->type == IMG_FILE ? img->width : RINGS_WIDTH(img->type);
0975     int imgHeight = (img->type == IMG_FILE ? img->height :
0976                      RINGS_HEIGHT(img->type));
0977 
0978     switch (img->type) {
0979     case IMG_NONE:
0980         break;
0981     case IMG_FILE:
0982         qtcLoadBgndImage(img);
0983         if (img->pixmap.img) {
0984             switch (img->pos) {
0985             case PP_TL:
0986                 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img, x, y);
0987                 break;
0988             case PP_TM:
0989                 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img,
0990                                             x + (width - img->width) / 2, y);
0991                 break;
0992             default:
0993             case PP_TR:
0994                 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img,
0995                                             x + width - img->width - 1, y);
0996                 break;
0997             case PP_BL:
0998                 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img, x,
0999                                             y + height - img->height);
1000                 break;
1001             case PP_BM:
1002                 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img,
1003                                             x + (width - img->width) / 2,
1004                                             y + height - img->height - 1);
1005                 break;
1006             case PP_BR:
1007                 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img,
1008                                             x + width - img->width - 1,
1009                                             y + height - img->height - 1);
1010                 break;
1011             case PP_LM:
1012                 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img, x,
1013                                             y + (height - img->height) / 2);
1014                 break;
1015             case PP_RM:
1016                 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img,
1017                                             x + width - img->width - 1,
1018                                             y + (height - img->height) / 2);
1019                 break;
1020             case PP_CENTRED:
1021                 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img,
1022                                             x + (width - img->width) / 2,
1023                                             y + (height - img->height) / 2);
1024             }
1025             cairo_paint(cr);
1026         }
1027         break;
1028     case IMG_PLAIN_RINGS:
1029     case IMG_BORDERED_RINGS: {
1030         cairo_surface_t *crImg = useWindow ? bgndImage : menuBgndImage;
1031 
1032         if (!crImg) {
1033             cairo_t *ci;
1034             crImg = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
1035                                                imgWidth + 1, imgHeight + 1);
1036             ci = cairo_create(crImg);
1037             drawBgndRing(ci, 0, 0, 200, 140, isWindow);
1038 
1039             drawBgndRing(ci, 210, 10, 230, 214, isWindow);
1040             drawBgndRing(ci, 226, 26, 198, 182, isWindow);
1041             drawBgndRing(ci, 300, 100, 50, 0, isWindow);
1042 
1043             drawBgndRing(ci, 100, 96, 160, 144, isWindow);
1044             drawBgndRing(ci, 116, 112, 128, 112, isWindow);
1045 
1046             drawBgndRing(ci, 250, 160, 200, 140, isWindow);
1047             drawBgndRing(ci, 310, 220, 80, 0, isWindow);
1048             cairo_destroy(ci);
1049             if (useWindow) {
1050                 bgndImage = crImg;
1051             } else {
1052                 menuBgndImage = crImg;
1053             }
1054         }
1055 
1056         cairo_set_source_surface(cr, crImg, width - imgWidth, y + 1);
1057         cairo_paint(cr);
1058         break;
1059     }
1060     case IMG_SQUARE_RINGS: {
1061         cairo_surface_t *crImg = useWindow ? bgndImage : menuBgndImage;
1062 
1063         if (!crImg) {
1064             double halfWidth = RINGS_SQUARE_LINE_WIDTH / 2.0;
1065             crImg = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
1066                                                imgWidth + 1, imgHeight + 1);
1067             cairo_t *ci = cairo_create(crImg);
1068 
1069             cairo_set_source_rgba(ci, 1.0, 1.0, 1.0, RINGS_SQUARE_SMALL_ALPHA);
1070             cairo_set_line_width(ci, RINGS_SQUARE_LINE_WIDTH);
1071             Cairo::pathWhole(ci, halfWidth + 0.5, halfWidth + 0.5,
1072                              RINGS_SQUARE_SMALL_SIZE, RINGS_SQUARE_SMALL_SIZE,
1073                              RINGS_SQUARE_RADIUS, ROUNDED_ALL);
1074             cairo_stroke(ci);
1075 
1076             cairo_new_path(ci);
1077             cairo_set_source_rgba(ci, 1.0, 1.0, 1.0, RINGS_SQUARE_SMALL_ALPHA);
1078             cairo_set_line_width(ci, RINGS_SQUARE_LINE_WIDTH);
1079             Cairo::pathWhole(ci, halfWidth + 0.5 + imgWidth -
1080                              RINGS_SQUARE_SMALL_SIZE - RINGS_SQUARE_LINE_WIDTH,
1081                              halfWidth + 0.5 + imgHeight -
1082                              RINGS_SQUARE_SMALL_SIZE - RINGS_SQUARE_LINE_WIDTH,
1083                              RINGS_SQUARE_SMALL_SIZE, RINGS_SQUARE_SMALL_SIZE,
1084                              RINGS_SQUARE_RADIUS, ROUNDED_ALL);
1085             cairo_stroke(ci);
1086 
1087             cairo_new_path(ci);
1088             cairo_set_source_rgba(ci, 1.0, 1.0, 1.0, RINGS_SQUARE_LARGE_ALPHA);
1089             cairo_set_line_width(ci, RINGS_SQUARE_LINE_WIDTH);
1090             Cairo::pathWhole(ci, halfWidth + 0.5 +
1091                              (imgWidth - RINGS_SQUARE_LARGE_SIZE -
1092                               RINGS_SQUARE_LINE_WIDTH) / 2.0,
1093                              halfWidth + 0.5 +
1094                              (imgHeight - RINGS_SQUARE_LARGE_SIZE -
1095                               RINGS_SQUARE_LINE_WIDTH) / 2.0,
1096                              RINGS_SQUARE_LARGE_SIZE, RINGS_SQUARE_LARGE_SIZE,
1097                              RINGS_SQUARE_RADIUS, ROUNDED_ALL);
1098             cairo_stroke(ci);
1099 
1100             cairo_destroy(ci);
1101 
1102             if (useWindow) {
1103                 bgndImage = crImg;
1104             } else {
1105                 menuBgndImage = crImg;
1106             }
1107         }
1108 
1109         cairo_set_source_surface(cr, crImg, width-imgWidth, y+1);
1110         cairo_paint(cr);
1111         break;
1112     }
1113     }
1114 }
1115 
1116 void
1117 drawBgndImage(cairo_t *cr, int x, int y, int w, int h, bool isWindow)
1118 {
1119     GdkPixbuf *pix = isWindow ? opts.bgndPixmap.img : opts.menuBgndPixmap.img;
1120     if (pix) {
1121         gdk_cairo_set_source_pixbuf(cr, pix, 0, 0);
1122         cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
1123         cairo_rectangle(cr, x, y, w, h);
1124         cairo_fill(cr);
1125     }
1126 }
1127 
1128 void
1129 drawStripedBgnd(cairo_t *cr, int x, int y, int w, int h,
1130                 const GdkColor *col, double alpha)
1131 {
1132     GdkColor col2;
1133     qtcShade(col, &col2, BGND_STRIPE_SHADE, opts.shading);
1134 
1135     cairo_pattern_t *pat = cairo_pattern_create_linear(x, y, x, y + 4);
1136     Cairo::patternAddColorStop(pat, 0.0, col, alpha);
1137     Cairo::patternAddColorStop(pat, 0.25 - 0.0001, col, alpha);
1138     Cairo::patternAddColorStop(pat, 0.5, &col2, alpha);
1139     Cairo::patternAddColorStop(pat, 0.75 - 0.0001, &col2, alpha);
1140     col2.red = (3 * col->red + col2.red) / 4;
1141     col2.green = (3 * col->green + col2.green) / 4;
1142     col2.blue = (3 * col->blue + col2.blue) / 4;
1143     Cairo::patternAddColorStop(pat, 0.25, &col2, alpha);
1144     Cairo::patternAddColorStop(pat, 0.5 - 0.0001, &col2, alpha);
1145     Cairo::patternAddColorStop(pat, 0.75, &col2, alpha);
1146     Cairo::patternAddColorStop(pat, CAIRO_GRAD_END, &col2, alpha);
1147 
1148     cairo_pattern_set_extend(pat, CAIRO_EXTEND_REPEAT);
1149     cairo_set_source(cr, pat);
1150     cairo_rectangle(cr, x, y, w, h);
1151     cairo_fill(cr);
1152     cairo_pattern_destroy(pat);
1153 }
1154 
1155 bool
1156 drawWindowBgnd(cairo_t *cr, GtkStyle *style, const QtcRect *area,
1157                GdkWindow *window, GtkWidget *widget, int x, int y,
1158                int width, int height)
1159 {
1160     GtkWidget *parent = nullptr;
1161     if (widget && (parent = gtk_widget_get_parent(widget)) &&
1162         isOnHandlebox(parent, nullptr, 0)) {
1163         return true;
1164     }
1165     if (!isFixedWidget(widget) && !isGimpDockable(widget)) {
1166         int wx = 0;
1167         int wy = 0;
1168         int wh = 0;
1169         int ww = 0;
1170 
1171         if (!mapToTopLevel(window, widget, &wx, &wy, &ww, &wh)) {
1172             return false;
1173         }
1174         GtkWidget *topLevel = gtk_widget_get_toplevel(widget);
1175         int opacity = (!topLevel || !GTK_IS_DIALOG(topLevel) ?
1176                        opts.bgndOpacity : opts.dlgOpacity);
1177         int xmod = 0;
1178         int ymod = 0;
1179         int wmod = 0;
1180         int hmod = 0;
1181         double alpha = 1.0;
1182         bool useAlpha = (opacity < 100 && isRgbaWidget(topLevel) &&
1183                          compositingActive(topLevel));
1184         bool flatBgnd = qtcIsFlatBgnd(opts.bgndAppearance);
1185 
1186         // Determine the color to use here
1187         // In commit 87404dba2447c8cba1c70bde72434c67642a7e7c:
1188         //     When drawing background gradients, use the background colour of
1189         //     the top-level widget's style.
1190         // the order was set to Toplevel -> Parent -> Global style.
1191         // This cause wrong color to be used in chomium.
1192         // The current order is Parent -> Toplevel -> Global style.
1193         // Keep this order unless other problems are found.
1194         // It may also be a good idea to figure out what is the original color
1195         // and make the color of choice here consistent with that.
1196         // (at least for chromium)
1197         const GdkColor *col = getParentBgCol(widget);
1198         if (!col) {
1199             col = &qtcDefault(gtk_widget_get_style(topLevel),
1200                               style)->bg[GTK_STATE_NORMAL];
1201         }
1202         if (!flatBgnd || (opts.bgndImage.type == IMG_FILE &&
1203                           opts.bgndImage.onBorder)) {
1204             WindowBorders borders = qtcGetWindowBorderSize(false);
1205             xmod = borders.sides;
1206             ymod = borders.titleHeight;
1207             wmod = 2 * borders.sides;
1208             hmod = borders.titleHeight + borders.bottom;
1209             wy += ymod;
1210             wx += xmod;
1211             wh += hmod;
1212             ww += wmod;
1213         }
1214         QtcRect clip = {x, y, width, height};
1215         Cairo::Saver saver(cr);
1216         Cairo::clipRect(cr, &clip);
1217         if (useAlpha) {
1218             alpha = opacity / 100.0;
1219             cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1220         }
1221         if (flatBgnd) {
1222             Cairo::rect(cr, area, -wx, -wy, ww, wh, col, alpha);
1223         } else if (opts.bgndAppearance == APPEARANCE_STRIPED) {
1224             drawStripedBgnd(cr, -wx, -wy, ww, wh, col, alpha);
1225         } else if (opts.bgndAppearance == APPEARANCE_FILE) {
1226             Cairo::Saver saver(cr);
1227             cairo_translate(cr, -wx, -wy);
1228             drawBgndImage(cr, 0, 0, ww, wh, true);
1229         } else {
1230             drawBevelGradient(cr, area, -wx, -wy, ww, wh + 1, col,
1231                               opts.bgndGrad == GT_HORIZ, false,
1232                               opts.bgndAppearance, WIDGET_OTHER, alpha);
1233             if (opts.bgndGrad == GT_HORIZ &&
1234                 qtcGetGradient(opts.bgndAppearance,
1235                                &opts)->border == GB_SHINE) {
1236                 int size = qtcMin(BGND_SHINE_SIZE, qtcMin(wh * 2, ww));
1237                 double alpha = qtcShineAlpha(col);
1238                 cairo_pattern_t *pat = nullptr;
1239 
1240                 size /= BGND_SHINE_STEPS;
1241                 size *= BGND_SHINE_STEPS;
1242                 pat = cairo_pattern_create_radial(
1243                     ww / 2.0 - wx, -wy, 0, ww / 2.0 - wx, -wy, size / 2.0);
1244                 cairo_pattern_add_color_stop_rgba(pat, 0, 1, 1, 1, alpha);
1245                 cairo_pattern_add_color_stop_rgba(pat, 0.5, 1, 1, 1,
1246                                                   alpha * 0.625);
1247                 cairo_pattern_add_color_stop_rgba(pat, 0.75, 1, 1, 1,
1248                                                   alpha * 0.175);
1249                 cairo_pattern_add_color_stop_rgba(pat, CAIRO_GRAD_END,
1250                                                   1, 1, 1, 0.0);
1251                 cairo_set_source(cr, pat);
1252                 cairo_rectangle(cr, (ww - size) / 2.0 - wx, -wy, size, size);
1253                 cairo_fill(cr);
1254                 cairo_pattern_destroy(pat);
1255             }
1256         }
1257         if (useAlpha) {
1258             cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1259         }
1260         if (!(opts.bgndImage.type == IMG_FILE && opts.bgndImage.onBorder)) {
1261             ww -= wmod + 1;
1262             wh -= hmod;
1263             wx -= xmod;
1264             wy -= ymod;
1265         }
1266         drawBgndRings(cr, -wx, -wy, ww, wh, true);
1267         return true;
1268     }
1269     return false;
1270 }
1271 
1272 void
1273 drawEntryField(cairo_t *cr, GtkStyle *style, GtkStateType state,
1274                GdkWindow *window, GtkWidget *widget, const QtcRect *area,
1275                int x, int y, int width, int height,
1276                ECornerBits round, EWidget w)
1277 {
1278     bool enabled = !(GTK_STATE_INSENSITIVE == state ||
1279                      (widget && !gtk_widget_is_sensitive(widget)));
1280     bool highlightReal =
1281         (enabled && widget && gtk_widget_has_focus(widget) &&
1282          qtSettings.app != GTK_APP_JAVA);
1283     bool mouseOver =
1284         (opts.unifyCombo && opts.unifySpin && enabled &&
1285          (GTK_STATE_PRELIGHT == state || Entry::isLastMo(widget)) &&
1286          qtcPalette.mouseover && GTK_APP_JAVA != qtSettings.app);
1287     bool highlight = highlightReal || mouseOver;
1288     bool doEtch = opts.buttonEffect != EFFECT_NONE && opts.etchEntry;
1289     bool comboOrSpin = oneOf(w, WIDGET_SPIN, WIDGET_COMBO_BUTTON);
1290     const GdkColor *colors = (mouseOver ? qtcPalette.mouseover : highlightReal ?
1291                               qtcPalette.focus : qtcPalette.background);
1292 
1293     if (qtSettings.app != GTK_APP_JAVA) {
1294         Entry::setup(widget);
1295     }
1296     if ((doEtch || opts.round != ROUND_NONE) &&
1297         (!widget || !g_object_get_data(G_OBJECT(widget),
1298                                        "transparent-bg-hint"))) {
1299         if (qtcIsFlatBgnd(opts.bgndAppearance) || !widget ||
1300             !drawWindowBgnd(cr, style, area, window, widget, x, y,
1301                             width, height)) {
1302             GdkColor parentBgCol;
1303             getEntryParentBgCol(widget, &parentBgCol);
1304             drawEntryCorners(cr, area, round, x, y, width, height,
1305                              &parentBgCol, 1.0);
1306         }
1307     }
1308 
1309     if (opts.gbFactor != 0 &&
1310         oneOf(opts.groupBox, FRAME_SHADED, FRAME_FADED) &&
1311         isInGroupBox(widget, 0)) {
1312         GdkColor col;
1313         col.red = col.green = col.blue = opts.gbFactor < 0 ? 0.0 : 1.0;
1314         drawEntryCorners(cr, area, round, x, y, width, height, &col,
1315                          TO_ALPHA(opts.gbFactor));
1316     }
1317 
1318     if (doEtch) {
1319         y++;
1320         x++;
1321         height -= 2;
1322         width -= 2;
1323     }
1324 
1325     if (DEBUG_ALL == qtSettings.debug) {
1326         printf(DEBUG_PREFIX "%s %d %d %d %d %d %d ", __FUNCTION__,
1327                state, x, y, width, height, round);
1328         debugDisplayWidget(widget, 10);
1329     }
1330 
1331     if (round != ROUNDED_ALL) {
1332         if (comboOrSpin) {
1333             x -= 2;
1334             width += 2;
1335         } else if (highlight) {
1336             if (doEtch) {
1337                 if (round == ROUNDED_RIGHT) {
1338                     /* RtoL */
1339                     x--;
1340                 } else {
1341                     width++;
1342                 }
1343             }
1344         } else {
1345             if (round == ROUNDED_RIGHT) {
1346                 /* RtoL */
1347                 x -= 2;
1348             } else {
1349                 width += 2;
1350             }
1351         }
1352     }
1353 
1354     Cairo::Saver saver(cr);
1355     if (opts.round > ROUND_FULL) {
1356         qtcClipPath(cr, x + 1, y + 1, width - 2, height - 2,
1357                     WIDGET_ENTRY, RADIUS_INTERNAL, ROUNDED_ALL);
1358     }
1359     Cairo::rect(cr, area, x + 1, y + 1, width - 2, height - 2,
1360                 enabled ? &style->base[GTK_STATE_NORMAL] :
1361                 &style->bg[GTK_STATE_INSENSITIVE]);
1362 
1363     saver.resave();
1364 
1365     if (qtSettings.app == GTK_APP_OPEN_OFFICE && comboOrSpin) {
1366         const QtcRect rect = {x, y, width, height};
1367         x -= 4;
1368         width += 4;
1369         Cairo::clipRect(cr, &rect);
1370     }
1371 
1372     int xo = x;
1373     int yo = y;
1374     int widtho = width;
1375     int heighto = height;
1376 
1377     if (doEtch) {
1378         y--;
1379         height += 2;
1380         x--;
1381         width += 2;
1382         if (!(w == WIDGET_SPIN && opts.unifySpin) &&
1383             !(w == WIDGET_COMBO_BUTTON && opts.unifyCombo)) {
1384             if (!(round & CORNER_TR) && !(round & CORNER_BR)) {
1385                 width += 4;
1386             }
1387             if (!(round & CORNER_TL) && !(round & CORNER_BL)) {
1388                 x -= 4;
1389             }
1390         }
1391         drawEtch(cr, area, widget, x, y, width, height, false, round,
1392                  WIDGET_ENTRY);
1393     }
1394 
1395     drawBorder(cr, style, (!widget || gtk_widget_is_sensitive(widget) ?
1396                            state : GTK_STATE_INSENSITIVE), area,
1397                xo, yo, widtho, heighto, colors, round,
1398                BORDER_SUNKEN, WIDGET_ENTRY, DF_BLEND);
1399     if (GTK_IS_ENTRY(widget) && !gtk_entry_get_visibility(GTK_ENTRY(widget))) {
1400         gtk_entry_set_invisible_char(GTK_ENTRY(widget), opts.passwordChar);
1401     }
1402 }
1403 
1404 static void
1405 qtcSetProgressStripeClipping(cairo_t *cr, const QtcRect *area, int x, int y,
1406                              int width, int height, int animShift, bool horiz)
1407 {
1408     switch (opts.stripedProgress) {
1409     default:
1410     case STRIPE_PLAIN: {
1411         QtcRect rect = {x, y, width - 2, height - 2};
1412         Rect::constrain(&rect, area);
1413         cairo_region_t *region = cairo_region_create_rectangle(&rect);
1414         if (horiz) {
1415             for (int stripeOffset = 0;
1416                  stripeOffset < width + PROGRESS_CHUNK_WIDTH;
1417                  stripeOffset += PROGRESS_CHUNK_WIDTH * 2) {
1418                 QtcRect innerRect = {x + stripeOffset + animShift, y + 1,
1419                                      PROGRESS_CHUNK_WIDTH, height - 2};
1420                 Rect::constrain(&innerRect, area);
1421                 if (innerRect.width > 0 && innerRect.height > 0) {
1422                     cairo_region_xor_rectangle(region, &innerRect);
1423                 }
1424             }
1425         } else {
1426             for (int stripeOffset = 0;
1427                  stripeOffset < height + PROGRESS_CHUNK_WIDTH;
1428                  stripeOffset += PROGRESS_CHUNK_WIDTH * 2) {
1429                 QtcRect innerRect = {x + 1, y + stripeOffset + animShift,
1430                                      width - 2, PROGRESS_CHUNK_WIDTH};
1431                 /* qtcRectConstrain(&innerRect, area); */
1432                 if (innerRect.width > 0 && innerRect.height > 0) {
1433                     cairo_region_xor_rectangle(region, &innerRect);
1434                 }
1435             }
1436         }
1437         Cairo::clipRegion(cr, region);
1438         cairo_region_destroy(region);
1439         break;
1440     }
1441     case STRIPE_DIAGONAL:
1442         cairo_new_path(cr);
1443         /* if (area) */
1444         /*     cairo_rectangle(cr, area->x, area->y, */
1445         /*                     area->width, area->height); */
1446         if (horiz) {
1447             for (int stripeOffset = 0;stripeOffset < width + height + 2;
1448                  stripeOffset += PROGRESS_CHUNK_WIDTH * 2) {
1449                 const GdkPoint pts[4] = {
1450                     {x + stripeOffset + animShift, y},
1451                     {x + stripeOffset + animShift + PROGRESS_CHUNK_WIDTH, y},
1452                     {x + stripeOffset + animShift +
1453                      PROGRESS_CHUNK_WIDTH - height, y + height - 1},
1454                     {x + stripeOffset + animShift - height, y + height - 1}};
1455                 Cairo::pathPoints(cr, pts, 4);
1456             }
1457         } else {
1458             for (int stripeOffset = 0;stripeOffset < height + width + 2;
1459                  stripeOffset += PROGRESS_CHUNK_WIDTH * 2) {
1460                 const GdkPoint pts[4] = {
1461                     {x, y + stripeOffset + animShift},
1462                     {x + width - 1, y + stripeOffset + animShift - width},
1463                     {x + width - 1, y + stripeOffset + animShift +
1464                      PROGRESS_CHUNK_WIDTH - width},
1465                     {x, y + stripeOffset + animShift + PROGRESS_CHUNK_WIDTH}};
1466                 Cairo::pathPoints(cr, pts, 4);
1467             }
1468         }
1469         cairo_clip(cr);
1470     }
1471 }
1472 
1473 void
1474 drawProgress(cairo_t *cr, GtkStyle *style, GtkStateType state,
1475              GtkWidget *widget, const QtcRect *area, int x, int y,
1476              int width, int height, bool rev, bool isEntryProg)
1477 {
1478 #if GTK_CHECK_VERSION(2, 90, 0)
1479     bool revProg = (widget && GTK_IS_PROGRESS_BAR(widget) &&
1480                     gtk_progress_bar_get_inverted(GTK_PROGRESS_BAR(widget)));
1481 #else
1482     GtkProgressBarOrientation orientation =
1483         (widget && GTK_IS_PROGRESS_BAR(widget) ?
1484          gtk_progress_bar_get_orientation(GTK_PROGRESS_BAR(widget)) :
1485          GTK_PROGRESS_LEFT_TO_RIGHT);
1486     bool revProg = oneOf(orientation, GTK_PROGRESS_RIGHT_TO_LEFT,
1487                          GTK_PROGRESS_BOTTOM_TO_TOP);
1488 #endif
1489     const bool horiz = isHorizontalProgressbar(widget);
1490     EWidget wid = isEntryProg ? WIDGET_ENTRY_PROGRESSBAR : WIDGET_PROGRESSBAR;
1491     int animShift = revProg ? 0 : -PROGRESS_CHUNK_WIDTH;
1492     int xo = x;
1493     int yo = y;
1494     int wo = width;
1495     int ho = height;
1496 
1497     if (opts.fillProgress) {
1498         x--;
1499         y--;
1500         width += 2;
1501         height += 2;
1502         xo = x;
1503         yo = y;
1504         wo = width;
1505         ho = height;
1506     }
1507 
1508     if (opts.stripedProgress != STRIPE_NONE &&
1509         opts.animatedProgress && (isEntryProg || qtcIsProgressBar(widget))) {
1510 #if !GTK_CHECK_VERSION(2, 90, 0) /* Gtk3:TODO !!! */
1511         if (isEntryProg || !GTK_PROGRESS(widget)->activity_mode)
1512 #endif
1513             Animation::addProgressBar(widget, isEntryProg);
1514 
1515         animShift+=(revProg ? -1 : 1)*
1516             (int(Animation::elapsed(widget) * PROGRESS_CHUNK_WIDTH) %
1517              (PROGRESS_CHUNK_WIDTH * 2));
1518     }
1519 
1520     bool grayItem = (state == GTK_STATE_INSENSITIVE &&
1521                      opts.progressGrooveColor != ECOLOR_BACKGROUND);
1522     const GdkColor *itemCols = (grayItem ? qtcPalette.background :
1523                                 qtcPalette.progress ? qtcPalette.progress :
1524                                 qtcPalette.highlight);
1525     auto new_state = GTK_STATE_PRELIGHT == state ? GTK_STATE_NORMAL : state;
1526     int fillVal = grayItem ? 4 : ORIGINAL_SHADE;
1527 
1528     x++;
1529     y++;
1530     width -= 2;
1531     height -= 2;
1532 
1533     Cairo::Saver saver(cr);
1534     if (opts.borderProgress && opts.round > ROUND_SLIGHT &&
1535         (horiz ? width : height) < 4) {
1536         qtcClipPath(cr, x, y, width, height, wid, RADIUS_EXTERNAL, ROUNDED_ALL);
1537     }
1538 
1539     if ((horiz ? width : height) > 1)
1540         drawLightBevel(cr, style, new_state, area, x, y, width,
1541                        height, &itemCols[fillVal], itemCols, ROUNDED_ALL,
1542                        wid, BORDER_FLAT, (horiz ? 0 : DF_VERT), widget);
1543     if (opts.stripedProgress && width > 4 && height > 4) {
1544         if (opts.stripedProgress == STRIPE_FADE) {
1545             int posMod = opts.animatedProgress ? STRIPE_WIDTH - animShift : 0;
1546             int sizeMod = opts.animatedProgress ? (STRIPE_WIDTH * 2) : 0;
1547             addStripes(cr, x - (horiz ? posMod : 0), y - (horiz ? 0 : posMod),
1548                        width + (horiz ? sizeMod : 0),
1549                        height + (horiz ? 0 : sizeMod), horiz);
1550         } else {
1551             Cairo::Saver saver(cr);
1552             qtcSetProgressStripeClipping(cr, area, xo, yo, wo, ho,
1553                                          animShift, horiz);
1554             drawLightBevel(cr, style, new_state, nullptr, x, y,
1555                            width, height, &itemCols[1], qtcPalette.highlight,
1556                            ROUNDED_ALL, wid, BORDER_FLAT,
1557                            (opts.fillProgress || !opts.borderProgress ? 0 :
1558                             DF_DO_BORDER) | (horiz ? 0 : DF_VERT), widget);
1559         }
1560     }
1561     if (opts.glowProgress && (horiz ? width : height)>3) {
1562         int offset = opts.borderProgress ? 1 : 0;
1563         cairo_pattern_t *pat =
1564             cairo_pattern_create_linear(x+offset, y+offset, horiz ?
1565                                         x + width - offset : x + offset,
1566                                         horiz ? y + offset :
1567                                         y + height - offset);
1568         bool inverted = false;
1569 
1570         if (GLOW_MIDDLE != opts.glowProgress && widget &&
1571             GTK_IS_PROGRESS_BAR(widget)) {
1572             if (horiz) {
1573                 if (revProg) {
1574                     inverted = !rev;
1575                 } else {
1576                     inverted = rev;
1577                 }
1578             } else {
1579                 inverted = revProg;
1580             }
1581         }
1582 
1583         cairo_pattern_add_color_stop_rgba(
1584             pat, 0.0, 1.0, 1.0, 1.0,
1585             (inverted ? GLOW_END : GLOW_START) == opts.glowProgress ?
1586             GLOW_PROG_ALPHA : 0.0);
1587 
1588         if (GLOW_MIDDLE == opts.glowProgress)
1589             cairo_pattern_add_color_stop_rgba(pat, 0.5, 1.0, 1.0, 1.0,
1590                                               GLOW_PROG_ALPHA);
1591 
1592         cairo_pattern_add_color_stop_rgba(
1593             pat, CAIRO_GRAD_END, 1.0, 1.0, 1.0,
1594             (inverted ? GLOW_START : GLOW_END) == opts.glowProgress ?
1595             GLOW_PROG_ALPHA : 0.0);
1596         cairo_set_source(cr, pat);
1597         cairo_rectangle(cr, x + offset, y + offset, width - 2 * offset,
1598                         height - 2 * offset);
1599         cairo_fill(cr);
1600         cairo_pattern_destroy(pat);
1601         if (width > 2 && height > 2 && opts.borderProgress)
1602             drawBorder(cr, style, state, area, x, y, width, height,
1603                        itemCols, ROUNDED_ALL, BORDER_FLAT, wid,
1604                        0, PBAR_BORDER);
1605 
1606         if (!opts.borderProgress) {
1607             if (horiz) {
1608                 Cairo::hLine(cr, x, y, width, &itemCols[PBAR_BORDER]);
1609                 Cairo::hLine(cr, x, y + height - 1, width,
1610                              &itemCols[PBAR_BORDER]);
1611             } else {
1612                 Cairo::vLine(cr, x, y, height, &itemCols[PBAR_BORDER]);
1613                 Cairo::vLine(cr, x + width - 1, y, height,
1614                              &itemCols[PBAR_BORDER]);
1615             }
1616         }
1617     }
1618 }
1619 
1620 void
1621 drawProgressGroove(cairo_t *cr, GtkStyle *style, GtkStateType state,
1622                    GdkWindow *window, GtkWidget *widget, const QtcRect *area,
1623                    int x, int y, int width, int height, bool isList, bool horiz)
1624 {
1625     bool doEtch = !isList && opts.buttonEffect != EFFECT_NONE;
1626     const GdkColor *col = &style->base[state];
1627     int offset = opts.borderProgress ? 1 : 0;
1628 
1629     switch (opts.progressGrooveColor) {
1630     default:
1631     case ECOLOR_BASE:
1632         col = &style->base[state];
1633         break;
1634     case ECOLOR_BACKGROUND:
1635         col = &qtcPalette.background[ORIGINAL_SHADE];
1636         break;
1637     case ECOLOR_DARK:
1638         col = &qtcPalette.background[2];
1639     }
1640 
1641     if (!isList && (qtcIsFlatBgnd(opts.bgndAppearance) ||
1642                     !(widget && drawWindowBgnd(cr, style, area, window, widget,
1643                                                x, y, width, height))) &&
1644         (!widget || !g_object_get_data(G_OBJECT(widget),
1645                                        "transparent-bg-hint"))) {
1646         Cairo::rect(cr, area, x, y, width, height,
1647                     &qtcPalette.background[ORIGINAL_SHADE]);
1648     }
1649 
1650     if (doEtch && opts.borderProgress) {
1651         x++;
1652         y++;
1653         width -= 2;
1654         height -= 2;
1655     }
1656 
1657     drawBevelGradient(cr, area, x + offset, y + offset,
1658                       width - 2 * offset, height - 2 * offset, col, horiz,
1659                       false, opts.progressGrooveAppearance, WIDGET_PBAR_TROUGH);
1660 
1661     if (doEtch && opts.borderProgress) {
1662         drawEtch(cr, area, widget, x - 1, y - 1, width + 2,
1663                  height + 2, false, ROUNDED_ALL, WIDGET_PBAR_TROUGH);
1664     }
1665     if (opts.borderProgress) {
1666         GtkWidget *parent = widget ? gtk_widget_get_parent(widget) : nullptr;
1667         GtkStyle *style = widget ? gtk_widget_get_style(parent ?
1668                                                         parent : widget) : nullptr;
1669         drawBorder(cr, style, state, area, x, y, width, height,
1670                    nullptr, ROUNDED_ALL,
1671                    (qtcIsFlat(opts.progressGrooveAppearance) &&
1672                     opts.progressGrooveColor != ECOLOR_DARK ?
1673                     BORDER_SUNKEN : BORDER_FLAT),
1674                    WIDGET_PBAR_TROUGH, DF_BLEND);
1675     } else { /* if(!opts.borderProgress) */
1676         if (horiz) {
1677             Cairo::hLine(cr, x, y, width,
1678                          &qtcPalette.background[QTC_STD_BORDER]);
1679             Cairo::hLine(cr, x, y + height - 1, width,
1680                          &qtcPalette.background[QTC_STD_BORDER]);
1681         } else {
1682             Cairo::vLine(cr, x, y, height,
1683                          &qtcPalette.background[QTC_STD_BORDER]);
1684             Cairo::vLine(cr, x + width - 1, y, height,
1685                          &qtcPalette.background[QTC_STD_BORDER]);
1686         }
1687     }
1688 }
1689 
1690 #define SLIDER_TROUGH_SIZE 5
1691 
1692 void
1693 drawSliderGroove(cairo_t *cr, GtkStyle *style, GtkStateType state,
1694                  GtkWidget *widget, const char *detail,
1695                  const QtcRect *area, int x, int y, int width, int height,
1696                  bool horiz)
1697 {
1698     const GdkColor *bgndcols = qtcPalette.background;
1699     const GdkColor *bgndcol = &bgndcols[2];
1700     GtkAdjustment *adjustment = gtk_range_get_adjustment(GTK_RANGE(widget));
1701     double upper = gtk_adjustment_get_upper(adjustment);
1702     double lower = gtk_adjustment_get_lower(adjustment);
1703     double value = gtk_adjustment_get_value(adjustment);
1704     int used_x = x;
1705     int used_y = y;
1706     int used_h = 0;
1707     int used_w = 0;
1708     int pos = (int)(((double)(horiz ? width : height) /
1709                      (upper - lower))  * (value - lower));
1710     bool inverted = gtk_range_get_inverted(GTK_RANGE(widget));
1711     bool doEtch = opts.buttonEffect != EFFECT_NONE;
1712     bool rev = (reverseLayout(widget) ||
1713                 (widget && reverseLayout(gtk_widget_get_parent(widget))));
1714     int troughSize = SLIDER_TROUGH_SIZE + (doEtch ? 2 : 0);
1715     const GdkColor *usedcols =
1716         (opts.fillSlider && upper != lower && state != GTK_STATE_INSENSITIVE ?
1717          qtcPalette.slider ? qtcPalette.slider : qtcPalette.highlight :
1718          qtcPalette.background);
1719     EWidget wid = WIDGET_SLIDER_TROUGH;
1720 
1721     if (horiz && rev)
1722         inverted = !inverted;
1723 
1724     if (horiz) {
1725         y += (height - troughSize) / 2;
1726         height = troughSize;
1727         used_y = y;
1728         used_h = height;
1729     } else {
1730         x += (width - troughSize) / 2;
1731         width = troughSize;
1732         used_x = x;
1733         used_w = width;
1734     }
1735 
1736     if (state == GTK_STATE_INSENSITIVE) {
1737         bgndcol = &bgndcols[ORIGINAL_SHADE];
1738     } else if (oneOf(detail, "trough-lower") && opts.fillSlider) {
1739         bgndcols = usedcols;
1740         bgndcol = &usedcols[ORIGINAL_SHADE];
1741         wid = WIDGET_FILLED_SLIDER_TROUGH;
1742     }
1743     drawLightBevel(cr, style, state, area, x, y, width, height, bgndcol,
1744                    bgndcols, (opts.square & SQUARE_SLIDER ? ROUNDED_NONE :
1745                               ROUNDED_ALL), wid, BORDER_FLAT,
1746                    DF_SUNKEN | DF_DO_BORDER | (horiz ? 0 : DF_VERT), nullptr);
1747 
1748     if (opts.fillSlider && upper != lower &&
1749         state != GTK_STATE_INSENSITIVE && oneOf(detail, "trough")) {
1750         if (horiz) {
1751             pos += width > 10 && pos < width / 2 ? 3 : 0;
1752 
1753             if (inverted) {
1754                 /* <rest><slider><used> */
1755                 used_x += width - pos;
1756             }
1757             used_w = pos;
1758         } else {
1759             pos += height > 10 && pos < height / 2 ? 3 : 0;
1760 
1761             if (inverted) {
1762                 used_y += height - pos;
1763             }
1764             used_h = pos;
1765         }
1766 
1767         if (used_w > 0 && used_h > 0) {
1768             drawLightBevel(cr, style, state, area, used_x, used_y, used_w,
1769                            used_h, &usedcols[ORIGINAL_SHADE], usedcols,
1770                            opts.square & SQUARE_SLIDER ? ROUNDED_NONE :
1771                            ROUNDED_ALL, WIDGET_FILLED_SLIDER_TROUGH,
1772                            BORDER_FLAT, DF_SUNKEN | DF_DO_BORDER |
1773                            (horiz ? 0 : DF_VERT), nullptr);
1774         }
1775     }
1776 }
1777 
1778 void
1779 drawTriangularSlider(cairo_t *cr, GtkStyle *style, GtkStateType state,
1780                      const char *detail, int x, int y, int width, int height)
1781 {
1782     GdkColor newColors[TOTAL_SHADES + 1];
1783     const GdkColor *btnColors = nullptr;
1784 
1785     /* Fix Java swing sliders looking pressed */
1786     if (state == GTK_STATE_ACTIVE)
1787         state = GTK_STATE_PRELIGHT;
1788 
1789     if (useButtonColor(detail)) {
1790         if (state == GTK_STATE_INSENSITIVE) {
1791             btnColors = qtcPalette.background;
1792         } else if (QT_CUSTOM_COLOR_BUTTON(style)) {
1793             shadeColors(&style->bg[state], newColors);
1794             btnColors = newColors;
1795         } else {
1796             GtkWidget *widget = nullptr; /* Keep SET_BTN_COLS happy */
1797             SET_BTN_COLS(false, true, false, state);
1798         }
1799     }
1800 
1801     bool coloredMouseOver = (state == GTK_STATE_PRELIGHT &&
1802                              opts.coloredMouseOver &&
1803                              !opts.colorSliderMouseOver);
1804     bool horiz = height > width || oneOf(detail, "hscale");
1805     int bgnd = getFill(state, false, opts.shadeSliders == SHADE_DARKEN);
1806     int xo = horiz ? 8 : 0;
1807     int yo = horiz ? 0 : 8;
1808     int size = 15;
1809     int light = opts.sliderAppearance == APPEARANCE_DULL_GLASS ? 1 : 0;
1810     const GdkColor *colors = btnColors;
1811     const GdkColor *borderCols = ((GTK_STATE_PRELIGHT == state &&
1812                                    oneOf(opts.coloredMouseOver, MO_GLOW,
1813                                          MO_COLORED)) ?
1814                                   qtcPalette.mouseover : btnColors);
1815     GtkArrowType direction = horiz ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT;
1816     bool drawLight = opts.coloredMouseOver != MO_PLASTIK || !coloredMouseOver;
1817     int borderVal = (qtcPalette.mouseover == borderCols ? SLIDER_MO_BORDER_VAL :
1818                      BORDER_VAL(state == GTK_STATE_INSENSITIVE));
1819     if (opts.coloredMouseOver == MO_GLOW && opts.buttonEffect != EFFECT_NONE) {
1820         x++;
1821         y++;
1822         xo++;
1823         yo++;
1824     }
1825     cairo_new_path(cr);
1826     cairo_save(cr);
1827     switch (direction) {
1828     case GTK_ARROW_UP:
1829     default:
1830     case GTK_ARROW_DOWN: {
1831         y += 2;
1832         const GdkPoint pts[] = {{x, y}, {x, y + 2}, {x + 2, y}, {x + 8, y},
1833                                 {x + 10, y + 2}, {x + 10, y + 9},
1834                                 {x + 5, y + 14}, {x, y + 9}};
1835         Cairo::pathPoints(cr, pts, 8);
1836         break;
1837     }
1838     case GTK_ARROW_RIGHT:
1839     case GTK_ARROW_LEFT: {
1840         x+=2;
1841         const GdkPoint pts[] = {{x, y}, {x + 2, y}, {x, y + 2}, {x, y + 8},
1842                                 {x + 2, y + 10}, {x + 9, y + 10},
1843                                 {x + 14, y + 5}, {x + 9, y}};
1844         Cairo::pathPoints(cr, pts, 8);
1845     }
1846     }
1847     cairo_clip(cr);
1848     if (qtcIsFlat(opts.sliderAppearance)) {
1849         Cairo::rect(cr, nullptr, x + 1, y + 1, width - 2, height - 2,
1850                     &colors[bgnd]);
1851         if (MO_PLASTIK == opts.coloredMouseOver && coloredMouseOver) {
1852             int col = SLIDER_MO_SHADE;
1853             int len = SLIDER_MO_LEN;
1854             if (horiz) {
1855                 Cairo::rect(cr, nullptr, x + 1, y + 1, len, size - 2,
1856                             &qtcPalette.mouseover[col]);
1857                 Cairo::rect(cr, nullptr, x + width - (1 + len), y + 1, len,
1858                             size - 2, &qtcPalette.mouseover[col]);
1859             } else {
1860                 Cairo::rect(cr, nullptr, x + 1, y + 1, size - 2, len,
1861                             &qtcPalette.mouseover[col]);
1862                 Cairo::rect(cr, nullptr, x + 1, y + height - (1 + len), size - 2,
1863                             len, &qtcPalette.mouseover[col]);
1864             }
1865         }
1866     } else {
1867         drawBevelGradient(cr, nullptr, x, y, horiz ? width - 1 : size,
1868                           horiz ? size : height - 1, &colors[bgnd],
1869                           horiz, false, MODIFY_AGUA(opts.sliderAppearance),
1870                           WIDGET_OTHER);
1871         if (opts.coloredMouseOver == MO_PLASTIK && coloredMouseOver) {
1872             int col = SLIDER_MO_SHADE;
1873             int len = SLIDER_MO_LEN;
1874             if (horiz) {
1875                 drawBevelGradient(cr, nullptr, x + 1, y + 1, len, size - 2,
1876                                   &qtcPalette.mouseover[col], horiz, false,
1877                                   MODIFY_AGUA(opts.sliderAppearance),
1878                                   WIDGET_OTHER);
1879                 drawBevelGradient(cr, nullptr, x + width - (1 + len), y + 1, len,
1880                                   size - 2, &qtcPalette.mouseover[col], horiz,
1881                                   false, MODIFY_AGUA(opts.sliderAppearance),
1882                                   WIDGET_OTHER);
1883             } else {
1884                 drawBevelGradient(cr, nullptr, x + 1, y + 1, size - 2, len,
1885                                   &qtcPalette.mouseover[col], horiz, false,
1886                                   MODIFY_AGUA(opts.sliderAppearance),
1887                                   WIDGET_OTHER);
1888                 drawBevelGradient(cr, nullptr, x + 1, y + height - (1 + len),
1889                                   size - 2, len, &qtcPalette.mouseover[col],
1890                                   horiz, false,
1891                                   MODIFY_AGUA(opts.sliderAppearance),
1892                                   WIDGET_OTHER);
1893             }
1894         }
1895     }
1896     cairo_restore(cr);
1897     double xd = x + 0.5;
1898     double yd = y + 0.5;
1899     double radius = 2.5;
1900     double xdg = xd - 1;
1901     double ydg = yd - 1;
1902     double radiusg = radius + 1;
1903     bool glowMo = (opts.coloredMouseOver == MO_GLOW &&
1904                    coloredMouseOver && opts.buttonEffect != EFFECT_NONE);
1905     cairo_new_path(cr);
1906     if (glowMo) {
1907         Cairo::setColor(cr, &borderCols[GLOW_MO], GLOW_ALPHA(false));
1908     } else {
1909         Cairo::setColor(cr, &borderCols[borderVal]);
1910     }
1911     switch (direction) {
1912     case GTK_ARROW_UP:
1913     default:
1914     case GTK_ARROW_DOWN:
1915         if (glowMo) {
1916             cairo_move_to(cr, xdg + radiusg, ydg);
1917             cairo_arc(cr, xdg + 12 - radiusg, ydg + radiusg, radiusg,
1918                       M_PI * 1.5, M_PI * 2);
1919             cairo_line_to(cr, xdg + 12, ydg + 10.5);
1920             cairo_line_to(cr, xdg + 6, ydg + 16.5);
1921             cairo_line_to(cr, xdg, ydg + 10.5);
1922             cairo_arc(cr, xdg + radiusg, ydg + radiusg, radiusg,
1923                       M_PI, M_PI * 1.5);
1924             cairo_stroke(cr);
1925             Cairo::setColor(cr, &borderCols[borderVal]);
1926         }
1927         cairo_move_to(cr, xd + radius, yd);
1928         cairo_arc(cr, xd + 10 - radius, yd + radius, radius,
1929                   M_PI * 1.5, M_PI * 2);
1930         cairo_line_to(cr, xd + 10, yd + 9);
1931         cairo_line_to(cr, xd + 5, yd + 14);
1932         cairo_line_to(cr, xd, yd + 9);
1933         cairo_arc(cr, xd + radius, yd + radius, radius, M_PI, M_PI * 1.5);
1934         cairo_stroke(cr);
1935         if (drawLight) {
1936             Cairo::vLine(cr, xd + 1, yd + 2, 7, &colors[light]);
1937             Cairo::hLine(cr, xd + 2, yd + 1, 6, &colors[light]);
1938         }
1939         break;
1940     case GTK_ARROW_RIGHT:
1941     case GTK_ARROW_LEFT:
1942         if (glowMo) {
1943             cairo_move_to(cr, xdg, ydg + 12-radiusg);
1944             cairo_arc(cr, xdg + radiusg, ydg + radiusg,
1945                       radiusg, M_PI, M_PI * 1.5);
1946             cairo_line_to(cr, xdg + 10.5, ydg);
1947             cairo_line_to(cr, xdg + 16.5, ydg + 6);
1948             cairo_line_to(cr, xdg + 10.5, ydg + 12);
1949             cairo_arc(cr, xdg + radiusg, ydg + 12 - radiusg,
1950                       radiusg, M_PI * 0.5, M_PI);
1951             cairo_stroke(cr);
1952             Cairo::setColor(cr, &borderCols[borderVal]);
1953         }
1954         cairo_move_to(cr, xd, yd + 10 - radius);
1955         cairo_arc(cr, xd + radius, yd + radius, radius, M_PI, M_PI * 1.5);
1956         cairo_line_to(cr, xd + 9, yd);
1957         cairo_line_to(cr, xd + 14, yd + 5);
1958         cairo_line_to(cr, xd + 9, yd + 10);
1959         cairo_arc(cr, xd + radius, yd + 10 - radius, radius, M_PI * 0.5, M_PI);
1960         cairo_stroke(cr);
1961         if (drawLight) {
1962             Cairo::hLine(cr, xd + 2, yd + 1, 7, &colors[light]);
1963             Cairo::vLine(cr, xd + 1, yd + 2, 6, &colors[light]);
1964         }
1965     }
1966 }
1967 
1968 void
1969 drawScrollbarGroove(cairo_t *cr, GtkStyle *style, GtkStateType state,
1970                     GtkWidget *widget, const QtcRect *area, int x, int y,
1971                     int width, int height, bool horiz)
1972 {
1973     ECornerBits sbarRound = ROUNDED_ALL;
1974     int xo = x;
1975     int yo = y;
1976     int wo = width;
1977     int ho = height;
1978     bool drawBg = opts.flatSbarButtons;
1979     bool thinner = (opts.thinSbarGroove &&
1980                     (opts.scrollbarType == SCROLLBAR_NONE ||
1981                      opts.flatSbarButtons));
1982 
1983     if (opts.flatSbarButtons) {
1984 #if GTK_CHECK_VERSION(2, 90, 0)
1985         bool lower = detail && strstr(detail, "-lower");
1986         sbarRound = (lower ? horiz ? ROUNDED_LEFT : ROUNDED_TOP : horiz ?
1987                      ROUNDED_RIGHT : ROUNDED_BOTTOM);
1988 
1989         switch (opts.scrollbarType) {
1990         case SCROLLBAR_KDE:
1991             if (lower) {
1992                 if (horiz) {
1993                     x += opts.sliderWidth;
1994                 } else {
1995                     y += opts.sliderWidth;
1996                 }
1997             } else {
1998                 if (horiz) {
1999                     width -= opts.sliderWidth * 2;
2000                 } else {
2001                     height -= opts.sliderWidth * 2;
2002                 }
2003             }
2004             break;
2005         case SCROLLBAR_WINDOWS:
2006             if (lower) {
2007                 if (horiz) {
2008                     x += opts.sliderWidth;
2009                 } else {
2010                     y += opts.sliderWidth;
2011                 }
2012             } else {
2013                 if (horiz) {
2014                     width -= opts.sliderWidth;
2015                 } else {
2016                     height -= opts.sliderWidth;
2017                 }
2018             }
2019             break;
2020         case SCROLLBAR_NEXT:
2021             if (lower) {
2022                 if (horiz) {
2023                     x += opts.sliderWidth * 2;
2024                 } else {
2025                     y += opts.sliderWidth * 2;
2026                 }
2027             }
2028             break;
2029         case SCROLLBAR_PLATINUM:
2030             if (!lower) {
2031                 if (horiz) {
2032                     width -= opts.sliderWidth * 2;
2033                 } else {
2034                     height -= opts.sliderWidth * 2;
2035                 }
2036             }
2037             break;
2038         }
2039 #else
2040         switch (opts.scrollbarType) {
2041         case SCROLLBAR_KDE:
2042             if (horiz) {
2043                 x += opts.sliderWidth;
2044                 width -= opts.sliderWidth * 3;
2045             } else {
2046                 y += opts.sliderWidth;
2047                 height -= opts.sliderWidth * 3;
2048             }
2049             break;
2050         case SCROLLBAR_WINDOWS:
2051             if (horiz) {
2052                 x += opts.sliderWidth;
2053                 width -= opts.sliderWidth * 2;
2054             } else {
2055                 y += opts.sliderWidth;
2056                 height -= opts.sliderWidth * 2;
2057             }
2058             break;
2059         case SCROLLBAR_NEXT:
2060             if (horiz) {
2061                 x+=opts.sliderWidth * 2;
2062                 width -= opts.sliderWidth * 2;
2063             } else {
2064                 y += opts.sliderWidth * 2;
2065                 height -= opts.sliderWidth * 2;
2066             }
2067             break;
2068         case SCROLLBAR_PLATINUM:
2069             if (horiz) {
2070                 width -= opts.sliderWidth * 2;
2071             } else {
2072                 height -= opts.sliderWidth * 2;
2073             }
2074             break;
2075         default:
2076             break;
2077         }
2078 #endif
2079     } else {
2080         switch (opts.scrollbarType) {
2081         default:
2082             break;
2083         case SCROLLBAR_NEXT:
2084             sbarRound = horiz ? ROUNDED_LEFT : ROUNDED_TOP;
2085             break;
2086         case SCROLLBAR_PLATINUM:
2087             sbarRound = horiz ? ROUNDED_RIGHT : ROUNDED_BOTTOM;
2088             break;
2089 #ifdef SIMPLE_SCROLLBARS
2090         case SCROLLBAR_NONE:
2091             sbarRound = ROUNDED_NONE;
2092             break;
2093 #endif
2094         }
2095     }
2096 
2097     if (opts.square & SQUARE_SB_SLIDER)
2098         sbarRound = ROUNDED_NONE;
2099 
2100     if (drawBg) {
2101         GtkWidget *parent=nullptr;
2102         if (opts.gtkScrollViews && qtcIsFlat(opts.sbarBgndAppearance) &&
2103             opts.tabBgnd != 0 && widget &&
2104            (parent = gtk_widget_get_parent(widget)) &&
2105             GTK_IS_SCROLLED_WINDOW(parent) &&
2106             (parent = gtk_widget_get_parent(parent)) &&
2107             GTK_IS_NOTEBOOK(parent)) {
2108             drawAreaModColor(cr, area, &qtcPalette.background[ORIGINAL_SHADE],
2109                              TO_FACTOR(opts.tabBgnd), xo, yo, wo, ho);
2110         } else if (!qtcIsFlat(opts.sbarBgndAppearance) ||
2111                    !opts.gtkScrollViews) {
2112             drawBevelGradient(cr, area, xo, yo, wo, ho,
2113                               &qtcPalette.background[ORIGINAL_SHADE], horiz,
2114                               false, opts.sbarBgndAppearance, WIDGET_SB_BGND);
2115         }
2116 #if !GTK_CHECK_VERSION(2, 90, 0)
2117         /* This was the old (pre 1.7.1) else if... but it messes up Gtk3 scrollbars wheb have custom background. And dont think its needed */
2118         /* But re-added in 1.7.2 for Mozilla! */
2119         /*  else if(!qtcIsCustomBgnd(&opts) || !(opts.gtkScrollViews && qtcIsFlat(opts.sbarBgndAppearance) &&
2120             widget && drawWindowBgnd(cr, style, area, widget, xo, yo, wo, ho)))
2121         */ else if (isMozilla()) {
2122             /* 1.7.3 added 'else' so as to not duplicate above! */
2123             drawBevelGradient(cr, area, xo, yo, wo, ho,
2124                               &qtcPalette.background[ORIGINAL_SHADE], horiz,
2125                               false, opts.sbarBgndAppearance, WIDGET_SB_BGND);
2126         }
2127 #endif
2128     }
2129 
2130     if (isMozilla()) {
2131         if (!drawBg) {
2132             const GdkColor *parent_col = getParentBgCol(widget);
2133             const GdkColor *bgnd_col =
2134                 (parent_col ? parent_col :
2135                  &qtcPalette.background[ORIGINAL_SHADE]);
2136 
2137             Cairo::Saver saver(cr);
2138             Cairo::clipRect(cr, area);
2139             Cairo::rect(cr, area, x, y, width, height,
2140                         &qtcPalette.background[ORIGINAL_SHADE]);
2141             if (horiz) {
2142                 if (oneOf(sbarRound, ROUNDED_LEFT, ROUNDED_ALL)) {
2143                     Cairo::vLine(cr, x, y, height, bgnd_col);
2144                 }
2145                 if (oneOf(sbarRound, ROUNDED_RIGHT, ROUNDED_ALL)) {
2146                     Cairo::vLine(cr, x + width - 1, y, height, bgnd_col);
2147                 }
2148             } else {
2149                 if (oneOf(sbarRound, ROUNDED_TOP, ROUNDED_ALL)) {
2150                     Cairo::hLine(cr, x, y, width, bgnd_col);
2151                 }
2152                 if (oneOf(sbarRound, ROUNDED_BOTTOM, ROUNDED_ALL)) {
2153                     Cairo::hLine(cr, x, y + height - 1, width, bgnd_col);
2154                 }
2155             }
2156         }
2157     } else if (qtSettings.app == GTK_APP_OPEN_OFFICE &&
2158                opts.flatSbarButtons && isFixedWidget(widget)) {
2159         if (horiz) {
2160             width--;
2161         } else {
2162             height--;
2163         }
2164     }
2165 
2166     if (thinner && !drawBg)
2167         drawBgnd(cr, &qtcPalette.background[ORIGINAL_SHADE], widget,
2168                  area, x, y, width, height);
2169 
2170     drawLightBevel(cr, style, state, area,
2171                    thinner && !horiz ? x + THIN_SBAR_MOD : x,
2172                    thinner && horiz ? y + THIN_SBAR_MOD : y,
2173                    thinner && !horiz ? width - THIN_SBAR_MOD * 2 : width,
2174                    thinner && horiz ? height - THIN_SBAR_MOD * 2 : height,
2175                    &qtcPalette.background[2], qtcPalette.background, sbarRound,
2176                    thinner ? WIDGET_SLIDER_TROUGH : WIDGET_TROUGH,
2177                    BORDER_FLAT, DF_SUNKEN | DF_DO_BORDER|
2178                    (horiz ? 0 : DF_VERT), widget);
2179 }
2180 
2181 void
2182 drawSelectionGradient(cairo_t *cr, const QtcRect *area, int x, int y,
2183                       int width, int height, ECornerBits round,
2184                       bool isLvSelection, double alpha, const GdkColor *col,
2185                       bool horiz)
2186 {
2187     Cairo::Saver saver(cr);
2188     if ((!isLvSelection || !(opts.square & SQUARE_LISTVIEW_SELECTION)) &&
2189         opts.round != ROUND_NONE) {
2190         Cairo::clipWhole(cr, x, y, width, height,
2191                          qtcGetRadius(&opts, width, height, WIDGET_SELECTION,
2192                                       RADIUS_SELECTION), round);
2193     }
2194     drawBevelGradient(cr, area, x, y, width, height, col, horiz, false,
2195                       opts.selectionAppearance, WIDGET_SELECTION, alpha);
2196 }
2197 
2198 void
2199 drawSelection(cairo_t *cr, GtkStyle *style, GtkStateType state,
2200               const QtcRect *area, GtkWidget *widget, int x, int y, int width,
2201               int height, ECornerBits round, bool isLvSelection,
2202               double alphaMod, int factor)
2203 {
2204     bool hasFocus = gtk_widget_has_focus(widget);
2205     double alpha = (alphaMod * (state == GTK_STATE_PRELIGHT ? 0.20 : 1.0) *
2206                     (hasFocus || !qtSettings.inactiveChangeSelectionColor ?
2207                      1.0 : INACTIVE_SEL_ALPHA));
2208     GdkColor col = style->base[hasFocus ? GTK_STATE_SELECTED : GTK_STATE_ACTIVE];
2209 
2210     if (factor != 0) {
2211         col = shadeColor(&col, TO_FACTOR(factor));
2212     }
2213     drawSelectionGradient(cr, area, x, y, width, height, round,
2214                           isLvSelection, alpha, &col, true);
2215 
2216     if (opts.borderSelection &&
2217         (!isLvSelection || !(opts.square & SQUARE_LISTVIEW_SELECTION))) {
2218         double xd = x + 0.5;
2219         double yd = y + 0.5;
2220         double alpha = (state == GTK_STATE_PRELIGHT || alphaMod < 1.0 ?
2221                         0.20 : 1.0);
2222         int xo = x;
2223         int widtho = width;
2224 
2225         if (isLvSelection && !(opts.square & SQUARE_LISTVIEW_SELECTION) &&
2226             round != ROUNDED_ALL) {
2227             if (!(round & ROUNDED_LEFT)) {
2228                 x -= 1;
2229                 xd -= 1;
2230                 width += 1;
2231             }
2232             if (!(round & ROUNDED_RIGHT)) {
2233                 width += 1;
2234             }
2235         }
2236 
2237         Cairo::Saver saver(cr);
2238         cairo_new_path(cr);
2239         cairo_rectangle(cr, xo, y, widtho, height);
2240         cairo_clip(cr);
2241         Cairo::setColor(cr, &col, alpha);
2242         Cairo::pathWhole(cr, xd, yd, width - 1, height - 1,
2243                          qtcGetRadius(&opts, widtho, height, WIDGET_OTHER,
2244                                       RADIUS_SELECTION), round);
2245         cairo_stroke(cr);
2246     }
2247 }
2248 
2249 void
2250 createRoundedMask(GtkWidget *widget, int x, int y, int width,
2251                   int height, double radius, bool isToolTip)
2252 {
2253     if (widget) {
2254         int size = ((width & 0xFFFF) << 16) + (height & 0xFFFF);
2255         GtkWidgetProps props(widget);
2256         int old = props->widgetMask;
2257 
2258         if (size != old) {
2259 #if GTK_CHECK_VERSION(2, 90, 0)
2260             GdkRegion *mask = windowMask(0, 0, width, height,
2261                                          opts.round > ROUND_SLIGHT);
2262 
2263             gtk_widget_shape_combine_region(widget, nullptr);
2264             gtk_widget_shape_combine_region(widget, mask);
2265             gdk_region_destroy(mask);
2266 #else
2267             GdkBitmap *mask = gdk_pixmap_new(nullptr, width, height, 1);
2268             cairo_t *crMask = gdk_cairo_create((GdkDrawable*)mask);
2269 
2270             cairo_rectangle(crMask, 0, 0, width, height);
2271             cairo_set_source_rgba(crMask, 1, 1, 1, 0);
2272             cairo_set_operator(crMask, CAIRO_OPERATOR_SOURCE);
2273             cairo_paint(crMask);
2274             cairo_new_path(crMask);
2275             Cairo::pathWhole(crMask, 0, 0, width, height, radius, ROUNDED_ALL);
2276             cairo_set_source_rgba(crMask, 0, 0, 0, 1);
2277             cairo_fill(crMask);
2278             if (isToolTip) {
2279                 gtk_widget_shape_combine_mask(widget, mask, x, y);
2280             } else {
2281                 gdk_window_shape_combine_mask(
2282                     gtk_widget_get_parent_window(widget), mask, 0, 0);
2283             }
2284             cairo_destroy(crMask);
2285             gdk_pixmap_unref(mask);
2286 #endif
2287             props->widgetMask = size;
2288             /* Setting the window type to 'popup menu' seems to
2289                re-eanble kwin shadows! */
2290             if (isToolTip && gtk_widget_get_window(widget)) {
2291                 gdk_window_set_type_hint(gtk_widget_get_window(widget),
2292                                          GDK_WINDOW_TYPE_HINT_POPUP_MENU);
2293             }
2294         }
2295     }
2296 }
2297 
2298 void
2299 clearRoundedMask(GtkWidget *widget, bool isToolTip)
2300 {
2301     if (widget) {
2302         GtkWidgetProps props(widget);
2303         if (props->widgetMask) {
2304 #if GTK_CHECK_VERSION(2, 90, 0)
2305             gtk_widget_shape_combine_region(widget, nullptr);
2306 #else
2307             if(isToolTip)
2308                 gtk_widget_shape_combine_mask(widget, nullptr, 0, 0);
2309             else
2310                 gdk_window_shape_combine_mask(gtk_widget_get_parent_window(widget), nullptr, 0, 0);
2311 #endif
2312             props->widgetMask = 0;
2313         }
2314     }
2315 }
2316 
2317 void
2318 drawTreeViewLines(cairo_t *cr, const GdkColor *col, int x, int y, int h,
2319                   int depth, int levelIndent, int expanderSize,
2320                   GtkTreeView *treeView, GtkTreePath *path)
2321 {
2322     int cellIndent = levelIndent + expanderSize + 4;
2323     int xStart = x + cellIndent / 2;
2324     int isLastMask = 0;
2325     bool haveChildren = treeViewCellHasChildren(treeView, path);
2326     bool useBitMask = depth < 33;
2327     GByteArray *isLast = (depth && !useBitMask ?
2328                           g_byte_array_sized_new(depth) : nullptr);
2329 
2330     if (useBitMask || isLast) {
2331         GtkTreePath  *p = path ? gtk_tree_path_copy(path) : nullptr;
2332         int index=depth-1;
2333 
2334         while (p && gtk_tree_path_get_depth(p) > 0 && index>=0) {
2335             GtkTreePath *next=treeViewPathParent(treeView, p);
2336             uint8_t last=treeViewCellIsLast(treeView, p) ? 1 : 0;
2337             if (useBitMask) {
2338                 if (last) {
2339                     isLastMask |= 1 << index;
2340                 }
2341             } else {
2342                 isLast = g_byte_array_prepend(isLast, &last, 1);
2343             }
2344             gtk_tree_path_free(p);
2345             p = next;
2346             index--;
2347         }
2348         Cairo::setColor(cr, col);
2349         for(int i = 0;i < depth;++i) {
2350             bool isLastCell = ((useBitMask ? isLastMask & (1 << i) :
2351                                 isLast->data[i]) ? true : false);
2352             bool last = i == depth - 1;
2353             double xCenter = xStart;
2354             if (last) {
2355                 double yCenter = (int)(y + h / 2);
2356 
2357                 if (haveChildren) {
2358                     // first vertical line
2359                     cairo_move_to(cr, xCenter + 0.5, y);
2360                     // (int)(expanderSize/3));
2361                     cairo_line_to(cr, xCenter + 0.5, yCenter - (LV_SIZE - 1));
2362                     // second vertical line
2363                     if (!isLastCell) {
2364                         cairo_move_to(cr, xCenter + 0.5, y + h);
2365                         cairo_line_to(cr, xCenter + 0.5,
2366                                       yCenter + LV_SIZE + 1);
2367                     }
2368 
2369                     // horizontal line
2370                     cairo_move_to(cr, xCenter + (int)(expanderSize / 3) + 1,
2371                                   yCenter + 0.5);
2372                     cairo_line_to(cr, xCenter + expanderSize * 2 / 3 - 1,
2373                                   yCenter + 0.5);
2374                 } else {
2375                     cairo_move_to(cr, xCenter + 0.5, y);
2376                     if(isLastCell) {
2377                         cairo_line_to(cr, xCenter + 0.5, yCenter);
2378                     } else {
2379                         cairo_line_to(cr, xCenter + 0.5, y + h);
2380                     }
2381                     // horizontal line
2382                     cairo_move_to(cr, xCenter, yCenter + 0.5);
2383                     cairo_line_to(cr, xCenter + expanderSize * 2 / 3 - 1,
2384                                   yCenter + 0.5);
2385                 }
2386             } else if (!isLastCell) {
2387                 // vertical line
2388                 cairo_move_to(cr, xCenter + 0.5, y);
2389                 cairo_line_to(cr, xCenter + 0.5, y + h);
2390             }
2391             cairo_stroke(cr);
2392             xStart += cellIndent;
2393         }
2394         if (isLast) {
2395             g_byte_array_free(isLast, false);
2396         }
2397     }
2398 }
2399 
2400 static void
2401 qtcSetGapClip(cairo_t *cr, const QtcRect *area, GtkPositionType gapSide,
2402               int gapX, int gapWidth, int x, int y, int width, int height,
2403               bool isTab)
2404 {
2405     if (gapWidth <= 0) {
2406         return;
2407     }
2408     QtcRect gapRect;
2409     int adjust = isTab ? (gapX > 1 ? 1 : 2) : 0;
2410     switch (gapSide) {
2411     case GTK_POS_TOP:
2412         gapRect = qtcRect(x + gapX + adjust, y, gapWidth - 2 * adjust, 2);
2413         if (qtSettings.app == GTK_APP_JAVA && isTab) {
2414             gapRect.width -= 3;
2415         }
2416         break;
2417     case GTK_POS_BOTTOM:
2418         gapRect = qtcRect(x + gapX + adjust, y + height - 2,
2419                           gapWidth - 2 * adjust, 2);
2420         break;
2421     case GTK_POS_LEFT:
2422         gapRect = qtcRect(x, y + gapX + adjust, 2, gapWidth - 2 * adjust);
2423         break;
2424     case GTK_POS_RIGHT:
2425         gapRect = qtcRect(x + width - 2, y + gapX + adjust,
2426                           2, gapWidth - 2 * adjust);
2427         break;
2428     }
2429 
2430     QtcRect r = {x, y, width, height};
2431     cairo_region_t *region = cairo_region_create_rectangle(area ? area : &r);
2432     cairo_region_xor_rectangle(region, &gapRect);
2433     Cairo::clipRegion(cr, region);
2434     cairo_region_destroy(region);
2435 }
2436 
2437 void
2438 fillTab(cairo_t *cr, GtkStyle *style, GtkWidget *widget, const QtcRect *area,
2439         GtkStateType state, const GdkColor *col, int x, int y,
2440         int width, int height, bool horiz, EWidget tab, bool grad)
2441 {
2442     bool selected = state == GTK_STATE_NORMAL;
2443     bool flatBgnd = !qtcIsCustomBgnd(opts) || opts.tabBgnd != 0;
2444 
2445     const GdkColor *c = col;
2446     GdkColor b;
2447     double alpha = 1.0;
2448 
2449     if (selected && opts.tabBgnd != 0) {
2450         qtcShade(col, &b, TO_FACTOR(opts.tabBgnd), opts.shading);
2451         c = &b;
2452     }
2453 
2454     if (!selected && (opts.bgndOpacity != 100 || opts.dlgOpacity != 100)) {
2455         GtkWidget *top = widget ? gtk_widget_get_toplevel(widget) : nullptr;
2456         bool isDialog = top && GTK_IS_DIALOG(top);
2457 
2458         // Note: opacity is divided by 150 to make dark inactive tabs
2459         // more translucent
2460         if (isDialog && opts.dlgOpacity != 100) {
2461             alpha = opts.dlgOpacity / 150.0;
2462         } else if (!isDialog && opts.bgndOpacity != 100) {
2463             alpha = opts.bgndOpacity / 150.0;
2464         }
2465     }
2466 
2467     if (selected && opts.appearance == APPEARANCE_INVERTED) {
2468         if (flatBgnd) {
2469             Cairo::rect(cr, area, x, y, width, height,
2470                         &style->bg[GTK_STATE_NORMAL], alpha);
2471         }
2472     } else if (grad) {
2473         drawBevelGradient(cr, area, x, y, width, height, c, horiz,
2474                           selected, selected ? SEL_TAB_APP : NORM_TAB_APP,
2475                           tab, alpha);
2476     } else if (!selected || flatBgnd) {
2477         Cairo::rect(cr, area, x, y, width, height, c, alpha);
2478     }
2479 }
2480 
2481 static void
2482 colorTab(cairo_t *cr, int x, int y, int width, int height, ECornerBits round,
2483          EWidget tab, bool horiz)
2484 {
2485     cairo_pattern_t *pt =
2486         cairo_pattern_create_linear(x, y, horiz ? x : x + width - 1,
2487                                     horiz ? y + height - 1 : y);
2488 
2489     Cairo::Saver saver(cr);
2490     qtcClipPath(cr, x, y, width, height, tab, RADIUS_EXTERNAL, round);
2491     Cairo::patternAddColorStop(pt, 0, &qtcPalette.highlight[ORIGINAL_SHADE],
2492                                tab == WIDGET_TAB_TOP ?
2493                                TO_ALPHA(opts.colorSelTab) : 0.0);
2494     Cairo::patternAddColorStop(pt, CAIRO_GRAD_END,
2495                                &qtcPalette.highlight[ORIGINAL_SHADE],
2496                                tab == WIDGET_TAB_TOP ? 0.0 :
2497                                TO_ALPHA(opts.colorSelTab));
2498     cairo_set_source(cr, pt);
2499     cairo_rectangle(cr, x, y, width, height);
2500     cairo_fill(cr);
2501     cairo_pattern_destroy(pt);
2502 }
2503 
2504 void
2505 drawToolTip(cairo_t *cr, GtkWidget *widget, const QtcRect *area,
2506             int x, int y, int width, int height)
2507 {
2508     const GdkColor *col = &qtSettings.colors[PAL_ACTIVE][COLOR_TOOLTIP];
2509 
2510     bool nonGtk = isFakeGtk();
2511     bool rounded = !nonGtk && widget && !(opts.square & SQUARE_TOOLTIPS);
2512     bool useAlpha = (!nonGtk && qtSettings.useAlpha &&
2513                      isRgbaWidget(widget) && compositingActive(widget));
2514 
2515     if (!nonGtk && !useAlpha && GTK_IS_WINDOW(widget)) {
2516         gtk_window_set_opacity(GTK_WINDOW(widget), 0.875);
2517     }
2518     Cairo::Saver saver(cr);
2519     if (rounded) {
2520         if (useAlpha) {
2521             cairo_rectangle(cr, x, y, width, height);
2522             cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
2523             cairo_set_source_rgba(cr, 0, 0, 0, 1);
2524             cairo_fill(cr);
2525             clearRoundedMask(widget, true);
2526         } else {
2527             createRoundedMask(widget, x, y, width, height,
2528                               opts.round >= ROUND_FULL ? 5.0 : 2.5, true);
2529         }
2530         Cairo::clipWhole(cr, x, y, width, height,
2531                          opts.round >= ROUND_FULL ? 5.0 : 2.5, ROUNDED_ALL);
2532     }
2533     if (useAlpha) {
2534         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
2535     }
2536     drawBevelGradient(cr, area, x, y, width, height, col, true, false,
2537                       opts.tooltipAppearance, WIDGET_TOOLTIP,
2538                       useAlpha ? 0.875 : 1.0);
2539     if (!rounded && qtcIsFlat(opts.tooltipAppearance)) {
2540         cairo_new_path(cr);
2541         /*if(qtcIsFlat(opts.tooltipAppearance))*/
2542         Cairo::setColor(cr,
2543                          &qtSettings.colors[PAL_ACTIVE][COLOR_TOOLTIP_TEXT]);
2544         /*else
2545           cairo_set_source_rgba(cr, 0, 0, 0, 0.25);*/
2546         cairo_rectangle(cr, x + 0.5, y + 0.5, width - 1, height - 1);
2547         cairo_stroke(cr);
2548     }
2549 }
2550 
2551 void
2552 drawSplitter(cairo_t *cr, GtkStateType state, GtkStyle *style,
2553              const QtcRect *area, int x, int y, int width, int height)
2554 {
2555     const GdkColor *cols =
2556         (opts.coloredMouseOver && state == GTK_STATE_PRELIGHT ?
2557          qtcPalette.mouseover : qtcPalette.background);
2558 
2559     if (state == GTK_STATE_PRELIGHT && opts.splitterHighlight) {
2560         GdkColor col = shadeColor(&style->bg[state],
2561                                   TO_FACTOR(opts.splitterHighlight));
2562         drawSelectionGradient(cr, area, x, y, width, height, ROUNDED_ALL,
2563                               false, 1.0, &col, width > height);
2564     }
2565 
2566     switch (opts.splitters) {
2567     case LINE_1DOT:
2568         Cairo::dot(cr, x, y, width, height, &cols[QTC_STD_BORDER]);
2569         break;
2570     case LINE_NONE:
2571         break;
2572     case LINE_DOTS:
2573     default:
2574         Cairo::dots(cr, x, y, width, height, height > width,
2575                     NUM_SPLITTER_DASHES, 1, area, 0, &cols[5], cols);
2576         break;
2577     case LINE_FLAT:
2578     case LINE_SUNKEN:
2579     case LINE_DASHES:
2580         drawLines(cr, x, y, width, height, height > width, NUM_SPLITTER_DASHES,
2581                   2, cols, area, 3, opts.splitters);
2582     }
2583 }
2584 
2585 void
2586 drawSidebarButton(cairo_t *cr, GtkStateType state, GtkStyle *style,
2587                   const QtcRect *area, int x, int y, int width, int height)
2588 {
2589     if (oneOf(state, GTK_STATE_PRELIGHT, GTK_STATE_ACTIVE)) {
2590         bool horiz = width > height;
2591         const GdkColor *cols = (state == GTK_STATE_ACTIVE ?
2592                                 qtcPalette.sidebar : qtcPalette.background);
2593         drawLightBevel(cr, style, state, area, x, y, width, height,
2594                        &cols[getFill(state, false)], cols, ROUNDED_NONE,
2595                        WIDGET_MENU_ITEM, BORDER_FLAT,
2596                        (horiz ? 0 : DF_VERT) | (state == GTK_STATE_ACTIVE ?
2597                                                 DF_SUNKEN : 0), nullptr);
2598 
2599         if (opts.coloredMouseOver && state == GTK_STATE_PRELIGHT) {
2600             const GdkColor *col = &qtcPalette.mouseover[1];
2601             if (horiz || opts.coloredMouseOver != MO_PLASTIK) {
2602                 cairo_new_path(cr);
2603                 Cairo::setColor(cr, col);
2604                 cairo_move_to(cr, x, y + 0.5);
2605                 cairo_line_to(cr, x + width - 1, y + 0.5);
2606                 cairo_move_to(cr, x + 1, y + 1.5);
2607                 cairo_line_to(cr, x + width - 2, y + 1.5);
2608                 cairo_stroke(cr);
2609             }
2610             if (!horiz || opts.coloredMouseOver != MO_PLASTIK) {
2611                 cairo_new_path(cr);
2612                 Cairo::setColor(cr, col);
2613                 cairo_move_to(cr, x + 0.5, y);
2614                 cairo_line_to(cr, x + 0.5, y + height - 1);
2615                 cairo_move_to(cr, x + 1.5, y + 1);
2616                 cairo_line_to(cr, x + 1.5, y + height - 2);
2617                 cairo_stroke(cr);
2618                 if (opts.coloredMouseOver != MO_PLASTIK) {
2619                     col = &qtcPalette.mouseover[2];
2620                 }
2621             }
2622             if (horiz || opts.coloredMouseOver != MO_PLASTIK) {
2623                 cairo_new_path(cr);
2624                 Cairo::setColor(cr, col);
2625                 cairo_move_to(cr, x, y + height - 1.5);
2626                 cairo_line_to(cr, x + width - 1, y + height - 1.5);
2627                 cairo_move_to(cr, x + 1, y + height - 2.5);
2628                 cairo_line_to(cr, x + width - 2, y + height - 2.5);
2629                 cairo_stroke(cr);
2630             }
2631             if (!horiz || opts.coloredMouseOver != MO_PLASTIK) {
2632                 cairo_new_path(cr);
2633                 Cairo::setColor(cr, col);
2634                 cairo_move_to(cr, x + width - 1.5, y);
2635                 cairo_line_to(cr, x + width - 1.5, y + height - 1);
2636                 cairo_move_to(cr, x + width - 2.5, y + 1);
2637                 cairo_line_to(cr, x + width - 2.5, y + height - 2);
2638                 cairo_stroke(cr);
2639             }
2640         }
2641     }
2642 }
2643 
2644 void
2645 drawMenuItem(cairo_t *cr, GtkStateType state, GtkStyle *style,
2646              GtkWidget *widget, const QtcRect *area, int x, int y,
2647              int width, int height)
2648 {
2649     GtkMenuBar *mb = isMenubar(widget, 0);
2650 #if GTK_CHECK_VERSION(2, 90, 0) /* Gtk3:TODO !!! */
2651     bool active_mb = isFakeGtk() || gdk_pointer_is_grabbed();
2652 #else
2653     bool active_mb = isFakeGtk() || (mb ? GTK_MENU_SHELL(mb)->active : false);
2654 
2655     // The handling of 'mouse pressed' in the menubar event handler doesn't
2656     // seem to set the menu as active, therefore the active_mb fails. However
2657     // the check below works...
2658     if (mb && !active_mb && widget)
2659         active_mb = widget == GTK_MENU_SHELL(mb)->active_menu_item;
2660 #endif
2661 
2662     /* The following 'if' is just a hack for a menubar item problem with
2663        pidgin. Sometime, a 12pix width
2664        empty menubar item is drawn on the right - and doesnt disappear! */
2665     if (!mb || width > 12) {
2666         bool grayItem = ((!opts.colorMenubarMouseOver && mb && !active_mb &&
2667                           qtSettings.app != GTK_APP_OPEN_OFFICE) ||
2668                          !opts.useHighlightForMenu);
2669         const GdkColor *itemCols = (grayItem ? qtcPalette.background :
2670                                     qtcPalette.highlight);
2671         auto round = (mb ? active_mb && opts.roundMbTopOnly ? ROUNDED_TOP :
2672                       ROUNDED_ALL : ROUNDED_ALL);
2673         auto new_state = state == GTK_STATE_PRELIGHT ? GTK_STATE_NORMAL : state;
2674         bool stdColors = (!mb ||
2675                           noneOf(opts.shadeMenubars, SHADE_BLEND_SELECTED,
2676                                  SHADE_SELECTED));
2677         int fillVal = grayItem ? 4 : ORIGINAL_SHADE;
2678         int borderVal = opts.borderMenuitems ? 0 : fillVal;
2679 
2680         if (grayItem && mb && !active_mb && !opts.colorMenubarMouseOver &&
2681             (opts.borderMenuitems || !qtcIsFlat(opts.menuitemAppearance))) {
2682             fillVal = ORIGINAL_SHADE;
2683         }
2684 
2685         if (mb && !opts.roundMbTopOnly && !(opts.square & SQUARE_POPUP_MENUS)) {
2686             x++;
2687             y++;
2688             width -= 2;
2689             height -= 2;
2690         }
2691         if (grayItem && !mb &&
2692             (opts.lighterPopupMenuBgnd || opts.shadePopupMenu)) {
2693             itemCols = qtcPalette.menu;
2694         }
2695         if (!mb && opts.menuitemAppearance == APPEARANCE_FADE) {
2696             bool reverse = false; /* TODO !!! */
2697             cairo_pattern_t *pt = nullptr;
2698             double fadePercent = 0.0;
2699             Cairo::Saver saver(cr);
2700 
2701             if (opts.round != ROUND_NONE) {
2702                 x++;
2703                 y++;
2704                 width -= 2;
2705                 height -= 2;
2706                 Cairo::clipWhole(cr, x, y, width, height, 4,
2707                                  reverse ? ROUNDED_RIGHT : ROUNDED_LEFT);
2708             }
2709 
2710             fadePercent = ((double)MENUITEM_FADE_SIZE) / (double)width;
2711             pt = cairo_pattern_create_linear(x, y, x + width - 1, y);
2712 
2713             Cairo::patternAddColorStop(pt, 0, &itemCols[fillVal],
2714                                        reverse ? 0.0 : 1.0);
2715             Cairo::patternAddColorStop(pt, (reverse ? fadePercent :
2716                                             1.0 - fadePercent),
2717                                        &itemCols[fillVal]);
2718             Cairo::patternAddColorStop(pt, CAIRO_GRAD_END, &itemCols[fillVal],
2719                                        reverse ? 1.0 : 0.0);
2720             cairo_set_source(cr, pt);
2721             cairo_rectangle(cr, x, y, width, height);
2722             cairo_fill(cr);
2723             cairo_pattern_destroy(pt);
2724         } else if (!opts.borderMenuitems && !mb) {
2725             /* For now dont round combos - getting weird effects with
2726                shadow/clipping :-( ...but these work ok if we have an rgba
2727                colormap, so in that case we dont care if its a combo...*/
2728             bool isCombo = (!(opts.square & SQUARE_POPUP_MENUS) && widget &&
2729                             isComboMenu(gtk_widget_get_parent(widget)) &&
2730                             !(qtSettings.useAlpha &&
2731                               compositingActive(widget) && isRgbaWidget(widget)));
2732             bool roundedMenu = ((!widget || !isCombo) &&
2733                                 !(opts.square & SQUARE_POPUP_MENUS));
2734             Cairo::Saver saver(cr);
2735 
2736             if (roundedMenu) {
2737                 Cairo::clipWhole(cr, x, y, width, height,
2738                                  (opts.round >= ROUND_FULL ? 5.0 : 2.5) - 1.0,
2739                                  round);
2740             }
2741             drawBevelGradient(cr, area, x, y, width, height,
2742                               &itemCols[fillVal], true, false,
2743                               opts.menuitemAppearance, WIDGET_MENU_ITEM);
2744         } else if (stdColors && opts.borderMenuitems) {
2745             drawLightBevel(cr, style, new_state, area, x, y,
2746                            width, height, &itemCols[fillVal], itemCols,
2747                            round, WIDGET_MENU_ITEM, BORDER_FLAT,
2748                            DF_DRAW_INSIDE | (stdColors ? DF_DO_BORDER : 0),
2749                            widget);
2750         } else {
2751             if (width > 2 && height > 2)
2752                 drawBevelGradient(cr, area, x + 1, y + 1, width - 2,height - 2,
2753                                   &itemCols[fillVal], true, false,
2754                                   opts.menuitemAppearance, WIDGET_MENU_ITEM);
2755 
2756             drawBorder(cr, style, state, area, x, y, width, height, itemCols,
2757                        round, BORDER_FLAT, WIDGET_MENU_ITEM, 0, borderVal);
2758         }
2759     }
2760 }
2761 
2762 void
2763 drawMenu(cairo_t *cr, GtkWidget *widget, const QtcRect *area,
2764          int x, int y, int width, int height)
2765 {
2766     double radius = 0.0;
2767     double alpha = 1.0;
2768     bool nonGtk = isFakeGtk();
2769     bool roundedMenu = !(opts.square & SQUARE_POPUP_MENUS) && !nonGtk;
2770     bool compsActive = compositingActive(widget);
2771     bool isAlphaWidget = compsActive && isRgbaWidget(widget);
2772     bool useAlpha = isAlphaWidget && opts.menuBgndOpacity < 100;
2773     bool useAlphaForCorners =
2774         !nonGtk && qtSettings.useAlpha && isAlphaWidget;
2775     bool comboMenu =
2776         useAlphaForCorners || !compsActive ? false : isComboMenu(widget);
2777     /* Cant round combos, unless using rgba - getting weird effects with
2778        shadow/clipping :-(. If 'useAlphaForCorners', then dont care if its a
2779        combo menu - as it can still be rounded */
2780 
2781     Cairo::Saver saver(cr); // For operator
2782     if (useAlpha) {
2783         if (widget && /*!comboMenu && */opts.menuBgndOpacity != 100) {
2784             enableBlurBehind(widget, true);
2785         }
2786         alpha = opts.menuBgndOpacity / 100.0;
2787         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
2788     }
2789     Cairo::Saver saver2(cr); // For clipping
2790     if (roundedMenu && !comboMenu) {
2791         radius = opts.round >= ROUND_FULL ? 5.0 : 2.5;
2792         if (useAlphaForCorners) {
2793             Cairo::Saver saver(cr);
2794             cairo_rectangle(cr, x, y, width, height);
2795             cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
2796             cairo_set_source_rgba(cr, 0, 0, 0, 1);
2797             cairo_fill(cr);
2798             clearRoundedMask(widget, false);
2799         } else {
2800             createRoundedMask(widget, x, y, width, height,
2801                               radius - 0.25, false);
2802         }
2803         Cairo::clipWhole(cr, x, y, width, height, radius, ROUNDED_ALL);
2804     }
2805 
2806     if (!qtcIsFlatBgnd(opts.menuBgndAppearance)) {
2807         if (opts.menuBgndAppearance == APPEARANCE_STRIPED) {
2808             drawStripedBgnd(cr, x, y, width, height,
2809                             &qtcPalette.menu[ORIGINAL_SHADE], alpha);
2810         } else if (opts.menuBgndAppearance == APPEARANCE_FILE) {
2811             drawBgndImage(cr, x, y, width, height, false);
2812         } else {
2813             drawBevelGradient(cr, area, x, y, width, height,
2814                               &qtcPalette.menu[ORIGINAL_SHADE],
2815                               opts.menuBgndGrad == GT_HORIZ, false,
2816                               opts.menuBgndAppearance, WIDGET_OTHER, alpha);
2817         }
2818     } else if (opts.shadePopupMenu || opts.lighterPopupMenuBgnd || useAlpha) {
2819         Cairo::rect(cr, area, x, y, width, height,
2820                     &qtcPalette.menu[ORIGINAL_SHADE], alpha);
2821     }
2822     if (opts.menuBgndImage.type != IMG_NONE) {
2823         drawBgndRings(cr, x, y, width, height, false);
2824     }
2825     if (opts.menuStripe && !comboMenu) {
2826         bool mozOo = isFakeGtk();
2827         int stripeWidth = mozOo ? 22 : 21;
2828 
2829         // To determine stripe size, we iterate over all menuitems of this menu.
2830         // If we find a GtkImageMenuItem then we can a width of 20. However, we
2831         // need to check that at least one enttry actually has an image! So, if
2832         // the first GtkImageMenuItem has an image then we're ok, otherwise we
2833         // give it a blank pixmap.
2834         if (!mozOo && widget) {
2835             GtkMenuShell *menuShell = GTK_MENU_SHELL(widget);
2836             GList *children =
2837                 gtk_container_get_children(GTK_CONTAINER(menuShell));
2838             for (GList *child = children;child;child = child->next) {
2839                 if (GTK_IS_IMAGE_MENU_ITEM(child->data)) {
2840                     GtkImageMenuItem *item = GTK_IMAGE_MENU_ITEM(child->data);
2841                     stripeWidth = 21;
2842                     if (!gtk_image_menu_item_get_image(item) ||
2843                         (GTK_IS_IMAGE(gtk_image_menu_item_get_image(item)) &&
2844                         gtk_image_get_storage_type(
2845                             GTK_IMAGE(gtk_image_menu_item_get_image(item))) ==
2846                          GTK_IMAGE_EMPTY)) {
2847                         // Give it a blank icon - so that menuStripe looks ok,
2848                         // plus this matches KDE style!
2849                         if (!gtk_image_menu_item_get_image(item)) {
2850                             gtk_image_menu_item_set_image(
2851                                 item, gtk_image_new_from_pixbuf(
2852                                     getPixbuf(qtcPalette.check_radio,
2853                                               PIX_BLANK, 1.0)));
2854                         } else {
2855                             gtk_image_set_from_pixbuf(
2856                                 GTK_IMAGE(gtk_image_menu_item_get_image(item)),
2857                                 getPixbuf(qtcPalette.check_radio,
2858                                           PIX_BLANK, 1.0));
2859                         }
2860                         break;
2861                     } else {
2862                         // TODO: Check image size!
2863                         break;
2864                     }
2865                 }
2866             }
2867             if (children) {
2868                 g_list_free(children);
2869             }
2870         }
2871 
2872         drawBevelGradient(cr, area, x + 1, y + 1, stripeWidth + 1,
2873                           height - 2, &opts.customMenuStripeColor, false, false,
2874                           opts.menuStripeAppearance, WIDGET_OTHER, alpha);
2875     }
2876 
2877     saver2.restore(); // For clipping
2878     if (opts.popupBorder) {
2879         EGradientBorder border =
2880             qtcGetGradient(opts.menuBgndAppearance, &opts)->border;
2881         cairo_new_path(cr);
2882         Cairo::setColor(cr, &qtcPalette.menu[QTC_STD_BORDER]);
2883         /* For now dont round combos - getting weird effects with
2884          * shadow/clipping :-( */
2885         if (roundedMenu && !comboMenu) {
2886             Cairo::pathWhole(cr, x + 0.5, y + 0.5, width - 1, height - 1,
2887                              radius - 1, ROUNDED_ALL);
2888         } else {
2889             cairo_rectangle(cr, x + 0.5, y + 0.5, width - 1, height - 1);
2890         }
2891         cairo_stroke(cr);
2892         if (qtcUseBorder(border) &&
2893             opts.menuBgndAppearance != APPEARANCE_FLAT) {
2894             if (roundedMenu) {
2895                 if (border != GB_3D) {
2896                     cairo_new_path(cr);
2897                     Cairo::setColor(cr, qtcPalette.menu);
2898                     Cairo::pathTopLeft(cr, x + 1.5, y + 1.5, width - 3,
2899                                        height - 3, radius - 2, ROUNDED_ALL);
2900                     cairo_stroke(cr);
2901                 }
2902                 cairo_new_path(cr);
2903                 Cairo::setColor(cr, &qtcPalette.menu[border == GB_LIGHT ? 0 :
2904                                                       FRAME_DARK_SHADOW]);
2905                 Cairo::pathBottomRight(cr, x + 1.5, y + 1.5, width - 3,
2906                                        height - 3, radius - 2, ROUNDED_ALL);
2907                 cairo_stroke(cr);
2908             } else {
2909                 if (border != GB_3D) {
2910                     Cairo::hLine(cr, x + 1, y + 1, width - 2, qtcPalette.menu);
2911                     Cairo::vLine(cr, x + 1, y + 1, height - 2,
2912                                  qtcPalette.menu);
2913                 }
2914                 Cairo::hLine(cr, x + 1, y + height - 2, width - 2,
2915                              &qtcPalette.menu[border == GB_LIGHT ? 0 :
2916                                               FRAME_DARK_SHADOW]);
2917                 Cairo::vLine(cr, x + width - 2, y + 1, height - 2,
2918                              &qtcPalette.menu[border == GB_LIGHT ? 0 :
2919                                               FRAME_DARK_SHADOW]);
2920             }
2921         }
2922     }
2923 }
2924 
2925 void
2926 drawBoxGap(cairo_t *cr, GtkStyle *style, GtkShadowType shadow,
2927            GtkStateType state, GtkWidget *widget, const QtcRect *area,
2928            int x, int y, int width, int height, GtkPositionType gapSide,
2929            int gapX, int gapWidth, EBorder borderProfile, bool isTab)
2930 {
2931     if (qtSettings.debug == DEBUG_ALL) {
2932         printf(DEBUG_PREFIX "%s %d %d %d %d %d %d %d %d %d ", __FUNCTION__,
2933                shadow, state, x, y, width, height, gapX, gapWidth, isTab);
2934         debugDisplayWidget(widget, 10);
2935     }
2936 
2937     // *Very* hacky fix for tabs in thunderbird main window!!!
2938     if (isTab && isMozilla() && gapWidth == 250 &&
2939         (width == 290 || width == 270) && height == 6) {
2940         return;
2941     }
2942     if (isTab && opts.tabBgnd != 0) {
2943         Cairo::Saver saver(cr);
2944         qtcClipPath(cr, x - 1, y - 1, width + 2, height + 2,
2945                     WIDGET_TAB_FRAME, RADIUS_EXTERNAL, ROUNDED_ALL);
2946         drawAreaMod(cr, style, state, area, TO_FACTOR(opts.tabBgnd),
2947                     x, y, width, height);
2948     }
2949     if (opts.tabMouseOver == TAB_MO_GLOW && gapWidth > 4 &&
2950         isMozillaWidget(widget)) {
2951         gapWidth -= 2;
2952     }
2953     if (shadow != GTK_SHADOW_NONE) {
2954         auto round = (((!isTab && opts.square & SQUARE_FRAME) ||
2955                        (isTab && opts.square & SQUARE_TAB_FRAME)) ?
2956                       ROUNDED_NONE : ROUNDED_ALL);
2957         GtkWidget *parent = widget ? gtk_widget_get_parent(widget) : nullptr;
2958 
2959         if (!(opts.square & SQUARE_TAB_FRAME) && gapX <= 0) {
2960             switch (gapSide) {
2961             case GTK_POS_TOP:
2962                 round = ECornerBits(CORNER_TR | CORNER_BL | CORNER_BR);
2963                 break;
2964             case GTK_POS_BOTTOM:
2965                 round = ECornerBits(CORNER_BR | CORNER_TL | CORNER_TR);
2966                 break;
2967             case GTK_POS_LEFT:
2968                 round = ECornerBits(CORNER_TR | CORNER_BL | CORNER_BR);
2969                 break;
2970             case GTK_POS_RIGHT:
2971                 round = ECornerBits(CORNER_TL | CORNER_BL | CORNER_BR);
2972                 break;
2973             }
2974         }
2975         Cairo::Saver saver(cr);
2976         qtcSetGapClip(cr, area, gapSide, gapX, gapWidth, x, y,
2977                       width, height, isTab);
2978         drawBorder(cr, gtk_widget_get_style(parent ? parent : widget), state,
2979                    area, x, y, width, height, nullptr, round,
2980                    borderProfile, isTab ? WIDGET_TAB_FRAME : WIDGET_FRAME,
2981                    isTab ? 0 : DF_BLEND);
2982     }
2983 }
2984 
2985 void
2986 drawBoxGapFixes(cairo_t *cr, GtkWidget *widget,  int x, int y,
2987                 int width, int height, GtkPositionType gapSide, int gapX,
2988                 int gapWidth)
2989 {
2990     const GdkColor *col1 = &qtcPalette.background[0];
2991     const GdkColor *col2 =
2992         &qtcPalette.background[opts.borderTab ? 0 :
2993                                (opts.appearance == APPEARANCE_FLAT ?
2994                                 ORIGINAL_SHADE : FRAME_DARK_SHADOW)];
2995     const GdkColor *outer = &qtcPalette.background[QTC_STD_BORDER];
2996     bool rev = reverseLayout(widget);
2997     bool thin = opts.thin & THIN_FRAMES;
2998     int rightPos = width - (gapX + gapWidth);
2999 
3000     switch (gapSide) {
3001     case GTK_POS_TOP:
3002         if (gapX > 0) {
3003             if (!thin) {
3004                 Cairo::hLine(cr, x + gapX - 1, y + 1, 3, col1);
3005                 Cairo::hLine(cr, x + gapX - 1, y, 3, col1);
3006             }
3007             Cairo::hLine(cr, x + gapX - 1, y, 2, outer);
3008         } else if (!thin) {
3009             Cairo::vLine(cr, x + 1, y, 2, col1);
3010         }
3011         if (rightPos >= 0) {
3012             if (!thin) {
3013                 Cairo::hLine(cr, x + gapX + gapWidth - 2, y + 1, 3, col1);
3014                 Cairo::vLine(cr, x + gapX + gapWidth - 2, y,
3015                              rightPos ? 1 : 0, col2);
3016             }
3017             Cairo::hLine(cr, x + gapX + gapWidth - 1, y, 2, outer);
3018         }
3019         if (!(opts.square & SQUARE_TAB_FRAME) && opts.round > ROUND_SLIGHT) {
3020             if (gapX > 0 && opts.tabMouseOver == TAB_MO_GLOW) {
3021                 Cairo::vLine(cr, rev ? x + width - 2 : x + 1, y, 2, outer);
3022             } else {
3023                 Cairo::vLine(cr, rev ? x + width - 1 : x, y, 3, outer);
3024                 if (gapX > 0 && !thin) {
3025                     Cairo::hLine(cr, x + 1, y, 1, &qtcPalette.background[2]);
3026                 }
3027             }
3028         }
3029         break;
3030     case GTK_POS_BOTTOM:
3031         if (gapX > 0) {
3032             if (!thin) {
3033                 Cairo::hLine(cr, x + gapX - 1, y + height - 1, 2, col1);
3034                 Cairo::hLine(cr, x + gapX - 1, y + height - 2, 2, col2);
3035             }
3036             Cairo::hLine(cr, x + gapX - 1, y + height - 1, 2, outer);
3037         } else if (!thin) {
3038             Cairo::vLine(cr, x + 1, y + height - 1, 2, col1);
3039         }
3040         if (rightPos >= 0) {
3041             if (!thin) {
3042                 Cairo::hLine(cr, x + gapX + gapWidth - 2,
3043                              y + height - 2, 3, col2);
3044                 Cairo::vLine(cr, x + gapX + gapWidth - 2,
3045                              y + height - 1, rightPos ? 1 : 0, col2);
3046             }
3047             Cairo::hLine(cr, x + gapX + gapWidth - 1,
3048                          y + height - 1, 2, outer);
3049         }
3050         if (!(opts.square & SQUARE_TAB_FRAME) && opts.round > ROUND_SLIGHT) {
3051             if (gapX > 0 && opts.tabMouseOver == TAB_MO_GLOW) {
3052                 Cairo::vLine(cr, rev ? x + width - 2 : x + 1,
3053                              y + height - 2, 2, outer);
3054             } else {
3055                 Cairo::vLine(cr, rev ? x + width - 1 : x,
3056                              y + height - 3, 3, outer);
3057             }
3058         }
3059         break;
3060     case GTK_POS_LEFT:
3061         if (gapX > 0) {
3062             if (!thin) {
3063                 Cairo::vLine(cr, x + 1, y + gapX - 1, 3, col1);
3064                 Cairo::vLine(cr, x, y + gapX - 1, 3, col1);
3065             }
3066             Cairo::vLine(cr, x, y + gapX - 1, 2, outer);
3067         } else if (!thin) {
3068             Cairo::hLine(cr, x, y + 1, 2, col1);
3069         }
3070         if (height - (gapX + gapWidth) > 0) {
3071             if (!thin) {
3072                 Cairo::vLine(cr, x + 1, y + gapX + gapWidth - 2, 3, col1);
3073                 Cairo::vLine(cr, x, y + gapX + gapWidth - 2, 1, col2);
3074             }
3075             Cairo::vLine(cr, x, y + gapX + gapWidth - 1, 2, outer);
3076         }
3077         if(!(opts.square & SQUARE_TAB_FRAME) && opts.round > ROUND_SLIGHT) {
3078             if (gapX > 0 && opts.tabMouseOver == TAB_MO_GLOW) {
3079                 Cairo::hLine(cr, x, y + 1, 2, outer);
3080             } else {
3081                 Cairo::hLine(cr, x, y, 3, outer);
3082                 if (gapX > 0 && !thin) {
3083                     Cairo::hLine(cr, x, y + 1, 1, &qtcPalette.background[2]);
3084                 }
3085             }
3086         }
3087         break;
3088     case GTK_POS_RIGHT:
3089         if (gapX > 0) {
3090             if (!thin)
3091                 Cairo::vLine(cr, x + width - 2, y + gapX - 1, 2, col2);
3092             Cairo::vLine(cr, x + width - 1, y + gapX - 1, 2, outer);
3093         } else if (!thin) {
3094             Cairo::hLine(cr, x + width - 2, y + 1, 3, col1);
3095         }
3096 
3097         if (height - (gapX + gapWidth) > 0) {
3098             if (!thin) {
3099                 Cairo::hLine(cr, x + width - 2,
3100                              y + gapX + gapWidth - 2, 3, col2);
3101                 Cairo::vLine(cr, x + width - 2,
3102                              y + gapX + gapWidth - 1, 2, col2);
3103             }
3104             Cairo::vLine(cr, x + width - 1, y + gapX + gapWidth - 1, 2, outer);
3105         }
3106         if (!(opts.square & SQUARE_TAB_FRAME) && opts.round > ROUND_SLIGHT) {
3107             if (gapX > 0 && opts.tabMouseOver == TAB_MO_GLOW) {
3108                 Cairo::hLine(cr, x + width - 2, y + 1, 2, outer);
3109             } else {
3110                 Cairo::hLine(cr, x + width - 3, y, 3, outer);
3111             }
3112         }
3113         break;
3114     }
3115 }
3116 
3117 void
3118 drawShadowGap(cairo_t *cr, GtkStyle *style, GtkShadowType shadow,
3119               GtkStateType state, GtkWidget *widget, const QtcRect *area,
3120               int x, int y, int width, int height, GtkPositionType gapSide,
3121               int gapX, int gapWidth)
3122 {
3123     bool drawFrame = true;
3124     bool isGroupBox = IS_GROUP_BOX(widget);
3125 
3126     if (isGroupBox) {
3127         if (gapX < 5) {
3128             gapX += 5;
3129             gapWidth += 2;
3130         }
3131         switch (opts.groupBox) {
3132         case FRAME_NONE:
3133             drawFrame = false;
3134             return;
3135         case FRAME_LINE:
3136         case FRAME_SHADED:
3137         case FRAME_FADED:
3138             if (opts.gbLabel & (GB_LBL_INSIDE | GB_LBL_OUTSIDE) && widget &&
3139                 GTK_IS_FRAME(widget)) {
3140                 GtkFrame *frame = GTK_FRAME(widget);
3141                 GtkRequisition child_requisition;
3142                 int height_extra;
3143                 GtkStyle *style =
3144                     (frame ? gtk_widget_get_style(GTK_WIDGET(frame)) : nullptr);
3145                 GtkWidget *label =
3146                     (frame ? gtk_frame_get_label_widget(frame) : nullptr);
3147 
3148                 if (style && label) {
3149                     gtk_widget_get_child_requisition(label, &child_requisition);
3150                     height_extra =
3151                         (qtcMax(0, child_requisition.height -
3152                                 style->ythickness) -
3153                          qtcFrameGetLabelYAlign(frame) *
3154                          child_requisition.height) + 2;
3155 
3156                     if (opts.gbLabel & GB_LBL_INSIDE) {
3157                         y -= height_extra;
3158                         height += height_extra;
3159                         gapWidth = 0;
3160                     } else if (opts.gbLabel & GB_LBL_OUTSIDE) {
3161                         y += height_extra;
3162                         height -= height_extra;
3163                         gapWidth = 0;
3164                     }
3165                 }
3166             }
3167             if (opts.groupBox == FRAME_LINE) {
3168                 QtcRect gap = {x, y, gapWidth, 1};
3169                 drawFadedLine(cr, x, y, width, 1,
3170                               &qtcPalette.background[QTC_STD_BORDER],
3171                               area, gapWidth > 0 ? &gap : nullptr,
3172                               false, true, true);
3173                 drawFrame = false;
3174             } else if (shadow != GTK_SHADOW_NONE) {
3175                 auto round = (opts.square & SQUARE_FRAME ?
3176                               ROUNDED_NONE : ROUNDED_ALL);
3177                 double col = opts.gbFactor < 0 ? 0.0 : 1.0;
3178                 double radius =
3179                     (round == ROUNDED_ALL ?
3180                      qtcGetRadius(&opts, width, height, WIDGET_FRAME,
3181                                   RADIUS_EXTERNAL) : 0.0);
3182                 if (opts.gbFactor != 0) {
3183                     Cairo::Saver saver(cr);
3184                     Cairo::clipWhole(cr, x + 0.5, y + 0.5, width - 1,
3185                                      height - 1, radius, round);
3186                     cairo_rectangle(cr, x, y, width, height);
3187                     if (opts.groupBox == FRAME_SHADED) {
3188                         cairo_set_source_rgba(cr, col, col, col,
3189                                               TO_ALPHA(opts.gbFactor));
3190                     } else {
3191                         cairo_pattern_t *pt =
3192                             cairo_pattern_create_linear(x, y, x,
3193                                                         y + height - 1);
3194                         cairo_pattern_add_color_stop_rgba(
3195                             pt, 0, col, col, col, TO_ALPHA(opts.gbFactor));
3196                         cairo_pattern_add_color_stop_rgba(
3197                             pt, CAIRO_GRAD_END, col, col, col, 0);
3198                         cairo_set_source(cr, pt);
3199                         cairo_pattern_destroy(pt);
3200                     }
3201                     cairo_fill(cr);
3202                 }
3203                 if (opts.groupBox == FRAME_FADED) {
3204                     cairo_pattern_t *pt =
3205                         cairo_pattern_create_linear(x, y, x, y + height - 1);
3206                     Cairo::patternAddColorStop(
3207                         pt, 0, &qtcPalette.background[QTC_STD_BORDER]);
3208                     Cairo::patternAddColorStop(
3209                         pt, CAIRO_GRAD_END,
3210                         &qtcPalette.background[QTC_STD_BORDER], 0);
3211                     Cairo::Saver saver(cr);
3212                     qtcSetGapClip(cr, area, gapSide, gapX, gapWidth,
3213                                   x, y, width, height, false);
3214                     cairo_set_source(cr, pt);
3215                     Cairo::pathWhole(cr, x + 0.5, y + 0.5, width - 1,
3216                                      height - 1, radius, round);
3217                     cairo_stroke(cr);
3218                     cairo_pattern_destroy(pt);
3219                     drawFrame = false;
3220                 }
3221             }
3222             break;
3223         default:
3224             break;
3225         }
3226     }
3227     if (drawFrame) {
3228         drawBoxGap(cr, style, shadow, state, widget, area, x, y,
3229                    width, height, gapSide, gapX, gapWidth,
3230                    isGroupBox && opts.groupBox == FRAME_SHADED &&
3231                    shadow != GTK_SHADOW_NONE ? BORDER_SUNKEN :
3232                    shadowToBorder(shadow), false);
3233     }
3234 }
3235 
3236 void
3237 drawCheckBox(cairo_t *cr, GtkStateType state, GtkShadowType shadow,
3238              GtkStyle *style, GtkWidget *widget, const char *detail,
3239              const QtcRect *area, int x, int y, int width, int height)
3240 {
3241     if (state == GTK_STATE_PRELIGHT &&
3242         oneOf(qtSettings.app, GTK_APP_MOZILLA, GTK_APP_JAVA)) {
3243         state = GTK_STATE_NORMAL;
3244     }
3245     bool mnu = oneOf(detail, "check");
3246     bool list = !mnu && isList(widget);
3247     bool on = shadow == GTK_SHADOW_IN;
3248     bool tri = shadow == GTK_SHADOW_ETCHED_IN;
3249     bool doEtch = opts.buttonEffect != EFFECT_NONE;
3250     GdkColor newColors[TOTAL_SHADES + 1];
3251     const GdkColor *btnColors;
3252     auto ind_state = ((list || (!mnu && state == GTK_STATE_INSENSITIVE)) ?
3253                       state : GTK_STATE_NORMAL);
3254     int checkSpace = doEtch ? opts.crSize + 2 : opts.crSize;
3255 
3256     if (opts.crColor && state != GTK_STATE_INSENSITIVE && (on || tri)) {
3257         btnColors = qtcPalette.selectedcr;
3258     } else if (!mnu && !list && QT_CUSTOM_COLOR_BUTTON(style)) {
3259         shadeColors(&style->bg[state], newColors);
3260         btnColors = newColors;
3261     } else {
3262         btnColors = qtcPalette.button[state == GTK_STATE_INSENSITIVE ?
3263                                       PAL_DISABLED : PAL_ACTIVE];
3264     }
3265     x += (width - checkSpace) / 2;
3266     y += (height - checkSpace) / 2;
3267     if (qtSettings.debug == DEBUG_ALL) {
3268         printf(DEBUG_PREFIX "%s %d %d %d %d %d %d %d %s  ",
3269                __FUNCTION__, state, shadow, x, y, width, height, mnu,
3270                detail ? detail : "nullptr");
3271         debugDisplayWidget(widget, 10);
3272     }
3273     if ((mnu && state == GTK_STATE_PRELIGHT) ||
3274         (list && state == GTK_STATE_ACTIVE)) {
3275         state = GTK_STATE_NORMAL;
3276     }
3277     if (mnu && isMozilla()) {
3278         x -= 2;
3279     }
3280     if (!mnu || qtSettings.qt4) {
3281         if (opts.crButton) {
3282             drawLightBevel(cr, style, state, area, x, y, checkSpace,
3283                            checkSpace, &btnColors[getFill(state, false)],
3284                            btnColors, ROUNDED_ALL, WIDGET_CHECKBOX, BORDER_FLAT,
3285                            DF_DO_BORDER |
3286                            (state == GTK_STATE_ACTIVE ? DF_SUNKEN : 0),
3287                            list ? nullptr : widget);
3288             if (doEtch) {
3289                 x++;
3290                 y++;
3291             }
3292         } else {
3293             bool coloredMouseOver =
3294                 state == GTK_STATE_PRELIGHT && opts.coloredMouseOver;
3295             bool glow = (doEtch && state == GTK_STATE_PRELIGHT &&
3296                          opts.coloredMouseOver == MO_GLOW);
3297             bool lightBorder = DRAW_LIGHT_BORDER(false, WIDGET_TROUGH,
3298                                                  APPEARANCE_INVERTED);
3299             const GdkColor *colors =
3300                 coloredMouseOver ? qtcPalette.mouseover : btnColors;
3301             const GdkColor *bgndCol =
3302                 (oneOf(state, GTK_STATE_INSENSITIVE, GTK_STATE_ACTIVE) ?
3303                  &style->bg[GTK_STATE_NORMAL] :
3304                  !mnu && state == GTK_STATE_PRELIGHT && !coloredMouseOver &&
3305                  !opts.crHighlight ? &btnColors[CR_MO_FILL] :
3306                  &style->base[GTK_STATE_NORMAL]);
3307             if (doEtch) {
3308                 x++;
3309                 y++;
3310             }
3311 
3312             drawBevelGradient(cr, area, x + 1, y + 1, opts.crSize - 2,
3313                               opts.crSize - 2, bgndCol, true, false,
3314                               APPEARANCE_INVERTED, WIDGET_TROUGH);
3315 
3316             if (coloredMouseOver && !glow) {
3317                 cairo_new_path(cr);
3318                 Cairo::setColor(cr, &colors[CR_MO_FILL]);
3319                 cairo_rectangle(cr, x + 1.5, y + 1.5, opts.crSize - 3,
3320                                 opts.crSize - 3);
3321                 /* cairo_rectangle(cr, x + 2.5, y + 2.5, opts.crSize - 5, */
3322                 /*                 opts.crSize - 5); */
3323                 cairo_stroke(cr);
3324             } else {
3325                 cairo_new_path(cr);
3326                 if (lightBorder) {
3327                     Cairo::setColor(
3328                         cr, &btnColors[LIGHT_BORDER(APPEARANCE_INVERTED)]);
3329                     cairo_rectangle(cr, x + 1.5, y + 1.5, opts.crSize - 3,
3330                                     opts.crSize - 3);
3331                 } else {
3332                     GdkColor mid = midColor(state == GTK_STATE_INSENSITIVE ?
3333                                             &style->bg[GTK_STATE_NORMAL] :
3334                                             &style->base[GTK_STATE_NORMAL],
3335                                             &colors[3]);
3336                     Cairo::setColor(cr, &mid);
3337                     cairo_move_to(cr, x + 1.5, y + opts.crSize - 1.5);
3338                     cairo_line_to(cr, x + 1.5, y + 1.5);
3339                     cairo_line_to(cr, x + opts.crSize - 1.5, y + 1.5);
3340                 }
3341                 cairo_stroke(cr);
3342             }
3343             if (doEtch && (!list || glow) && !mnu) {
3344                 if(glow && !(opts.thin & THIN_FRAMES)) {
3345                     drawGlow(cr, area, x - 1, y - 1, opts.crSize + 2,
3346                              opts.crSize + 2, ROUNDED_ALL, WIDGET_CHECKBOX);
3347                 } else {
3348                     drawEtch(cr, area, widget, x - 1, y - 1,
3349                              opts.crSize + 2, opts.crSize + 2, false,
3350                              ROUNDED_ALL, WIDGET_CHECKBOX);
3351                 }
3352             }
3353             drawBorder(cr, style, state, area, x, y, opts.crSize,
3354                        opts.crSize, colors, ROUNDED_ALL, BORDER_FLAT,
3355                        WIDGET_CHECKBOX, 0);
3356         }
3357     }
3358 
3359     if (on) {
3360         GdkPixbuf *pix = getPixbuf(getCheckRadioCol(style, ind_state, mnu),
3361                                    PIX_CHECK, 1.0);
3362         int pw = gdk_pixbuf_get_width(pix);
3363         int ph = gdk_pixbuf_get_height(pix);
3364         int dx = x + opts.crSize / 2 - pw / 2;
3365         int dy = y + opts.crSize / 2 - ph/2;
3366 
3367         gdk_cairo_set_source_pixbuf(cr, pix, dx, dy);
3368         cairo_paint(cr);
3369     } else if (tri) {
3370         int ty = y + opts.crSize / 2;
3371         const GdkColor *col = getCheckRadioCol(style, ind_state, mnu);
3372 
3373         Cairo::hLine(cr, x + 3, ty, opts.crSize - 6, col);
3374         Cairo::hLine(cr, x + 3, ty + 1, opts.crSize - 6, col);
3375     }
3376 }
3377 
3378 void
3379 drawRadioButton(cairo_t *cr, GtkStateType state, GtkShadowType shadow,
3380                 GtkStyle *style, GtkWidget *widget, const char *detail,
3381                 const QtcRect *area, int x, int y, int width, int height)
3382 {
3383     if (state == GTK_STATE_PRELIGHT &&
3384         oneOf(qtSettings.app, GTK_APP_MOZILLA, GTK_APP_JAVA)) {
3385         state = GTK_STATE_NORMAL;
3386     }
3387     bool mnu = oneOf(detail, "option");
3388     bool list = !mnu && isList(widget);
3389     if ((mnu && state == GTK_STATE_PRELIGHT) ||
3390         (list && state == GTK_STATE_ACTIVE)) {
3391         state = GTK_STATE_NORMAL;
3392     }
3393 
3394     if (!qtSettings.qt4 && mnu) {
3395         drawCheckBox(cr, state, shadow, style, widget, "check", area,
3396                      x, y, width, height);
3397     } else {
3398         bool on = shadow == GTK_SHADOW_IN;
3399         bool tri = shadow == GTK_SHADOW_ETCHED_IN;
3400         bool doEtch = opts.buttonEffect != EFFECT_NONE;
3401         auto ind_state = (state == GTK_STATE_INSENSITIVE ?
3402                           state : GTK_STATE_NORMAL);
3403         int optSpace = doEtch ? opts.crSize + 2 : opts.crSize;
3404         GdkColor newColors[TOTAL_SHADES + 1];
3405         const GdkColor *btnColors;
3406         x += (width - optSpace) / 2;
3407         y += (height - optSpace) / 2;
3408         if (opts.crColor && state != GTK_STATE_INSENSITIVE && (on || tri)) {
3409             btnColors = qtcPalette.selectedcr;
3410         } else if (!mnu && !list && QT_CUSTOM_COLOR_BUTTON(style)) {
3411             shadeColors(&style->bg[state], newColors);
3412             btnColors = newColors;
3413         } else {
3414             btnColors = qtcPalette.button[state == GTK_STATE_INSENSITIVE ?
3415                                           PAL_DISABLED : PAL_ACTIVE];
3416         }
3417         if (opts.crButton) {
3418             drawLightBevel(cr, style, state, area, x, y, optSpace,
3419                            optSpace, &btnColors[getFill(state, false)],
3420                            btnColors, ROUNDED_ALL, WIDGET_RADIO_BUTTON,
3421                            BORDER_FLAT, DF_DO_BORDER |
3422                            (state == GTK_STATE_ACTIVE ? DF_SUNKEN : 0),
3423                            list ? nullptr : widget);
3424             if (doEtch) {
3425                 x++;
3426                 y++;
3427             }
3428         } else {
3429             bool glow = (doEtch && state == GTK_STATE_PRELIGHT &&
3430                          opts.coloredMouseOver == MO_GLOW);
3431             bool lightBorder = DRAW_LIGHT_BORDER(false, WIDGET_TROUGH,
3432                                                  APPEARANCE_INVERTED);
3433             bool coloredMouseOver = (state == GTK_STATE_PRELIGHT &&
3434                                      opts.coloredMouseOver);
3435             bool doneShadow = false;
3436             const GdkColor *colors = (coloredMouseOver ?
3437                                       qtcPalette.mouseover : btnColors);
3438             const GdkColor *bgndCol =
3439                 (oneOf(state, GTK_STATE_INSENSITIVE, GTK_STATE_ACTIVE) ?
3440                  &style->bg[GTK_STATE_NORMAL] :
3441                  !mnu && GTK_STATE_PRELIGHT == state &&
3442                  !coloredMouseOver && !opts.crHighlight ?
3443                  &colors[CR_MO_FILL] : &style->base[GTK_STATE_NORMAL]);
3444             double radius = (opts.crSize + 1) / 2.0;
3445 
3446             if (doEtch) {
3447                 x++;
3448                 y++;
3449             }
3450             cairo_save(cr);
3451             qtcClipPath(cr, x, y, opts.crSize, opts.crSize,
3452                         WIDGET_RADIO_BUTTON, RADIUS_EXTERNAL, ROUNDED_ALL);
3453             drawBevelGradient(cr, nullptr, x + 1, y + 1, opts.crSize - 2,
3454                               opts.crSize - 2, bgndCol,true, false,
3455                               APPEARANCE_INVERTED, WIDGET_TROUGH);
3456             cairo_restore(cr);
3457             if (!mnu && coloredMouseOver && !glow) {
3458                 double radius = (opts.crSize - 2) / 2.0;
3459                 Cairo::setColor(cr, &colors[CR_MO_FILL]);
3460                 cairo_arc(cr, x + radius + 1, y+radius + 1,
3461                           radius, 0, 2 * M_PI);
3462                 cairo_stroke(cr);
3463                 radius--;
3464                 cairo_arc(cr, x + radius + 2, y + radius + 2,
3465                           radius, 0, 2 * M_PI);
3466                 cairo_stroke(cr);
3467             }
3468             if (!doneShadow && doEtch && !mnu && (!list || glow)) {
3469                 double radius = (opts.crSize + 1) / 2.0;
3470                 if (glow) {
3471                     Cairo::setColor(cr, &qtcPalette.mouseover[GLOW_MO]);
3472                 } else {
3473                     cairo_set_source_rgba(cr, 0.0, 0.0, 0.0,
3474                                           ETCH_RADIO_TOP_ALPHA);
3475                 }
3476                 if (opts.buttonEffect != EFFECT_NONE || glow) {
3477                     cairo_arc(cr, x + radius - 0.5, y + radius - 0.5,
3478                               radius, 0.75 * M_PI, 1.75 * M_PI);
3479                     cairo_stroke(cr);
3480                     if (!glow) {
3481                         setLowerEtchCol(cr, widget);
3482                     }
3483                 }
3484                 cairo_arc(cr, x + radius - 0.5, y + radius - 0.5,
3485                           radius, 1.75 * M_PI, 0.75 * M_PI);
3486                 cairo_stroke(cr);
3487             }
3488             Cairo::setColor(
3489                 cr, &colors[coloredMouseOver ? 4 :
3490                             BORDER_VAL(state != GTK_STATE_INSENSITIVE)]);
3491             radius = (opts.crSize - 0.5)/2.0;
3492             cairo_arc(cr, x + 0.25 + radius, y + 0.25 + radius,
3493                       radius, 0, 2 * M_PI);
3494             cairo_stroke(cr);
3495             if (!coloredMouseOver) {
3496                 radius = (opts.crSize - 1) / 2.0;
3497                 Cairo::setColor(cr, &btnColors[coloredMouseOver ? 3 : 4]);
3498                 cairo_arc(cr, x + 0.75 + radius, y + 0.75 + radius, radius,
3499                           lightBorder ? 0 : 0.75 * M_PI,
3500                           lightBorder ? 2 * M_PI : 1.75 * M_PI);
3501                 cairo_stroke(cr);
3502             }
3503         }
3504         if (on) {
3505             const GdkColor *col = getCheckRadioCol(style, ind_state, mnu);
3506             double radius = opts.smallRadio ? 2.5 : 3.5;
3507             double offset = opts.crSize / 2.0 - radius;
3508 
3509             Cairo::setColor(cr, col);
3510             cairo_arc(cr, x + offset + radius, y + offset + radius,
3511                       radius, 0, 2 * M_PI);
3512             cairo_fill(cr);
3513         } else if (tri) {
3514             int ty = y + opts.crSize / 2;
3515             const GdkColor *col = getCheckRadioCol(style, ind_state, mnu);
3516 
3517             Cairo::hLine(cr, x + 3, ty, opts.crSize - 6, col);
3518             Cairo::hLine(cr, x + 3, ty + 1, opts.crSize - 6, col);
3519         }
3520     }
3521 }
3522 
3523 void
3524 drawTab(cairo_t *cr, GtkStateType state, GtkStyle *style, GtkWidget *widget,
3525         QtcRect *area, int x, int y, int width, int height,
3526         GtkPositionType gapSide)
3527 {
3528     GtkNotebook *notebook =
3529         GTK_IS_NOTEBOOK(widget) ? GTK_NOTEBOOK(widget) : nullptr;
3530     bool highlightingEnabled = notebook && (opts.highlightFactor ||
3531                                             opts.coloredMouseOver);
3532     bool highlight = false;
3533     int highlightedTabIndex = Tab::currentHoveredIndex(widget);
3534     int moOffset = ((opts.round == ROUND_NONE ||
3535                      opts.tabMouseOver != TAB_MO_TOP) ? 1 : opts.round);
3536     GtkWidget *parent = widget ? gtk_widget_get_parent(widget) : nullptr;
3537     bool firstTab = !notebook;
3538     bool lastTab = !notebook;
3539     bool vertical = oneOf(gapSide, GTK_POS_LEFT, GTK_POS_RIGHT);
3540     bool active = state == GTK_STATE_NORMAL; /* Normal -> active tab? */
3541     bool rev = (oneOf(gapSide, GTK_POS_TOP, GTK_POS_BOTTOM) && parent &&
3542                 reverseLayout(parent));
3543     bool mozTab = isMozillaTab(widget);
3544     bool glowMo = (!active && notebook && opts.coloredMouseOver &&
3545                    opts.tabMouseOver == TAB_MO_GLOW);
3546     bool drawOuterGlow = glowMo && !(opts.thin & THIN_FRAMES);
3547     int mod = active ? 1 : 0;
3548     int highlightOffset = (opts.highlightTab &&
3549                            opts.round > ROUND_SLIGHT ? 2 : 1);
3550     int highlightBorder = opts.round > ROUND_FULL ? 4 : 3;
3551     int sizeAdjust = ((!active || mozTab) &&
3552                       opts.tabMouseOver == TAB_MO_GLOW ? 1 : 0);
3553     int tabIndex = -1;
3554     const GdkColor *col = (active ? &style->bg[GTK_STATE_NORMAL] :
3555                            &qtcPalette.background[2]);
3556     const GdkColor *selCol1 = &qtcPalette.highlight[0];
3557     QtcRect clipArea;
3558     EBorder borderProfile = (active || opts.borderInactiveTab ? opts.borderTab ?
3559                              BORDER_LIGHT : BORDER_RAISED : BORDER_FLAT);
3560 
3561 #if !GTK_CHECK_VERSION(2, 90, 0)
3562     /* Hacky fix for tabs in Thunderbird */
3563     if (mozTab && area && area->x < x - 10) {
3564         return;
3565     }
3566 #endif
3567 
3568     /* f'in mozilla apps dont really use Gtk widgets - they just paint to a
3569        pixmap. So, no way of knowing the position of a tab! The 'best' look
3570        seems to be to round both corners. Not nice, but... */
3571     if (mozTab || qtSettings.app == GTK_APP_JAVA) {
3572         firstTab = lastTab = true;
3573     } else if (notebook) {
3574         /* Borrowed from Qt engine... */
3575         GList *children = gtk_container_get_children(GTK_CONTAINER(widget));
3576         int num_children = children ? g_list_length(children) : 0;
3577         int sdiff = 10000;
3578         int first_shown = -1;
3579         int last_shown = -1;
3580         if (children) {
3581             g_list_free(children);
3582         }
3583         for (int i = 0; i < num_children;i++) {
3584             GtkWidget *page = gtk_notebook_get_nth_page(notebook, i);
3585             GtkWidget *tab_label = gtk_notebook_get_tab_label(notebook, page);
3586             int diff = -1;
3587 
3588             if (tab_label) {
3589                 QtcRect alloc = Widget::getAllocation(tab_label);
3590                 diff = vertical ? alloc.y - y : alloc.x - x;
3591             }
3592 
3593             if (diff > 0 && diff < sdiff) {
3594                 sdiff = diff;
3595                 tabIndex = i;
3596             }
3597 
3598             if (page && gtk_widget_get_visible(page)) {
3599                 if (i > last_shown) {
3600                     last_shown = i;
3601                 }
3602                 if (first_shown == -1) {
3603                     first_shown = i;
3604                 }
3605             }
3606         }
3607 
3608         if (oneOf(tabIndex, 0, first_shown)) {
3609             firstTab = true;
3610         } else if (oneOf(tabIndex, num_children - 1, last_shown)) {
3611             lastTab = true;
3612         }
3613         if (noneOf(highlightedTabIndex, -1, tabIndex) && !active) {
3614             highlight = true;
3615             col = &qtcPalette.background[SHADE_2_HIGHLIGHT];
3616         }
3617     }
3618 
3619     if (rev) {
3620         bool oldLast = lastTab;
3621 
3622         lastTab = firstTab;
3623         firstTab = oldLast;
3624     }
3625 
3626     if (!mozTab && qtSettings.app != GTK_APP_JAVA) {
3627         if (highlightedTabIndex == -1 &&
3628             (highlightingEnabled || opts.windowDrag >= WM_DRAG_ALL)) {
3629             Tab::setup(widget);
3630         }
3631         Tab::updateRect(widget, tabIndex, x, y, width, height);
3632     }
3633 
3634 /*
3635   gtk_style_apply_default_background(style, window, widget && !qtcWidgetNoWindow(widget),
3636   GTK_STATE_NORMAL, area, x, y, width, height);
3637 */
3638     /*
3639       TODO: This is not good, should respect 'area' as passed in. However,
3640       it works for the moment - if the thunderbird hack above is used.
3641       Needs to be fixed tho.
3642     */
3643 
3644     /* In addition to the above, doing this section only for the active mozilla
3645        tab seems to fix some drawing errors with firefox3...*/
3646     /* CPD 28/02/2008 Dont need to do any of this for firefox 3beta4 */
3647     if (!mozTab) {
3648         clipArea = qtcRect(x, y, width, height);
3649         area = &clipArea;
3650     }
3651 
3652     glowMo = glowMo && highlight;
3653     drawOuterGlow = drawOuterGlow && highlight;
3654 
3655     switch (gapSide) {
3656     case GTK_POS_TOP: {
3657         /* tabs are on bottom !!! */
3658         auto round = (active || (firstTab && lastTab) ||
3659                       opts.tabMouseOver == TAB_MO_GLOW ||
3660                       opts.roundAllTabs ? ROUNDED_BOTTOM :
3661                       firstTab ? ROUNDED_BOTTOMLEFT : lastTab ?
3662                       ROUNDED_BOTTOMRIGHT : ROUNDED_NONE);
3663         cairo_save(cr);
3664         qtcClipPath(cr, x, y - 4, width, height + 4, WIDGET_TAB_BOT,
3665                     RADIUS_EXTERNAL, round);
3666         fillTab(cr, style, widget, area, state, col,
3667                 x + mod + sizeAdjust, y, width - (2 * mod + sizeAdjust),
3668                 height - 1, true, WIDGET_TAB_BOT, notebook != nullptr);
3669         cairo_restore(cr);
3670         drawBorder(cr, style, state, area, x + sizeAdjust, y - 4,
3671                    width - 2 * sizeAdjust, height + 4,
3672                    glowMo ? qtcPalette.mouseover : qtcPalette.background,
3673                    round, borderProfile, WIDGET_TAB_BOT, 0);
3674         if (drawOuterGlow) {
3675             if (area) {
3676                 area->height++;
3677             }
3678             drawGlow(cr, area, x, y - 4, width, height + 5,
3679                      round, WIDGET_OTHER);
3680         }
3681 
3682         if (notebook && opts.highlightTab && active) {
3683             Cairo::hLine(cr, x + 1, y + height - 3, width - 2, selCol1, 0.5);
3684             Cairo::hLine(cr, x + highlightOffset, y + height - 2,
3685                          width - 2 * highlightOffset, selCol1);
3686 
3687             clipArea.y = y + height - highlightBorder;
3688             clipArea.height = highlightBorder;
3689             drawBorder(cr, style, state, &clipArea, x, y,
3690                        width, height, qtcPalette.highlight, ROUNDED_BOTTOM,
3691                        BORDER_FLAT, WIDGET_OTHER, 0, 3);
3692         }
3693 
3694         if (opts.colorSelTab && notebook && active)
3695             colorTab(cr, x + mod + sizeAdjust, y,
3696                      width - (2 * mod + sizeAdjust), height - 1, round,
3697                      WIDGET_TAB_BOT, true);
3698 
3699         if (notebook && opts.coloredMouseOver && highlight &&
3700             opts.tabMouseOver != TAB_MO_GLOW)
3701             drawHighlight(cr, x + (firstTab ? moOffset : 1),
3702                           y + (opts.tabMouseOver == TAB_MO_TOP ?
3703                                height - 2 : -1),
3704                           width - (firstTab || lastTab ? moOffset : 1), 2,
3705                           nullptr, true, opts.tabMouseOver != TAB_MO_TOP);
3706         break;
3707     }
3708     case GTK_POS_BOTTOM: {
3709         /* tabs are on top !!! */
3710         auto round = (active || (firstTab && lastTab) ||
3711                       opts.tabMouseOver == TAB_MO_GLOW ||
3712                       opts.roundAllTabs ? ROUNDED_TOP :
3713                       firstTab ? ROUNDED_TOPLEFT : lastTab ?
3714                       ROUNDED_TOPRIGHT : ROUNDED_NONE);
3715         cairo_save(cr);
3716         qtcClipPath(cr, x + mod + sizeAdjust, y,
3717                     width - 2 * (mod + (mozTab ? 2 * sizeAdjust : sizeAdjust)),
3718                     height + 5, WIDGET_TAB_TOP, RADIUS_EXTERNAL, round);
3719         fillTab(cr, style, widget, area, state, col,
3720                 x + mod + sizeAdjust, y + 1,
3721                 width - 2 * (mod + (mozTab ? 2 * sizeAdjust : sizeAdjust)),
3722                 height - 1, true, WIDGET_TAB_TOP,notebook != nullptr);
3723         cairo_restore(cr);
3724         drawBorder(cr, style, state, area, x + sizeAdjust, y,
3725                    width - 2 * (mozTab ? 2 : 1) * sizeAdjust, height + 4,
3726                    glowMo ? qtcPalette.mouseover : qtcPalette.background,
3727                    round, borderProfile, WIDGET_TAB_TOP, 0);
3728         if (drawOuterGlow) {
3729             if (area) {
3730                 area->y--;
3731                 area->height += 2;
3732             }
3733             drawGlow(cr, area, x, y - 1, width, height + 5,
3734                      round, WIDGET_OTHER);
3735         }
3736 
3737         if (notebook && opts.highlightTab && active) {
3738             Cairo::hLine(cr, x + 1, y + 2, width - 2, selCol1, 0.5);
3739             Cairo::hLine(cr, x + highlightOffset, y + 1,
3740                          width - 2 * highlightOffset, selCol1);
3741 
3742             clipArea.y = y;
3743             clipArea.height = highlightBorder;
3744             drawBorder(cr, style, state, &clipArea, x, y, width, height,
3745                        qtcPalette.highlight, ROUNDED_TOP, BORDER_FLAT,
3746                        WIDGET_OTHER, 0, 3);
3747         }
3748 
3749         if (opts.colorSelTab && notebook && active)
3750             colorTab(cr, x + mod + sizeAdjust, y + 1,
3751                      width - 2 * (mod + (mozTab ? 2 * sizeAdjust : sizeAdjust)),
3752                      height - 1, round, WIDGET_TAB_TOP, true);
3753 
3754         if (notebook && opts.coloredMouseOver && highlight &&
3755             opts.tabMouseOver != TAB_MO_GLOW) {
3756             drawHighlight(cr, x + (firstTab ? moOffset : 1),
3757                           y + (opts.tabMouseOver == TAB_MO_TOP ?
3758                                0 : height - 1),
3759                           width - (firstTab || lastTab ? moOffset : 1),
3760                           2, nullptr, true, opts.tabMouseOver == TAB_MO_TOP);
3761         }
3762         break;
3763     }
3764     case GTK_POS_LEFT: {
3765         /* tabs are on right !!! */
3766         auto round = (active || (firstTab && lastTab) ||
3767                       opts.tabMouseOver == TAB_MO_GLOW ||
3768                       opts.roundAllTabs ? ROUNDED_RIGHT :
3769                       firstTab ? ROUNDED_TOPRIGHT : lastTab ?
3770                       ROUNDED_BOTTOMRIGHT : ROUNDED_NONE);
3771         cairo_save(cr);
3772         qtcClipPath(cr, x - 4, y, width + 4, height, WIDGET_TAB_BOT,
3773                     RADIUS_EXTERNAL, round);
3774         fillTab(cr, style, widget, area, state, col, x,
3775                 y + mod + sizeAdjust, width - 1,
3776                 height - 2 * (mod + sizeAdjust), false,
3777                 WIDGET_TAB_BOT, notebook != nullptr);
3778         cairo_restore(cr);
3779         drawBorder(cr, style, state, area, x - 4, y + sizeAdjust,
3780                    width + 4, height - 2 * sizeAdjust,
3781                    glowMo ? qtcPalette.mouseover : qtcPalette.background,
3782                    round, borderProfile, WIDGET_TAB_BOT, 0);
3783         if (drawOuterGlow) {
3784             if (area) {
3785                 area->width++;
3786             }
3787             drawGlow(cr, area, x - 4, y, width + 5, height,
3788                      round, WIDGET_OTHER);
3789         }
3790 
3791         if (notebook && opts.highlightTab && active) {
3792             Cairo::vLine(cr, x + width - 3, y + 1, height - 2, selCol1, 0.5);
3793             Cairo::vLine(cr, x + width - 2, y + highlightOffset,
3794                          height - 2 * highlightOffset, selCol1);
3795 
3796             clipArea.x = x + width - highlightBorder;
3797             clipArea.width = highlightBorder;
3798             drawBorder(cr, style, state, &clipArea, x, y,
3799                        width, height, qtcPalette.highlight, ROUNDED_RIGHT,
3800                        BORDER_FLAT, WIDGET_OTHER, 0, 3);
3801         }
3802 
3803         if (opts.colorSelTab && notebook && active)
3804             colorTab(cr, x, y + mod + sizeAdjust, width - 1,
3805                      height - 2 * (mod + sizeAdjust), round,
3806                      WIDGET_TAB_BOT, false);
3807 
3808         if (notebook && opts.coloredMouseOver && highlight &&
3809             opts.tabMouseOver != TAB_MO_GLOW)
3810             drawHighlight(cr, x + (opts.tabMouseOver == TAB_MO_TOP ?
3811                                    width - 2 : -1),
3812                           y + (firstTab ? moOffset : 1), 2,
3813                           height - (firstTab || lastTab ? moOffset : 1),
3814                           nullptr, false, opts.tabMouseOver != TAB_MO_TOP);
3815         break;
3816     }
3817     case GTK_POS_RIGHT: {
3818         /* tabs are on left !!! */
3819         auto round = (active || (firstTab && lastTab) ||
3820                       opts.tabMouseOver == TAB_MO_GLOW ||
3821                       opts.roundAllTabs ? ROUNDED_LEFT :
3822                       firstTab ? ROUNDED_TOPLEFT : lastTab ?
3823                       ROUNDED_BOTTOMLEFT : ROUNDED_NONE);
3824         cairo_save(cr);
3825         qtcClipPath(cr, x, y, width + 4, height, WIDGET_TAB_TOP,
3826                     RADIUS_EXTERNAL, round);
3827         fillTab(cr, style, widget, area, state, col, x + 1,
3828                 y + mod + sizeAdjust, width - 1,
3829                 height - 2 * (mod + sizeAdjust), false, WIDGET_TAB_TOP,
3830                 notebook != nullptr);
3831         cairo_restore(cr);
3832         drawBorder(cr, style, state, area, x, y + sizeAdjust,
3833                    width + 4, height - 2 * sizeAdjust,
3834                    glowMo ? qtcPalette.mouseover : qtcPalette.background,
3835                    round, borderProfile, WIDGET_TAB_TOP, 0);
3836         if (drawOuterGlow) {
3837             if (area) {
3838                 area->x--;
3839                 area->width += 2;
3840             }
3841             drawGlow(cr, area, x - 1, y, width + 5, height,
3842                      round, WIDGET_OTHER);
3843         }
3844         if (notebook && opts.highlightTab && active) {
3845             Cairo::vLine(cr, x + 2, y + 1, height - 2, selCol1, 0.5);
3846             Cairo::vLine(cr, x + 1, y + highlightOffset,
3847                          height - 2 * highlightOffset, selCol1);
3848 
3849             clipArea.x = x;
3850             clipArea.width = highlightBorder;
3851             drawBorder(cr, style, state, &clipArea, x, y,
3852                        width, height, qtcPalette.highlight, ROUNDED_LEFT,
3853                        BORDER_FLAT, WIDGET_OTHER, 0, 3);
3854         }
3855 
3856         if (opts.colorSelTab && notebook && active)
3857             colorTab(cr, x + 1, y + mod + sizeAdjust, width - 1,
3858                      height - 2 * (mod + sizeAdjust), round,
3859                      WIDGET_TAB_TOP, false);
3860 
3861         if (notebook && opts.coloredMouseOver && highlight &&
3862             opts.tabMouseOver != TAB_MO_GLOW)
3863             drawHighlight(cr, x + (opts.tabMouseOver == TAB_MO_TOP ?
3864                                    0 : width - 1),
3865                           y + (firstTab ? moOffset : 1), 2,
3866                           height - (firstTab || lastTab ? moOffset : 1),
3867                           nullptr, false, opts.tabMouseOver == TAB_MO_TOP);
3868         break;
3869     }
3870     }
3871 }
3872 
3873 void
3874 drawToolbarBorders(cairo_t *cr, GtkStateType state, int x, int y, int width,
3875                    int height, bool isActiveWindowMenubar, const char *detail)
3876 {
3877     bool top = false;
3878     bool bottom = false;
3879     bool left = false;
3880     bool right = false;
3881     bool all = oneOf(opts.toolbarBorders, TB_LIGHT_ALL, TB_DARK_ALL);
3882     int border = oneOf(opts.toolbarBorders, TB_DARK, TB_DARK_ALL) ? 3 : 4;
3883     const GdkColor *cols = (isActiveWindowMenubar &&
3884                             (state != GTK_STATE_INSENSITIVE ||
3885                              opts.shadeMenubars != SHADE_NONE) ?
3886                             menuColors(isActiveWindowMenubar) :
3887                             qtcPalette.background);
3888     if (oneOf(detail, "menubar")) {
3889         if (all) {
3890             top = bottom = left = right = true;
3891         } else {
3892             bottom = true;
3893         }
3894     } else if (oneOf(detail, "toolbar")) {
3895         if (all) {
3896             if (width < height) {
3897                 left = right = bottom = true;
3898             } else {
3899                 top = bottom = right = true;
3900             }
3901         } else {
3902             if (width < height) {
3903                 left = right = true;
3904             } else {
3905                 top = bottom = true;
3906             }
3907         }
3908     } else if (oneOf(detail,"dockitem_bin", "handlebox_bin")) {
3909         /* CPD: bit risky - what if only 1 item ??? */
3910         if (all) {
3911             if (width < height) {
3912                 left = right = bottom = true;
3913             } else {
3914                 top = bottom = right = true;
3915             }
3916         } else {
3917             if (width < height) {
3918                 left = right = true;
3919             } else {
3920                 top = bottom = true;
3921             }
3922         }
3923     } else {
3924         /* handle */
3925         if (all) {
3926             if (width < height) {
3927                 /* on horiz toolbar */
3928                 top = bottom = left = true;
3929             } else {
3930                 left = right = top = true;
3931             }
3932         } else {
3933             if (width < height) {
3934                 /* on horiz toolbar */
3935                 top = bottom = true;
3936             } else {
3937                 left = right = true;
3938             }
3939         }
3940     }
3941     if (top) {
3942         Cairo::hLine(cr, x, y, width, cols);
3943     }
3944     if (left) {
3945         Cairo::vLine(cr, x, y, height, cols);
3946     }
3947     if (bottom) {
3948         Cairo::hLine(cr, x, y + height - 1, width, &cols[border]);
3949     }
3950     if (right) {
3951         Cairo::vLine(cr, x + width - 1, y, height, &cols[border]);
3952     }
3953 }
3954 
3955 void
3956 drawListViewHeader(cairo_t *cr, GtkStateType state, const GdkColor *btnColors,
3957                    int bgnd, const QtcRect *area, int x, int y,
3958                    int width, int height)
3959 {
3960     drawBevelGradient(cr, area, x, y, width, height, &btnColors[bgnd],
3961                       true, state == GTK_STATE_ACTIVE || bgnd == 2 || bgnd == 3,
3962                       opts.lvAppearance, WIDGET_LISTVIEW_HEADER);
3963 
3964     if (opts.lvAppearance == APPEARANCE_RAISED) {
3965         Cairo::hLine(cr, x, y + height - 2, width, &qtcPalette.background[4]);
3966     }
3967     Cairo::hLine(cr, x, y + height - 1, width,
3968                  &qtcPalette.background[QTC_STD_BORDER]);
3969 
3970     if (state == GTK_STATE_PRELIGHT && opts.coloredMouseOver) {
3971         drawHighlight(cr, x, y + height - 2, width, 2, area, true, true);
3972     }
3973 
3974 #if GTK_CHECK_VERSION(2, 90, 0) /* Gtk3:TODO !!! */
3975     drawFadedLine(cr, x + width - 2, y + 4, 1, height - 8,
3976                   &btnColors[QTC_STD_BORDER], area, nullptr, true, true, false);
3977     drawFadedLine(cr, x + width - 1, y + 4, 1, height - 8, &btnColors[0],
3978                   area, nullptr, true, true, false);
3979 #else
3980     if (x > 3 && height > 10) {
3981         drawFadedLine(cr, x, y + 4, 1, height - 8, &btnColors[QTC_STD_BORDER],
3982                       area, nullptr, true, true, false);
3983         drawFadedLine(cr, x + 1, y + 4, 1, height - 8, &btnColors[0],
3984                       area, nullptr, true, true, false);
3985     }
3986 #endif
3987 }
3988 
3989 void
3990 drawDefBtnIndicator(cairo_t *cr, GtkStateType state, const GdkColor *btnColors,
3991                     int bgnd, bool sunken, const QtcRect *area, int x, int y,
3992                     int width, int height)
3993 {
3994     if (opts.defBtnIndicator == IND_CORNER) {
3995         int offset = sunken ? 5 : 4;
3996         int etchOffset = opts.buttonEffect != EFFECT_NONE ? 1 : 0;
3997         // TODO: used to be switching between focus and highlight
3998         const GdkColor *cols = qtcPalette.focus;
3999         const GdkColor *col = &cols[state == GTK_STATE_ACTIVE ? 0 : 4];
4000 
4001         cairo_new_path(cr);
4002         Cairo::setColor(cr, col);
4003         cairo_move_to(cr, x + offset + etchOffset, y + offset + etchOffset);
4004         cairo_line_to(cr, x + offset + 6 + etchOffset, y + offset + etchOffset);
4005         cairo_line_to(cr, x + offset + etchOffset, y + offset + 6 + etchOffset);
4006         cairo_fill(cr);
4007     } else if (opts.defBtnIndicator == IND_COLORED && COLORED_BORDER_SIZE > 2) {
4008         // offset needed because of etch
4009         int o = (COLORED_BORDER_SIZE +
4010                  (opts.buttonEffect != EFFECT_NONE ? 1 : 0));
4011         drawBevelGradient(cr, area, x + o, y + o, width - 2 * o,
4012                           height - 2 * o, &btnColors[bgnd], true,
4013                           state == GTK_STATE_ACTIVE, opts.appearance,
4014                           WIDGET_STD_BUTTON);
4015     }
4016 }
4017 
4018 static GdkPixbuf*
4019 scaleOrRef(GdkPixbuf *src, int width, int height)
4020 {
4021     if (gdk_pixbuf_get_width(src) == width &&
4022         gdk_pixbuf_get_height(src) == height) {
4023         return (GdkPixbuf*)g_object_ref(G_OBJECT(src));
4024     } else {
4025         return gdk_pixbuf_scale_simple(src, width, height, GDK_INTERP_BILINEAR);
4026     }
4027 }
4028 
4029 static GdkPixbuf*
4030 setTransparency(const GdkPixbuf *pixbuf, double alpha_percent)
4031 {
4032     QTC_RET_IF_FAIL(pixbuf != nullptr, nullptr);
4033     QTC_RET_IF_FAIL(GDK_IS_PIXBUF(pixbuf), nullptr);
4034     /* Returns a copy of pixbuf with it's non-completely-transparent pixels to
4035        have an alpha level "alpha_percent" of their original value. */
4036     GdkPixbuf *target = gdk_pixbuf_add_alpha (pixbuf, false, 0, 0, 0);
4037     if (alpha_percent == 1.0) {
4038         return target;
4039     } else {
4040         unsigned width = gdk_pixbuf_get_width(target);
4041         unsigned height = gdk_pixbuf_get_height(target);
4042         unsigned rowstride = gdk_pixbuf_get_rowstride(target);
4043         unsigned char *data = gdk_pixbuf_get_pixels(target);
4044         for (unsigned y = 0;y < height;y++) {
4045             for (unsigned x = 0;x < width;x++) {
4046                 data[y * rowstride + x * 4 + 3] *= alpha_percent;
4047             }
4048         }
4049     }
4050     return target;
4051 }
4052 
4053 GdkPixbuf*
4054 renderIcon(GtkStyle *style, const GtkIconSource *source, GtkStateType state,
4055            GtkIconSize size, GtkWidget *widget)
4056 {
4057     int width = 1;
4058     int height = 1;
4059     GdkPixbuf *scaled;
4060     GdkPixbuf *stated;
4061     GdkPixbuf *base_pixbuf;
4062     GdkScreen *screen;
4063     GtkSettings *settings;
4064     bool scaleMozilla = (opts.mapKdeIcons && isMozilla() &&
4065                          size == GTK_ICON_SIZE_DIALOG);
4066 
4067     /* Oddly, style can be nullptr in this function, because GtkIconSet can be
4068      * used without a style and if so it uses this function. */
4069     base_pixbuf = gtk_icon_source_get_pixbuf(source);
4070 
4071     QTC_RET_IF_FAIL(base_pixbuf != nullptr, nullptr);
4072 
4073     if (widget && gtk_widget_has_screen(widget)) {
4074         screen = gtk_widget_get_screen(widget);
4075         settings = screen ? gtk_settings_get_for_screen(screen) : nullptr;
4076     }
4077 #if GTK_CHECK_VERSION(2, 90, 0)
4078     else if (style->visual) {
4079         screen = gdk_visual_get_screen(style->visual);
4080         settings = screen ? gtk_settings_get_for_screen(screen) : nullptr;
4081     }
4082 #else
4083     else if(style->colormap) {
4084         screen = gdk_colormap_get_screen(style->colormap);
4085         settings = screen ? gtk_settings_get_for_screen(screen) : nullptr;
4086     }
4087 #endif
4088     else {
4089         settings = gtk_settings_get_default();
4090         GTK_NOTE(MULTIHEAD, g_warning("Using the default screen for "
4091                                       "gtk_default_render_icon()"));
4092     }
4093 
4094     if (scaleMozilla) {
4095         width = height = 48;
4096     } else if (size != (GtkIconSize)-1 &&
4097                !gtk_icon_size_lookup_for_settings(settings, size,
4098                                                   &width, &height)) {
4099         g_warning(G_STRLOC ": invalid icon size '%d'", size);
4100         return nullptr;
4101     }
4102 
4103     /* If the size was wildcarded, and we're allowed to scale, then scale;
4104      * otherwise, leave it alone. */
4105     if (scaleMozilla || (size != (GtkIconSize)-1 &&
4106                          gtk_icon_source_get_size_wildcarded(source))) {
4107         scaled = scaleOrRef(base_pixbuf, width, height);
4108     } else {
4109         scaled = (GdkPixbuf*)g_object_ref(G_OBJECT(base_pixbuf));
4110     }
4111 
4112     /* If the state was wildcarded, then generate a state. */
4113     if (gtk_icon_source_get_state_wildcarded(source)) {
4114         if (state == GTK_STATE_INSENSITIVE) {
4115             stated = setTransparency(scaled, 0.5);
4116             gdk_pixbuf_saturate_and_pixelate(stated, stated, 0.0, false);
4117             g_object_unref(scaled);
4118         }
4119 #if 0 /* KDE does not highlight icons */
4120         else if (state == GTK_STATE_PRELIGHT) {
4121             stated = gdk_pixbuf_copy(scaled);
4122             gdk_pixbuf_saturate_and_pixelate(scaled, stated, 1.2, false);
4123             g_object_unref(scaled);
4124         }
4125 #endif
4126         else {
4127             stated = scaled;
4128         }
4129     } else {
4130         stated = scaled;
4131     }
4132     return stated;
4133 }
4134 
4135 }