File indexing completed on 2024-04-28 09:42:19

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 <qtcurve-utils/color.h>
0026 #include <qtcurve-utils/strs.h>
0027 #include <qtcurve-utils/gtkprops.h>
0028 #include <qtcurve-utils/x11base.h>
0029 #include <qtcurve-cairo/draw.h>
0030 
0031 #include <gmodule.h>
0032 #include <gdk/gdk.h>
0033 #include <gdk/gdkx.h>
0034 #include <cairo.h>
0035 #include "compatability.h"
0036 #include <common/config_file.h>
0037 
0038 #define MO_ARROW(MENU, COL)                             \
0039     (!MENU && MO_NONE != opts.coloredMouseOver &&       \
0040      GTK_STATE_PRELIGHT == state ?                      \
0041      &qtcPalette.mouseover[ARROW_MO_SHADE] : (COL))
0042 
0043 #include "qt_settings.h"
0044 #include "animation.h"
0045 #include "menu.h"
0046 #include "tab.h"
0047 #include "widgetmap.h"
0048 #include "window.h"
0049 #include "entry.h"
0050 #include "treeview.h"
0051 #include "combobox.h"
0052 #include "scrolledwindow.h"
0053 #include "scrollbar.h"
0054 #include "wmmove.h"
0055 #include "helpers.h"
0056 #include "drawing.h"
0057 #include "pixcache.h"
0058 #include "shadowhelper.h"
0059 #include "config.h"
0060 
0061 namespace QtCurve {
0062 
0063 static GType style_type = 0;
0064 static GType rc_style_type = 0;
0065 
0066 struct StyleClass {
0067     GtkStyleClass parent_class;
0068 };
0069 
0070 struct Style {
0071     GtkStyle parent_instance;
0072     GdkColor *button_text[2];
0073     GdkColor *menutext[2];
0074 };
0075 
0076 struct RcStyleClass {
0077     GtkRcStyleClass parent_class;
0078 };
0079 
0080 struct RcStyle {
0081     GtkRcStyle parent_instance;
0082 };
0083 
0084 template<typename T>
0085 static inline bool
0086 isRcStyle(T *object)
0087 {
0088     return G_TYPE_CHECK_INSTANCE_TYPE(object, rc_style_type);
0089 }
0090 
0091 static GtkStyleClass *parent_class = nullptr;
0092 
0093 #ifdef INCREASE_SB_SLIDER
0094 typedef struct {
0095     GtkStyle *style;
0096 #if GTK_CHECK_VERSION(2, 90, 0)
0097     cairo_t *cr;
0098 #else
0099     GdkWindow *window;
0100 #endif
0101     GtkStateType state;
0102     GtkShadowType shadow;
0103     GtkWidget *widget;
0104     const char *detail;
0105     int x;
0106     int y;
0107     int width;
0108     int height;
0109     GtkOrientation orientation;
0110 } QtCSlider;
0111 
0112 static QtCSlider lastSlider;
0113 #endif
0114 
0115 template<typename Widget>
0116 static inline bool
0117 widgetIsType(Widget *widget, const char *name)
0118 {
0119     return oneOf(gTypeName(widget), name);
0120 }
0121 
0122 static void gtkDrawBox(GtkStyle *style, GdkWindow *window, GtkStateType state,
0123                        GtkShadowType shadow, GdkRectangle *area,
0124                        GtkWidget *widget, const char *detail, int x, int y,
0125                        int width, int height);
0126 
0127 static void gtkDrawSlider(GtkStyle *style, GdkWindow *window,
0128                           GtkStateType state, GtkShadowType shadow,
0129                           GdkRectangle *area, GtkWidget *widget,
0130                           const char *detail, int x, int y, int width,
0131                           int height, GtkOrientation orientation);
0132 
0133 static void
0134 gtkLogHandler(const char*, GLogLevelFlags, const char*, void*)
0135 {
0136 }
0137 
0138 static void
0139 gtkDrawFlatBox(GtkStyle *style, GdkWindow *window, GtkStateType state,
0140                GtkShadowType shadow, GdkRectangle *area, GtkWidget *widget,
0141                const char *_detail, int x, int y, int width, int height)
0142 {
0143     QTC_RET_IF_FAIL(GTK_IS_STYLE(style));
0144     QTC_RET_IF_FAIL(GDK_IS_DRAWABLE(window));
0145     const char *detail = _detail ? _detail : "";
0146     cairo_t *cr = Cairo::gdkCreateClip(window, area);
0147 
0148     bool isMenuOrToolTipWindow =
0149         (widget && GTK_IS_WINDOW(widget) &&
0150          ((gtk_widget_get_name(widget) &&
0151            strcmp(gtk_widget_get_name(widget), "gtk-tooltip") == 0) ||
0152           isMenuWindow(widget)));
0153 
0154     if (qtSettings.debug == DEBUG_ALL) {
0155         printf(DEBUG_PREFIX "%s %d %d %d %d %d %d %s  ", __FUNCTION__,
0156                state, shadow, x, y, width, height, _detail);
0157         debugDisplayWidget(widget, 10);
0158     }
0159 
0160     sanitizeSize(window, &width, &height);
0161 
0162     if (!opts.gtkButtonOrder && opts.reorderGtkButtons &&
0163         GTK_IS_WINDOW(widget) && oneOf(detail, "base")) {
0164         GtkWidget *topLevel = gtk_widget_get_toplevel(widget);
0165         GtkWidgetProps topProps(topLevel);
0166 
0167         if (topLevel && GTK_IS_DIALOG(topLevel) &&
0168             !topProps->buttonOrderHacked) {
0169             // gtk_dialog_set_alternative_button_order will cause errors to be
0170             // logged, but dont want these so register our own error handler,
0171             // and then unregister afterwards...
0172             unsigned id = g_log_set_handler("Gtk", G_LOG_LEVEL_CRITICAL,
0173                                             gtkLogHandler, nullptr);
0174             topProps->buttonOrderHacked = true;
0175 
0176             gtk_dialog_set_alternative_button_order(
0177                 GTK_DIALOG(topLevel), GTK_RESPONSE_HELP, GTK_RESPONSE_OK,
0178                 GTK_RESPONSE_YES, GTK_RESPONSE_ACCEPT, GTK_RESPONSE_APPLY,
0179                 GTK_RESPONSE_REJECT, GTK_RESPONSE_CLOSE, GTK_RESPONSE_NO,
0180                 GTK_RESPONSE_CANCEL, -1);
0181             g_log_remove_handler("Gtk", id);
0182         }
0183     }
0184 
0185     if (opts.windowDrag > WM_DRAG_MENU_AND_TOOLBAR &&
0186         oneOf(detail, "base", "eventbox", "viewportbin")) {
0187         WMMove::setup(widget);
0188     }
0189 
0190     if (widget && ((100!=opts.bgndOpacity && GTK_IS_WINDOW(widget)) ||
0191                    (100!=opts.dlgOpacity && GTK_IS_DIALOG(widget))) &&
0192         !isFixedWidget(widget) && isRgbaWidget(widget)) {
0193         enableBlurBehind(widget, true);
0194     }
0195 
0196     if ((opts.menubarHiding || opts.statusbarHiding || BLEND_TITLEBAR ||
0197          opts.windowBorder & WINDOW_BORDER_USE_MENUBAR_COLOR_FOR_TITLEBAR) &&
0198         widget && GTK_IS_WINDOW(widget) && !isFixedWidget(widget) &&
0199         !isGimpDockable(widget) && !isMenuOrToolTipWindow) {
0200         if (Window::setup(widget, GTK_IS_DIALOG(widget) ? opts.dlgOpacity :
0201                           opts.bgndOpacity)) {
0202             GtkWidget *menuBar = Window::getMenuBar(widget, 0);
0203             GtkWidget *statusBar = (opts.statusbarHiding ?
0204                                     Window::getStatusBar(widget, 0) : nullptr);
0205 
0206             if (menuBar) {
0207                 bool hiddenMenubar =
0208                     (opts.menubarHiding ?
0209                      qtcMenuBarHidden(qtSettings.appName) : false);
0210                 QtcRect alloc = Widget::getAllocation(menuBar);
0211 
0212                 if (hiddenMenubar)
0213                     gtk_widget_hide(menuBar);
0214 
0215                 if (BLEND_TITLEBAR || opts.menubarHiding & HIDE_KWIN ||
0216                     opts.windowBorder &
0217                     WINDOW_BORDER_USE_MENUBAR_COLOR_FOR_TITLEBAR) {
0218                     Menu::emitSize(menuBar, hiddenMenubar ? 0 : alloc.height);
0219                 }
0220                 if (opts.menubarHiding&HIDE_KWIN) {
0221                     Window::menuBarDBus(widget,
0222                                         hiddenMenubar ? 0 : alloc.height);
0223                 }
0224             }
0225 
0226 #if GTK_CHECK_VERSION(2, 90, 0)
0227             if(gtk_window_get_has_resize_grip(GTK_WINDOW(widget)))
0228                 gtk_window_set_has_resize_grip(GTK_WINDOW(widget), false);
0229 #else
0230             if(statusBar && gtk_statusbar_get_has_resize_grip(GTK_STATUSBAR(statusBar)))
0231                 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(statusBar), false);
0232 #endif
0233 
0234             if (opts.statusbarHiding && statusBar) {
0235                 bool hiddenStatusBar = qtcStatusBarHidden(qtSettings.appName);
0236                 if (hiddenStatusBar) {
0237                     gtk_widget_hide(statusBar);
0238                 }
0239                 if (opts.statusbarHiding & HIDE_KWIN) {
0240                     Window::statusBarDBus(widget, !hiddenStatusBar);
0241                     Window::setStatusBarProp(widget);
0242                 }
0243             }
0244         }
0245     }
0246 
0247     if (widget && qtcIsCustomBgnd(opts) && oneOf(detail, "base", "eventbox")) {
0248         Scrollbar::setup(widget);
0249     }
0250 
0251     if (qtcIsCustomBgnd(opts) && oneOf(detail, "viewportbin")) {
0252         GtkRcStyle *st = widget ? gtk_widget_get_modifier_style(widget) : nullptr;
0253         // if the app hasn't modified bg, draw background gradient
0254         if (st && !(st->color_flags[state]&GTK_RC_BG)) {
0255             drawWindowBgnd(cr, style, (QtcRect*)area, window, widget,
0256                            x, y, width, height);
0257             Scrollbar::setup(widget);
0258         } else {
0259             parent_class->draw_flat_box(style, window, state, shadow, area,
0260                                         widget, _detail, x, y, width, height);
0261         }
0262     } else if (qtcIsCustomBgnd(opts) && widget && GTK_IS_WINDOW(widget) &&
0263                !isMenuOrToolTipWindow &&
0264                drawWindowBgnd(cr, style, (QtcRect*)area, window, widget,
0265                               x, y, width, height)) {
0266         Window::setup(widget, GTK_IS_DIALOG(widget) ? opts.dlgOpacity :
0267                       opts.bgndOpacity);
0268     } else if (widget && GTK_IS_TREE_VIEW(widget)) {
0269         bool isCombo = isComboBoxPopupWindow(widget, 0);
0270         GtkTreeView *treeView = GTK_TREE_VIEW(widget);
0271         bool checkRules = (opts.forceAlternateLvCols ||
0272                            gtk_tree_view_get_rules_hint(treeView));
0273         bool isEven = checkRules && strstr(detail, "cell_even");
0274 
0275         if (qtSettings.app == GTK_APP_JAVA_SWT)
0276             area = nullptr;
0277 
0278         /* SWT seems to draw a 'cell_even', and then 'cell_odd' at the same position. This causes the view painting
0279          * to be messed up. Try and hack around this... */
0280         if (qtSettings.app == GTK_APP_JAVA_SWT && state == GTK_STATE_SELECTED &&
0281             checkRules && !isCombo && widget) {
0282             static GtkWidget *lastWidget = nullptr;
0283             static int lastEven = -1;
0284 
0285             if (strstr(detail, "cell_even")) {
0286                 lastWidget = widget;
0287                 lastEven = y;
0288             } else if (strstr(detail, "cell_odd")) {
0289                 if (lastWidget == widget) {
0290                     if (y == lastEven) {
0291                         isEven = true;
0292                     }
0293                 }
0294                 lastWidget = nullptr;
0295                 lastEven = -1;
0296             }
0297         }
0298 
0299         if (!isCombo || state != GTK_STATE_SELECTED) {
0300             Cairo::rect(cr, (QtcRect*)area, x, y, width, height,
0301                         getCellCol(haveAlternateListViewCol() &&
0302                                    checkRules && !isEven ?
0303                                    &qtSettings.colors[PAL_ACTIVE][COLOR_LV] :
0304                                    &style->base[GTK_STATE_NORMAL], detail));
0305         }
0306         if (isCombo) {
0307             if (state == GTK_STATE_SELECTED) {
0308                 Cairo::rect(cr, (QtcRect*)area, x, y, width, height,
0309                             &style->base[widget &&
0310                                          gtk_widget_has_focus(widget) ?
0311                                          GTK_STATE_SELECTED :
0312                                          GTK_STATE_ACTIVE]);
0313             }
0314         } else {
0315             double alpha = 1.0;
0316             int selX = x;
0317             int selW = width;
0318             int factor = 0;
0319             bool forceCellStart = false;
0320             bool forceCellEnd = false;
0321 
0322             if (!isFixedWidget(widget)) {
0323                 GtkTreePath *path = nullptr;
0324                 GtkTreeViewColumn *column = nullptr;
0325                 GtkTreeViewColumn *expanderColumn =
0326                     gtk_tree_view_get_expander_column(treeView);
0327                 int levelIndent = 0;
0328                 int expanderSize = 0;
0329                 int depth = 0;
0330 
0331                 TreeView::getCell(treeView, &path, &column,
0332                                   x, y, width, height);
0333                 TreeView::setup(widget);
0334                 if (path && TreeView::isCellHovered(widget, path, column)) {
0335                     if (state == GTK_STATE_SELECTED) {
0336                         factor = 10;
0337                     } else {
0338                         alpha = 0.2;
0339                     }
0340                 }
0341 
0342                 if (column == expanderColumn) {
0343                     gtk_widget_style_get(widget,
0344                                          "expander-size", &expanderSize, nullptr);
0345                     levelIndent = gtk_tree_view_get_level_indentation(treeView),
0346                     depth = path ? (int)gtk_tree_path_get_depth(path) : 0;
0347 
0348                     forceCellStart = true;
0349                     if (opts.lvLines) {
0350                         drawTreeViewLines(cr, &style->mid[GTK_STATE_ACTIVE],
0351                                           x, y, height, depth, levelIndent,
0352                                           expanderSize, treeView, path);
0353                     }
0354                 } else if (column &&
0355                            TreeView::cellIsLeftOfExpanderColumn(treeView,
0356                                                                 column)) {
0357                     forceCellEnd = true;
0358                 }
0359 
0360                 if ((state == GTK_STATE_SELECTED || alpha < 1.0) &&
0361                     column == expanderColumn) {
0362                     int offset = (3 + expanderSize * depth +
0363                                   (4 + levelIndent) * (depth - 1));
0364                     selX += offset;
0365                     selW -= offset;
0366                 }
0367 
0368                 if(path)
0369                     gtk_tree_path_free(path);
0370             }
0371 
0372             if (state == GTK_STATE_SELECTED || alpha < 1.0) {
0373                 auto round = ROUNDED_NONE;
0374                 if (opts.round != ROUND_NONE) {
0375                     if (forceCellStart && forceCellEnd) {
0376                         round = ROUNDED_ALL;
0377                     } else if (forceCellStart || strstr(detail, "_start")) {
0378                         round = ROUNDED_LEFT;
0379                     } else if (forceCellEnd || strstr(detail, "_end")) {
0380                         round = ROUNDED_RIGHT;
0381                     } else if (!strstr(detail, "_middle")) {
0382                         round = ROUNDED_ALL;
0383                     }
0384                 }
0385                 drawSelection(cr, style, state, (QtcRect*)area, widget, selX,
0386                               y, selW, height, round, true, alpha, factor);
0387             }
0388         }
0389     } else if (oneOf(detail, "checkbutton")) {
0390         if (state == GTK_STATE_PRELIGHT && opts.crHighlight &&
0391             width > opts.crSize * 2) {
0392             GdkColor col=shadeColor(&style->bg[state], TO_FACTOR(opts.crHighlight));
0393             drawSelectionGradient(cr, (QtcRect*)area, x, y, width, height,
0394                                   ROUNDED_ALL, false, 1.0, &col, true);
0395         }
0396     } else if (oneOf(detail, "expander")) {
0397         if (state == GTK_STATE_PRELIGHT && opts.expanderHighlight) {
0398             GdkColor col = shadeColor(&style->bg[state],
0399                                       TO_FACTOR(opts.expanderHighlight));
0400             drawSelectionGradient(cr, (QtcRect*)area, x, y, width, height,
0401                                   ROUNDED_ALL, false, 1.0, &col, true);
0402         }
0403     } else if (oneOf(detail, "tooltip")) {
0404         drawToolTip(cr, widget, (QtcRect*)area, x, y, width, height);
0405     } else if (oneOf(detail, "icon_view_item")) {
0406         drawSelection(cr, style, state, (QtcRect*)area, widget, x, y,
0407                       width, height, ROUNDED_ALL, false, 1.0, 0);
0408     } else if (state != GTK_STATE_SELECTED &&
0409                qtcIsCustomBgnd(opts) && oneOf(detail, "eventbox")) {
0410         drawWindowBgnd(cr, style, nullptr, window, widget, x, y, width, height);
0411     } else if (!(qtSettings.app == GTK_APP_JAVA && widget &&
0412                  GTK_IS_LABEL(widget))) {
0413         if (state != GTK_STATE_PRELIGHT || opts.crHighlight ||
0414             noneOf(detail, "checkbutton")) {
0415             parent_class->draw_flat_box(style, window, state, shadow, area,
0416                                         widget, _detail, x, y, width, height);
0417         }
0418 
0419         /* For SWT (e.g. eclipse) apps. For some reason these only seem to allow a ythickness of at max 2 - but
0420            for etching we need 3. So we fake this by drawing the 3rd lines here...*/
0421 
0422 /*
0423         if(DO_EFFECT && GTK_STATE_INSENSITIVE!=state && oneOf(detail, "entry_bg") &&
0424            isSwtComboBoxEntry(widget) && gtk_widget_has_focus(widget))
0425         {
0426             Cairo::hLine(cr, x, y, width,
0427                          &qtcPalette.highlight[FRAME_DARK_SHADOW]);
0428             Cairo::hLine(cr, x, y + height - 1, width,
0429                          &qtcPalette.highlight[0]);
0430         }
0431 */
0432     }
0433     cairo_destroy(cr);
0434 }
0435 
0436 static void
0437 gtkDrawHandle(GtkStyle *style, GdkWindow *window, GtkStateType state,
0438               GtkShadowType shadow, GdkRectangle *_area, GtkWidget *widget,
0439               const char *_detail, int x, int y, int width, int height,
0440               GtkOrientation)
0441 {
0442     QTC_RET_IF_FAIL(GTK_IS_STYLE(style));
0443     QTC_RET_IF_FAIL(GDK_IS_WINDOW(window));
0444     const char *detail = _detail ? _detail : "";
0445     QtcRect *area = (QtcRect*)_area;
0446     bool paf = widgetIsType(widget, "PanelAppletFrame");
0447     cairo_t *cr = Cairo::gdkCreateClip(window, area);
0448 
0449     if (qtSettings.debug == DEBUG_ALL) {
0450         printf(DEBUG_PREFIX "%s %d %d %d %d %s  ", __FUNCTION__, state, shadow,
0451                width, height, _detail);
0452         debugDisplayWidget(widget, 10);
0453     }
0454 
0455     sanitizeSize(window, &width, &height);
0456     if (qtcIsFlatBgnd(opts.bgndAppearance) ||
0457         !(widget && drawWindowBgnd(cr, style, area, window, widget,
0458                                    x, y, width, height))) {
0459         if (widget && opts.bgndImage.type != IMG_NONE) {
0460             drawWindowBgnd(cr, style, area, window, widget,
0461                            x, y, width, height);
0462         }
0463     }
0464 
0465     if (oneOf(detail, "paned") || oneOf(detail + 1, "paned")) {
0466         drawSplitter(cr, state, style, area, x, y, width, height);
0467     } else if ((oneOf(detail, "handlebox") &&
0468                 (qtSettings.app == GTK_APP_JAVA ||
0469                  (widget && GTK_IS_HANDLE_BOX(widget)))) ||
0470                oneOf(detail, "dockitem") || paf) {
0471         /* Note: I'm not sure why the 'widget && GTK_IS_HANDLE_BOX(widget)' is in
0472          * the following 'if' - its been there for a while. But this breaks the
0473          * toolbar handles for Java Swing apps. I'm leaving it in for non Java
0474          * apps, as there must've been a reason for it.... */
0475         if (widget && state != GTK_STATE_INSENSITIVE) {
0476             state = gtk_widget_get_state(widget);
0477         }
0478         if (paf) {
0479             /* The paf here is expected to be on the gnome panel */
0480             if (height < width) {
0481                 y++;
0482             } else {
0483                 x++;
0484             }
0485         } else {
0486             gtkDrawBox(style, window, state, shadow, (GdkRectangle*)area,
0487                        widget, "handlebox", x, y, width, height);
0488         }
0489 
0490         switch (opts.handles) {
0491         case LINE_1DOT:
0492             Cairo::dot(cr, x, y, width, height,
0493                        &qtcPalette.background[QTC_STD_BORDER]);
0494             break;
0495         case LINE_NONE:
0496             break;
0497         case LINE_DOTS:
0498             Cairo::dots(cr, x, y, width, height, height < width, 2, 5,
0499                         area, 2, &qtcPalette.background[5],
0500                         qtcPalette.background);
0501             break;
0502         case LINE_DASHES:
0503             if (height > width) {
0504                 drawLines(cr, x + 3, y, 3, height, true, (height - 8) / 2, 0,
0505                           qtcPalette.background, area, 5, opts.handles);
0506             } else {
0507                 drawLines(cr, x, y + 3, width, 3, false, (width - 8) / 2,
0508                           0, qtcPalette.background, area, 5, opts.handles);
0509             }
0510             break;
0511         case LINE_FLAT:
0512             drawLines(cr, x, y, width, height, height < width, 2, 4,
0513                       qtcPalette.background, area, 4, opts.handles);
0514             break;
0515         default:
0516             drawLines(cr, x, y, width, height, height < width, 2, 4,
0517                       qtcPalette.background, area, 3, opts.handles);
0518         }
0519     }
0520     cairo_destroy(cr);
0521 }
0522 
0523 static void
0524 drawArrow(GdkWindow *window, const GdkColor *col, const QtcRect *area,
0525           GtkArrowType arrow_type, int x, int y, bool small, bool fill)
0526 {
0527     cairo_t *cr = gdk_cairo_create(window);
0528     Cairo::arrow(cr, col, area, arrow_type, x, y, small, fill, opts.vArrows);
0529     cairo_destroy(cr);
0530 }
0531 
0532 static void
0533 gtkDrawArrow(GtkStyle *style, GdkWindow *window, GtkStateType state,
0534              GtkShadowType shadow, GdkRectangle *_area, GtkWidget *widget,
0535              const char *_detail, GtkArrowType arrow_type, gboolean,
0536              int x, int y, int width, int height)
0537 {
0538     QTC_RET_IF_FAIL(GDK_IS_DRAWABLE(window));
0539     const char *detail = _detail ? _detail : "";
0540     if (qtSettings.debug == DEBUG_ALL) {
0541         printf(DEBUG_PREFIX "%s %d %d %d %d %d %d %d %s  ", __FUNCTION__,
0542                state, shadow, arrow_type, x, y, width, height, _detail);
0543         debugDisplayWidget(widget, 10);
0544     }
0545     QtcRect *area = (QtcRect*)_area;
0546     cairo_t *cr = gdk_cairo_create(window);
0547 
0548     if (oneOf(detail, "arrow")) {
0549         bool onComboEntry = isOnComboEntry(widget, 0);
0550 
0551         if (isOnComboBox(widget, 0) && !onComboEntry) {
0552             if (state == GTK_STATE_ACTIVE)
0553                 state = GTK_STATE_PRELIGHT;
0554             const GdkColor *arrowColor =
0555                 MO_ARROW(false,
0556                          &qtSettings.colors[state == GTK_STATE_INSENSITIVE ?
0557                                             PAL_DISABLED : PAL_ACTIVE]
0558                          [COLOR_BUTTON_TEXT]);
0559             x++;
0560             // NOTE: Dont do this for moz - as looks odd fir widgets in
0561             // HTML pages - arrow is shifted too much :-(
0562             if (!(opts.buttonEffect != EFFECT_NONE))
0563                 x += 2;
0564             if (opts.doubleGtkComboArrow) {
0565                 int pad = opts.vArrows ? 0 : 1;
0566                 Cairo::arrow(cr, arrowColor, area, GTK_ARROW_UP, x + width / 2,
0567                              y + height / 2 - (LARGE_ARR_HEIGHT - pad),
0568                              false, true, opts.vArrows);
0569                 Cairo::arrow(cr, arrowColor, area,  GTK_ARROW_DOWN,
0570                              x + width / 2,
0571                              y + height / 2 + (LARGE_ARR_HEIGHT - pad),
0572                              false, true, opts.vArrows);
0573             } else {
0574                 GtkWidget *parent = nullptr;
0575                 if (!opts.gtkComboMenus &&
0576                     !((parent = gtk_widget_get_parent(widget)) &&
0577                       (parent = gtk_widget_get_parent(parent)) &&
0578                       !ComboBox::hasFrame(parent))) {
0579                     x += 2;
0580                 }
0581                 Cairo::arrow(cr, arrowColor, area,  GTK_ARROW_DOWN,
0582                              x + width / 2, y + height / 2, false, true,
0583                              opts.vArrows);
0584             }
0585         } else {
0586             bool combo = onComboEntry || isOnCombo(widget, 0);
0587             int origState = state;
0588 
0589             if (combo && state == GTK_STATE_ACTIVE)
0590                 state = GTK_STATE_PRELIGHT;
0591 
0592             const GdkColor *col =
0593                 (combo || isOnListViewHeader(widget, 0) ||
0594                  isOnButton(widget, 0, nullptr) ?
0595                  &qtSettings.colors[state == GTK_STATE_INSENSITIVE ?
0596                                     PAL_DISABLED :
0597                                     PAL_ACTIVE][COLOR_BUTTON_TEXT] :
0598                  &style->text[ARROW_STATE(state)]);
0599             if (onComboEntry && origState == GTK_STATE_ACTIVE &&
0600                 opts.unifyCombo) {
0601                 x--;
0602                 y--;
0603             }
0604             Cairo::arrow(cr, MO_ARROW(false, col), area, arrow_type,
0605                          x + width / 2, y + height / 2,
0606                          false, true, opts.vArrows);
0607         }
0608     } else {
0609         int isSpinButton = oneOf(detail, "spinbutton");
0610         bool isMenuItem = oneOf(detail, "menuitem");
0611         /* int a_width = LARGE_ARR_WIDTH; */
0612         /* int a_height = LARGE_ARR_HEIGHT; */
0613         bool sbar = isSbarDetail(detail);
0614         bool smallArrows = isSpinButton && !opts.unifySpin;
0615         int stepper = (sbar ? getStepper(widget, x, y, opts.sliderWidth,
0616                                          opts.sliderWidth) : STEPPER_NONE);
0617 
0618         sanitizeSize(window, &width, &height);
0619 
0620         if (isSpinButton)  {
0621             /* if (GTK_ARROW_UP == arrow_type) */
0622             /*     y++; */
0623             /* a_height = SMALL_ARR_HEIGHT; */
0624             /* a_width = SMALL_ARR_WIDTH; */
0625         } else if (oneOf(arrow_type, GTK_ARROW_LEFT, GTK_ARROW_RIGHT) ||
0626                    isMenuItem) {
0627             /* a_width = LARGE_ARR_HEIGHT; */
0628             /* a_height = LARGE_ARR_WIDTH; */
0629             if (isMozilla() && opts.vArrows /* && a_height */ &&
0630                 height < LARGE_ARR_WIDTH) {
0631                 smallArrows = true;
0632             }
0633         }
0634         x += width / 2;
0635         y += height / 2;
0636         if (state == GTK_STATE_ACTIVE && ((sbar && !opts.flatSbarButtons) ||
0637                                           (isSpinButton && !opts.unifySpin))) {
0638             x++;
0639             y++;
0640         }
0641         if (sbar) {
0642             switch (stepper) {
0643             case STEPPER_B:
0644                 if (opts.flatSbarButtons || !opts.vArrows) {
0645                     if (GTK_ARROW_RIGHT == arrow_type) {
0646                         x--;
0647                     } else {
0648                         y--;
0649                     }
0650                 }
0651                 break;
0652             case STEPPER_C:
0653                 if (opts.flatSbarButtons || !opts.vArrows) {
0654                     if (GTK_ARROW_LEFT == arrow_type) {
0655                         x++;
0656                     } else {
0657                         y++;
0658                     }
0659                 }
0660             default:
0661                 break;
0662             }
0663         }
0664 
0665         if (isSpinButton && isFixedWidget(widget) && isFakeGtk()) {
0666             x--;
0667         }
0668         if (isSpinButton && !(opts.buttonEffect != EFFECT_NONE)) {
0669             y += arrow_type == GTK_ARROW_UP ? -1 : 1;
0670         }
0671         if (opts.unifySpin && isSpinButton && !opts.vArrows &&
0672             arrow_type == GTK_ARROW_DOWN) {
0673             y--;
0674         }
0675         if (state == GTK_STATE_ACTIVE && (sbar  || isSpinButton) &&
0676             opts.coloredMouseOver == MO_GLOW) {
0677             state = GTK_STATE_PRELIGHT;
0678         }
0679         if (isMenuItem && arrow_type == GTK_ARROW_RIGHT && !isFakeGtk()) {
0680             x -= 2;
0681         }
0682         const GdkColor *col =
0683             (isSpinButton || sbar ?
0684              &qtSettings.colors[state == GTK_STATE_INSENSITIVE ?
0685                                 PAL_DISABLED : PAL_ACTIVE][COLOR_BUTTON_TEXT] :
0686              &style->text[isMenuItem && state == GTK_STATE_PRELIGHT ?
0687                           GTK_STATE_SELECTED : ARROW_STATE(state)]);
0688         if (isMenuItem && state != GTK_STATE_PRELIGHT && opts.shadePopupMenu) {
0689             if (opts.shadeMenubars == SHADE_WINDOW_BORDER) {
0690                 col = &qtSettings.colors[PAL_ACTIVE][COLOR_WINDOW_BORDER_TEXT];
0691             } else if (opts.customMenuTextColor) {
0692                 col = &opts.customMenuNormTextColor;
0693             } else if (oneOf(opts.shadeMenubars, SHADE_BLEND_SELECTED,
0694                              SHADE_SELECTED) ||
0695                         (opts.shadeMenubars == SHADE_CUSTOM &&
0696                          TOO_DARK(qtcPalette.menubar[ORIGINAL_SHADE]))) {
0697                 col = &style->text[GTK_STATE_SELECTED];
0698             }
0699         }
0700         Cairo::arrow(cr, MO_ARROW(isMenuItem, col), area, arrow_type, x, y,
0701                      smallArrows, true, opts.vArrows);
0702     }
0703     cairo_destroy(cr);
0704 }
0705 
0706 static void
0707 drawBox(GtkStyle *style, GdkWindow *window, GtkStateType state,
0708         GtkShadowType shadow, GdkRectangle *area, GtkWidget *widget,
0709         const char *_detail, int x, int y, int width, int height,
0710         bool btnDown)
0711 {
0712     QTC_RET_IF_FAIL(GTK_IS_STYLE(style));
0713     QTC_RET_IF_FAIL(GDK_IS_DRAWABLE(window));
0714     const char *detail = _detail ? _detail : "";
0715     bool sbar = isSbarDetail(detail);
0716     bool pbar = oneOf(detail, "bar"); //  && GTK_IS_PROGRESS_BAR(widget);
0717     bool qtcSlider = !pbar && oneOf(detail, "qtc-slider");
0718     bool slider = qtcSlider || (!pbar && oneOf(detail, "slider"));
0719     bool hscale = !slider && oneOf(detail, "hscale");
0720     bool vscale = !hscale && oneOf(detail, "vscale");
0721     bool menubar = !vscale && oneOf(detail, "menubar");
0722     bool button = !menubar && oneOf(detail, "button");
0723     bool togglebutton = !button && oneOf(detail, "togglebutton");
0724     bool optionmenu = !togglebutton && oneOf(detail, "optionmenu");
0725     bool stepper = !optionmenu && oneOf(detail, "stepper");
0726     bool vscrollbar = (!optionmenu && Str::startsWith(detail, "vscrollbar"));
0727     bool hscrollbar = (!vscrollbar && Str::startsWith(detail, "hscrollbar"));
0728     bool spinUp = !hscrollbar && oneOf(detail, "spinbutton_up");
0729     bool spinDown = !spinUp && oneOf(detail, "spinbutton_down");
0730     bool menuScroll = strstr(detail, "menu_scroll_arrow_");
0731     bool rev = (reverseLayout(widget) ||
0732                 (widget && reverseLayout(gtk_widget_get_parent(widget))));
0733     bool activeWindow = true;
0734     GdkColor new_cols[TOTAL_SHADES + 1];
0735     const GdkColor *btnColors = qtcPalette.background;
0736     int bgnd = getFill(state, btnDown);
0737     auto round = getRound(detail, widget, rev);
0738     bool lvh = (isListViewHeader(widget) ||
0739                 isEvolutionListViewHeader(widget, detail));
0740     bool sunken = (btnDown || shadow == GTK_SHADOW_IN ||
0741                    state == GTK_STATE_ACTIVE || bgnd == 2 || bgnd == 3);
0742     GtkWidget *parent = nullptr;
0743 
0744     if (button && GTK_IS_TOGGLE_BUTTON(widget)) {
0745         button = false;
0746         togglebutton = true;
0747     }
0748 
0749     if (qtSettings.debug == DEBUG_ALL) {
0750         printf(DEBUG_PREFIX "%s %d %d %d %d %d %d %d %s  ", __FUNCTION__,
0751                btnDown, state, shadow, x, y, width, height, _detail);
0752         debugDisplayWidget(widget, 10);
0753     }
0754 
0755     // FIXME, need to update useButtonColor if the logic below changes right now
0756     if (useButtonColor(detail)) {
0757         if (slider | hscale | vscale | sbar && state == GTK_STATE_INSENSITIVE) {
0758             btnColors = qtcPalette.background;
0759         } else if (QT_CUSTOM_COLOR_BUTTON(style)) {
0760             shadeColors(&style->bg[state], new_cols);
0761             btnColors = new_cols;
0762         } else {
0763             SET_BTN_COLS(slider, hscale | vscale, lvh, state);
0764         }
0765     }
0766 
0767     if (menubar && !isFakeGtk() && opts.shadeMenubarOnlyWhenActive) {
0768         GtkWindow *topLevel = GTK_WINDOW(gtk_widget_get_toplevel(widget));
0769 
0770         if (topLevel && GTK_IS_WINDOW(topLevel)) {
0771             GtkWidgetProps topProps(topLevel);
0772             if (!topProps->shadeActiveMBHacked) {
0773                 topProps->shadeActiveMBHacked = true;
0774                 g_signal_connect(G_OBJECT(topLevel), "event",
0775                                  G_CALLBACK(windowEvent), widget);
0776             }
0777             activeWindow = Window::isActive(GTK_WIDGET(topLevel));
0778         }
0779     }
0780 
0781     if (opts.menubarMouseOver && GTK_IS_MENU_SHELL(widget) && !isFakeGtk()) {
0782         Menu::shellSetup(widget);
0783     }
0784 
0785     cairo_t *cr = Cairo::gdkCreateClip(window, area);
0786     if (spinUp || spinDown) {
0787         if (!opts.unifySpin && (!opts.unifySpinBtns || sunken)) {
0788             EWidget wid = spinUp ? WIDGET_SPIN_UP : WIDGET_SPIN_DOWN;
0789             QtcRect *a = (QtcRect*)area;
0790             QtcRect b;
0791             QtcRect unified;
0792             bool ooOrMoz = isFakeGtk();
0793             if (!a && isFixedWidget(widget) && ooOrMoz) {
0794                 b = qtcRect(x, y, width, height);
0795                 a = &b;
0796             }
0797             if (wid == WIDGET_SPIN_UP) {
0798                 if (opts.buttonEffect != EFFECT_NONE && opts.etchEntry) {
0799                     if (!opts.unifySpinBtns)
0800                         drawEtch(cr, a, widget, x - 2, y, width + 2, height * 2,
0801                                  false, ROUNDED_RIGHT, WIDGET_SPIN_UP);
0802                     y++;
0803                     width--;
0804                 }
0805                 height++;
0806 
0807                 if (opts.unifySpinBtns) {
0808                     unified = qtcRect(x, y, width,
0809                                       height - (state == GTK_STATE_PRELIGHT ?
0810                                                 2 : 1));
0811                     height *= 2;
0812                     area = (GdkRectangle*)&unified;
0813                 } else if (!opts.etchEntry) {
0814                     height++;
0815                 }
0816             } else if (opts.buttonEffect != EFFECT_NONE && opts.etchEntry) {
0817                 QtcRect clip = {x - 2, y, width + 2, height};
0818                 if (!opts.unifySpinBtns) {
0819                     drawEtch(cr, ooOrMoz ? a : &clip, widget, x - 2, y - 2,
0820                              width + 2, height + 2, false,
0821                              ROUNDED_RIGHT, WIDGET_SPIN_DOWN);
0822                 }
0823                 height--;
0824                 width--;
0825                 if (opts.unifySpinBtns) {
0826                     unified = qtcRect(
0827                         x, y + (state == GTK_STATE_PRELIGHT ? 1 : 0),
0828                         width, height - (state == GTK_STATE_PRELIGHT ? 1 : 0));
0829                     y -= height;
0830                     height *= 2;
0831                     area = (GdkRectangle*)&unified;
0832                 }
0833             }
0834 
0835             drawBgnd(cr, &btnColors[bgnd], widget, (QtcRect*)area,
0836                      x + 1, y + 1, width - 2, height - 2);
0837             drawLightBevel(cr, style, state, (QtcRect*)area, x, y, width,
0838                            height - (WIDGET_SPIN_UP == wid &&
0839                                      opts.buttonEffect != EFFECT_NONE ? 1 : 0),
0840                            &btnColors[bgnd], btnColors, round, wid, BORDER_FLAT,
0841                            DF_DO_BORDER | (sunken ? DF_SUNKEN : 0), widget);
0842         }
0843     } else if (oneOf(detail, "spinbutton")) {
0844         if (qtcIsFlatBgnd(opts.bgndAppearance) ||
0845             !(widget && drawWindowBgnd(cr, style, (QtcRect*)area, window,
0846                                        widget, x, y, width, height))) {
0847             gtk_style_apply_default_background(
0848                 style, window, widget && gtk_widget_get_has_window(widget),
0849                 state == GTK_STATE_INSENSITIVE ? GTK_STATE_INSENSITIVE :
0850                 GTK_STATE_NORMAL, area, x, y, width, height);
0851             if (widget && opts.bgndImage.type != IMG_NONE) {
0852                 drawWindowBgnd(cr, style, (QtcRect*)area, window, widget,
0853                                x, y, width, height);
0854             }
0855         }
0856 
0857         if (opts.unifySpin) {
0858             bool rev = (reverseLayout(widget) ||
0859                         (widget &&
0860                          reverseLayout(gtk_widget_get_parent(widget))));
0861             bool moz = isMozillaWidget(widget);
0862             if (!rev) {
0863                 x -= 4;
0864             }
0865             width += 4;
0866 
0867             Cairo::Saver saver(cr);
0868             if (moz) {
0869                 QtcRect a = {x + 2, y, width - 2, height};
0870                 Cairo::clipRect(cr, &a);
0871             }
0872             drawEntryField(cr, style, state, window, widget, (QtcRect*)area,
0873                            x, y, width, height,
0874                            rev ? ROUNDED_LEFT : ROUNDED_RIGHT, WIDGET_SPIN);
0875         } else if (opts.unifySpinBtns) {
0876             int offset = (opts.buttonEffect != EFFECT_NONE && opts.etchEntry ?
0877                           1 : 0);
0878             if (offset) {
0879                 drawEtch(cr, (QtcRect*)area, widget, x, y, width, height, false,
0880                          ROUNDED_RIGHT, WIDGET_SPIN);
0881             }
0882 #if GTK_CHECK_VERSION(2, 90, 0)
0883             bgnd = getFill(state == GTK_STATE_ACTIVE ? GTK_STATE_NORMAL : state,
0884                            false);
0885 #endif
0886             drawLightBevel(cr, style, state, (QtcRect*)area, x, y + offset,
0887                            width - offset, height - 2 * offset,
0888                            &btnColors[bgnd], btnColors, ROUNDED_RIGHT,
0889                            WIDGET_SPIN, BORDER_FLAT,
0890                            DF_DO_BORDER | (sunken ? DF_SUNKEN : 0), widget);
0891             drawFadedLine(cr, x + 2, y + height / 2, width - (offset + 4), 1,
0892                           &btnColors[QTC_STD_BORDER], (QtcRect*)area, nullptr,
0893                           true, true, true);
0894         }
0895     } else if (!opts.stdSidebarButtons && (button || togglebutton) &&
0896                isSideBarBtn(widget)) {
0897         drawSidebarButton(cr, state, style, (QtcRect*)area,
0898                           x, y, width, height);
0899     } else if (lvh) {
0900         if (opts.highlightScrollViews && widget) {
0901             GtkWidget *parent = gtk_widget_get_parent(widget);
0902             if (parent && GTK_IS_TREE_VIEW(parent)) {
0903                 ScrolledWindow::registerChild(parent);
0904             }
0905         }
0906         drawListViewHeader(cr, state, btnColors, bgnd, (QtcRect*)area,
0907                            x, y, width, height);
0908     } else if (isPathButton(widget)) {
0909         if (state == GTK_STATE_PRELIGHT) {
0910             drawSelection(cr, style, state, (QtcRect*)area, widget,
0911                           x, y, width, height, ROUNDED_ALL, false, 1.0, 0);
0912         }
0913         if (opts.windowDrag > WM_DRAG_MENU_AND_TOOLBAR) {
0914             WMMove::setup(widget);
0915         }
0916         if (GTK_IS_TOGGLE_BUTTON(widget)) {
0917             drawArrow(window, &qtcPalette.background[5], (QtcRect*)area,
0918                       GTK_ARROW_RIGHT, x + width - (LARGE_ARR_WIDTH / 2 + 4),
0919                       y + (height - LARGE_ARR_HEIGHT / 2) / 2 + 1, false, true);
0920         }
0921     } else if (button || togglebutton || optionmenu || sbar ||
0922                hscale || vscale || stepper || slider) {
0923         bool combo = oneOf(detail, "optionmenu") || isOnComboBox(widget, 0);
0924         bool combo_entry = combo && isOnComboEntry(widget, 0);
0925         bool horiz_tbar;
0926         bool tbar_button = isButtonOnToolbar(widget, &horiz_tbar);
0927         bool handle_button = (!tbar_button &&
0928                               isButtonOnHandlebox(widget, &horiz_tbar));
0929         int xAdjust = 0;
0930         int yAdjust = 0;
0931         int wAdjust = 0;
0932         int hAdjust = 0;
0933         bool horiz = ((tbar_button || handle_button) &&
0934                       IS_GLASS(opts.appearance) &&
0935                       IS_GLASS(opts.toolbarAppearance) ? horiz_tbar :
0936                       (slider && width < height) || vscrollbar || vscale ||
0937                       (stepper && widget && GTK_IS_VSCROLLBAR(widget)) ?
0938                       false : true);
0939         bool defBtn = (state != GTK_STATE_INSENSITIVE &&
0940                        (button || togglebutton) && widget &&
0941                        gtk_widget_has_default(widget));
0942         if (combo && !sunken && isActiveOptionMenu(widget)) {
0943             sunken = true;
0944             bgnd = 4;
0945         }
0946         if (tbar_button && opts.tbarBtns == TBTN_JOINED) {
0947             adjustToolbarButtons(widget, &xAdjust, &yAdjust, &wAdjust, &hAdjust,
0948                                  &round, horiz_tbar);
0949             x += xAdjust;
0950             y += yAdjust;
0951             width += wAdjust;
0952             height += hAdjust;
0953         }
0954 
0955         {
0956             /* Yuck this is a horrible mess!!!!! */
0957             bool glowFocus = (widget && gtk_widget_has_focus(widget) &&
0958                               opts.coloredMouseOver == MO_GLOW &&
0959                               oneOf(opts.focus, FOCUS_FULL, FOCUS_FILLED));
0960             EWidget widgetType=isComboBoxButton(widget)
0961                                 ? WIDGET_COMBO_BUTTON
0962                                 : slider
0963                                     ? qtcSlider ? WIDGET_SLIDER : WIDGET_SB_SLIDER
0964                                     : hscale||vscale
0965                                         ? WIDGET_SLIDER
0966                                         : combo || optionmenu
0967                                             ? WIDGET_COMBO
0968                                             : tbar_button
0969                                                 ? (opts.coloredTbarMo ? WIDGET_TOOLBAR_BUTTON : WIDGET_UNCOLOURED_MO_BUTTON)
0970                                                 : togglebutton
0971                                                     ? (glowFocus && !sunken ? WIDGET_DEF_BUTTON : WIDGET_TOGGLE_BUTTON)
0972                                                     : button
0973                                                         ? defBtn || glowFocus
0974                                                             ? WIDGET_DEF_BUTTON
0975                                                             : WIDGET_STD_BUTTON
0976                                                         : stepper || sbar
0977                                                             ? WIDGET_SB_BUTTON
0978                                                             : WIDGET_OTHER;
0979             int xo=x, yo=y, wo=width, ho=height, stepper=STEPPER_NONE;
0980 
0981             /* Try and guess if this button is a toolbar button... */
0982             if (oneOf(widgetType, WIDGET_STD_BUTTON, WIDGET_TOGGLE_BUTTON) &&
0983                 isMozillaWidget(widget) && GTK_IS_BUTTON(widget) &&
0984                 oneOf(detail, "button") && ((width > 22 && width < 56 &&
0985                                              height > 30) || height >= 32 ||
0986                                             ((width == 30 || width == 45) &&
0987                                              height == 30)))
0988                 widgetType = (opts.coloredTbarMo ? WIDGET_TOOLBAR_BUTTON :
0989                               WIDGET_UNCOLOURED_MO_BUTTON);
0990 
0991             if (ROUND_MAX==opts.round &&
0992                 ((WIDGET_TOGGLE_BUTTON==widgetType && height>(opts.crSize+8) && width<(height+10)) ||
0993                  (GTK_APP_GIMP==qtSettings.app && WIDGET_STD_BUTTON==widgetType && widgetIsType(widget, "GimpViewableButton")) ||
0994                     (opts.stdSidebarButtons && WIDGET_STD_BUTTON==widgetType && widget && isSideBarBtn(widget)) ||
0995                     (WIDGET_STD_BUTTON==widgetType && GTK_APP_OPEN_OFFICE==qtSettings.app && isFixedWidget(widget) &&
0996                     height>30 && height<40 && width>16 && width<50) ) )
0997                 widgetType=WIDGET_TOOLBAR_BUTTON;
0998 
0999             /* For some reason SWT combo's dont un-prelight when activated! So dont pre-light at all! */
1000 /*
1001             if(GTK_APP_JAVA_SWT==qtSettings.app && WIDGET_STD_BUTTON==widgetType && GTK_STATE_PRELIGHT==state && WIDGET_COMBO==widgetType)
1002             {
1003                 state=GTK_STATE_NORMAL;
1004                 bgnd=getFill(state, btnDown);
1005             }
1006             else */ if(WIDGET_SB_BUTTON==widgetType && GTK_APP_MOZILLA!=qtSettings.app)
1007             {
1008                 stepper = getStepper(widget, x, y, width, height);
1009                 switch (stepper) {
1010                 case STEPPER_B:
1011                     if (horiz) {
1012                         x--;
1013                         width++;
1014                     } else {
1015                         y--;
1016                         height++;
1017                     }
1018                     break;
1019                 case STEPPER_C:
1020                     if (horiz) {
1021                         width++;
1022                     } else {
1023                         height++;
1024                     }
1025                 default:
1026                     break;
1027                 }
1028             }
1029 
1030             if(/*GTK_APP_JAVA_SWT==qtSettings.app && */
1031                 widget && !isFixedWidget(widget) && /* Don't do for Firefox, etc. */
1032                 WIDGET_SB_SLIDER==widgetType && GTK_STATE_INSENSITIVE!=state && GTK_IS_RANGE(widget))
1033             {
1034                 QtcRect alloc = Widget::getAllocation(widget);
1035                 bool horizontal = !Widget::isHorizontal(widget);
1036                 int sbarTroughLen = (horizontal ? alloc.height : alloc.width) -
1037                     ((qtcRangeHasStepperA(widget) ? opts.sliderWidth : 0) +
1038                      (qtcRangeHasStepperB(widget) ? opts.sliderWidth : 0) +
1039                      (qtcRangeHasStepperC(widget) ? opts.sliderWidth : 0) +
1040                      (qtcRangeHasStepperD(widget) ? opts.sliderWidth : 0));
1041                 int sliderLen = horizontal ? height : width;
1042 
1043                 if(sbarTroughLen==sliderLen)
1044                 {
1045                     state=GTK_STATE_INSENSITIVE;
1046                     btnColors=qtcPalette.background;
1047                     bgnd=getFill(state, false);
1048                 }
1049             }
1050 #ifdef INCREASE_SB_SLIDER
1051             if(slider && widget && GTK_IS_RANGE(widget) && !opts.flatSbarButtons && SCROLLBAR_NONE!=opts.scrollbarType
1052                 /*&& !(GTK_STATE_PRELIGHT==state && MO_GLOW==opts.coloredMouseOver)*/)
1053             {
1054                 GtkAdjustment *adj = gtk_range_get_adjustment(GTK_RANGE(widget));
1055                 bool horizontal = Widget::isHorizontal(widget);
1056 #if GTK_CHECK_VERSION(2, 90, 0)
1057                 bool hasStartStepper = SCROLLBAR_PLATINUM!=opts.scrollbarType;
1058                 bool hasEndStepper = SCROLLBAR_NEXT!=opts.scrollbarType;
1059 #else
1060                 bool hasStartStepper = (qtcRangeHasStepperA(widget) ||
1061                                         qtcRangeHasStepperB(widget));
1062                 bool hasEndStepper = (qtcRangeHasStepperC(widget) ||
1063                                       qtcRangeHasStepperD(widget));
1064 #endif
1065                 bool atEnd = false;
1066                 double value = gtk_adjustment_get_value(adj);
1067 
1068                 if (hasStartStepper && value <= gtk_adjustment_get_lower(adj)) {
1069                     if (horizontal) {
1070                         x--;
1071                         width++;
1072                     } else {
1073                         y--;
1074                         height++;
1075                     }
1076                     atEnd = true;
1077                 }
1078                 if (hasEndStepper &&
1079                     value >= (gtk_adjustment_get_upper(adj) -
1080                               gtk_adjustment_get_page_size(adj))) {
1081                     if (horizontal) {
1082                         width++;
1083                     } else {
1084                         height++;
1085                     }
1086                     atEnd = true;
1087                 }
1088                 if (!isMozilla() && widget &&
1089                     lastSlider.widget == widget && !atEnd) {
1090                     lastSlider.widget = nullptr;
1091                 }
1092             }
1093 #endif
1094 
1095 #if !GTK_CHECK_VERSION(2, 90, 0) /* Gtk3:TODO !!! */
1096             if(GTK_APP_OPEN_OFFICE==qtSettings.app && opts.flatSbarButtons && slider &&
1097                 (SCROLLBAR_KDE==opts.scrollbarType || SCROLLBAR_WINDOWS==opts.scrollbarType) &&
1098                 widget && GTK_IS_RANGE(widget) && isFixedWidget(widget)) {
1099                 if (!Widget::isHorizontal(widget)) {
1100                     y++;
1101                     height--;
1102                 } else {
1103                     x += 2;
1104                     width -= 2;
1105                 }
1106             }
1107 #endif
1108             if(WIDGET_COMBO==widgetType && !opts.gtkComboMenus && !isMozilla() &&
1109                 ((parent=gtk_widget_get_parent(widget)) && GTK_IS_COMBO_BOX(parent) && !QTC_COMBO_ENTRY(parent)))
1110             {
1111                 GtkWidget *mapped = nullptr;
1112                 bool changedFocus = false;
1113                 bool draw = true;
1114                 int mod = 7;
1115 
1116                 if (!opts.gtkComboMenus && !ComboBox::hasFrame(parent)) {
1117                     mod = 0;
1118                     draw = oneOf(state, GTK_STATE_ACTIVE, GTK_STATE_PRELIGHT);
1119                     ComboBox::setup(nullptr, parent);
1120                 } else {
1121                     changedFocus = ComboBox::isFocusChanged(widget);
1122                     mapped = WidgetMap::getWidget(parent, 1);
1123                     WidgetMap::setup(parent, widget, 0);
1124 
1125                     if (parent && ComboBox::isHovered(parent)) {
1126                         state = GTK_STATE_PRELIGHT;
1127                     }
1128                 }
1129 
1130                 if (draw)
1131                     drawLightBevel(cr, style, state, (QtcRect*)area, x - mod, y,
1132                                    width + mod, height, &btnColors[bgnd],
1133                                    btnColors, round, WIDGET_TOOLBAR_BUTTON,
1134                                    BORDER_FLAT, (state == GTK_STATE_ACTIVE ?
1135                                                  DF_SUNKEN : 0) | DF_DO_BORDER,
1136                                    widget);
1137 
1138                 if(mapped)
1139                 {
1140                     if(changedFocus)
1141                         gtk_widget_queue_draw(mapped);
1142                     else
1143                     {
1144                         GtkStateType mappedState=gtk_widget_get_state(mapped);
1145                         if(GTK_STATE_INSENSITIVE==state && GTK_STATE_INSENSITIVE!=mappedState)
1146                             state=mappedState;
1147                         if(mappedState!=gtk_widget_get_state(widget) && GTK_STATE_INSENSITIVE!=mappedState && GTK_STATE_INSENSITIVE!=state)
1148                             gtk_widget_set_state(mapped, state);
1149                     }
1150                 }
1151             }
1152             else if(opts.unifyCombo && WIDGET_COMBO_BUTTON==widgetType)
1153             {
1154                 GtkWidget    *parent=widget ? gtk_widget_get_parent(widget) : nullptr;
1155                 GtkWidget    *entry=parent ? getComboEntry(parent) : nullptr;
1156                 GtkStateType entryState=entry ? gtk_widget_get_state(entry) : GTK_STATE_NORMAL;
1157                 bool rev = false;
1158                 bool mozToolbar = (isMozilla() && parent &&
1159                                    GTK_IS_TOGGLE_BUTTON(widget) &&
1160                                    QTC_COMBO_ENTRY(parent) &&
1161                                    (parent = gtk_widget_get_parent(parent)) &&
1162                                    GTK_IS_FIXED(parent) &&
1163                                    (parent = gtk_widget_get_parent(parent)) &&
1164                                    GTK_IS_WINDOW(parent) &&
1165                                    strcmp(gtk_widget_get_name(parent),
1166                                           "MozillaGtkWidget") == 0);
1167 
1168                 if (!entry && widget && gtk_widget_get_parent(widget)) {
1169                     entry = WidgetMap::getWidget(
1170                         gtk_widget_get_parent(widget), 1);
1171                 }
1172 
1173                 if(entry)
1174                     rev=reverseLayout(entry);
1175 
1176                 if(!rev)
1177                     x-=4;
1178                 width+=4;
1179                 if((mozToolbar && state==GTK_STATE_PRELIGHT) || state==GTK_STATE_ACTIVE)
1180                     state=GTK_STATE_NORMAL;
1181 
1182                 // When we draw the entry, if its highlighted we want to highlight this button as well.
1183                 // Unfortunately, when the entry of a GtkComboBoxEntry draws itself, there is no way to
1184                 // determine the button associated with it. So, we store the mapping here...
1185                 if(!mozToolbar && parent && QTC_COMBO_ENTRY(parent))
1186                     WidgetMap::setup(parent, widget, 0);
1187                 // If the button is disabled, but the entry field is not - then use entry field's state
1188                 // for the button. This fixes an issue with LinuxDC++ and Gtk 2.18
1189                 if(GTK_STATE_INSENSITIVE==state && entry && GTK_STATE_INSENSITIVE!=entryState)
1190                     state=entryState;
1191 
1192                 drawEntryField(cr, style, state, window, entry, (QtcRect*)area, x, y, width, height, rev ? ROUNDED_LEFT : ROUNDED_RIGHT, WIDGET_COMBO_BUTTON);
1193 
1194                 // Get entry to redraw by setting its state...
1195                 // ...cant do a queue redraw, as then entry does for the button, else we get stuck in a loop!
1196                 if(!mozToolbar && widget && entry && entryState!=gtk_widget_get_state(widget) && GTK_STATE_INSENSITIVE!=entryState &&
1197                     GTK_STATE_INSENSITIVE!=state)
1198                     gtk_widget_set_state(entry, state);
1199             } else if (opts.flatSbarButtons && WIDGET_SB_BUTTON==widgetType) {
1200 #if !GTK_CHECK_VERSION(2, 90, 0)
1201                 if (isMozilla()) {
1202                     /* This section messes up Gtk3 scrollbars with custom background - and doesnt seem to be required for Gtk2 either. remove at 1.7.1 */
1203                     /* Re-added in 1.7.2 as needed by Mozilla! */
1204                     if(opts.gtkScrollViews && qtcIsFlat(opts.sbarBgndAppearance) && 0!=opts.tabBgnd && widget && gtk_widget_get_parent(widget) && gtk_widget_get_parent(widget)->parent &&
1205                        GTK_IS_SCROLLED_WINDOW(gtk_widget_get_parent(widget)) && GTK_IS_NOTEBOOK(gtk_widget_get_parent(widget)->parent))
1206                         drawAreaModColor(cr, (QtcRect*)area, &qtcPalette.background[ORIGINAL_SHADE], TO_FACTOR(opts.tabBgnd), xo, yo, wo, ho);
1207                     else if(qtcIsFlatBgnd(opts.bgndAppearance) || !(opts.gtkScrollViews && qtcIsFlat(opts.sbarBgndAppearance) &&
1208                                                               widget && drawWindowBgnd(cr, style, (QtcRect*)area, window, widget, xo, yo, wo, ho)))
1209                     {
1210                         if (!qtcIsFlat(opts.sbarBgndAppearance) &&
1211                             opts.scrollbarType != SCROLLBAR_NONE) {
1212                             drawBevelGradient(
1213                                 cr, (QtcRect*)area, xo, yo, wo, ho,
1214                                 &qtcPalette.background[ORIGINAL_SHADE], horiz,
1215                                 false, opts.sbarBgndAppearance, WIDGET_SB_BGND);
1216                         } else {
1217                              drawBgnd(
1218                                  cr, &qtcPalette.background[ORIGINAL_SHADE],
1219                                  widget, (QtcRect*)area, xo, yo, wo, ho);
1220                         }
1221                     }
1222                 }
1223 #endif
1224             } else {
1225                 const GdkColor *cols =
1226                     (defBtn && oneOf(opts.defBtnIndicator, IND_TINT,
1227                                      IND_COLORED, IND_SELECTED) ?
1228                      qtcPalette.defbtn : widgetType == WIDGET_COMBO_BUTTON &&
1229                      qtcPalette.combobtn && state != GTK_STATE_INSENSITIVE ?
1230                      qtcPalette.combobtn : btnColors);
1231                 int bg = (WIDGET_COMBO_BUTTON==widgetType &&
1232                           (SHADE_DARKEN==opts.comboBtn ||
1233                            (SHADE_NONE != opts.comboBtn && GTK_STATE_INSENSITIVE==state))) ||
1234                             (WIDGET_SB_SLIDER==widgetType && SHADE_DARKEN==opts.shadeSliders) ||
1235                             (defBtn && IND_DARKEN==opts.defBtnIndicator)
1236                                 ? getFill(state, btnDown, true) : bgnd;
1237 
1238                 drawLightBevel(cr, style, state, (QtcRect*)area, x, y, width,
1239                                height, &cols[bg], cols, round, widgetType,
1240                                BORDER_FLAT, (sunken ? DF_SUNKEN : 0) |
1241                                DF_DO_BORDER | (horiz ? 0 : DF_VERT), widget);
1242 
1243                 if(tbar_button && TBTN_JOINED==opts.tbarBtns)
1244                 {
1245                     const int constSpace=4;
1246                     int xo=x-xAdjust, yo=y-yAdjust, wo=width-wAdjust, ho=height-hAdjust;
1247 
1248                     if(xAdjust)
1249                         drawFadedLine(cr, xo, yo + constSpace, 1,
1250                                       ho - 2 * constSpace, &btnColors[0],
1251                                       (QtcRect*)area, nullptr, true, true, false);
1252                     if (yAdjust)
1253                         drawFadedLine(cr, xo + constSpace, yo,
1254                                       wo - 2 * constSpace, 1, &btnColors[0],
1255                                       (QtcRect*)area, nullptr, true, true, true);
1256                     if(wAdjust && ROUNDED_RIGHT!=round)
1257                         drawFadedLine(cr, xo + wo - 1, yo + constSpace, 1,
1258                                       ho - 2 * constSpace,
1259                                       &btnColors[QTC_STD_BORDER],
1260                                       (QtcRect*)area, nullptr, true, true, false);
1261                     if (hAdjust && ROUNDED_BOTTOM!=round)
1262                         drawFadedLine(cr, xo + constSpace, yo + ho - 1,
1263                                       wo - 2 * constSpace, 1,
1264                                       &btnColors[QTC_STD_BORDER],
1265                                       (QtcRect*)area, nullptr, true, true, true);
1266                 }
1267             }
1268 
1269 #ifdef INCREASE_SB_SLIDER
1270             /* Gtk draws slider first, and then the buttons. But if we have a shaded slider, and extend this so that it
1271                 overlaps (by 1 pixel) the buttons, then the top/bottom is vut off if this is shaded...
1272                 So, work-around this by re-drawing the slider here! */
1273             if(!opts.flatSbarButtons && SHADE_NONE!=opts.shadeSliders && SCROLLBAR_NONE!=opts.scrollbarType &&
1274                 WIDGET_SB_BUTTON==widgetType && widget && widget==lastSlider.widget && !isMozilla() &&
1275                 ( (SCROLLBAR_NEXT==opts.scrollbarType && STEPPER_B==stepper) || STEPPER_D==stepper))
1276             {
1277 #if GTK_CHECK_VERSION(2, 90, 0)
1278                 gtkDrawSlider(lastSlider.style, lastSlider.cr, lastSlider.state, lastSlider.shadow, lastSlider.widget,
1279                                 lastSlider.detail, lastSlider.x, lastSlider.y, lastSlider.width, lastSlider.height, lastSlider.orientation);
1280 #else
1281                 gtkDrawSlider(lastSlider.style, lastSlider.window, lastSlider.state, lastSlider.shadow, nullptr, lastSlider.widget,
1282                                 lastSlider.detail, lastSlider.x, lastSlider.y, lastSlider.width, lastSlider.height, lastSlider.orientation);
1283 #endif
1284                 lastSlider.widget=nullptr;
1285             }
1286 #endif
1287         }
1288         if (defBtn) {
1289             drawDefBtnIndicator(cr, state, btnColors, bgnd, sunken,
1290                                 (QtcRect*)area, x, y, width, height);
1291         }
1292         if (opts.comboSplitter || opts.comboBtn != SHADE_NONE) {
1293             if (optionmenu) {
1294                 GtkRequisition indicator_size;
1295                 GtkBorder      indicator_spacing;
1296                 int            cx=x, cy=y, cheight=height, cwidth=width,
1297                                ind_width=0,
1298                                darkLine=BORDER_VAL(GTK_STATE_INSENSITIVE!=state);
1299 
1300                 optionMenuGetProps(widget, &indicator_size, &indicator_spacing);
1301 
1302                 ind_width=indicator_size.width+indicator_spacing.left+indicator_spacing.right;
1303 
1304                 if (opts.buttonEffect != EFFECT_NONE)
1305                     cx--;
1306 
1307                 cy+=3;
1308                 cheight-=6;
1309 
1310                 if (opts.comboBtn != SHADE_NONE) {
1311                     const GdkColor *cols = (qtcPalette.combobtn &&
1312                                             state != GTK_STATE_INSENSITIVE ?
1313                                             qtcPalette.combobtn : btnColors);
1314                     int bg = SHADE_DARKEN==opts.comboBtn || (GTK_STATE_INSENSITIVE==state && SHADE_NONE!=opts.comboBtn) ? getFill(state, btnDown, true) : bgnd;
1315 
1316                     QtcRect btn = {
1317                         cx + (rev ? ind_width + style->xthickness :
1318                               (cwidth - ind_width - style->xthickness) + 1),
1319                         y, ind_width + 3, height
1320                     };
1321                     Cairo::Saver saver(cr);
1322                     if (!opts.comboSplitter) {
1323                         Cairo::clipRect(cr, &btn);
1324                     }
1325                     if (rev) {
1326                         btn.width += 3;
1327                     } else {
1328                         btn.x -= 3;
1329                         if (opts.buttonEffect != EFFECT_NONE) {
1330                             btn.width += 3;
1331                         } else {
1332                             btn.width += 1;
1333                         }
1334                     }
1335                     drawLightBevel(cr, style, state, (QtcRect*)area,
1336                                    btn.x, btn.y, btn.width, btn.height,
1337                                    &cols[bg], cols,
1338                                    rev ? ROUNDED_LEFT : ROUNDED_RIGHT,
1339                                    WIDGET_COMBO, BORDER_FLAT,
1340                                    (sunken ? DF_SUNKEN : 0) | DF_DO_BORDER |
1341                                    DF_HIDE_EFFECT, widget);
1342                 } else if (opts.comboSplitter) {
1343                     if(sunken)
1344                         cx++, cy++, cheight--;
1345 
1346                     drawFadedLine(
1347                         cr, cx + (rev ? ind_width + style->xthickness :
1348                                   cwidth - ind_width - style->xthickness),
1349                         cy + style->ythickness - 1, 1, cheight - 3,
1350                         &btnColors[darkLine], (QtcRect*)area, nullptr,
1351                         true, true, false);
1352 
1353                     if (!sunken) {
1354                         drawFadedLine(
1355                             cr, cx + 1 + (rev ? ind_width + style->xthickness :
1356                                           cwidth - ind_width -
1357                                           style->xthickness),
1358                             cy + style->ythickness-1, 1, cheight - 3,
1359                             &btnColors[0], (QtcRect*)area, nullptr,
1360                             true, true, false);
1361                     }
1362                 }
1363             } else if((button || togglebutton) && (combo || combo_entry)) {
1364                 int vx = x + (width - (1 + (combo_entry ? 24 : 20)));
1365                 /* int vwidth = width - (vx - x); */
1366                 int darkLine = BORDER_VAL(GTK_STATE_INSENSITIVE != state);
1367 
1368                 if (rev) {
1369                     vx = x + LARGE_ARR_WIDTH;
1370                     if (combo_entry) {
1371                         vx += 2;
1372                     }
1373                 }
1374 
1375                 if (opts.buttonEffect != EFFECT_NONE)
1376                     vx -= 2;
1377 
1378                 if (!combo_entry) {
1379                     if (opts.comboBtn != SHADE_NONE) {
1380                         const GdkColor *cols =
1381                             (qtcPalette.combobtn &&
1382                              state != GTK_STATE_INSENSITIVE ?
1383                              qtcPalette.combobtn : btnColors);
1384                         int bg = SHADE_DARKEN==opts.comboBtn ||
1385                             (GTK_STATE_INSENSITIVE==state && SHADE_NONE!=opts.comboBtn) ? getFill(state, btnDown, true) : bgnd;
1386 
1387                         QtcRect btn = {
1388                             vx + (rev ? LARGE_ARR_WIDTH + 4 : 0),
1389                             y, 20 + 3, height
1390                         };
1391                         Cairo::Saver saver(cr);
1392                         if (!opts.comboSplitter) {
1393                             Cairo::clipRect(cr, &btn);
1394                         }
1395                         if (rev) {
1396                             btn.width += 3;
1397                         } else {
1398                             btn.x -= 3;
1399                             if (opts.buttonEffect != EFFECT_NONE) {
1400                                 btn.width += 3;
1401                             }
1402                         }
1403                         drawLightBevel(cr, style, state, (QtcRect*)area, btn.x, btn.y,
1404                                        btn.width, btn.height, &cols[bg], cols,
1405                                        rev ? ROUNDED_LEFT : ROUNDED_RIGHT,
1406                                        WIDGET_COMBO, BORDER_FLAT,
1407                                        (sunken ? DF_SUNKEN : 0) | DF_DO_BORDER |
1408                                        DF_HIDE_EFFECT, widget);
1409                     } else if (opts.comboSplitter) {
1410                         drawFadedLine(cr, vx + (rev ? LARGE_ARR_WIDTH + 4 : 0),
1411                                       y + 4, 1, height - 8,
1412                                       &btnColors[darkLine], (QtcRect*)area,
1413                                       nullptr, true, true, false);
1414 
1415                         if(!sunken)
1416                             drawFadedLine(cr, vx + 1 +
1417                                           (rev ? LARGE_ARR_WIDTH + 4 : 0),
1418                                           y + 4, 1, height - 8, &btnColors[0],
1419                                           (QtcRect*)area, nullptr,
1420                                           true, true, false);
1421                     }
1422                 }
1423             }
1424         }
1425     } else if (oneOf(detail, "buttondefault", "togglebuttondefault")) {
1426     } else if (widget && (oneOf(detail, "trough") ||
1427                           Str::startsWith(detail, "trough-"))) {
1428         bool list = isList(widget);
1429         bool pbar = list || GTK_IS_PROGRESS_BAR(widget);
1430         bool scale = !pbar && GTK_IS_SCALE(widget);
1431         /* int border = BORDER_VAL(GTK_STATE_INSENSITIVE != state || !scale); */
1432         bool horiz = (GTK_IS_RANGE(widget) ? Widget::isHorizontal(widget) :
1433                       width > height);
1434 
1435         if (scale) {
1436             drawSliderGroove(cr, style, state, widget, detail, (QtcRect*)area,
1437                              x, y, width, height, horiz);
1438         } else if (pbar) {
1439             drawProgressGroove(cr, style, state, window, widget, (QtcRect*)area,
1440                                x, y, width, height, list, horiz);
1441         } else {
1442             drawScrollbarGroove(cr, style, state, widget, (QtcRect*)area,
1443                                 x, y, width, height, horiz);
1444         }
1445     } else if (oneOf(detail, "entry-progress")) {
1446         int adjust = (opts.fillProgress ? 4 : 3) - (opts.etchEntry ? 1 : 0);
1447         drawProgress(cr, style, state, widget, (QtcRect*)area, x - adjust,
1448                      y - adjust, width + adjust, height + 2 * adjust,
1449                      rev, true);
1450     } else if (oneOf(detail, "dockitem", "dockitem_bin")) {
1451         if (qtcIsCustomBgnd(opts) && widget) {
1452             drawWindowBgnd(cr, style, (QtcRect*)area, window, widget,
1453                            x, y, width, height);
1454         }
1455     } else if (widget && ((menubar || oneOf(detail, "toolbar", "handlebox",
1456                                             "handlebox_bin")) ||
1457                           widgetIsType(widget, "PanelAppletFrame"))) {
1458         //if(GTK_SHADOW_NONE!=shadow)
1459         {
1460             const GdkColor *col = menubar && (GTK_STATE_INSENSITIVE!=state || SHADE_NONE!=opts.shadeMenubars)
1461                                 ? &menuColors(activeWindow)[ORIGINAL_SHADE]
1462                                 : &style->bg[state];
1463             EAppearance app=menubar ? opts.menubarAppearance : opts.toolbarAppearance;
1464             int         menuBarAdjust=0,
1465                         opacity=getOpacity(widget);
1466             double      alpha=opacity!=100 ? (opacity/100.00) : 1.0;
1467             bool drawGradient = shadow != GTK_SHADOW_NONE && !qtcIsFlat(app);
1468             bool fillBackground = menubar && opts.shadeMenubars != SHADE_NONE;
1469 
1470             if ((menubar && opts.windowDrag) ||
1471                 opts.windowDrag > WM_DRAG_MENUBAR) {
1472                 WMMove::setup(widget);
1473             }
1474 
1475             if (menubar && BLEND_TITLEBAR) {
1476                 menuBarAdjust = qtcGetWindowBorderSize(false).titleHeight;
1477                 if (widget && Menu::emitSize(widget, height) &&
1478                     (opts.menubarHiding ||
1479                      opts.windowBorder &
1480                      WINDOW_BORDER_USE_MENUBAR_COLOR_FOR_TITLEBAR)) {
1481                     Window::menuBarDBus(widget, height);
1482                 }
1483             }
1484 
1485             if (widget && (opacity!=100 || qtcIsCustomBgnd(opts))) {
1486                 drawWindowBgnd(cr, style, (QtcRect*)area, window, widget,
1487                                x, y, width, height);
1488             }
1489             if (drawGradient) {
1490                 drawBevelGradient(cr, (QtcRect*)area, x, y - menuBarAdjust, width,
1491                                   height + menuBarAdjust, col,
1492                                   (menubar ? true : oneOf(detail, "handlebox") ?
1493                                    width < height : width > height),
1494                                   false, MODIFY_AGUA(app), WIDGET_OTHER, alpha);
1495             } else if (fillBackground) {
1496                 Cairo::rect(cr, (QtcRect*)area, x, y, width, height,
1497                             col, alpha);
1498             }
1499             if (shadow != GTK_SHADOW_NONE && opts.toolbarBorders != TB_NONE) {
1500                 drawToolbarBorders(cr, state, x, y, width, height,
1501                                    menubar && activeWindow, detail);
1502             }
1503         }
1504     } else if (widget && pbar) {
1505         drawProgress(cr, style, state, widget, (QtcRect*)area,
1506                      x, y, width, height, rev, false);
1507     } else if (oneOf(detail, "menuitem")) {
1508         drawMenuItem(cr, state, style, widget, (QtcRect*)area,
1509                      x, y, width, height);
1510     } else if (oneOf(detail, "menu")) {
1511         drawMenu(cr, widget, (QtcRect*)area, x, y, width, height);
1512     } else if ((!strcmp(detail, "paned") || !strcmp(detail + 1, "paned"))) {
1513         gtkDrawHandle(style, window, state, shadow, area, widget, detail,
1514                       x, y, width, height,
1515                       *detail == 'h' ? GTK_ORIENTATION_VERTICAL :
1516                       GTK_ORIENTATION_HORIZONTAL);
1517     } else if (strcmp(detail + 1, "ruler") == 0) {
1518         drawBevelGradient(cr, (QtcRect*)area, x, y, width, height,
1519                           &qtcPalette.background[ORIGINAL_SHADE],
1520                           detail[0] == 'h', false, opts.lvAppearance,
1521                           WIDGET_LISTVIEW_HEADER);
1522 
1523 //        if(qtcIsFlatBgnd(opts.bgndAppearance) || !widget || !drawWindowBgnd(cr, style, area, widget, x, y, width, height))
1524 //        {
1525 //             drawAreaColor(cr, area, &style->bg[state], x, y, width, height);
1526 //             if(widget && IMG_NONE!=opts.bgndImage.type)
1527 //                 drawWindowBgnd(cr, style, area, widget, x, y, width, height);
1528 //        }
1529     } else if (oneOf(detail, "hseparator")) {
1530         bool isMenuItem = widget && GTK_IS_MENU_ITEM(widget);
1531         const GdkColor *cols=qtcPalette.background;
1532         int offset=opts.menuStripe && (isMozilla() || isMenuItem) ? 20 : 0;
1533 
1534         if(offset && isFakeGtk())
1535             offset+=2;
1536 
1537         if (isMenuItem && (opts.lighterPopupMenuBgnd || opts.shadePopupMenu)) {
1538             cols = qtcPalette.menu;
1539         }
1540 
1541         drawFadedLine(cr, x + 1 + offset, y + height / 2, width - (1 + offset),
1542                       1, &cols[isMenuItem ? MENU_SEP_SHADE : QTC_STD_BORDER],
1543                       (QtcRect*)area, nullptr, true, true, true);
1544     } else if (oneOf(detail, "vseparator")) {
1545         drawFadedLine(cr, x + width / 2, y, 1, height,
1546                       &qtcPalette.background[QTC_STD_BORDER], (QtcRect*)area,
1547                       nullptr, true, true, false);
1548     } else {
1549         EWidget wt = (!_detail && GTK_IS_TREE_VIEW(widget) ?
1550                       WIDGET_PBAR_TROUGH : WIDGET_FRAME);
1551         Cairo::Saver saver(cr);
1552         qtcClipPath(cr, x + 1, y + 1, width - 2, height - 2,
1553                     WIDGET_OTHER, RADIUS_INTERNAL, round);
1554         if (qtcIsFlatBgnd(opts.bgndAppearance) || !widget ||
1555             !drawWindowBgnd(cr, style, (QtcRect*)area, window, widget,
1556                             x + 1, y + 1, width - 2, height - 2)) {
1557             Cairo::rect(cr, (QtcRect*)area, x + 1, y + 1,
1558                         width - 2, height - 2, &style->bg[state]);
1559             if (widget && opts.bgndImage.type != IMG_NONE) {
1560                 drawWindowBgnd(cr, style, (QtcRect*)area, window, widget, x, y,
1561                                width, height);
1562             }
1563         }
1564         saver.restore();
1565 
1566         if (wt == WIDGET_PBAR_TROUGH) {
1567             drawProgressGroove(cr, style, state, window, widget,
1568                                (QtcRect*)area, x, y, width, height, true, true);
1569         } else {
1570             drawBorder(cr, style, state, (QtcRect*)area, x, y, width, height,
1571                        nullptr, (menuScroll || opts.square & SQUARE_FRAME ?
1572                               ROUNDED_NONE : ROUNDED_ALL),
1573                        shadowToBorder(shadow), wt, QTC_STD_BORDER);
1574         }
1575     }
1576     cairo_destroy(cr);
1577 }
1578 
1579 static void
1580 gtkDrawBox(GtkStyle *style, GdkWindow *window, GtkStateType state,
1581            GtkShadowType shadow, GdkRectangle *area, GtkWidget *widget,
1582            const char *detail, int x, int y, int width, int height)
1583 {
1584     sanitizeSize(window, &width, &height);
1585     drawBox(style, window, state, shadow, area, widget, detail, x, y,
1586             width, height,
1587             state == GTK_STATE_ACTIVE || shadow == GTK_SHADOW_IN);
1588 }
1589 
1590 static void
1591 gtkDrawShadow(GtkStyle *style, GdkWindow *window, GtkStateType state,
1592               GtkShadowType shadow, GdkRectangle *area, GtkWidget *widget,
1593               const char *_detail, int x, int y, int width, int height)
1594 {
1595     QTC_RET_IF_FAIL(GTK_IS_STYLE(style));
1596     QTC_RET_IF_FAIL(GDK_IS_DRAWABLE(window));
1597     const char *detail = _detail ? _detail : "";
1598     sanitizeSize(window, &width, &height);
1599     cairo_t *cr = Cairo::gdkCreateClip(window, area);
1600     bool comboBoxList = isComboBoxList(widget);
1601     bool comboList = !comboBoxList && isComboList(widget);
1602 
1603     if (comboBoxList || comboList) {
1604         bool square = opts.square & SQUARE_POPUP_MENUS;
1605 
1606         if ((!square || opts.popupBorder) &&
1607             (!comboList || noneOf(detail, "viewport"))) {
1608             bool nonGtk = square || isFakeGtk();
1609             bool composActive = !nonGtk && compositingActive(widget);
1610             bool isAlphaWidget = (!nonGtk && composActive &&
1611                                   isRgbaWidget(widget));
1612             bool useAlpha = !nonGtk && qtSettings.useAlpha && isAlphaWidget;
1613 
1614             if (opts.popupBorder && square) {
1615                 Cairo::rect(cr, (QtcRect*)area, x, y, width, height,
1616                             &style->base[state]);
1617                 cairo_new_path(cr);
1618                 cairo_rectangle(cr, x + 0.5, y + 0.5, width - 1, height - 1);
1619                 Cairo::setColor(cr, &qtcPalette.background[QTC_STD_BORDER]);
1620                 cairo_stroke(cr);
1621             } else /* if (!opts.popupBorder || */
1622                    /*     !(opts.square & SQUARE_POPUP_MENUS)) */ {
1623                 if (useAlpha) {
1624                     cairo_rectangle(cr, x, y, width, height);
1625                     cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
1626                     cairo_set_source_rgba(cr, 0, 0, 0, 1);
1627                     cairo_fill(cr);
1628                     cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1629                     clearRoundedMask(widget, false);
1630                 } else {
1631                     createRoundedMask(widget, x, y, width, height,
1632                                       opts.round >= ROUND_FULL ? 5.0 : 2.5,
1633                                       false);
1634                 }
1635 
1636                 Cairo::clipWhole(cr, x, y, width, height,
1637                                  opts.round >= ROUND_FULL ? 5.0 : 2.5,
1638                                  ROUNDED_ALL);
1639                 Cairo::rect(cr, (QtcRect*)area, x, y, width, height,
1640                             &style->base[state]);
1641                 if(useAlpha)
1642                     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1643                 if (opts.popupBorder) {
1644                     Cairo::pathWhole(cr, x + 0.5, y + 0.5, width - 1,
1645                                      height - 1, (opts.round >= ROUND_FULL ?
1646                                                   5.0 : 2.5) - 1,
1647                                      ROUNDED_ALL);
1648                     Cairo::setColor(cr,
1649                                      &qtcPalette.background[QTC_STD_BORDER]);
1650                     cairo_stroke(cr);
1651                 }
1652             }
1653         } else {
1654             Cairo::rect(cr, (QtcRect*)area, x, y, width, height,
1655                         &style->base[state]);
1656         }
1657     }
1658     else if(!opts.gtkComboMenus && !isMozilla() && isComboFrame(widget))
1659     {
1660         GdkColor newColors[TOTAL_SHADES + 1];
1661         GdkColor *btnColors;
1662         int bgnd = getFill(state, false); // TODO!!! btnDown???
1663         bool sunken = //btnDown || (GTK_IS_BUTTON(widget) && qtcButtonIsDepressed(widget)) ||
1664             state == GTK_STATE_ACTIVE || oneOf(bgnd, 2, 3);
1665         GtkWidget *parent = gtk_widget_get_parent(widget);
1666         GtkWidget *mapped = parent ? WidgetMap::getWidget(parent, 0) : nullptr;
1667 
1668         if(parent && ComboBox::isHovered(parent))
1669             state=GTK_STATE_PRELIGHT;
1670 
1671         if(QT_CUSTOM_COLOR_BUTTON(style))
1672         {
1673             shadeColors(&style->bg[state], newColors);
1674             btnColors=newColors;
1675         }
1676         else
1677             btnColors=qtcPalette.button[GTK_STATE_INSENSITIVE==state ? PAL_DISABLED : PAL_ACTIVE];
1678 
1679         drawLightBevel(cr, style, state, (QtcRect*)area, x, y, width + 4, height,
1680                        &btnColors[bgnd], btnColors, ROUNDED_LEFT,
1681                        WIDGET_TOOLBAR_BUTTON, BORDER_FLAT,
1682                        (sunken ? DF_SUNKEN : 0) | DF_DO_BORDER |
1683                        (ComboBox::hasFocus(widget, mapped) ? DF_HAS_FOCUS : 0),
1684                        widget);
1685 
1686         if(GTK_STATE_PRELIGHT!=state)
1687         {
1688             if(mapped && GTK_STATE_PRELIGHT==gtk_widget_get_state(mapped))
1689                 state=GTK_STATE_PRELIGHT, gtk_widget_set_state(widget, GTK_STATE_PRELIGHT);
1690         }
1691         if(mapped && GTK_STATE_INSENSITIVE!=gtk_widget_get_state(widget))
1692             gtk_widget_queue_draw(mapped);
1693 
1694         WidgetMap::setup(parent, widget, 1);
1695         ComboBox::setup(widget, parent);
1696     } else if (oneOf(detail, "entry", "text")) {
1697         GtkWidget *parent=widget ? gtk_widget_get_parent(widget) : nullptr;
1698         if (parent && isList(parent)) {
1699             // Dont draw shadow for entries in listviews...
1700             // Fixes RealPlayer's in-line editing of its favourites.
1701         } else {
1702             bool combo = isComboBoxEntry(widget);
1703             bool isSpin = !combo && isSpinButton(widget);
1704             bool rev = reverseLayout(widget) || (combo && parent &&
1705                                                  reverseLayout(parent));
1706             GtkWidget *btn = nullptr;
1707             /* GtkStateType savedState = state; */
1708 
1709 #if GTK_CHECK_VERSION(2, 16, 0)
1710 #if !GTK_CHECK_VERSION(2, 90, 0) /* Gtk3:TODO !!! */
1711             if (isSpin && widget &&
1712                 width == Widget::getAllocation(widget).width) {
1713                 int btnWidth, dummy;
1714                 gdk_drawable_get_size(GTK_SPIN_BUTTON(widget)->panel, &btnWidth, &dummy);
1715                 width-=btnWidth;
1716                 if(rev)
1717                     x+=btnWidth;
1718             }
1719 #endif
1720 #endif
1721             if((opts.unifySpin && isSpin) || (combo && opts.unifyCombo))
1722                 width+=(combo ? 4 : 2);
1723 
1724             // If we're a combo entry, and not prelight, check to see if the button is
1725             // prelighted, if so so are we!
1726             if(GTK_STATE_PRELIGHT!=state && combo && opts.unifyCombo && parent)
1727             {
1728                 btn=getComboButton(parent);
1729                 if (!btn && parent) {
1730                     btn = WidgetMap::getWidget(parent, 0);
1731                 }
1732                 if(btn && GTK_STATE_PRELIGHT==gtk_widget_get_state(btn))
1733                     state=GTK_STATE_PRELIGHT, gtk_widget_set_state(widget, GTK_STATE_PRELIGHT);
1734             }
1735 
1736 #if GTK_CHECK_VERSION(2, 90, 0)
1737             if(!opts.unifySpin && isSpin)
1738                 width-=16;
1739 #endif
1740             drawEntryField(cr, style, state, window, widget, (QtcRect*)area,
1741                            x, y, width, height, combo || isSpin ? rev ?
1742                            ROUNDED_RIGHT : ROUNDED_LEFT : ROUNDED_ALL,
1743                            WIDGET_ENTRY);
1744             if(combo && opts.unifyCombo && parent)
1745             {
1746                 if(btn && GTK_STATE_INSENSITIVE!=gtk_widget_get_state(widget))
1747                     gtk_widget_queue_draw(btn);
1748 
1749                 if (QTC_COMBO_ENTRY(parent)) {
1750                     WidgetMap::setup(parent, widget, 1);
1751                 }
1752             }
1753         }
1754     } else {
1755         bool frame = !_detail || strcmp(detail, "frame") == 0;
1756         bool scrolledWindow = oneOf(detail, "scrolled_window");
1757         bool viewport = !scrolledWindow && strstr(detail, "viewport");
1758         bool drawSquare = ((frame && opts.square & SQUARE_FRAME) ||
1759                            (!viewport && !scrolledWindow &&
1760                             !_detail && !widget));
1761         bool statusBar = (isFakeGtk() ? frame : isStatusBarFrame(widget));
1762         bool checkScrollViewState = (opts.highlightScrollViews && widget &&
1763                                      GTK_IS_SCROLLED_WINDOW(widget));
1764         bool isHovered = false;
1765         bool hasFocus = false;
1766         GdkColor *cols = nullptr;
1767 
1768         if (qtSettings.debug == DEBUG_ALL) {
1769             printf(DEBUG_PREFIX "%s %d %d %d %d %d %d %s  ", __FUNCTION__,
1770                    state, shadow, x, y, width, height, _detail);
1771             debugDisplayWidget(widget, 10);
1772         }
1773 
1774         if(scrolledWindow && GTK_SHADOW_IN!=shadow && widget && GTK_IS_SCROLLED_WINDOW(widget) &&
1775            GTK_IS_TREE_VIEW(gtk_bin_get_child(GTK_BIN(widget))))
1776             gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(widget), GTK_SHADOW_IN), shadow=GTK_SHADOW_IN;
1777         else if(frame && !statusBar && GTK_IS_FRAME(widget))
1778         {
1779             /*
1780             check for scrolled windows embedded in frames, that contain a treeview.
1781             if found, change the shadowtypes for consistency with normal -sunken- scrolled windows.
1782             this should improve rendering of most mandriva drake tools
1783             */
1784             GtkWidget *child=gtk_bin_get_child(GTK_BIN(widget));
1785             if(GTK_IS_SCROLLED_WINDOW(child) && GTK_IS_TREE_VIEW(gtk_bin_get_child(GTK_BIN(child))))
1786             {
1787                 gtk_frame_set_shadow_type(GTK_FRAME(widget), GTK_SHADOW_NONE);
1788                 shadow=GTK_SHADOW_NONE;
1789 
1790                 // also change scrolled window shadow if needed
1791                 GtkScrolledWindow *sw=GTK_SCROLLED_WINDOW(child);
1792                 if(GTK_SHADOW_IN!=gtk_scrolled_window_get_shadow_type(sw))
1793                     gtk_scrolled_window_set_shadow_type(sw, GTK_SHADOW_IN);
1794             }
1795         }
1796 
1797         if (checkScrollViewState) {
1798             ScrolledWindow::setup(widget);
1799             isHovered = ScrolledWindow::hovered(widget);
1800             hasFocus = !isHovered && ScrolledWindow::hasFocus(widget);
1801         }
1802 
1803         cols=isHovered ? qtcPalette.mouseover
1804                        : hasFocus
1805                             ? qtcPalette.focus
1806                             : qtcPalette.background;
1807         if(!statusBar && !drawSquare && (frame || scrolledWindow || viewport/* || drawSquare*/)) // && ROUNDED)
1808         {
1809             if (shadow != GTK_SHADOW_NONE &&
1810                 (!frame || opts.drawStatusBarFrames || !isFakeGtk())) {
1811                 GtkWidget *parent = (widget ? gtk_widget_get_parent(widget) :
1812                                      nullptr);
1813                 bool doBorder = !viewport && !drawSquare;
1814                 bool windowFrame = (parent && !isFixedWidget(widget) &&
1815                                     GTK_IS_FRAME(widget) &&
1816                                     GTK_IS_WINDOW(parent));
1817 
1818                 if (windowFrame) {
1819                     QtcRect wAlloc = Widget::getAllocation(widget);
1820                     QtcRect pAlloc = Widget::getAllocation(parent);
1821                     windowFrame = Rect::equal(wAlloc, pAlloc);
1822                 }
1823 
1824 //                 if(!drawSquare && widget && gtk_widget_get_parent(widget) && !isFixedWidget(widget) &&
1825 //                    GTK_IS_FRAME(widget) && GTK_IS_WINDOW(gtk_widget_get_parent(widget)))
1826 //                     drawSquare=true;
1827 
1828                 if(scrolledWindow)
1829                 {
1830                     /* See code in qt_settings.c as to isMozill part */
1831                     if((opts.square&SQUARE_SCROLLVIEW && !opts.highlightScrollViews) || isMozillaWidget(widget))
1832                     {
1833                         /* Flat style...
1834                         drawBorder(cr, style, state, area, x, y, width, height,
1835                                    nullptr, ROUNDED_NONE, BORDER_FLAT, WIDGET_SCROLLVIEW, 0);
1836                         */
1837                         /* 3d... */
1838                         Cairo::setColor(cr, &cols[QTC_STD_BORDER]);
1839                         Cairo::pathTopLeft(cr, x + 0.5, y + 0.5, width - 1,
1840                                            height - 1, 0.0, ROUNDED_NONE);
1841                         cairo_stroke(cr);
1842                         if(!opts.gtkScrollViews)
1843                             Cairo::setColor(cr, &cols[QTC_STD_BORDER],
1844                                              LOWER_BORDER_ALPHA);
1845                             /* Cairo::setColor(cr, &qtcPalette.background[ */
1846                             /*                      STD_BORDER_BR]); */
1847                         Cairo::pathBottomRight(cr, x + 0.5, y + 0.5, width - 1,
1848                                                height - 1, 0, ROUNDED_NONE);
1849                         cairo_stroke(cr);
1850                         doBorder=false;
1851                     } else if (opts.etchEntry) {
1852                         drawEtch(cr, (QtcRect*)area, widget, x, y, width,
1853                                  height, false, ROUNDED_ALL, WIDGET_SCROLLVIEW);
1854                         x++;
1855                         y++;
1856                         width -= 2;
1857                         height -= 2;
1858                     }
1859                 }
1860                 if (viewport || windowFrame/* || drawSquare*/) {
1861                     cairo_new_path(cr);
1862                     cairo_rectangle(cr, x + 0.5, y + 0.5,
1863                                     width - 1, height - 1);
1864                     if (windowFrame) {
1865                         Cairo::setColor(cr, &cols[QTC_STD_BORDER]);
1866                     } else {
1867                         Cairo::setColor(cr, &cols[ORIGINAL_SHADE]);
1868                     }
1869                     cairo_stroke(cr);
1870                 }
1871                 else if(doBorder)
1872                     drawBorder(cr, style, state, (QtcRect*)area, x, y, width,
1873                                height, cols, ROUNDED_ALL,
1874                                scrolledWindow ? BORDER_SUNKEN : BORDER_FLAT,
1875                                scrolledWindow ? WIDGET_SCROLLVIEW :
1876                                WIDGET_FRAME, DF_BLEND);
1877             }
1878         } else if (!statusBar || opts.drawStatusBarFrames) {
1879             int c1 = 0;
1880             int c2 = 0;
1881 
1882             switch(shadow) {
1883             case GTK_SHADOW_NONE:
1884                 if (!statusBar)
1885                     break;
1886                 shadow = GTK_SHADOW_IN;
1887                 /* FALLTHROUGH */
1888             case GTK_SHADOW_IN:
1889             case GTK_SHADOW_ETCHED_IN:
1890                 c1 = 0;
1891                 c2 = QTC_STD_BORDER;
1892                 break;
1893             case GTK_SHADOW_OUT:
1894             case GTK_SHADOW_ETCHED_OUT:
1895                 c1 = QTC_STD_BORDER;
1896                 c2 = 0;
1897                 break;
1898             }
1899 
1900             switch(shadow) {
1901             case GTK_SHADOW_NONE:
1902                 if (!frame) {
1903                     cairo_new_path(cr);
1904                     cairo_rectangle(cr, x + 0.5, y + 0.5,
1905                                     width - 1, height - 1);
1906                     Cairo::setColor(cr, &cols[QTC_STD_BORDER]);
1907                     cairo_stroke(cr);
1908                 }
1909                 break;
1910             case GTK_SHADOW_IN:
1911             case GTK_SHADOW_OUT:
1912                 // if(drawSquare || frame || !ROUNDED)
1913             {
1914                 double c2Alpha =
1915                     shadow == GTK_SHADOW_IN ? 1.0 : LOWER_BORDER_ALPHA;
1916                 double c1Alpha =
1917                     shadow == GTK_SHADOW_OUT ? 1.0 : LOWER_BORDER_ALPHA;
1918                 Cairo::hLine(cr, x, y, width,
1919                              &cols[QTC_STD_BORDER], c2Alpha);
1920                 Cairo::vLine(cr, x, y, height,
1921                              &cols[QTC_STD_BORDER], c2Alpha);
1922                 if (opts.appearance != APPEARANCE_FLAT) {
1923                     Cairo::hLine(cr, x, y + height - 1, width,
1924                                  &cols[QTC_STD_BORDER], c1Alpha);
1925                     Cairo::vLine(cr, x + width - 1, y, height,
1926                                  &cols[QTC_STD_BORDER], c1Alpha);
1927                 }
1928                 break;
1929             }
1930             case GTK_SHADOW_ETCHED_IN:
1931                 cairo_new_path(cr);
1932                 cairo_rectangle(cr, x + 1.5, y + 1.5, width - 2, height - 2);
1933                 Cairo::setColor(cr, &cols[c1]);
1934                 cairo_stroke(cr);
1935                 cairo_new_path(cr);
1936                 cairo_rectangle(cr, x + 0.5, y + 0.5, width - 2, height - 2);
1937                 Cairo::setColor(cr, &cols[c2]);
1938                 cairo_stroke(cr);
1939                 break;
1940             case GTK_SHADOW_ETCHED_OUT:
1941                 cairo_new_path(cr);
1942                 cairo_rectangle(cr, x + 1.5, y + 1.5, width - 2, height - 2);
1943                 Cairo::setColor(cr, &cols[c2]);
1944                 cairo_stroke(cr);
1945                 cairo_new_path(cr);
1946                 cairo_rectangle(cr, x + 0.5, y + 0.5, width - 2, height - 2);
1947                 Cairo::setColor(cr, &cols[c1]);
1948                 cairo_stroke(cr);
1949                 break;
1950             }
1951         }
1952     }
1953     cairo_destroy(cr);
1954 }
1955 
1956 // static gboolean isHoveredCell(GtkWidget *widget, int x, int y, int width, int height)
1957 // {
1958 //     gboolean hovered=false;
1959 //
1960 //     if(widget && GTK_IS_TREE_VIEW(widget))
1961 //     {
1962 //         GtkTreePath       *path=nullptr;
1963 //         GtkTreeViewColumn *column=nullptr;
1964 //
1965 //         qtcTreeViewSetup(widget);
1966 //         qtcTreeViewGetCell(GTK_TREE_VIEW(widget), &path, &column, x, y, width, height);
1967 //         hovered=path && qtcTreeViewIsCellHovered(widget, path, column);
1968 //     }
1969 //
1970 //     return hovered;
1971 // }
1972 
1973 static void
1974 gtkDrawCheck(GtkStyle *style, GdkWindow *window, GtkStateType state,
1975              GtkShadowType shadow, GdkRectangle *_area, GtkWidget *widget,
1976              const char *_detail, int x, int y, int width, int height)
1977 {
1978     QTC_RET_IF_FAIL(GTK_IS_STYLE(style));
1979     QTC_RET_IF_FAIL(GDK_IS_DRAWABLE(window));
1980     const char *detail = _detail ? _detail : "";
1981     QtcRect *area = (QtcRect*)_area;
1982     cairo_t *cr = Cairo::gdkCreateClip(window, area);
1983     drawCheckBox(cr, state, shadow, style, widget, detail, area,
1984                  x, y, width, height);
1985     cairo_destroy(cr);
1986 }
1987 
1988 static void
1989 gtkDrawOption(GtkStyle *style, GdkWindow *window, GtkStateType state,
1990               GtkShadowType shadow, GdkRectangle *_area, GtkWidget *widget,
1991               const char *_detail, int x, int y, int width, int height)
1992 {
1993     QTC_RET_IF_FAIL(GTK_IS_STYLE(style));
1994     QTC_RET_IF_FAIL(GDK_IS_DRAWABLE(window));
1995     const char *detail = _detail ? _detail : "";
1996     QtcRect *area = (QtcRect*)_area;
1997     cairo_t *cr = Cairo::gdkCreateClip(window, area);
1998     drawRadioButton(cr, state, shadow, style, widget, detail, area,
1999                     x, y, width, height);
2000     cairo_destroy(cr);
2001 }
2002 
2003 #define NUM_GCS 5
2004 
2005 static void
2006 drawLayout(cairo_t *cr, GtkStyle *style, GtkStateType state,
2007            bool use_text, const QtcRect *area, int x, int y,
2008            PangoLayout *layout)
2009 {
2010     Cairo::layout(cr, area, x, y, layout,
2011                   use_text || state == GTK_STATE_INSENSITIVE ?
2012                   &style->text[state] : &style->fg[state]);
2013 }
2014 
2015 static void
2016 gtkDrawLayout(GtkStyle *style, GdkWindow *window, GtkStateType state,
2017               gboolean use_text, GdkRectangle *_area, GtkWidget *widget,
2018               const char *_detail, int x, int y, PangoLayout *layout)
2019 {
2020     QTC_RET_IF_FAIL(GTK_IS_STYLE(style));
2021     QTC_RET_IF_FAIL(GDK_IS_DRAWABLE(window));
2022     const char *detail = _detail ? _detail : "";
2023     const QtcRect *area = (QtcRect*)_area;
2024     cairo_t *cr = gdk_cairo_create(window);
2025     if (GTK_IS_PROGRESS(widget) || oneOf(detail, "progressbar")) {
2026         drawLayout(cr, style, state, use_text, area, x, y, layout);
2027     } else {
2028         Style *qtc_style = (Style*)style;
2029         bool isMenuItem = isMenuitem(widget);
2030         GtkMenuBar *mb = isMenuItem ? isMenubar(widget, 0) : nullptr;
2031         bool activeMb = mb ? GTK_MENU_SHELL(mb)->active : false;
2032         bool selectedText = ((opts.useHighlightForMenu ||
2033                               opts.customMenuTextColor) && isMenuItem &&
2034                              (opts.colorMenubarMouseOver ?
2035                               state == GTK_STATE_PRELIGHT :
2036                               ((!mb || activeMb) &&
2037                                state == GTK_STATE_PRELIGHT)));
2038         bool def_but = false;
2039         bool but = isOnButton(widget, 0, &def_but);
2040         bool swapColors = false;
2041         QtcRect area2;
2042         GtkWidget *parent = widget ? gtk_widget_get_parent(widget) : nullptr;
2043 
2044         if (!opts.colorMenubarMouseOver && mb && !activeMb &&
2045             state == GTK_STATE_PRELIGHT)
2046             state = GTK_STATE_NORMAL;
2047 
2048         GdkColor prevColors[NUM_GCS];
2049 
2050         if (qtSettings.debug == DEBUG_ALL) {
2051             printf(DEBUG_PREFIX "%s %s %d %d %d %d %d %s  ", __FUNCTION__,
2052                    pango_layout_get_text(layout), x, y, state, use_text,
2053                    isMenuitem(widget), _detail);
2054             debugDisplayWidget(widget, 10);
2055         }
2056 
2057         if (oneOf(detail, "cellrenderertext") && widget &&
2058             gtk_widget_get_state(widget) == GTK_STATE_INSENSITIVE)
2059              state = GTK_STATE_INSENSITIVE;
2060 
2061 #ifndef READ_INACTIVE_PAL
2062         /* If we reead the inactive palette, then there is no need for the
2063            following... The following fixes the text in list views...
2064            if not used, when an item is selected it gets the selected text
2065            color - but when the window changes focus it gets the normal
2066            text color! */
2067          if (oneOf(detail, "cellrenderertext") && state == GTK_STATE_ACTIVE)
2068              state = GTK_STATE_SELECTED;
2069 #endif
2070 
2071         if (!isMenuItem && state == GTK_STATE_PRELIGHT)
2072             state = GTK_STATE_NORMAL;
2073 
2074         if (!use_text && parent && GTK_IS_LABEL(widget) &&
2075             (isOnOptionMenu(parent, 0) ||
2076              (GTK_IS_BUTTON(parent) && isOnMenuItem(parent, 0)))) {
2077             use_text = true;
2078         }
2079 
2080         /*
2081            This check of 'requisition' size (and not 'allocation') seems to
2082            match better with Qt4's text positioning. For example, 10pt verdana
2083            - no shift is required 9pt DejaVu Sans requires the shift
2084         */
2085         if (but && widget) {
2086             GtkRequisition req = Widget::getRequisition(widget);
2087             if (req.height < Widget::getAllocation(widget).height &&
2088                 req.height % 2) {
2089                 y++;
2090             }
2091         }
2092 
2093         but = but || isOnComboBox(widget, 0);
2094 
2095         if (isOnListViewHeader(widget, 0))
2096             y--;
2097 
2098         if (but && ((qtSettings.qt4 && state == GTK_STATE_INSENSITIVE) ||
2099                     (!qtSettings.qt4 && state != GTK_STATE_INSENSITIVE))) {
2100             use_text = true;
2101             swapColors = true;
2102             for (int i = 0;i < NUM_GCS;++i) {
2103                 prevColors[i] = style->text[i];
2104                 style->text[i] =
2105                     *qtc_style->button_text[state == GTK_STATE_INSENSITIVE ?
2106                                             PAL_DISABLED : PAL_ACTIVE];
2107             }
2108             if (state == GTK_STATE_INSENSITIVE) {
2109                 state = GTK_STATE_NORMAL;
2110             }
2111         } else if (isMenuItem) {
2112             bool activeWindow =
2113                 (mb && opts.shadeMenubarOnlyWhenActive && widget ?
2114                  Window::isActive(gtk_widget_get_toplevel(widget)) : true);
2115 
2116             if ((opts.shadePopupMenu && state == GTK_STATE_PRELIGHT) ||
2117                 (mb && (activeWindow ||
2118                         opts.shadeMenubars == SHADE_WINDOW_BORDER))) {
2119                 if (opts.shadeMenubars == SHADE_WINDOW_BORDER) {
2120                     for (int i = 0;i < NUM_GCS;i++) {
2121                         prevColors[i] = style->text[i];
2122                     }
2123                     swapColors = true;
2124                     style->text[GTK_STATE_NORMAL] =
2125                         *qtc_style->menutext[activeWindow ? 1 : 0];
2126                     use_text = true;
2127                 } else if (opts.customMenuTextColor &&
2128                            qtc_style->menutext[0]) {
2129                     for (int i = 0;i < NUM_GCS;i++) {
2130                         prevColors[i] = style->text[i];
2131                     }
2132                     swapColors = true;
2133                     style->text[GTK_STATE_NORMAL] = *qtc_style->menutext[0];
2134                     style->text[GTK_STATE_ACTIVE] = *qtc_style->menutext[1];
2135                     style->text[GTK_STATE_PRELIGHT] = *qtc_style->menutext[0];
2136                     style->text[GTK_STATE_SELECTED] = *qtc_style->menutext[1];
2137                     style->text[GTK_STATE_INSENSITIVE] =
2138                         *qtc_style->menutext[0];
2139                     use_text = true;
2140                 } else if (oneOf(opts.shadeMenubars, SHADE_BLEND_SELECTED,
2141                                  SHADE_SELECTED) ||
2142                            (opts.shadeMenubars == SHADE_CUSTOM &&
2143                             TOO_DARK(qtcPalette.menubar[ORIGINAL_SHADE]))) {
2144                     selectedText = true;
2145                 }
2146             }
2147         }
2148 
2149         if (parent && GTK_IS_LABEL(widget) && GTK_IS_FRAME(parent) &&
2150             !isOnStatusBar(widget, 0)) {
2151             int diff = (Widget::getAllocation(widget).x -
2152                         Widget::getAllocation(parent).x);
2153 
2154             if (qtcNoFrame(opts.groupBox)) {
2155                 x -= qtcBound(0, diff, 8);
2156             } else if (opts.gbLabel&GB_LBL_OUTSIDE) {
2157                 x -= qtcBound(0, diff, 4);
2158             } else if(opts.gbLabel&GB_LBL_INSIDE) {
2159                 x -= qtcBound(0, diff, 2);
2160             } else {
2161                 x += 5;
2162             }
2163 #if GTK_CHECK_VERSION(2, 90, 0)
2164             cairo_reset_clip(cr);
2165 #else
2166             if (area) {
2167                 area2 = *area;
2168                 if (qtcNoFrame(opts.groupBox)) {
2169                     area2.x -= qtcBound(0, diff, 8);
2170                 } else if (opts.gbLabel & GB_LBL_OUTSIDE) {
2171                     area2.x -= qtcBound(0, diff, 4);
2172                 } else if(opts.gbLabel&GB_LBL_INSIDE) {
2173                     area2.x -= qtcBound(0, diff, 2);
2174                 } else {
2175                     area2.x += 5;
2176                 }
2177                 area = &area2;
2178             }
2179 #endif
2180         }
2181 
2182         if (!opts.useHighlightForMenu && (isMenuItem || mb) &&
2183             state != GTK_STATE_INSENSITIVE)
2184             state = GTK_STATE_NORMAL;
2185 
2186         drawLayout(cr, style, selectedText ? GTK_STATE_SELECTED : state,
2187                    use_text || selectedText, area, x, y, layout);
2188 
2189         if (opts.embolden && def_but) {
2190             drawLayout(cr, style, selectedText ? GTK_STATE_SELECTED : state,
2191                        use_text || selectedText, area, x + 1, y, layout);
2192         }
2193 
2194         if (swapColors) {
2195             for (int i = 0;i < 5;++i) {
2196                 style->text[i] = prevColors[i];
2197             }
2198         }
2199     }
2200     cairo_destroy(cr);
2201 }
2202 
2203 static GdkPixbuf*
2204 gtkRenderIcon(GtkStyle *style, const GtkIconSource *source,
2205               GtkTextDirection, GtkStateType state, GtkIconSize size,
2206               GtkWidget *widget, const char*)
2207 {
2208     return renderIcon(style, source, state, size, widget);
2209 }
2210 
2211 static void
2212 gtkDrawTab(GtkStyle*, GdkWindow *window, GtkStateType state,
2213            GtkShadowType shadow, GdkRectangle *_area, GtkWidget *widget,
2214            const char *_detail, int x, int y, int width, int height)
2215 {
2216     QTC_RET_IF_FAIL(GDK_IS_DRAWABLE(window));
2217     if (qtSettings.debug == DEBUG_ALL) {
2218         printf(DEBUG_PREFIX "%s %d %d %s  ", __FUNCTION__, state, shadow,
2219                _detail);
2220         debugDisplayWidget(widget, 10);
2221     }
2222     const QtcRect *area = (QtcRect*)_area;
2223     cairo_t *cr = gdk_cairo_create(window);
2224     const GdkColor *arrowColor =
2225         MO_ARROW(false, &qtSettings.colors[state == GTK_STATE_INSENSITIVE ?
2226                                            PAL_DISABLED :
2227                                            PAL_ACTIVE][COLOR_BUTTON_TEXT]);
2228     if (isActiveOptionMenu(widget)) {
2229         x++;
2230         y++;
2231     }
2232     x = (reverseLayout(widget) ||
2233          ((widget = gtk_widget_get_parent(widget)) && reverseLayout(widget)) ?
2234          x + 1 : x + width / 2);
2235     if (opts.doubleGtkComboArrow) {
2236         int pad = opts.vArrows ? 0 : 1;
2237         Cairo::arrow(cr, arrowColor, area,  GTK_ARROW_UP,
2238                      x, y + height / 2 - (LARGE_ARR_HEIGHT - pad),
2239                      false, true, opts.vArrows);
2240         Cairo::arrow(cr, arrowColor, area,  GTK_ARROW_DOWN,
2241                      x, y + height / 2 + (LARGE_ARR_HEIGHT - pad),
2242                      false, true, opts.vArrows);
2243     } else {
2244         Cairo::arrow(cr, arrowColor, area,  GTK_ARROW_DOWN,
2245                      x, y + height / 2, false, true, opts.vArrows);
2246     }
2247     cairo_destroy(cr);
2248 }
2249 
2250 static void
2251 gtkDrawBoxGap(GtkStyle *style, GdkWindow *window, GtkStateType state,
2252               GtkShadowType, GdkRectangle *area, GtkWidget *widget,
2253               const char *_detail, int x, int y, int width, int height,
2254               GtkPositionType gapSide, int gapX, int gapWidth)
2255 {
2256     QTC_RET_IF_FAIL(GTK_IS_STYLE(style));
2257     QTC_RET_IF_FAIL(GDK_IS_DRAWABLE(window));
2258     const char *detail = _detail ? _detail : "";
2259     cairo_t *cr = Cairo::gdkCreateClip(window, area);
2260 
2261     if ((opts.thin & THIN_FRAMES) && gapX == 0) {
2262         gapX--;
2263         gapWidth += 2;
2264     }
2265 
2266     sanitizeSize(window, &width, &height);
2267     drawBoxGap(cr, style, GTK_SHADOW_OUT, state, widget, (QtcRect*)area, x, y,
2268                width, height, gapSide, gapX, gapWidth,
2269                opts.borderTab ? BORDER_LIGHT : BORDER_RAISED, true);
2270 
2271     if (opts.windowDrag > WM_DRAG_MENU_AND_TOOLBAR && oneOf(detail, "notebook")) {
2272         WMMove::setup(widget);
2273     }
2274 
2275     if (!isMozilla())
2276         drawBoxGapFixes(cr, widget, x, y, width, height,
2277                         gapSide, gapX, gapWidth);
2278     cairo_destroy(cr);
2279 }
2280 
2281 static void
2282 gtkDrawExtension(GtkStyle *style, GdkWindow *window, GtkStateType state,
2283                  GtkShadowType shadow, GdkRectangle *_area, GtkWidget *widget,
2284                  const char *_detail, int x, int y, int width, int height,
2285                  GtkPositionType gapSide)
2286 {
2287     QTC_RET_IF_FAIL(GTK_IS_STYLE(style));
2288     QTC_RET_IF_FAIL(GDK_IS_DRAWABLE(window));
2289     const char *detail = _detail ? _detail : "";
2290     if (qtSettings.debug == DEBUG_ALL) {
2291         printf(DEBUG_PREFIX "%s %d %d %d %d %d %d %d %s  ", __FUNCTION__, state,
2292                shadow, gapSide, x, y, width, height, _detail);
2293         debugDisplayWidget(widget, 10);
2294     }
2295     sanitizeSize(window, &width, &height);
2296 
2297     if (oneOf(detail, "tab")) {
2298         QtcRect *area = (QtcRect*)_area;
2299         cairo_t *cr = Cairo::gdkCreateClip(window, area);
2300         drawTab(cr, state, style, widget, area, x, y, width, height, gapSide);
2301         cairo_destroy(cr);
2302     } else {
2303         parent_class->draw_extension(style, window, state, shadow, _area,
2304                                      widget, _detail, x, y, width, height,
2305                                      gapSide);
2306     }
2307 }
2308 
2309 static void
2310 gtkDrawSlider(GtkStyle *style, GdkWindow *window, GtkStateType state,
2311               GtkShadowType shadow, GdkRectangle *area, GtkWidget *widget,
2312               const char *_detail, int x, int y, int width, int height,
2313               GtkOrientation orientation)
2314 {
2315     QTC_RET_IF_FAIL(GTK_IS_STYLE(style));
2316     QTC_RET_IF_FAIL(GDK_IS_DRAWABLE(window));
2317     const char *detail = _detail ? _detail : "";
2318     bool scrollbar = oneOf(detail, "slider");
2319     bool scale = oneOf(detail, "hscale", "vscale");
2320 
2321     if (qtSettings.debug == DEBUG_ALL) {
2322         printf(DEBUG_PREFIX "%s %d %d %d %d %d %d %s  ", __FUNCTION__, state,
2323                shadow, x, y, width, height, _detail);
2324         debugDisplayWidget(widget, 10);
2325     }
2326 
2327     cairo_t *cr = Cairo::gdkCreateClip(window, area);
2328     sanitizeSize(window, &width, &height);
2329 
2330     if (scrollbar || SLIDER_TRIANGULAR!=opts.sliderStyle) {
2331         GdkColor newColors[TOTAL_SHADES + 1];
2332         GdkColor *btnColors = qtcPalette.background;
2333         int min = MIN_SLIDER_SIZE(opts.sliderThumbs);
2334 
2335 #ifdef INCREASE_SB_SLIDER
2336         if (scrollbar)
2337             lastSlider.widget = nullptr;
2338 #endif
2339         /* Fix Java swing sliders looking pressed */
2340         if(!scrollbar && GTK_STATE_ACTIVE==state)
2341             state=GTK_STATE_PRELIGHT;
2342 
2343         // FIXME, need to update useButtonColor if the logic below changes
2344         if (useButtonColor(detail)) {
2345             if(scrollbar|scale && GTK_STATE_INSENSITIVE==state)
2346                 btnColors=qtcPalette.background;
2347             else if(QT_CUSTOM_COLOR_BUTTON(style))
2348             {
2349                 shadeColors(&style->bg[state], newColors);
2350                 btnColors=newColors;
2351             }
2352             else
2353                 SET_BTN_COLS(scrollbar, scale, false, state)
2354         }
2355 
2356 #ifdef INCREASE_SB_SLIDER
2357         if(scrollbar && !opts.flatSbarButtons && SHADE_NONE!=opts.shadeSliders && SCROLLBAR_NONE!=opts.scrollbarType && !isMozilla())
2358         {
2359             lastSlider.style=style;
2360 #if GTK_CHECK_VERSION(2, 90, 0)
2361             lastSlider.cr=cr;
2362 #else
2363             lastSlider.window=window;
2364 #endif
2365             lastSlider.state=state;
2366             lastSlider.shadow=shadow;
2367             lastSlider.widget=widget;
2368             lastSlider.detail=detail;
2369             lastSlider.x=x;
2370             lastSlider.y=y;
2371             lastSlider.width=width;
2372             lastSlider.height=height;
2373             lastSlider.orientation=orientation;
2374         }
2375 #endif
2376 
2377 #if GTK_CHECK_VERSION(2, 90, 0)
2378         if(scrollbar && GTK_STATE_ACTIVE==state)
2379             state=GTK_STATE_PRELIGHT;
2380 #endif
2381 
2382         drawBox(style, window, state, shadow, area, widget,
2383                 !scrollbar ? "qtc-slider" : "slider",
2384                 x, y, width, height, false);
2385 
2386        /* Orientation is always vertical with Mozilla, why? Anyway this hack
2387           should be OK - as we only draw dashes when slider is larger than
2388           'min' pixels... */
2389         orientation = (width < height ? GTK_ORIENTATION_VERTICAL :
2390                        GTK_ORIENTATION_HORIZONTAL);
2391         if (opts.sliderThumbs != LINE_NONE &&
2392             (scrollbar || opts.sliderStyle != SLIDER_CIRCULAR) &&
2393             (scale || ((orientation == GTK_ORIENTATION_HORIZONTAL &&
2394                         width >= min) || height >= min))) {
2395             GdkColor *markers=/*opts.coloredMouseOver && GTK_STATE_PRELIGHT==state
2396                                 ? qtcPalette.mouseover
2397                                 : */btnColors;
2398             bool horiz = orientation == GTK_ORIENTATION_HORIZONTAL;
2399 
2400             if (opts.sliderThumbs == LINE_SUNKEN) {
2401                 if (horiz) {
2402                     y--;
2403                     height++;
2404                 } else {
2405                     x--;
2406                     width++;
2407                 }
2408             } else if (horiz) {
2409                 x++;
2410             } else {
2411                 y++;
2412             }
2413 
2414             switch (opts.sliderThumbs) {
2415             case LINE_1DOT:
2416                 Cairo::dot(cr, x, y, width, height,
2417                            &markers[QTC_STD_BORDER]);
2418                 break;
2419             case LINE_FLAT:
2420                 drawLines(cr, x, y, width, height, !horiz, 3, 5, markers,
2421                           (QtcRect*)area, 5, opts.sliderThumbs);
2422                 break;
2423             case LINE_SUNKEN:
2424                 drawLines(cr, x, y, width, height, !horiz, 4, 3, markers,
2425                           (QtcRect*)area, 3, opts.sliderThumbs);
2426                 break;
2427             default:
2428             case LINE_DOTS:
2429                 Cairo::dots(cr, x, y, width, height, !horiz,
2430                             scale ? 3 : 5, scale ? 4 : 2, (QtcRect*)area,
2431                             0, &markers[5], markers);
2432             }
2433         }
2434     } else {
2435         drawTriangularSlider(cr, style, state, detail, x, y, width, height);
2436     }
2437     cairo_destroy(cr);
2438 }
2439 
2440 static void
2441 gtkDrawShadowGap(GtkStyle *style, GdkWindow *window, GtkStateType state,
2442                  GtkShadowType shadow, GdkRectangle *_area, GtkWidget *widget,
2443                  const char*, int x, int y, int width, int height,
2444                  GtkPositionType gapSide, int gapX, int gapWidth)
2445 {
2446     QTC_RET_IF_FAIL(GTK_IS_STYLE(style));
2447     QTC_RET_IF_FAIL(GDK_IS_DRAWABLE(window));
2448     QtcRect *area = (QtcRect*)_area;
2449     cairo_t *cr = Cairo::gdkCreateClip(window, area);
2450     sanitizeSize(window, &width, &height);
2451     drawShadowGap(cr, style, shadow, state, widget, area, x, y,
2452                   width, height, gapSide, gapX, gapWidth);
2453     cairo_destroy(cr);
2454 }
2455 
2456 static void
2457 gtkDrawHLine(GtkStyle *style, GdkWindow *window, GtkStateType state,
2458              GdkRectangle *area, GtkWidget *widget, const char *_detail,
2459              int x1, int x2, int y)
2460 {
2461     QTC_RET_IF_FAIL(GTK_IS_STYLE(style));
2462     QTC_RET_IF_FAIL(GDK_IS_DRAWABLE(window));
2463     const char *detail = _detail ? _detail : "";
2464     bool tbar = strcmp(detail, "toolbar");
2465     int light = 0;
2466     int dark = tbar ? (opts.toolbarSeparators == LINE_FLAT ? 4 : 3) : 5;
2467 
2468     if (qtSettings.debug == DEBUG_ALL) {
2469         printf(DEBUG_PREFIX "%s %d %d %d %d %s  ", __FUNCTION__, state, x1, x2,
2470                y, _detail);
2471         debugDisplayWidget(widget, 10);
2472     }
2473 
2474     cairo_t *cr = Cairo::gdkCreateClip(window, area);
2475 
2476     if (tbar) {
2477         switch (opts.toolbarSeparators) {
2478             default:
2479             case LINE_DOTS:
2480                 Cairo::dots(cr, x1, y, x2 - x1, 2, false,
2481                             (x2 - x1) / 3.0 + 0.5, 0, (QtcRect*)area, 0,
2482                             &qtcPalette.background[5], qtcPalette.background);
2483                 break;
2484             case LINE_NONE:
2485                 break;
2486             case LINE_FLAT:
2487             case LINE_SUNKEN:
2488             {
2489                 drawFadedLine(cr, x1 < x2 ? x1 : x2, y, abs(x2 - x1), 1,
2490                               &qtcPalette.background[dark], (QtcRect*)area,
2491                               nullptr, true, true, true);
2492                 /* Cairo::hLine(cr, x1 < x2 ? x1 : x2, y, abs(x2 - x1), */
2493                 /*              &qtcPalette.background[dark]); */
2494                 if(LINE_SUNKEN==opts.toolbarSeparators)
2495                 {
2496                     cairo_new_path(cr);
2497                     /* Cairo::hLine(cr, x1 < x2 ? x1 : x2, y + 1, abs(x2 - x1), */
2498                     /*              &qtcPalette.background[light]); */
2499                     drawFadedLine(cr, x1 < x2 ? x1 : x2, y + 1, abs(x2 - x1), 1,
2500                                   &qtcPalette.background[light], (QtcRect*)area,
2501                                   nullptr, true, true, true);
2502                 }
2503             }
2504         }
2505     } else if (oneOf(detail, "label")) {
2506         if (state == GTK_STATE_INSENSITIVE) {
2507             /* Cairo::hLine(cr, (x1 < x2 ? x1 : x2) + 1, y + 1, abs(x2 - x1), */
2508             /*              &qtcPalette.background[light]); */
2509             drawFadedLine(cr, x1 < x2 ? x1 : x2, y + 1, abs(x2 - x1), 1,
2510                           &qtcPalette.background[light], (QtcRect*)area, nullptr,
2511                           true, true, true);
2512         }
2513         /* Cairo::hLine(cr, x1 < x2 ? x1 : x2, y, abs(x2 - x1), */
2514         /*              &style->text[state]); */
2515         drawFadedLine(cr, x1 < x2 ? x1 : x2, y, abs(x2 - x1), 1,
2516                       &qtcPalette.background[dark], (QtcRect*)area, nullptr,
2517                       true, true, true);
2518     } else if (oneOf(detail, "menuitem") ||
2519                (widget && oneOf(detail, "hseparator") && isMenuitem(widget))) {
2520         int       offset=opts.menuStripe && (isMozilla() || (widget && GTK_IS_MENU_ITEM(widget))) ? 20 : 0;
2521         GdkColor *cols=qtcPalette.background;
2522 
2523         if(offset && isFakeGtk())
2524             offset+=2;
2525 
2526         if (opts.lighterPopupMenuBgnd || opts.shadePopupMenu) {
2527             cols = qtcPalette.menu;
2528         }
2529         if (offset && isFakeGtk()) {
2530             offset += 2;
2531         }
2532 
2533         /* Cairo::hLine(cr, x1 < x2 ? x1 : x2, y, abs(x2 - x1), */
2534         /*              &qtcPalette.background[MENU_SEP_SHADE]); */
2535         drawFadedLine(cr, offset + (x1 < x2 ? x1 : x2), y + 1,
2536                       abs(x2 - x1) - offset, 1, &cols[MENU_SEP_SHADE],
2537                       (QtcRect*)area, nullptr, true, true, true);
2538     } else {
2539         /* Cairo::hLine(cr, x1 < x2 ? x1 : x2, y, abs(x2 - x1), */
2540         /*              qtcPalette.background[dark]); */
2541         drawFadedLine(cr, x1 < x2 ? x1 : x2, y, abs(x2 - x1), 1,
2542                       &qtcPalette.background[dark], (QtcRect*)area, nullptr,
2543                       true, true, true);
2544     }
2545 
2546     cairo_destroy(cr);
2547 }
2548 
2549 static void
2550 gtkDrawVLine(GtkStyle *style, GdkWindow *window, GtkStateType state,
2551              GdkRectangle *area, GtkWidget *widget, const char *_detail,
2552              int y1, int y2, int x)
2553 {
2554     QTC_RET_IF_FAIL(GTK_IS_STYLE(style));
2555     QTC_RET_IF_FAIL(GDK_IS_DRAWABLE(window));
2556     const char *detail = _detail ? _detail : "";
2557 
2558     if (qtSettings.debug == DEBUG_ALL) {
2559         printf(DEBUG_PREFIX "%s %d %d %d %d %s  ", __FUNCTION__, state, x, y1,
2560                y2, _detail);
2561         debugDisplayWidget(widget, 10);
2562     }
2563 
2564     cairo_t *cr = Cairo::gdkCreateClip(window, area);
2565 
2566     if (!(oneOf(detail, "vseparator") && isOnComboBox(widget, 0))) {
2567          /* CPD: Combo handled in drawBox */
2568         bool tbar = oneOf(detail, "toolbar");
2569         int dark = tbar ? 3 : 5;
2570         int light = 0;
2571 
2572         if (tbar) {
2573             switch (opts.toolbarSeparators) {
2574             default:
2575             case LINE_DOTS:
2576                 Cairo::dots(cr, x, y1, 2, y2 - y1, true,
2577                             (y2 - y1) / 3.0 + 0.5, 0, (QtcRect*)area, 0,
2578                             &qtcPalette.background[5],
2579                             qtcPalette.background);
2580                 break;
2581             case LINE_NONE:
2582                 break;
2583             case LINE_FLAT:
2584             case LINE_SUNKEN:
2585                 /* Cairo::vLine(cr, x, y1 < y2 ? y1 : y2, abs(y2 - y1), */
2586                 /*              &qtcPalette.background[dark]); */
2587                 drawFadedLine(cr, x, y1 < y2 ? y1 : y2, 1, abs(y2 - y1),
2588                               &qtcPalette.background[dark],
2589                               (QtcRect*)area, nullptr, true, true, false);
2590                 if (opts.toolbarSeparators == LINE_SUNKEN)
2591                     /* Cairo::vLine(cr, x + 1, y1 < y2 ? y1 : y2, */
2592                     /*              abs(y2 - y1), */
2593                     /*              &qtcPalette.background[light]); */
2594                     drawFadedLine(cr, x + 1, y1 < y2 ? y1 : y2, 1,
2595                                   abs(y2 - y1), &qtcPalette.background[light],
2596                                   (QtcRect*)area, nullptr, true, true, false);
2597             }
2598         } else {
2599             /* Cairo::vLine(cr, x, y1 < y2 ? y1 : y2, abs(y2 - y1), */
2600             /*              &qtcPalette.background[dark]); */
2601             drawFadedLine(cr, x, y1 < y2 ? y1 : y2, 1, abs(y2 - y1),
2602                           &qtcPalette.background[dark], (QtcRect*)area,
2603                           nullptr, true, true, false);
2604         }
2605     }
2606     cairo_destroy(cr);
2607 }
2608 
2609 static void
2610 gtkDrawFocus(GtkStyle *style, GdkWindow *window, GtkStateType state,
2611              GdkRectangle *area, GtkWidget *widget, const char *_detail,
2612              int x, int y, int width, int height)
2613 {
2614     if (opts.focus == FOCUS_NONE) {
2615         return;
2616     }
2617     if (GTK_IS_EDITABLE(widget))
2618         return;
2619     QTC_RET_IF_FAIL(GDK_IS_DRAWABLE(window));
2620     QTC_RET_IF_FAIL(GTK_IS_STYLE(style));
2621 
2622     sanitizeSize(window, &width, &height);
2623 
2624     if (qtSettings.debug == DEBUG_ALL) {
2625         printf(DEBUG_PREFIX "%s %d %d %d %d %d %s ", __FUNCTION__, state, x, y,
2626                width, height, _detail);
2627         debugDisplayWidget(widget, 10);
2628     }
2629     GtkWidget *parent = widget ? gtk_widget_get_parent(widget) : nullptr;
2630     bool doEtch = opts.buttonEffect != EFFECT_NONE;
2631     bool btn = false;
2632     bool comboButton = false;
2633     bool rev = parent && reverseLayout(parent);
2634     bool view = isList(widget);
2635     bool listViewHeader = isListViewHeader(widget);
2636     bool toolbarBtn = (!listViewHeader && !view &&
2637                        isButtonOnToolbar(widget, nullptr));
2638 
2639     if (opts.comboSplitter &&
2640         noneOf(opts.focus, FOCUS_FULL, FOCUS_FILLED) && isComboBox(widget)) {
2641         /* x++; */
2642         /* y++; */
2643         /* height -= 2; */
2644         width += 2; /* Remove if re-add the above */
2645 
2646         if (widget && rev) {
2647             x += 20;
2648         }
2649         width -= 22;
2650 
2651         if (isGimpCombo(widget)) {
2652             x += 2;
2653             y += 2;
2654             width -= 4;
2655             height -= 4;
2656         }
2657         btn = true;
2658     }
2659 #if !GTK_CHECK_VERSION(2, 90, 0)
2660     else if (GTK_IS_OPTION_MENU(widget)) {
2661         if ((!opts.comboSplitter ||
2662              oneOf(opts.focus, FOCUS_FULL, FOCUS_FILLED)) && widget) {
2663             QtcRect alloc = Widget::getAllocation(widget);
2664             if (alloc.width > width) {
2665                 width = alloc.width - (doEtch ? 8 : 4);
2666             }
2667         }
2668         x++;
2669         y++;
2670         width -= 2;
2671         height -= 2;
2672         btn = true;
2673     }
2674 #endif
2675     if (isComboBoxEntryButton(widget)) {
2676 #if GTK_CHECK_VERSION(2, 90, 0)
2677         if (doEtch) {
2678             x -= 2;
2679             y++;
2680             width += 3;
2681             height -= 2;
2682         } else {
2683             x -= 2;
2684             width += 4;
2685         }
2686 #else
2687         if (doEtch) {
2688             x++;
2689             y += 2;
2690             width -= 3;
2691             height -= 4;
2692         } else {
2693             x++;
2694             y++;
2695             width -= 2;
2696             height -= 2;
2697         }
2698 #endif
2699         comboButton = true;
2700         btn = true;
2701     } else if (isGimpCombo(widget)) {
2702         if (opts.focus == FOCUS_GLOW) {
2703             return;
2704         }
2705         x -= 2;
2706         width += 4;
2707         if (!doEtch) {
2708             x--;
2709             y--;
2710             width += 2;
2711             height += 2;
2712         }
2713     } else if (GTK_IS_BUTTON(widget)) {
2714         if (GTK_IS_RADIO_BUTTON(widget) || GTK_IS_CHECK_BUTTON(widget)) {
2715             // Gimps buttons in its toolbox are
2716             const char *text = nullptr;
2717             toolbarBtn = (qtSettings.app == GTK_APP_GIMP &&
2718                           ((text =
2719                             gtk_button_get_label(GTK_BUTTON(widget))) == nullptr ||
2720                            text[0] == '\0'));
2721 
2722             if (!toolbarBtn && opts.focus == FOCUS_GLOW && !isMozilla()) {
2723                 return;
2724             }
2725 
2726             if (toolbarBtn) {
2727                 if (qtSettings.app == GTK_APP_GIMP &&
2728                     opts.focus == FOCUS_GLOW && toolbarBtn) {
2729                     x -= 2;
2730                     width += 4;
2731                     y -= 1;
2732                     height += 2;
2733                 }
2734             }
2735 #if 0 /* Removed in 1.7.2 */
2736             else {
2737                 if (opts.focus == FOCUS_LINE) {
2738                     height--;
2739                 } else if (oneOf(opts.focus, FOCUS_FULL, FOCUS_FILLED)) {
2740                     y--;
2741                     x -= 3;
2742                     width += 6;
2743                     height += 2;
2744                     if (!doEtch) {
2745                         y--;
2746                         x--;
2747                         width += 2;
2748                         height += 2;
2749                     }
2750                 }
2751             }
2752 #endif
2753         } else if (opts.focus == FOCUS_GLOW && toolbarBtn) {
2754             x -= 2;
2755             width += 4;
2756             y -= 2;
2757             height += 4;
2758         } else {
2759             if (doEtch) {
2760                 x--;
2761                 width += 2;
2762             } else {
2763                 x -= 2;
2764                 width += 4;
2765             }
2766             if (doEtch && (opts.thin & THIN_BUTTONS)) {
2767                 y++;
2768                 height -= 2;
2769             }
2770             btn = true;
2771         }
2772     }
2773     if (state == GTK_STATE_PRELIGHT && opts.coloredMouseOver != MO_NONE &&
2774         oneOf(opts.focus, FOCUS_FULL, FOCUS_FILLED) && !listViewHeader &&
2775         (btn || comboButton)) {
2776         return;
2777     }
2778     if (opts.focus == FOCUS_GLOW && !comboButton && !listViewHeader &&
2779         !toolbarBtn && (btn || GTK_IS_SCALE(widget))) {
2780         return;
2781     }
2782     if (opts.focus == FOCUS_GLOW && toolbarBtn && state != GTK_STATE_NORMAL) {
2783         return;
2784     }
2785     if (opts.focus == FOCUS_STANDARD) {
2786         parent_class->draw_focus(style, window, state, area, widget, _detail,
2787                                  x, y, width, height);
2788     } else {
2789         bool drawRounded = (opts.round != ROUND_NONE);
2790         GdkColor *col =
2791             (view && state == GTK_STATE_SELECTED ? &style->text[state] :
2792              &qtcPalette.focus[FOCUS_SHADE(state == GTK_STATE_SELECTED)]);
2793 
2794         cairo_t *cr = Cairo::gdkCreateClip(window, area);
2795 
2796         if (qtSettings.app == GTK_APP_JAVA_SWT && view && widget &&
2797             GTK_IS_TREE_VIEW(widget)) {
2798             GtkTreeView *treeView = GTK_TREE_VIEW(widget);
2799             GtkTreePath *path = nullptr;
2800             GtkTreeViewColumn *column = nullptr;
2801             GtkTreeViewColumn *expanderColumn =
2802                 gtk_tree_view_get_expander_column(treeView);
2803 
2804             TreeView::getCell(treeView, &path, &column, x, y, width, height);
2805             if (column == expanderColumn) {
2806                 int expanderSize = 0;
2807                 gtk_widget_style_get(widget, "expander-size",
2808                                      &expanderSize, nullptr);
2809                 if (expanderSize > 0) {
2810                     int depth = path ? (int)gtk_tree_path_get_depth(path) : 0;
2811                     int offset =
2812                         (3 + expanderSize * depth +
2813                          (4 + gtk_tree_view_get_level_indentation(treeView)) *
2814                          (depth - 1));
2815                     x += offset;
2816                     width -= offset;
2817                 }
2818             }
2819 
2820             if (path) {
2821                 gtk_tree_path_free(path);
2822             }
2823         }
2824 
2825         if (oneOf(opts.focus, FOCUS_LINE, FOCUS_GLOW)) {
2826             if (view || listViewHeader) {
2827                 height -= 2;
2828             }
2829             drawFadedLine(cr, x, y + height - 1, width, 1, col,
2830                           (QtcRect*)area, nullptr, true, true, true);
2831         } else {
2832             /* double alpha = (opts.focus == FOCUS_GLOW ? */
2833             /*                 FOCUS_GLOW_LINE_ALPHA : 1.0); */
2834 
2835             if (width < 3 || height < 3) {
2836                 drawRounded = false;
2837             }
2838             cairo_new_path(cr);
2839 
2840             if (isListViewHeader(widget)) {
2841                 btn = false;
2842                 y++;
2843                 x++;
2844                 width -= 2;
2845                 height -= 3;
2846             }
2847             if (oneOf(opts.focus, FOCUS_FULL, FOCUS_FILLED)) {
2848                 if (btn) {
2849                     if (toolbarBtn) {
2850                         x -= 2;
2851                         y -= 2;
2852                         width += 4;
2853                         height += 4;
2854                         if (!doEtch) {
2855                             x -= 2;
2856                             width += 4;
2857                             y--;
2858                             height += 2;
2859                         }
2860                     } else if (!widget  || !(GTK_IS_RADIO_BUTTON(widget) ||
2861                                              GTK_IS_CHECK_BUTTON(widget))) {
2862                         /* 1.7.2 - dont asjust fot check/radio */
2863                         x -= 3;
2864                         y -= 3;
2865                         width += 6;
2866                         height += 6;
2867                     }
2868                 }
2869 
2870                 if (opts.focus == FOCUS_FILLED) {
2871                     if (drawRounded) {
2872                         Cairo::pathWhole(cr, x + 0.5, y + 0.5, width - 1,
2873                                          height - 1,
2874                                          qtcGetRadius(&opts, width, height,
2875                                                       WIDGET_OTHER,
2876                                                       RADIUS_EXTERNAL),
2877                                          comboButton ?
2878                                          (rev ? ROUNDED_LEFT : ROUNDED_RIGHT) :
2879                                          ROUNDED_ALL);
2880                     } else {
2881                         cairo_rectangle(cr, x + 0.5, y + 0.5,
2882                                         width - 1, height - 1);
2883                     }
2884                     Cairo::setColor(cr, col, FOCUS_ALPHA);
2885                     cairo_fill(cr);
2886                     cairo_new_path(cr);
2887                 }
2888             }
2889             if (drawRounded) {
2890                 Cairo::pathWhole(cr, x + 0.5, y + 0.5, width - 1, height - 1,
2891                                  (view &&
2892                                   opts.square & SQUARE_LISTVIEW_SELECTION) &&
2893                                  opts.round != ROUND_NONE ? SLIGHT_INNER_RADIUS :
2894                                  qtcGetRadius(&opts, width, height, WIDGET_OTHER,
2895                                               oneOf(opts.focus, FOCUS_FULL,
2896                                                     FOCUS_FILLED) ?
2897                                               RADIUS_EXTERNAL :
2898                                               RADIUS_SELECTION),
2899                                  oneOf(opts.focus, FOCUS_FULL,
2900                                        FOCUS_FILLED) && comboButton ?
2901                                  (rev ? ROUNDED_LEFT : ROUNDED_RIGHT) :
2902                                  ROUNDED_ALL);
2903             } else {
2904                 cairo_rectangle(cr, x+0.5, y+0.5, width-1, height-1);
2905             }
2906             /* Cairo::setColor(cr, col, alpha); */
2907             Cairo::setColor(cr, col);
2908             cairo_stroke(cr);
2909         }
2910         cairo_destroy(cr);
2911     }
2912 }
2913 
2914 static void
2915 gtkDrawResizeGrip(GtkStyle *style, GdkWindow *window, GtkStateType state,
2916                   GdkRectangle *_area, GtkWidget *widget, const char *_detail,
2917                   GdkWindowEdge edge, int x, int y, int width, int height)
2918 {
2919     QTC_RET_IF_FAIL(GTK_IS_STYLE(style));
2920     QTC_RET_IF_FAIL(GDK_IS_DRAWABLE(window));
2921     QtcRect *area = (QtcRect*)_area;
2922     cairo_t *cr = Cairo::gdkCreateClip(window, area);
2923     int size = SIZE_GRIP_SIZE - 2;
2924 
2925     /* Clear background */
2926     if (qtcIsFlatBgnd(opts.bgndAppearance) ||
2927         !(widget && drawWindowBgnd(cr, style, area, window, widget,
2928                                    x, y, width, height))) {
2929         if (widget && opts.bgndImage.type != IMG_NONE) {
2930             drawWindowBgnd(cr, style, area, window, widget,
2931                            x, y, width, height);
2932         }
2933     }
2934 
2935     switch (edge) {
2936     case GDK_WINDOW_EDGE_SOUTH_EAST: {
2937         // Adjust Firefox's resize grip so that it can be completely covered
2938         // by QtCurve's KWin resize grip.
2939         if (isMozilla()) {
2940             x++;
2941             y++;
2942         }
2943         const GdkPoint a[] = {{x + width, y + height - size},
2944                               {x + width, y + height},
2945                               {x + width - size,  y + height}};
2946         Cairo::polygon(cr, &qtcPalette.background[2], area, a, 3, true);
2947         break;
2948     }
2949     case GDK_WINDOW_EDGE_SOUTH_WEST: {
2950         const GdkPoint a[] = {{x + width - size, y + height - size},
2951                               {x + width, y + height},
2952                               {x + width - size, y + height}};
2953         Cairo::polygon(cr, &qtcPalette.background[2], area, a, 3, true);
2954         break;
2955     }
2956     case GDK_WINDOW_EDGE_NORTH_EAST:
2957         // TODO!!
2958     case GDK_WINDOW_EDGE_NORTH_WEST:
2959         // TODO!!
2960     default:
2961         parent_class->draw_resize_grip(style, window, state, _area, widget,
2962                                        _detail, edge, x, y, width, height);
2963     }
2964     cairo_destroy(cr);
2965 }
2966 
2967 static void
2968 gtkDrawExpander(GtkStyle *style, GdkWindow *window, GtkStateType state,
2969                 GdkRectangle *_area, GtkWidget *widget, const char *_detail,
2970                 int x, int y, GtkExpanderStyle expander_style)
2971 {
2972     QTC_RET_IF_FAIL(GDK_IS_DRAWABLE(window));
2973     if (qtSettings.debug == DEBUG_ALL) {
2974         printf(DEBUG_PREFIX "%s %d %s  ", __FUNCTION__, state, _detail);
2975         debugDisplayWidget(widget, 10);
2976     }
2977     QtcRect *area = (QtcRect*)_area;
2978     cairo_t *cr = gdk_cairo_create(window);
2979     bool isExpander = widget && (GTK_IS_EXPANDER(widget) ||
2980                                  GTK_IS_TREE_VIEW(widget));
2981     bool fill = (!isExpander || opts.coloredMouseOver ||
2982                  state != GTK_STATE_PRELIGHT);
2983     const GdkColor *col = (isExpander && opts.coloredMouseOver &&
2984                            state == GTK_STATE_PRELIGHT ?
2985                            &qtcPalette.mouseover[ARROW_MO_SHADE] :
2986                            &style->text[ARROW_STATE(state)]);
2987 
2988     x -= LV_SIZE / 2.0 + 0.5;
2989     x += 2;
2990     y -= LV_SIZE / 2.0 + 0.5;
2991 
2992     if (expander_style == GTK_EXPANDER_COLLAPSED) {
2993         Cairo::arrow(cr, col, area,
2994                      reverseLayout(widget) ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT,
2995                      x + LARGE_ARR_WIDTH / 2, y + LARGE_ARR_HEIGHT,
2996                      false, fill, opts.vArrows);
2997     } else {
2998         Cairo::arrow(cr, col, area, GTK_ARROW_DOWN, x + LARGE_ARR_WIDTH / 2,
2999                      y + LARGE_ARR_HEIGHT, false, fill, opts.vArrows);
3000     }
3001     cairo_destroy(cr);
3002 }
3003 
3004 static void
3005 styleRealize(GtkStyle *style)
3006 {
3007     Style *qtc_style = (Style*)style;
3008 
3009     parent_class->realize(style);
3010 
3011     qtc_style->button_text[PAL_ACTIVE] =
3012         &qtSettings.colors[PAL_ACTIVE][COLOR_BUTTON_TEXT];
3013     qtc_style->button_text[PAL_DISABLED] =
3014         (qtSettings.qt4 ? &qtSettings.colors[PAL_DISABLED][COLOR_BUTTON_TEXT] :
3015          &style->text[GTK_STATE_INSENSITIVE]);
3016 
3017     if (opts.shadeMenubars == SHADE_WINDOW_BORDER) {
3018         qtc_style->menutext[0] =
3019             &qtSettings.colors[PAL_INACTIVE][COLOR_WINDOW_BORDER_TEXT];
3020         qtc_style->menutext[1] =
3021             &qtSettings.colors[PAL_ACTIVE][COLOR_WINDOW_BORDER_TEXT];
3022     } else if (opts.customMenuTextColor) {
3023         qtc_style->menutext[0] = &opts.customMenuNormTextColor;
3024         qtc_style->menutext[1] = &opts.customMenuSelTextColor;
3025     } else {
3026         qtc_style->menutext[0] = nullptr;
3027     }
3028 }
3029 
3030 static void
3031 styleUnrealize(GtkStyle *style)
3032 {
3033     parent_class->unrealize(style);
3034 }
3035 
3036 static void
3037 style_init_from_rc(GtkStyle *style, GtkRcStyle *rc_style)
3038 {
3039     parent_class->init_from_rc(style, rc_style);
3040 }
3041 
3042 static void style_class_init(void *_klass, void*)
3043 {
3044     StyleClass *klass = (StyleClass*)_klass;
3045     GtkStyleClass *style_class = GTK_STYLE_CLASS(klass);
3046 
3047     parent_class = (GtkStyleClass*)g_type_class_peek_parent(klass);
3048 
3049     style_class->realize = styleRealize;
3050     style_class->unrealize = styleUnrealize;
3051     style_class->init_from_rc = style_init_from_rc;
3052     style_class->draw_resize_grip = gtkDrawResizeGrip;
3053     style_class->draw_expander = gtkDrawExpander;
3054     style_class->draw_arrow = gtkDrawArrow;
3055     style_class->draw_tab = gtkDrawTab;
3056     style_class->draw_shadow = gtkDrawShadow;
3057     style_class->draw_box_gap = gtkDrawBoxGap;
3058     style_class->draw_extension = gtkDrawExtension;
3059     style_class->draw_handle = gtkDrawHandle;
3060     style_class->draw_box = gtkDrawBox;
3061     style_class->draw_flat_box = gtkDrawFlatBox;
3062     style_class->draw_check = gtkDrawCheck;
3063     style_class->draw_slider = gtkDrawSlider;
3064     style_class->draw_option = gtkDrawOption;
3065     style_class->draw_shadow_gap = gtkDrawShadowGap;
3066     style_class->draw_hline = gtkDrawHLine;
3067     style_class->draw_vline = gtkDrawVLine;
3068     style_class->draw_focus = gtkDrawFocus;
3069     style_class->draw_layout = gtkDrawLayout;
3070     style_class->render_icon = gtkRenderIcon;
3071 }
3072 
3073 static GtkRcStyleClass *parent_rc_class;
3074 
3075 static unsigned
3076 rc_style_parse(GtkRcStyle*, GtkSettings*, GScanner *scanner)
3077 {
3078     unsigned old_scope;
3079     unsigned token;
3080 
3081     /* Set up a new scope in this scanner. */
3082     static GQuark scope_id = g_quark_from_string("qtcurve_theme_engine");
3083 
3084     /* If we bail out due to errors, we *don't* reset the scope, so the error
3085        messaging code can make sense of our tokens. */
3086     old_scope = g_scanner_set_scope(scanner, scope_id);
3087 
3088     token = g_scanner_peek_next_token(scanner);
3089     while (token != G_TOKEN_RIGHT_CURLY) {
3090         switch (token) {
3091         default:
3092             g_scanner_get_next_token(scanner);
3093             token = G_TOKEN_RIGHT_CURLY;
3094         }
3095         if (token != G_TOKEN_NONE)
3096             return token;
3097         token = g_scanner_peek_next_token(scanner);
3098     }
3099 
3100     g_scanner_get_next_token(scanner);
3101     g_scanner_set_scope(scanner, old_scope);
3102     return G_TOKEN_NONE;
3103 }
3104 
3105 static void
3106 rc_style_merge(GtkRcStyle *dest, GtkRcStyle *src)
3107 {
3108 
3109     GtkRcStyle copy;
3110     bool destIsQtc = isRcStyle(dest);
3111     bool srcIsQtc = (!src->name || Str::startsWith(src->name, RC_SETTING) ||
3112                      Str::startsWith(src->name, getProgName()));
3113     bool isQtCNoteBook = (opts.tabBgnd != 0 && src->name &&
3114                           oneOf(src->name, "qtcurve-notebook_bg"));
3115     bool dontChangeColors = destIsQtc && !srcIsQtc && !isQtCNoteBook &&
3116         // Only allow GtkRcStyle and QtCurve::RcStyle to change colours
3117         // ...this should catch most cases whre another themes gtkrc is in the
3118         // GTK2_RC_FILES path
3119         (noneOf(gTypeName(src), "GtkRcStyle", "QtCurveRcStyle") ||
3120          // If run as root (probably via kdesu/kdesudo) then dont allow KDE
3121          // settings to take effect - as these are sometimes from the user's
3122          // settings, not roots!
3123          (getuid() == 0 && src && src->name &&
3124           oneOf(src->name, "ToolTip", "default")));
3125 
3126     if (isQtCNoteBook) {
3127         qtcShade(&qtcPalette.background[ORIGINAL_SHADE],
3128                  &src->bg[GTK_STATE_NORMAL], TO_FACTOR(opts.tabBgnd),
3129                  opts.shading);
3130     }
3131 
3132     if(dontChangeColors)
3133     {
3134         memcpy(copy.color_flags, dest->color_flags, sizeof(GtkRcFlags)*5);
3135         memcpy(copy.fg, dest->fg, sizeof(GdkColor)*5);
3136         memcpy(copy.bg, dest->bg, sizeof(GdkColor)*5);
3137         memcpy(copy.text, dest->text, sizeof(GdkColor)*5);
3138         memcpy(copy.base, dest->base, sizeof(GdkColor)*5);
3139     }
3140 
3141     parent_rc_class->merge(dest, src);
3142 
3143     if(dontChangeColors)
3144     {
3145         memcpy(dest->color_flags, copy.color_flags, sizeof(GtkRcFlags)*5);
3146         memcpy(dest->fg, copy.fg, sizeof(GdkColor)*5);
3147         memcpy(dest->bg, copy.bg, sizeof(GdkColor)*5);
3148         memcpy(dest->text, copy.text, sizeof(GdkColor)*5);
3149         memcpy(dest->base, copy.base, sizeof(GdkColor)*5);
3150     }
3151 }
3152 
3153 /* Create an empty style suitable to this RC style */
3154 static GtkStyle*
3155 rc_style_create_style(GtkRcStyle *rc_style)
3156 {
3157     GtkStyle *style = (GtkStyle*)g_object_new(style_type, nullptr);
3158 
3159     qtSettingsSetColors(style, rc_style);
3160     return style;
3161 }
3162 
3163 static void style_init(void*, void*)
3164 {
3165     Shadow::initialize();
3166 }
3167 
3168 static void
3169 style_register_type(GTypeModule *module)
3170 {
3171     static const GTypeInfo object_info = {
3172         sizeof(StyleClass),
3173         (GBaseInitFunc)nullptr,
3174         (GBaseFinalizeFunc)nullptr,
3175         (GClassInitFunc)style_class_init,
3176         nullptr, /* class_finalize */
3177         nullptr, /* class_data */
3178         sizeof(Style),
3179         0, /* n_preallocs */
3180         (GInstanceInitFunc)style_init,
3181         nullptr
3182     };
3183 
3184     style_type = g_type_module_register_type(module, GTK_TYPE_STYLE,
3185                                              "QtCurveStyle", &object_info,
3186                                              GTypeFlags(0));
3187 }
3188 
3189 static gboolean
3190 style_set_hook(GSignalInvocationHint*, unsigned, const GValue *argv, void*)
3191 {
3192     GtkWidget *widget = GTK_WIDGET(g_value_get_object(argv));
3193     GdkScreen *screen = gtk_widget_get_screen(widget);
3194     if (!screen) {
3195         return true;
3196     }
3197 #if GTK_CHECK_VERSION(3, 0, 0)
3198     GdkVisual *visual = nullptr;
3199     if (gtk_widget_is_toplevel(widget)) {
3200         visual = gdk_screen_get_rgba_visual(screen);
3201     } else if (GTK_IS_DRAWING_AREA(widget)) {
3202         visual = gdk_screen_get_system_visual(screen);
3203     }
3204     if (visual) {
3205         gtk_widget_set_visual(widget, visual);
3206     }
3207 #else
3208     GdkColormap *colormap = nullptr;
3209     if (gtk_widget_is_toplevel(widget)) {
3210         colormap = gdk_screen_get_rgba_colormap(screen);
3211     } else if (GTK_IS_DRAWING_AREA(widget)) {
3212         // For inkscape and flash (and probably others).
3213         // Inkscape's (at least the Gtk2 version) EekPreview widget
3214         // uses system default colormap instead of the one for the widget.
3215         // Not sure what's wrong with flash...
3216         colormap = gdk_screen_get_default_colormap(screen);
3217     }
3218     if (colormap) {
3219         gtk_widget_set_colormap(widget, colormap);
3220     }
3221 #endif
3222     return true;
3223 }
3224 
3225 static void
3226 rc_style_init(void*, void*s)
3227 {
3228 #ifdef INCREASE_SB_SLIDER
3229     lastSlider.widget = nullptr;
3230 #endif
3231     if (qtSettingsInit()) {
3232         generateColors();
3233         if (qtSettings.useAlpha) {
3234             // Somehow GtkWidget is not loaded yet
3235             // when this function is called.
3236             g_type_class_ref(GTK_TYPE_WIDGET);
3237             g_signal_add_emission_hook(
3238                 g_signal_lookup("style-set", GTK_TYPE_WIDGET),
3239                 0, style_set_hook, nullptr, nullptr);
3240         }
3241     }
3242 }
3243 
3244 static void
3245 rc_style_finalize(GObject *object)
3246 {
3247     Animation::cleanup();
3248     qtcCall(G_OBJECT_CLASS(parent_rc_class)->finalize, object);
3249 }
3250 
3251 static void
3252 rc_style_class_init(void *_klass, void*)
3253 {
3254     RcStyleClass *klass = (RcStyleClass*)_klass;
3255     GtkRcStyleClass *rc_style_class = GTK_RC_STYLE_CLASS(klass);
3256     GObjectClass *object_class = G_OBJECT_CLASS(klass);
3257 
3258     parent_rc_class = (GtkRcStyleClass*)g_type_class_peek_parent(klass);
3259 
3260     rc_style_class->parse = rc_style_parse;
3261     rc_style_class->create_style = rc_style_create_style;
3262     rc_style_class->merge = rc_style_merge;
3263 
3264     object_class->finalize = rc_style_finalize;
3265 }
3266 
3267 static void
3268 rc_style_register_type(GTypeModule *module)
3269 {
3270     static const GTypeInfo object_info = {
3271         sizeof(RcStyleClass),
3272         nullptr,
3273         nullptr,
3274         (GClassInitFunc)rc_style_class_init,
3275         nullptr, /* class_finalize */
3276         nullptr, /* class_data */
3277         sizeof(RcStyle),
3278         0, /* n_preallocs */
3279         (GInstanceInitFunc)rc_style_init,
3280         nullptr
3281     };
3282 
3283     rc_style_type = g_type_module_register_type(module, GTK_TYPE_RC_STYLE,
3284                                                 "QtCurveRcStyle", &object_info,
3285                                                 GTypeFlags(0));
3286 }
3287 }
3288 
3289 QTC_BEGIN_DECLS
3290 
3291 QTC_EXPORT void
3292 theme_init(GTypeModule *module)
3293 {
3294     qtcX11InitXlib(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()));
3295     QtCurve::rc_style_register_type(module);
3296     QtCurve::style_register_type(module);
3297 }
3298 
3299 QTC_EXPORT void
3300 theme_exit()
3301 {
3302 }
3303 
3304 QTC_EXPORT GtkRcStyle*
3305 theme_create_rc_style()
3306 {
3307     return GTK_RC_STYLE(g_object_new(QtCurve::rc_style_type, nullptr));
3308 }
3309 
3310 /* The following function will be called by GTK+ when the module is loaded and
3311  * checks to see if we are compatible with the version of GTK+ that loads us.
3312  */
3313 QTC_EXPORT const char*
3314 g_module_check_init(GModule*)
3315 {
3316     return gtk_check_version(GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
3317                              GTK_MICRO_VERSION - GTK_INTERFACE_AGE);
3318 }
3319 
3320 QTC_END_DECLS