File indexing completed on 2024-04-21 05:46:58

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 "helpers.h"
0024 
0025 #include <qtcurve-utils/gtkprops.h>
0026 #include <qtcurve-utils/x11blur.h>
0027 #include <qtcurve-utils/color.h>
0028 #include <qtcurve-utils/log.h>
0029 #include <qtcurve-utils/strs.h>
0030 
0031 #include "qt_settings.h"
0032 #include <gdk/gdkx.h>
0033 
0034 namespace QtCurve {
0035 
0036 void
0037 debugDisplayWidget(GtkWidget *widget, int level)
0038 {
0039     if (Log::level() > LogLevel::Debug)
0040         return;
0041     if (level < 0 || !widget) {
0042         printf("\n");
0043         return;
0044     }
0045     const char *widget_name = gtk_widget_get_name(widget);
0046     qtcDebug("%s(%s)[%p] ", gTypeName(widget),
0047              widget_name ? widget_name : "NULL", widget);
0048     debugDisplayWidget(gtk_widget_get_parent(widget), level - 1);
0049 }
0050 
0051 bool
0052 haveAlternateListViewCol()
0053 {
0054     return (qtSettings.colors[PAL_ACTIVE][COLOR_LV].red != 0 ||
0055             qtSettings.colors[PAL_ACTIVE][COLOR_LV].green != 0 ||
0056             qtSettings.colors[PAL_ACTIVE][COLOR_LV].blue != 0);
0057 }
0058 
0059 GdkColor*
0060 menuColors(bool active)
0061 {
0062     return (SHADE_WINDOW_BORDER == opts.shadeMenubars ?
0063             qtcPalette.wborder[active ? 1 : 0] :
0064             SHADE_NONE == opts.shadeMenubars ||
0065             (opts.shadeMenubarOnlyWhenActive && !active) ?
0066             qtcPalette.background : qtcPalette.menubar);
0067 }
0068 
0069 EBorder
0070 shadowToBorder(GtkShadowType shadow)
0071 {
0072     switch (shadow) {
0073     default:
0074     case GTK_SHADOW_NONE:
0075         return BORDER_FLAT;
0076     case GTK_SHADOW_IN:
0077     case GTK_SHADOW_ETCHED_IN:
0078         return BORDER_SUNKEN;
0079     case GTK_SHADOW_OUT:
0080     case GTK_SHADOW_ETCHED_OUT:
0081         return BORDER_RAISED;
0082     }
0083 }
0084 
0085 bool
0086 useButtonColor(const char *detail)
0087 {
0088     return (detail &&
0089             (oneOf(detail, "optionmenu", "button", "buttondefault",
0090                    "togglebuttondefault", "togglebutton", "hscale", "vscale",
0091                    "spinbutton", "spinbutton_up", "spinbutton_down", "slider",
0092                    "qtc-slider", "stepper") ||
0093              (detail[0] && Str::startsWith(detail + 1, "scrollbar"))));
0094 }
0095 
0096 void
0097 shadeColors(const GdkColor *base, GdkColor *vals)
0098 {
0099     bool useCustom = USE_CUSTOM_SHADES(opts);
0100     double hl = TO_FACTOR(opts.highlightFactor);
0101 
0102     for (int i = 0;i < QTC_NUM_STD_SHADES;i++) {
0103         qtcShade(base, &vals[i], useCustom ? opts.customShades[i] :
0104                  qtcShadeGetIntern(opts.contrast, i, opts.darkerBorders,
0105                                    opts.shading), opts.shading);
0106     }
0107     qtcShade(base, &vals[SHADE_ORIG_HIGHLIGHT], hl, opts.shading);
0108     qtcShade(&vals[4], &vals[SHADE_4_HIGHLIGHT], hl, opts.shading);
0109     qtcShade(&vals[2], &vals[SHADE_2_HIGHLIGHT], hl, opts.shading);
0110     vals[ORIGINAL_SHADE] = *base;
0111 }
0112 
0113 bool
0114 isSortColumn(GtkWidget *button)
0115 {
0116     GtkWidget *parent = nullptr;
0117     if (button && (parent = gtk_widget_get_parent(button)) &&
0118         GTK_IS_TREE_VIEW(parent)) {
0119 #if GTK_CHECK_VERSION(2, 90, 0)
0120         GtkWidget *box = (GTK_IS_BUTTON(button) ?
0121                           gtk_bin_get_child(GTK_BIN(button)) : nullptr);
0122 
0123         if (box && GTK_IS_BOX(box)) {
0124             GList *children = gtk_container_get_children(GTK_CONTAINER(box));
0125             bool found = false;
0126             for (GList *child = children;child && !found;
0127                  child = g_list_next(child)) {
0128                 if (GTK_IS_ARROW(child->data)) {
0129                     int val;
0130                     g_object_get(child->data, "arrow-type", &val, nullptr);
0131                     if (GTK_ARROW_NONE != val) {
0132                         found = true;
0133                     }
0134                 }
0135             }
0136             if (children) {
0137                 g_list_free(children);
0138             }
0139             return found;
0140         }
0141 #else
0142         GtkWidget *sort = nullptr;
0143         GList *columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(parent));
0144         for (GList *column = columns;column && !sort && sort != button;
0145              column = g_list_next(column)) {
0146             if (GTK_IS_TREE_VIEW_COLUMN(column->data)) {
0147                 GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN(column->data);
0148                 if (gtk_tree_view_column_get_sort_indicator(c)) {
0149                     sort = c->button;
0150                 }
0151             }
0152         }
0153 
0154         if (columns) {
0155             g_list_free(columns);
0156         }
0157         return sort == button;
0158 #endif
0159     }
0160     return false;
0161 };
0162 
0163 GdkColor*
0164 getCellCol(GdkColor *std, const char *detail)
0165 {
0166     if (!qtSettings.shadeSortedList || !strstr(detail, "_sorted"))
0167         return std;
0168 
0169     static GdkColor shaded;
0170     shaded = *std;
0171 
0172     if (isBlack(shaded)) {
0173         shaded.red = shaded.green = shaded.blue = 55 << 8;
0174     } else {
0175         double r = shaded.red / 65535.0;
0176         double g = shaded.green / 65535.0;
0177         double b = shaded.blue / 65535.0;
0178         double h, s, v;
0179 
0180         qtcRgbToHsv(r, g, b, &h, &s, &v);
0181 
0182         if (v > 175.0 / 255.0) {
0183             v *= 100.0 / 104.0;
0184         } else {
0185             v *= 120.0 / 100.0;
0186         }
0187 
0188         if (v > 1.0) {
0189             s = qtcMax(0, s - (v - 1.0));
0190             v = 1.0;
0191         }
0192 
0193         qtcHsvToRgb(&r, &g, &b, h, s, v);
0194         shaded.red = r * 65535.0;
0195         shaded.green = g * 65535.0;
0196         shaded.blue = b * 65535.0;
0197     }
0198     return &shaded;
0199 }
0200 
0201 bool
0202 reverseLayout(GtkWidget *widget)
0203 {
0204     if (widget) {
0205         return gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL;
0206     }
0207     return false;
0208 }
0209 
0210 bool
0211 isOnToolbar(GtkWidget *widget, bool *horiz, int level)
0212 {
0213     if (widget) {
0214         if (GTK_IS_TOOLBAR(widget)) {
0215             qtcAssign(horiz, Widget::isHorizontal(widget));
0216             return true;
0217         } else if (level < 4) {
0218             return isOnToolbar(gtk_widget_get_parent(widget), horiz, level + 1);
0219         }
0220     }
0221     return false;
0222 }
0223 
0224 bool
0225 isOnHandlebox(GtkWidget *widget, bool *horiz, int level)
0226 {
0227     if (widget) {
0228         if (GTK_IS_HANDLE_BOX(widget)) {
0229             qtcAssign(horiz, oneOf(gtk_handle_box_get_handle_position(
0230                                        GTK_HANDLE_BOX(widget)),
0231                                    GTK_POS_LEFT, GTK_POS_RIGHT));
0232             return true;
0233         } else if (level < 4) {
0234             return isOnHandlebox(gtk_widget_get_parent(widget), horiz,
0235                                  level + 1);
0236         }
0237     }
0238     return false;
0239 }
0240 
0241 bool
0242 isButtonOnToolbar(GtkWidget *widget, bool *horiz)
0243 {
0244     GtkWidget *parent = nullptr;
0245     if (widget && (parent = gtk_widget_get_parent(widget)) &&
0246         GTK_IS_BUTTON(widget)) {
0247         return isOnToolbar(parent, horiz, 0);
0248     }
0249     return false;
0250 }
0251 
0252 bool
0253 isButtonOnHandlebox(GtkWidget *widget, bool *horiz)
0254 {
0255     GtkWidget *parent = nullptr;
0256     if (widget && (parent = gtk_widget_get_parent(widget)) &&
0257         GTK_IS_BUTTON(widget)) {
0258         return isOnHandlebox(parent, horiz, 0);
0259     }
0260     return false;
0261 }
0262 
0263 bool
0264 isOnStatusBar(GtkWidget *widget, int level)
0265 {
0266     GtkWidget *parent = gtk_widget_get_parent(widget);
0267     if (parent) {
0268         if (GTK_IS_STATUSBAR(parent)) {
0269             return true;
0270         } else if (level < 4) {
0271             return isOnStatusBar(parent, level + 1);
0272         }
0273     }
0274     return false;
0275 }
0276 
0277 bool
0278 isList(GtkWidget *widget)
0279 {
0280     return widget && (GTK_IS_TREE_VIEW(widget) ||
0281 #if !GTK_CHECK_VERSION(2, 90, 0)
0282                       GTK_IS_CLIST(widget) || GTK_IS_LIST(widget) ||
0283 #ifdef GTK_ENABLE_BROKEN
0284                       GTK_IS_TREE(widget) ||
0285 #endif
0286                       GTK_IS_CTREE(widget) ||
0287 #endif
0288                       oneOf(gTypeName(widget), "GtkSCTree"));
0289 }
0290 
0291 bool
0292 isListViewHeader(GtkWidget *widget)
0293 {
0294     GtkWidget *parent = nullptr;
0295     return widget && GTK_IS_BUTTON(widget) && (parent=gtk_widget_get_parent(widget)) &&
0296            (isList(parent) ||
0297             (GTK_APP_GIMP == qtSettings.app && GTK_IS_BOX(parent) &&
0298              (parent=gtk_widget_get_parent(parent)) &&
0299              GTK_IS_EVENT_BOX(parent) &&
0300              (parent=gtk_widget_get_parent(parent)) &&
0301              oneOf(gTypeName(parent), "GimpThumbBox")));
0302 }
0303 
0304 bool
0305 isEvolutionListViewHeader(GtkWidget *widget, const char *detail)
0306 {
0307     GtkWidget *parent = nullptr;
0308     return ((qtSettings.app == GTK_APP_EVOLUTION) && widget &&
0309             oneOf(detail, "button") &&
0310             oneOf(gTypeName(widget), "ECanvas") &&
0311             (parent = gtk_widget_get_parent(widget)) &&
0312             (parent = gtk_widget_get_parent(parent)) &&
0313             GTK_IS_SCROLLED_WINDOW(parent));
0314 }
0315 
0316 bool isOnListViewHeader(GtkWidget *w, int level)
0317 {
0318     if (w) {
0319         if (isListViewHeader(w)) {
0320             return true;
0321         } else if (level < 4) {
0322             return isOnListViewHeader(gtk_widget_get_parent(w), level + 1);
0323         }
0324     }
0325     return false;
0326 }
0327 
0328 bool
0329 isPathButton(GtkWidget *widget)
0330 {
0331     return (widget && GTK_IS_BUTTON(widget) &&
0332             oneOf(gTypeName(gtk_widget_get_parent(widget)), "GtkPathBar"));
0333 }
0334 
0335 // static gboolean isTabButton(GtkWidget *widget)
0336 // {
0337 //     return widget && GTK_IS_BUTTON(widget) && gtk_widget_get_parent(widget) &&
0338 //            (GTK_IS_NOTEBOOK(gtk_widget_get_parent(widget)) ||
0339 //             (gtk_widget_get_parent(widget)->parent && GTK_IS_BOX(gtk_widget_get_parent(widget)) && GTK_IS_NOTEBOOK(gtk_widget_get_parent(widget)->parent)));
0340 // }
0341 
0342 GtkWidget*
0343 getComboEntry(GtkWidget *widget)
0344 {
0345     GList *children = gtk_container_get_children(GTK_CONTAINER(widget));
0346     GtkWidget *rv = nullptr;
0347     for (GList *child = children;child && !rv;child = child->next) {
0348         GtkWidget *boxChild = (GtkWidget *)child->data;
0349         if (GTK_IS_ENTRY(boxChild)) {
0350             rv = (GtkWidget*)boxChild;
0351         }
0352     }
0353     if (children) {
0354         g_list_free(children);
0355     }
0356     return rv;
0357 }
0358 
0359 GtkWidget*
0360 getComboButton(GtkWidget *widget)
0361 {
0362     GList *children = gtk_container_get_children(GTK_CONTAINER(widget));
0363     GtkWidget *rv = nullptr;
0364     for (GList *child = children;child && !rv;child = child->next) {
0365         GtkWidget *boxChild = (GtkWidget*)child->data;
0366         if (GTK_IS_BUTTON(boxChild)) {
0367             rv = (GtkWidget*)boxChild;
0368         }
0369     }
0370     if (children) {
0371         g_list_free(children);
0372     }
0373     return rv;
0374 }
0375 
0376 bool isSideBarBtn(GtkWidget *widget)
0377 {
0378     return widget && oneOf(gTypeName(gtk_widget_get_parent(widget)),
0379                            "GdlDockBar", "GdlSwitcher");
0380 }
0381 
0382 bool isComboBoxButton(GtkWidget *widget)
0383 {
0384     GtkWidget *parent = nullptr;
0385     return widget && GTK_IS_BUTTON(widget) && (parent=gtk_widget_get_parent(widget)) &&
0386            (QTC_COMBO_ENTRY(parent) || QTC_IS_COMBO(parent));
0387 }
0388 
0389 bool isComboBox(GtkWidget *widget)
0390 {
0391     GtkWidget *parent=nullptr;
0392     return widget && GTK_IS_BUTTON(widget) && (parent=gtk_widget_get_parent(widget)) &&
0393            !QTC_COMBO_ENTRY(parent) && (GTK_IS_COMBO_BOX(parent) || QTC_IS_COMBO(parent));
0394 }
0395 
0396 bool isComboBoxEntry(GtkWidget *widget)
0397 {
0398     GtkWidget *parent=nullptr;
0399     return widget && GTK_IS_ENTRY(widget) && (parent=gtk_widget_get_parent(widget)) &&
0400            (QTC_COMBO_ENTRY(parent) || QTC_IS_COMBO(parent));
0401 }
0402 
0403 bool isComboBoxEntryButton(GtkWidget *widget)
0404 {
0405     GtkWidget *parent=nullptr;
0406     return widget && (parent=gtk_widget_get_parent(widget)) && GTK_IS_TOGGLE_BUTTON(widget) && QTC_COMBO_ENTRY(parent);
0407 }
0408 
0409 /*
0410 static gboolean isSwtComboBoxEntry(GtkWidget *widget)
0411 {
0412     return GTK_APP_JAVA_SWT == qtSettings.app &&
0413            isComboBoxEntry(widget) &&
0414            gtk_widget_get_parent(widget)->parent && 0 == strcmp(g_type_name(G_OBJECT_TYPE(gtk_widget_get_parent(widget)->parent)), "SwtFixed");
0415 }
0416 */
0417 
0418 bool isGimpCombo(GtkWidget *widget)
0419 {
0420     return (qtSettings.app == GTK_APP_GIMP && widget &&
0421             GTK_IS_TOGGLE_BUTTON(widget) &&
0422             oneOf(gTypeName(gtk_widget_get_parent(widget)),
0423                   "GimpEnumComboBox"));
0424 }
0425 
0426 bool
0427 isOnComboEntry(GtkWidget *w, int level)
0428 {
0429     if (w) {
0430         if (QTC_COMBO_ENTRY(w)) {
0431             return true;
0432         } else if (level < 4) {
0433             return isOnComboEntry(gtk_widget_get_parent(w), level + 1);
0434         }
0435     }
0436     return false;
0437 }
0438 
0439 bool
0440 isOnComboBox(GtkWidget *w, int level)
0441 {
0442     if (w) {
0443         if (GTK_IS_COMBO_BOX(w)) {
0444             return true;
0445         } else if (level < 4) {
0446             return isOnComboBox(gtk_widget_get_parent(w), level + 1);
0447         }
0448     }
0449     return false;
0450 }
0451 
0452 bool
0453 isOnCombo(GtkWidget *w, int level)
0454 {
0455     if (w) {
0456         if (QTC_IS_COMBO(w)) {
0457             return true;
0458         } else if (level < 4) {
0459             return isOnCombo(gtk_widget_get_parent(w), level + 1);
0460         }
0461     }
0462     return false;
0463 }
0464 
0465 #if !GTK_CHECK_VERSION(2, 90, 0)
0466 bool isOnOptionMenu(GtkWidget *w, int level)
0467 {
0468     if (w) {
0469         if (GTK_IS_OPTION_MENU(w)) {
0470             return true;
0471         } else if (level < 4) {
0472             return isOnOptionMenu(gtk_widget_get_parent(w), level + 1);
0473         }
0474     }
0475     return false;
0476 }
0477 
0478 bool isActiveOptionMenu(GtkWidget *widget)
0479 {
0480     if (GTK_IS_OPTION_MENU(widget)) {
0481         GtkWidget *menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(widget));
0482         if(menu && gtk_widget_get_visible(menu) &&
0483            gtk_widget_get_realized(menu)) {
0484             return true;
0485         }
0486     }
0487     return false;
0488 }
0489 #endif
0490 
0491 bool isOnMenuItem(GtkWidget *w, int level)
0492 {
0493     if(w)
0494     {
0495         if(GTK_IS_MENU_ITEM(w))
0496             return true;
0497         else if(level<4)
0498             return isOnMenuItem(gtk_widget_get_parent(w), ++level);
0499     }
0500     return false;
0501 }
0502 
0503 bool isSpinButton(GtkWidget *widget)
0504 {
0505     return widget && GTK_IS_SPIN_BUTTON(widget);
0506 }
0507 
0508 bool isStatusBarFrame(GtkWidget *widget)
0509 {
0510     GtkWidget *parent=nullptr;
0511     return widget && (parent=gtk_widget_get_parent(widget)) && GTK_IS_FRAME(widget) &&
0512            (GTK_IS_STATUSBAR(parent) || ((parent=gtk_widget_get_parent(parent)) && GTK_IS_STATUSBAR(parent)));
0513 }
0514 
0515 GtkMenuBar * isMenubar(GtkWidget *w, int level)
0516 {
0517     if(w)
0518     {
0519         if(GTK_IS_MENU_BAR(w))
0520             return (GtkMenuBar*)w;
0521         else if(level<3)
0522             return isMenubar(gtk_widget_get_parent(w), level++);
0523     }
0524 
0525     return nullptr;
0526 }
0527 
0528 bool isMenuitem(GtkWidget *w, int level)
0529 {
0530     if(w)
0531     {
0532         if(GTK_IS_MENU_ITEM(w))
0533             return true;
0534         else if(level<3)
0535             return isMenuitem(gtk_widget_get_parent(w), level++);
0536     }
0537 
0538     return false;
0539 }
0540 
0541 bool isMenuWindow(GtkWidget *w)
0542 {
0543     GtkWidget *def = gtk_window_get_default_widget(GTK_WINDOW(w));
0544 
0545     return def && GTK_IS_MENU(def);
0546 }
0547 
0548 bool isInGroupBox(GtkWidget *w, int level)
0549 {
0550     if(w)
0551     {
0552         if(IS_GROUP_BOX(w))
0553             return true;
0554         else if(level<5)
0555             return isInGroupBox(gtk_widget_get_parent(w), level++);
0556     }
0557 
0558     return false;
0559 }
0560 
0561 bool isOnButton(GtkWidget *w, int level, bool *def)
0562 {
0563     if (w) {
0564         if ((GTK_IS_BUTTON(w) || GTK_IS_OPTION_MENU(w)) &&
0565             (!(GTK_IS_RADIO_BUTTON(w) || GTK_IS_CHECK_BUTTON(w)))) {
0566             if (def) {
0567                 *def = gtk_widget_has_default(w);
0568             }
0569             return true;
0570         } else if (level < 3) {
0571             return isOnButton(gtk_widget_get_parent(w), level++, def);
0572         }
0573     }
0574     return false;
0575 }
0576 
0577 static GtkRequisition defaultOptionIndicatorSize = {6, 13};
0578 static GtkBorder defaultOptionIndicatorSpacing = {7, 5, 1, 1};
0579 
0580 void
0581 optionMenuGetProps(GtkWidget *widget, GtkRequisition *indicator_size,
0582                    GtkBorder *indicator_spacing)
0583 {
0584     GtkRequisition *tmp_size = nullptr;
0585     GtkBorder *tmp_spacing = nullptr;
0586 
0587     if (widget)
0588         gtk_widget_style_get(widget, "indicator_size", &tmp_size,
0589                              "indicator_spacing", &tmp_spacing,
0590                              nullptr);
0591     *indicator_size= tmp_size ? *tmp_size : defaultOptionIndicatorSize;
0592     *indicator_spacing = (tmp_spacing ? *tmp_spacing :
0593                           defaultOptionIndicatorSpacing);
0594 
0595     if (tmp_size) {
0596         gtk_requisition_free(tmp_size);
0597     }
0598     if (tmp_spacing) {
0599         gtk_border_free(tmp_spacing);
0600     }
0601 }
0602 
0603 EStepper
0604 getStepper(GtkWidget *widget, int x, int y, int width, int height)
0605 {
0606     if (widget && GTK_IS_RANGE(widget)) {
0607         const QtcRect stepper = {x, y, width, height};
0608         GtkOrientation orientation = Widget::getOrientation(widget);
0609         QtcRect alloc = Widget::getAllocation(widget);
0610         QtcRect check_rectangle = {alloc.x, alloc.y,
0611                                    stepper.width, stepper.height};
0612 
0613         if (alloc.x == -1 && alloc.y == -1) {
0614             return STEPPER_NONE;
0615         }
0616         if (Rect::intersect(&stepper, &check_rectangle, nullptr)) {
0617             return STEPPER_A;
0618         }
0619 
0620         if (orientation == GTK_ORIENTATION_HORIZONTAL) {
0621             check_rectangle.x = alloc.x + stepper.width;
0622         } else {
0623             check_rectangle.y = alloc.y + stepper.height;
0624         }
0625         if (Rect::intersect(&stepper, &check_rectangle, nullptr)) {
0626             return STEPPER_B;
0627         }
0628 
0629         if (orientation == GTK_ORIENTATION_HORIZONTAL) {
0630             check_rectangle.x = alloc.x + alloc.width - stepper.width * 2;
0631         } else {
0632             check_rectangle.y = alloc.y + alloc.height - stepper.height * 2;
0633         }
0634         if (Rect::intersect(&stepper, &check_rectangle, nullptr)) {
0635             return STEPPER_C;
0636         }
0637 
0638         if (orientation == GTK_ORIENTATION_HORIZONTAL) {
0639             check_rectangle.x = alloc.x + alloc.width - stepper.width;
0640         } else {
0641             check_rectangle.y = alloc.y + alloc.height - stepper.height;
0642         }
0643         if (Rect::intersect(&stepper, &check_rectangle, nullptr)) {
0644             return STEPPER_D;
0645         }
0646     }
0647     return STEPPER_NONE;
0648 }
0649 
0650 #if GTK_CHECK_VERSION(2, 90, 0)
0651 void gdk_drawable_get_size(GdkWindow *window, int *width, int *height)
0652 {
0653     *width = gdk_window_get_width(window);
0654     *height = gdk_window_get_height(window);
0655 }
0656 
0657 void sanitizeSizeReal(GtkWidget *widget, int *width, int *height)
0658 {
0659     if (*width == -1 || *height == -1) {
0660         GdkWindow *window = gtk_widget_get_window(widget);
0661         if (window) {
0662             if (*width == -1) {
0663                 *width = gdk_window_get_width(window);
0664             }
0665             if (*height == -1) {
0666                 *height = gdk_window_get_height(window);
0667             }
0668         }
0669     }
0670 }
0671 #else
0672 void sanitizeSize(GdkWindow *window, int *width, int *height)
0673 {
0674     if (*width == -1 && *height == -1) {
0675         gdk_window_get_size(window, width, height);
0676     } else if (*width == -1) {
0677         gdk_window_get_size(window, width, nullptr);
0678     } else if (*height == -1) {
0679         gdk_window_get_size(window, nullptr, height);
0680     }
0681 }
0682 #endif
0683 
0684 int
0685 getFill(GtkStateType state, bool set, bool darker)
0686 {
0687     if (state == GTK_STATE_INSENSITIVE) {
0688         return darker ? 2 : ORIGINAL_SHADE;
0689     } else if (state == GTK_STATE_PRELIGHT) {
0690         if (set) {
0691             return darker ? 3 : SHADE_4_HIGHLIGHT;
0692         } else {
0693             return darker ? SHADE_2_HIGHLIGHT : SHADE_ORIG_HIGHLIGHT;
0694         }
0695     } else if (set || state == GTK_STATE_ACTIVE) {
0696         return darker ? 5 : 4;
0697     } else {
0698         return darker ? 2 : ORIGINAL_SHADE;
0699     }
0700 }
0701 
0702 bool
0703 isSbarDetail(const char *detail)
0704 {
0705     return (detail && detail[0] && (oneOf(detail, "stepper") ||
0706                                     Str::startsWith(detail + 1, "scrollbar")));
0707 }
0708 
0709 ECornerBits
0710 getRound(const char *detail, GtkWidget *widget, bool rev)
0711 {
0712     if (detail) {
0713         if (oneOf(detail, "slider")) {
0714 #ifndef SIMPLE_SCROLLBARS
0715             if (!(opts.square & SQUARE_SB_SLIDER) &&
0716                 (opts.scrollbarType == SCROLLBAR_NONE ||
0717                  opts.flatSbarButtons)) {
0718                 return ROUNDED_ALL;
0719             }
0720 #endif
0721             return ROUNDED_NONE;
0722         } else if (oneOf(detail, "qtc-slider")) {
0723             return opts.square&SQUARE_SLIDER && (SLIDER_PLAIN == opts.sliderStyle || SLIDER_PLAIN_ROTATED == opts.sliderStyle)
0724                 ? ROUNDED_NONE : ROUNDED_ALL;
0725         } else if (oneOf(detail, "splitter", "optionmenu", "togglebutton",
0726                          "hscale", "vscale")) {
0727             return ROUNDED_ALL;
0728         } else if (oneOf(detail, "spinbutton_up"))
0729             return rev ? ROUNDED_TOPLEFT : ROUNDED_TOPRIGHT;
0730         else if(oneOf(detail, "spinbutton_down"))
0731             return rev ? ROUNDED_BOTTOMLEFT : ROUNDED_BOTTOMRIGHT;
0732         else if (isSbarDetail(detail)) {
0733             // Requires `GtkRange::stepper-position-details = 1`
0734             if (Str::endsWith(detail, "_start")) {
0735                 return detail[0] == 'h' ? ROUNDED_LEFT : ROUNDED_TOP;
0736             } else if (Str::endsWith(detail, "_end")) {
0737                 return detail[0] == 'v' ? ROUNDED_BOTTOM : ROUNDED_RIGHT;
0738             }
0739             return ROUNDED_NONE;
0740         } else if (oneOf(detail, "button")) {
0741             if(isListViewHeader(widget))
0742                 return ROUNDED_NONE;
0743             else if(isComboBoxButton(widget))
0744                 return rev ? ROUNDED_LEFT : ROUNDED_RIGHT;
0745             else
0746                 return ROUNDED_ALL;
0747         }
0748     }
0749 
0750     return ROUNDED_NONE;
0751 }
0752 
0753 bool
0754 isHorizontalProgressbar(GtkWidget *widget)
0755 {
0756     if (!widget || isMozilla() || !GTK_IS_PROGRESS_BAR(widget))
0757         return true;
0758 #if GTK_CHECK_VERSION(2, 90, 0)
0759     return Widget::isHorizontal(widget);
0760 #else
0761     switch (GTK_PROGRESS_BAR(widget)->orientation) {
0762     default:
0763     case GTK_PROGRESS_LEFT_TO_RIGHT:
0764     case GTK_PROGRESS_RIGHT_TO_LEFT:
0765         return true;
0766     case GTK_PROGRESS_BOTTOM_TO_TOP:
0767     case GTK_PROGRESS_TOP_TO_BOTTOM:
0768         return false;
0769     }
0770 #endif
0771 }
0772 
0773 bool
0774 isComboBoxPopupWindow(GtkWidget *widget, int level)
0775 {
0776     if (widget) {
0777         if (GTK_IS_WINDOW(widget) && oneOf(gtk_widget_get_name(widget),
0778                                            "gtk-combobox-popup-window")) {
0779             return true;
0780         } else if (level < 4) {
0781             return isComboBoxPopupWindow(gtk_widget_get_parent(widget),
0782                                          level + 1);
0783         }
0784     }
0785     return false;
0786 }
0787 
0788 bool isComboBoxList(GtkWidget *widget)
0789 {
0790     GtkWidget *parent=nullptr;
0791     return widget && (parent=gtk_widget_get_parent(widget)) && /*GTK_IS_FRAME(widget) && */isComboBoxPopupWindow(parent, 0);
0792 }
0793 
0794 bool
0795 isComboPopupWindow(GtkWidget *widget, int level)
0796 {
0797     if (widget) {
0798         if (GTK_IS_WINDOW(widget) && oneOf(gtk_widget_get_name(widget),
0799                                            "gtk-combo-popup-window")) {
0800             return true;
0801         } else if (level < 4) {
0802             return isComboPopupWindow(gtk_widget_get_parent(widget), level + 1);
0803         }
0804     }
0805     return false;
0806 }
0807 
0808 bool isComboList(GtkWidget *widget)
0809 {
0810     return widget && isComboPopupWindow(gtk_widget_get_parent(widget), 0);
0811 }
0812 
0813 bool
0814 isComboMenu(GtkWidget *widget)
0815 {
0816     if (widget && gtk_widget_get_name(widget) && GTK_IS_MENU(widget) &&
0817         oneOf(gtk_widget_get_name(widget), "gtk-combobox-popup-menu")) {
0818         return true;
0819     } else {
0820         GtkWidget *top = gtk_widget_get_toplevel(widget);
0821         GtkWidget *topChild = top ? gtk_bin_get_child(GTK_BIN(top)) : nullptr;
0822         GtkWidget *transChild = nullptr;
0823         GtkWindow *trans = nullptr;
0824 
0825         return (topChild &&
0826                 (isComboBoxPopupWindow(topChild, 0) ||
0827                  (GTK_IS_WINDOW(top) &&
0828                   (trans = gtk_window_get_transient_for(GTK_WINDOW(top))) &&
0829                   (transChild = gtk_bin_get_child(GTK_BIN(trans))) &&
0830                   isComboMenu(transChild))));
0831     }
0832 }
0833 
0834 bool isComboFrame(GtkWidget *widget)
0835 {
0836     GtkWidget *parent=nullptr;
0837     return !QTC_COMBO_ENTRY(widget) && GTK_IS_FRAME(widget) && (parent=gtk_widget_get_parent(widget)) && GTK_IS_COMBO_BOX(parent);
0838 }
0839 
0840 bool isFixedWidget(GtkWidget *widget)
0841 {
0842     GtkWidget *parent = nullptr;
0843     return (widget && (parent = gtk_widget_get_parent(widget)) &&
0844             GTK_IS_FIXED(parent) &&
0845             (parent = gtk_widget_get_parent(parent)) && GTK_IS_WINDOW(parent));
0846 }
0847 
0848 bool isGimpDockable(GtkWidget *widget)
0849 {
0850     if (qtSettings.app == GTK_APP_GIMP) {
0851         for (GtkWidget *wid = widget;wid;wid = gtk_widget_get_parent(wid)) {
0852             if (oneOf(gTypeName(wid), "GimpDockable", "GimpToolbox")) {
0853                 return true;
0854             }
0855         }
0856     }
0857     return false;
0858 }
0859 
0860 GdkColor*
0861 getParentBgCol(GtkWidget *widget)
0862 {
0863     if (GTK_IS_SCROLLBAR(widget)) {
0864         widget = gtk_widget_get_parent(widget);
0865     }
0866     if (widget) {
0867         widget = gtk_widget_get_parent(widget);
0868         while (widget && GTK_IS_BOX(widget)) {
0869             widget = gtk_widget_get_parent(widget);
0870         }
0871     }
0872 
0873     GtkStyle *style = widget ? gtk_widget_get_style(widget) : nullptr;
0874     return style ? &style->bg[gtk_widget_get_state(widget)] : nullptr;
0875 }
0876 
0877 int
0878 getOpacity(GtkWidget *widget)
0879 {
0880     if (opts.bgndOpacity == opts.dlgOpacity)
0881         return opts.bgndOpacity;
0882 
0883     if (opts.bgndOpacity != 100 || opts.dlgOpacity != 100) {
0884         if (!widget) {
0885             return opts.bgndOpacity;
0886         } else {
0887             GtkWidget *top = gtk_widget_get_toplevel(widget);
0888             return (top && GTK_IS_DIALOG(top) ? opts.dlgOpacity :
0889                     opts.bgndOpacity);
0890         }
0891     }
0892     return 100;
0893 }
0894 
0895 void setLowerEtchCol(cairo_t *cr, GtkWidget *widget)
0896 {
0897     if(USE_CUSTOM_ALPHAS(opts))
0898         cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, opts.customAlphas[ALPHA_ETCH_LIGHT]);
0899     else if(qtcIsFlatBgnd(opts.bgndAppearance) && (!widget || !g_object_get_data(G_OBJECT (widget), "transparent-bg-hint")))
0900     {
0901         GdkColor *parentBg=getParentBgCol(widget);
0902 
0903         if (parentBg) {
0904             GdkColor col;
0905             qtcShade(parentBg, &col, 1.06, opts.shading);
0906             Cairo::setColor(cr, &col);
0907         } else {
0908             cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.1); // 0.25);
0909         }
0910     } else {
0911         cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.1); // 0.4);
0912     }
0913 }
0914 
0915 GdkColor
0916 shadeColor(const GdkColor *orig, double mod)
0917 {
0918     if (!qtcEqual(mod, 0.0)) {
0919         GdkColor modified;
0920         qtcShade(orig, &modified, mod, opts.shading);
0921         return modified;
0922     }
0923     return *orig;
0924 }
0925 
0926 gboolean
0927 windowEvent(GtkWidget*, GdkEvent *event, void *user_data)
0928 {
0929     if (GDK_FOCUS_CHANGE == event->type)
0930         gtk_widget_queue_draw((GtkWidget*)user_data);
0931     return false;
0932 }
0933 
0934 void
0935 adjustToolbarButtons(GtkWidget *widget, int *x, int *y, int *width,
0936                      int *height, ECornerBits *round, bool horiz)
0937 {
0938     GtkToolbar *toolbar = nullptr;
0939     GtkToolItem *toolitem = nullptr;
0940     GtkWidget *w = widget;
0941 
0942     for (int i = 0;i < 5 && w && (!toolbar || !toolitem);++i) {
0943         if (GTK_IS_TOOLBAR(w)) {
0944             toolbar = GTK_TOOLBAR(w);
0945         } else if (GTK_IS_TOOL_ITEM(w)) {
0946             toolitem = GTK_TOOL_ITEM(w);
0947         }
0948         w = gtk_widget_get_parent(w);
0949     }
0950 
0951     if (toolbar && toolitem) {
0952         int num = gtk_toolbar_get_n_items(toolbar);
0953         if (num > 1) {
0954             int index = gtk_toolbar_get_item_index(toolbar, toolitem);
0955             GtkToolItem *prev =
0956                 (index ? gtk_toolbar_get_nth_item(toolbar, index - 1) : nullptr);
0957             GtkToolItem *next =
0958                 (index < num - 1 ?
0959                  gtk_toolbar_get_nth_item(toolbar, index + 1) : nullptr);
0960             GtkWidget *parent = nullptr;
0961             bool roundLeft = !prev || !GTK_IS_TOOL_BUTTON(prev);
0962             bool roundRight = !next || !GTK_IS_TOOL_BUTTON(next);
0963             bool isMenuButton =
0964                 (widget && GTK_IS_BUTTON(widget) &&
0965                  (parent = gtk_widget_get_parent(widget)) &&
0966                  GTK_IS_BOX(parent) &&
0967                  (parent = gtk_widget_get_parent(parent)) &&
0968                  GTK_IS_MENU_TOOL_BUTTON(parent));
0969             bool isArrowButton = isMenuButton && GTK_IS_TOGGLE_BUTTON(widget);
0970             int *pos = horiz ? x : y;
0971             int *size = horiz ? width : height;
0972 
0973             if (isArrowButton) {
0974                 *pos -= 4;
0975                 if (roundLeft && roundRight) {
0976                     *round = horiz ? ROUNDED_RIGHT : ROUNDED_BOTTOM;
0977                     *size += 4;
0978                 } else if (roundLeft) {
0979                     *round = ROUNDED_NONE;
0980                     *size += 8;
0981                 } else if (roundRight) {
0982                     *round = horiz ? ROUNDED_RIGHT : ROUNDED_BOTTOM;
0983                     *size += 4;
0984                 } else {
0985                     *round = ROUNDED_NONE;
0986                     *size += 8;
0987                 }
0988             } else if (isMenuButton) {
0989                 if (roundLeft && roundRight) {
0990                     *round = horiz ? ROUNDED_LEFT : ROUNDED_TOP;
0991                     *size += 4;
0992                 } else if (roundLeft) {
0993                     *round = horiz ? ROUNDED_LEFT : ROUNDED_TOP;
0994                     *size += 4;
0995                 } else if(roundRight) {
0996                     *round = ROUNDED_NONE;
0997                     *pos -= 4;
0998                     *size += 8;
0999                 } else {
1000                     *round = ROUNDED_NONE;
1001                     *pos -= 4;
1002                     *size += 8;
1003                 }
1004             } else if (roundLeft && roundRight) {
1005             } else if (roundLeft) {
1006                 *round = horiz ? ROUNDED_LEFT : ROUNDED_TOP;
1007                 *size += 4;
1008             } else if (roundRight) {
1009                 *round = horiz ? ROUNDED_RIGHT : ROUNDED_BOTTOM;
1010                 *pos -= 4;
1011                 *size += 4;
1012             } else {
1013                 *round = ROUNDED_NONE;
1014                 *pos -= 4;
1015                 *size += 8;
1016             }
1017         }
1018     }
1019 }
1020 
1021 void
1022 getEntryParentBgCol(GtkWidget *widget, GdkColor *color)
1023 {
1024     GtkWidget *parent = nullptr;
1025     GtkStyle *style = nullptr;
1026 
1027     if (!widget) {
1028         color->red = color->green = color->blue = 65535;
1029         return;
1030     }
1031     parent = gtk_widget_get_parent(widget);
1032     while (parent && !gtk_widget_get_has_window(parent)) {
1033         GtkStyle *style = nullptr;
1034         if (opts.tabBgnd && GTK_IS_NOTEBOOK(parent) &&
1035             (style = gtk_widget_get_style(parent))) {
1036             qtcShade(&style->bg[GTK_STATE_NORMAL], color,
1037                      TO_FACTOR(opts.tabBgnd), opts.shading);
1038             return;
1039         }
1040         parent = gtk_widget_get_parent(parent);
1041     }
1042     if (!parent) {
1043         parent = widget;
1044     }
1045     if ((style = gtk_widget_get_style(parent))) {
1046         *color = style->bg[gtk_widget_get_state(parent)];
1047     }
1048 }
1049 
1050 bool
1051 compositingActive(GtkWidget *widget)
1052 {
1053     GdkScreen *screen = (widget ? gtk_widget_get_screen(widget) :
1054                          gdk_screen_get_default());
1055     return screen && gdk_screen_is_composited(screen);
1056 }
1057 
1058 bool
1059 isRgbaWidget(GtkWidget *widget)
1060 {
1061     if (widget) {
1062         GdkVisual *visual = gtk_widget_get_visual(widget);
1063         return gdk_visual_get_depth(visual) == 32;
1064     }
1065     return false;
1066 }
1067 
1068 void
1069 enableBlurBehind(GtkWidget *w, bool enable)
1070 {
1071     GtkWindow *topLevel = GTK_WINDOW(gtk_widget_get_toplevel(w));
1072     if (topLevel) {
1073         GtkWidgetProps props(w);
1074         int oldValue = props->blurBehind;
1075         if (oldValue == 0 || (enable && oldValue != 1) ||
1076             (!enable && oldValue != 2)) {
1077             props->blurBehind = enable ? 1 : 2;
1078             xcb_window_t wid =
1079                 GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(topLevel)));
1080             qtcX11BlurTrigger(wid, enable, 0, nullptr);
1081         }
1082     }
1083 }
1084 
1085 void
1086 getTopLevelSize(GdkWindow *window, int *w, int *h)
1087 {
1088     if (!(window && GDK_IS_WINDOW(window))) {
1089         qtcAssign(w, -1);
1090         qtcAssign(h, -1);
1091     } else {
1092         GdkWindow *topLevel = gdk_window_get_toplevel(window);
1093         if (topLevel) {
1094             gdk_drawable_get_size(topLevel, w, h);
1095         } else {
1096             gdk_drawable_get_size(window, w, h);
1097         }
1098     }
1099 }
1100 
1101 void
1102 getTopLevelOrigin(GdkWindow *window, int *x, int *y)
1103 {
1104     qtcAssign(x, 0);
1105     qtcAssign(y, 0);
1106     if (window) {
1107         while(window && GDK_IS_WINDOW(window) &&
1108               gdk_window_get_window_type(window) != GDK_WINDOW_TOPLEVEL &&
1109               gdk_window_get_window_type(window) != GDK_WINDOW_TEMP) {
1110             int xloc;
1111             int yloc;
1112             gdk_window_get_position(window, &xloc, &yloc);
1113             qtcAssign(x, *x + xloc);
1114             qtcAssign(y, *y + yloc);
1115             window = gdk_window_get_parent(window);
1116         }
1117     }
1118 }
1119 
1120 bool
1121 mapToTopLevel(GdkWindow *window, GtkWidget *widget,
1122               int *x, int *y, int *w, int *h)
1123 {
1124     // always initialize arguments (to invalid values)
1125     qtcAssign(x, 0);
1126     qtcAssign(y, 0);
1127     int _w;
1128     int _h;
1129     w = qtcDefault(w, &_w);
1130     h = qtcDefault(h, &_h);
1131     *w = -1;
1132     *h = -1;
1133     if (!(window && GDK_IS_WINDOW(window))) {
1134         if (widget) {
1135             int xlocal;
1136             int ylocal;
1137             // this is an alternative way to get widget position with respect to
1138             // top level window and top level window size. This is used in case
1139             // the GdkWindow passed as argument is actually a 'non window'
1140             // drawable
1141             window = gtk_widget_get_parent_window(widget);
1142             getTopLevelSize(window, w, h);
1143             if (gtk_widget_translate_coordinates(
1144                     widget, gtk_widget_get_toplevel(widget), 0, 0,
1145                     &xlocal, &ylocal)) {
1146                 qtcAssign(x, xlocal);
1147                 qtcAssign(y, ylocal);
1148                 return *w > 0 && *h > 0;
1149             }
1150         }
1151     } else {
1152         // get window size and height
1153         getTopLevelSize(window, w, h);
1154         getTopLevelOrigin(window, x, y);
1155         return *w > 0 && *h > 0;
1156     }
1157     return false;
1158 }
1159 
1160 bool
1161 treeViewCellHasChildren(GtkTreeView *treeView, GtkTreePath *path)
1162 {
1163     // check treeview and path
1164     if (treeView && path) {
1165         GtkTreeModel *model = gtk_tree_view_get_model(treeView);
1166         if (model) {
1167             GtkTreeIter iter;
1168             if (gtk_tree_model_get_iter(model, &iter, path)) {
1169                 return gtk_tree_model_iter_has_child(model, &iter);
1170             }
1171         }
1172     }
1173     return false;
1174 }
1175 
1176 bool
1177 treeViewCellIsLast(GtkTreeView *treeView, GtkTreePath *path)
1178 {
1179     // check treeview and path
1180     if (treeView && path) {
1181         GtkTreeModel *model = gtk_tree_view_get_model(treeView);
1182         if (model) {
1183             GtkTreeIter iter;
1184             if (gtk_tree_model_get_iter(model, &iter, path)) {
1185                 return !gtk_tree_model_iter_next(model, &iter);
1186             }
1187         }
1188     }
1189     return false;
1190 }
1191 
1192 GtkTreePath*
1193 treeViewPathParent(GtkTreeView*, GtkTreePath *path)
1194 {
1195     if (path) {
1196         GtkTreePath *parent = gtk_tree_path_copy(path);
1197         if (gtk_tree_path_up(parent)) {
1198             return parent;
1199         } else {
1200             gtk_tree_path_free(parent);
1201         }
1202     }
1203     return nullptr;
1204 }
1205 
1206 void
1207 generateColors()
1208 {
1209     shadeColors(&qtSettings.colors[PAL_ACTIVE][COLOR_WINDOW],
1210                 qtcPalette.background);
1211     shadeColors(&qtSettings.colors[PAL_ACTIVE][COLOR_BUTTON],
1212                 qtcPalette.button[PAL_ACTIVE]);
1213     shadeColors(&qtSettings.colors[PAL_DISABLED][COLOR_BUTTON],
1214                 qtcPalette.button[PAL_DISABLED]);
1215     shadeColors(&qtSettings.colors[PAL_ACTIVE][COLOR_SELECTED],
1216                 qtcPalette.highlight);
1217     shadeColors(&qtSettings.colors[PAL_ACTIVE][COLOR_FOCUS],
1218                 qtcPalette.focus);
1219     switch (opts.shadeMenubars) {
1220     case SHADE_WINDOW_BORDER:
1221         qtcPalette.wborder[0] = qtcNew(GdkColor, TOTAL_SHADES + 1);
1222         qtcPalette.wborder[1] = qtcNew(GdkColor, TOTAL_SHADES + 1);
1223         shadeColors(&qtSettings.colors[PAL_INACTIVE][COLOR_WINDOW_BORDER],
1224                     qtcPalette.wborder[0]);
1225         shadeColors(&qtSettings.colors[PAL_ACTIVE][COLOR_WINDOW_BORDER],
1226                     qtcPalette.wborder[1]);
1227         break;
1228     case SHADE_NONE:
1229         memcpy(qtcPalette.menubar, qtcPalette.background,
1230                sizeof(GdkColor) * (TOTAL_SHADES + 1));
1231         break;
1232     case SHADE_BLEND_SELECTED: {
1233         GdkColor mid = midColor(&qtcPalette.highlight[ORIGINAL_SHADE],
1234                                 &qtcPalette.background[ORIGINAL_SHADE]);
1235         shadeColors(&mid, qtcPalette.menubar);
1236         break;
1237     }
1238     case SHADE_SELECTED: {
1239         GdkColor color;
1240         if (IS_GLASS(opts.appearance)) {
1241             qtcShade(&qtcPalette.highlight[ORIGINAL_SHADE], &color,
1242                      MENUBAR_GLASS_SELECTED_DARK_FACTOR, opts.shading);
1243         } else {
1244             color = qtcPalette.highlight[ORIGINAL_SHADE];
1245         }
1246         shadeColors(&color, qtcPalette.menubar);
1247         break;
1248     }
1249     case SHADE_CUSTOM:
1250         shadeColors(&opts.customMenubarsColor, qtcPalette.menubar);
1251         break;
1252     case SHADE_DARKEN: {
1253         GdkColor color;
1254         qtcShade(&qtcPalette.background[ORIGINAL_SHADE], &color,
1255                  MENUBAR_DARK_FACTOR, opts.shading);
1256         shadeColors(&color, qtcPalette.menubar);
1257         break;
1258     }
1259     }
1260     switch (opts.shadeSliders) {
1261     case SHADE_SELECTED:
1262         qtcPalette.slider = qtcPalette.highlight;
1263         break;
1264     case SHADE_CUSTOM:
1265         qtcPalette.slider = qtcNew(GdkColor, TOTAL_SHADES + 1);
1266         shadeColors(&opts.customSlidersColor, qtcPalette.slider);
1267         break;
1268     case SHADE_BLEND_SELECTED: {
1269         GdkColor mid = midColor(&qtcPalette.highlight[ORIGINAL_SHADE],
1270                                 &qtcPalette.button[PAL_ACTIVE][ORIGINAL_SHADE]);
1271         qtcPalette.slider = qtcNew(GdkColor, TOTAL_SHADES + 1);
1272         shadeColors(&mid, qtcPalette.slider);
1273     }
1274     default:
1275         break;
1276     }
1277     qtcPalette.combobtn = nullptr;
1278     switch (opts.comboBtn) {
1279     case SHADE_SELECTED:
1280         qtcPalette.combobtn = qtcPalette.highlight;
1281         break;
1282     case SHADE_CUSTOM:
1283         if (opts.shadeSliders == SHADE_CUSTOM &&
1284             EQUAL_COLOR(opts.customSlidersColor, opts.customComboBtnColor)) {
1285             qtcPalette.combobtn = qtcPalette.slider;
1286         } else {
1287             qtcPalette.combobtn = qtcNew(GdkColor, TOTAL_SHADES + 1);
1288             shadeColors(&opts.customComboBtnColor, qtcPalette.combobtn);
1289         }
1290         break;
1291     case SHADE_BLEND_SELECTED:
1292         if (opts.shadeSliders == SHADE_BLEND_SELECTED) {
1293             qtcPalette.combobtn = qtcPalette.slider;
1294         } else {
1295             GdkColor mid =
1296                 midColor(&qtcPalette.highlight[ORIGINAL_SHADE],
1297                          &qtcPalette.button[PAL_ACTIVE][ORIGINAL_SHADE]);
1298             qtcPalette.combobtn = qtcNew(GdkColor, TOTAL_SHADES + 1);
1299             shadeColors(&mid, qtcPalette.combobtn);
1300         }
1301     default:
1302         break;
1303     }
1304     qtcPalette.sortedlv = nullptr;
1305     switch (opts.sortedLv) {
1306     case SHADE_DARKEN: {
1307         GdkColor color;
1308         qtcPalette.sortedlv = qtcNew(GdkColor, TOTAL_SHADES + 1);
1309         qtcShade(opts.lvButton ?
1310                  &qtcPalette.button[PAL_ACTIVE][ORIGINAL_SHADE] :
1311                  &qtcPalette.background[ORIGINAL_SHADE],
1312                  &color, LV_HEADER_DARK_FACTOR, opts.shading);
1313         shadeColors(&color, qtcPalette.sortedlv);
1314         break;
1315     }
1316     case SHADE_SELECTED:
1317         qtcPalette.sortedlv = qtcPalette.highlight;
1318         break;
1319     case SHADE_CUSTOM:
1320         if (opts.shadeSliders == SHADE_CUSTOM &&
1321             EQUAL_COLOR(opts.customSlidersColor, opts.customSortedLvColor)) {
1322             qtcPalette.sortedlv = qtcPalette.slider;
1323         } else if (opts.comboBtn == SHADE_CUSTOM &&
1324                    EQUAL_COLOR(opts.customComboBtnColor,
1325                                opts.customSortedLvColor)) {
1326             qtcPalette.sortedlv = qtcPalette.combobtn;
1327         } else {
1328             qtcPalette.sortedlv = qtcNew(GdkColor, TOTAL_SHADES + 1);
1329             shadeColors(&opts.customSortedLvColor, qtcPalette.sortedlv);
1330         }
1331         break;
1332     case SHADE_BLEND_SELECTED:
1333         if (opts.shadeSliders == SHADE_BLEND_SELECTED) {
1334             qtcPalette.sortedlv = qtcPalette.slider;
1335         } else if (opts.comboBtn == SHADE_BLEND_SELECTED) {
1336             qtcPalette.sortedlv=qtcPalette.combobtn;
1337         } else {
1338             GdkColor mid =
1339                 midColor(&qtcPalette.highlight[ORIGINAL_SHADE], opts.lvButton ?
1340                          &qtcPalette.button[PAL_ACTIVE][ORIGINAL_SHADE] :
1341                          &qtcPalette.background[ORIGINAL_SHADE]);
1342             qtcPalette.sortedlv = qtcNew(GdkColor, TOTAL_SHADES + 1);
1343             shadeColors(&mid, qtcPalette.sortedlv);
1344         }
1345     default:
1346         break;
1347     }
1348     switch (opts.defBtnIndicator) {
1349     case IND_TINT: {
1350         GdkColor col = tint(&qtcPalette.button[PAL_ACTIVE][ORIGINAL_SHADE],
1351                             &qtcPalette.highlight[ORIGINAL_SHADE],
1352                             DEF_BNT_TINT);
1353         qtcPalette.defbtn = qtcNew(GdkColor, TOTAL_SHADES + 1);
1354         shadeColors(&col, qtcPalette.defbtn);
1355         break;
1356     }
1357     case IND_GLOW:
1358     case IND_SELECTED:
1359         qtcPalette.defbtn = qtcPalette.highlight;
1360         break;
1361     default:
1362         break;
1363     case IND_COLORED:
1364         if (opts.shadeSliders == SHADE_BLEND_SELECTED) {
1365             qtcPalette.defbtn = qtcPalette.slider;
1366         } else {
1367             GdkColor mid =
1368                 midColor(&qtcPalette.highlight[ORIGINAL_SHADE],
1369                          &qtcPalette.button[PAL_ACTIVE][ORIGINAL_SHADE]);
1370             qtcPalette.defbtn = qtcNew(GdkColor, TOTAL_SHADES + 1);
1371             shadeColors(&mid, qtcPalette.defbtn);
1372         }
1373     }
1374 
1375     if (opts.coloredMouseOver) {
1376         qtcPalette.mouseover = qtcNew(GdkColor, TOTAL_SHADES + 1);
1377         shadeColors(&qtSettings.colors[PAL_ACTIVE][COLOR_HOVER],
1378                     qtcPalette.mouseover);
1379     }
1380 
1381     switch (opts.shadeCheckRadio) {
1382     default:
1383         qtcPalette.check_radio =
1384             &qtSettings.colors[PAL_ACTIVE][opts.crButton ?
1385                                            COLOR_BUTTON_TEXT : COLOR_TEXT];
1386         break;
1387     case SHADE_BLEND_SELECTED:
1388     case SHADE_SELECTED:
1389         qtcPalette.check_radio = &qtSettings.colors[PAL_ACTIVE][COLOR_SELECTED];
1390         break;
1391     case SHADE_CUSTOM:
1392         qtcPalette.check_radio = &opts.customCheckRadioColor;
1393     }
1394 
1395     {
1396         GdkColor color;
1397         GdkColor *cols = (opts.shadePopupMenu ? menuColors(true) :
1398                           qtcPalette.background);
1399         if (opts.lighterPopupMenuBgnd) {
1400             qtcShade(&cols[ORIGINAL_SHADE], &color,
1401                      TO_FACTOR(opts.lighterPopupMenuBgnd), opts.shading);
1402         } else {
1403             color = cols[ORIGINAL_SHADE];
1404         }
1405         shadeColors(&color, qtcPalette.menu);
1406     }
1407 
1408     /* Tear off menu items dont seem to draw they're background, and the
1409      * default background is drawn :-(  Fix/hack this by making that
1410      * background the correct color */
1411     if (opts.lighterPopupMenuBgnd || opts.shadePopupMenu) {
1412         static const char *format="style \"" RC_SETTING "Mnu\" { "
1413                                     "bg[NORMAL]=\"#%02X%02X%02X\" "
1414                                     "fg[NORMAL]=\"#%02X%02X%02X\" "
1415                                     "text[INSENSITIVE]=\"#%02X%02X%02X\" "
1416                                     "} class \"GtkMenu\" style \"" RC_SETTING "Mnu\" "
1417                                     "widget_class \"*Menu.*Label\" style \"" RC_SETTING "Mnu\""
1418                                     " style  \"" RC_SETTING "CView\" = \"" RC_SETTING "Mnu\" { text[NORMAL]=\"#%02X%02X%02X\" } "
1419                                     " widget_class \"*<GtkMenuItem>*<GtkCellView>\" style \"" RC_SETTING "CView\"";
1420         char *str = (char*)malloc(strlen(format) + 24 + 1);
1421 
1422         if (str) {
1423             GdkColor *col = &qtcPalette.menu[ORIGINAL_SHADE];
1424             GdkColor text = opts.shadePopupMenu ? SHADE_WINDOW_BORDER == opts.shadeMenubars
1425                                 ? qtSettings.colors[PAL_ACTIVE][COLOR_WINDOW_BORDER_TEXT]
1426                                 : opts.customMenuTextColor
1427                                     ? opts.customMenuNormTextColor
1428                                     : SHADE_BLEND_SELECTED == opts.shadeMenubars || SHADE_SELECTED == opts.shadeMenubars ||
1429                                     (SHADE_CUSTOM == opts.shadeMenubars && TOO_DARK(qtcPalette.menubar[ORIGINAL_SHADE]))
1430                                     ? qtSettings.colors[PAL_ACTIVE][COLOR_TEXT_SELECTED]
1431                                     : qtSettings.colors[PAL_ACTIVE][COLOR_TEXT]
1432                             : qtSettings.colors[PAL_ACTIVE][COLOR_TEXT],
1433                      mid=opts.shadePopupMenu ? midColor(col, &text) : qtSettings.colors[PAL_DISABLED][COLOR_TEXT];
1434             sprintf(str, format, toQtColor(col->red), toQtColor(col->green), toQtColor(col->blue),
1435                                  toQtColor(text.red), toQtColor(text.green), toQtColor(text.blue),
1436                                  toQtColor(mid.red),  toQtColor(mid.green),  toQtColor(mid.blue),
1437                                  toQtColor(text.red), toQtColor(text.green), toQtColor(text.blue));
1438             gtk_rc_parse_string(str);
1439             free(str);
1440         }
1441     }
1442 
1443     switch (opts.menuStripe) {
1444     default:
1445     case SHADE_NONE:
1446         opts.customMenuStripeColor = qtcPalette.background[ORIGINAL_SHADE];
1447         break;
1448     case SHADE_DARKEN:
1449         opts.customMenuStripeColor =
1450             (opts.lighterPopupMenuBgnd || opts.shadePopupMenu ?
1451              qtcPalette.menu[ORIGINAL_SHADE] :
1452              qtcPalette.background[MENU_STRIPE_SHADE]);
1453         break;
1454     case SHADE_CUSTOM:
1455         break;
1456     case SHADE_BLEND_SELECTED:
1457         opts.customMenuStripeColor =
1458             midColor(&qtcPalette.highlight[ORIGINAL_SHADE],
1459                      opts.lighterPopupMenuBgnd || opts.shadePopupMenu ?
1460                      &qtcPalette.menu[ORIGINAL_SHADE] :
1461                      &qtcPalette.background[ORIGINAL_SHADE]);
1462         break;
1463     case SHADE_SELECTED:
1464         opts.customMenuStripeColor = qtcPalette.highlight[MENU_STRIPE_SHADE];
1465     }
1466 
1467     qtcPalette.selectedcr = nullptr;
1468     switch (opts.crColor) {
1469     case SHADE_DARKEN: {
1470         GdkColor color;
1471         qtcPalette.selectedcr = qtcNew(GdkColor, TOTAL_SHADES + 1);
1472         qtcShade(&qtcPalette.button[PAL_ACTIVE][ORIGINAL_SHADE], &color,
1473                  LV_HEADER_DARK_FACTOR, opts.shading);
1474         shadeColors(&color, qtcPalette.selectedcr);
1475         break;
1476     }
1477     default:
1478     case SHADE_NONE:
1479         qtcPalette.selectedcr = qtcPalette.button[PAL_ACTIVE];
1480         break;
1481     case SHADE_SELECTED:
1482         qtcPalette.selectedcr = qtcPalette.highlight;
1483         break;
1484     case SHADE_CUSTOM:
1485         if (opts.shadeSliders == SHADE_CUSTOM &&
1486             EQUAL_COLOR(opts.customSlidersColor, opts.customCrBgndColor)) {
1487             qtcPalette.selectedcr = qtcPalette.slider;
1488         } else if (opts.comboBtn == SHADE_CUSTOM &&
1489                    EQUAL_COLOR(opts.customComboBtnColor,
1490                                opts.customCrBgndColor)) {
1491             qtcPalette.selectedcr = qtcPalette.combobtn;
1492         } else if (opts.sortedLv == SHADE_CUSTOM &&
1493                    EQUAL_COLOR(opts.customSortedLvColor,
1494                                opts.customCrBgndColor)) {
1495             qtcPalette.selectedcr = qtcPalette.sortedlv;
1496         } else {
1497             qtcPalette.selectedcr = qtcNew(GdkColor, TOTAL_SHADES + 1);
1498             shadeColors(&opts.customCrBgndColor, qtcPalette.selectedcr);
1499         }
1500         break;
1501     case SHADE_BLEND_SELECTED:
1502         if (opts.shadeSliders == SHADE_BLEND_SELECTED) {
1503             qtcPalette.selectedcr = qtcPalette.slider;
1504         } else if (opts.comboBtn == SHADE_BLEND_SELECTED) {
1505             qtcPalette.selectedcr = qtcPalette.combobtn;
1506         } else if (opts.sortedLv == SHADE_BLEND_SELECTED) {
1507             qtcPalette.selectedcr = qtcPalette.sortedlv;
1508         } else {
1509             GdkColor mid =
1510                 midColor(&qtcPalette.highlight[ORIGINAL_SHADE],
1511                          &qtcPalette.button[PAL_ACTIVE][ORIGINAL_SHADE]);
1512             qtcPalette.selectedcr = qtcNew(GdkColor, TOTAL_SHADES + 1);
1513             shadeColors(&mid, qtcPalette.selectedcr);
1514         }
1515     }
1516 
1517     qtcPalette.sidebar = nullptr;
1518     if (!opts.stdSidebarButtons) {
1519         if (opts.shadeSliders == SHADE_BLEND_SELECTED) {
1520              qtcPalette.sidebar = qtcPalette.slider;
1521         } else if (opts.defBtnIndicator == IND_COLORED) {
1522             qtcPalette.sidebar = qtcPalette.defbtn;
1523         } else {
1524             GdkColor mid =
1525                 midColor(&qtcPalette.highlight[ORIGINAL_SHADE],
1526                          &qtcPalette.button[PAL_ACTIVE][ORIGINAL_SHADE]);
1527             qtcPalette.sidebar = qtcNew(GdkColor, TOTAL_SHADES + 1);
1528             shadeColors(&mid, qtcPalette.sidebar);
1529         }
1530     }
1531 
1532     qtcPalette.progress = nullptr;
1533     switch (opts.progressColor) {
1534     case SHADE_NONE:
1535         qtcPalette.progress = qtcPalette.background;
1536     default:
1537         /* Not set! */
1538         break;
1539     case SHADE_CUSTOM:
1540         if (opts.shadeSliders == SHADE_CUSTOM &&
1541             EQUAL_COLOR(opts.customSlidersColor, opts.customProgressColor)) {
1542             qtcPalette.progress = qtcPalette.slider;
1543         } else if (opts.comboBtn == SHADE_CUSTOM &&
1544                    EQUAL_COLOR(opts.customComboBtnColor,
1545                                opts.customProgressColor)) {
1546             qtcPalette.progress = qtcPalette.combobtn;
1547         } else if (opts.sortedLv == SHADE_CUSTOM &&
1548                    EQUAL_COLOR(opts.customSortedLvColor,
1549                                opts.customProgressColor)) {
1550             qtcPalette.progress = qtcPalette.sortedlv;
1551         } else if (opts.crColor == SHADE_CUSTOM &&
1552                    EQUAL_COLOR(opts.customCrBgndColor,
1553                                opts.customProgressColor)) {
1554             qtcPalette.progress = qtcPalette.selectedcr;
1555         } else {
1556             qtcPalette.progress = qtcNew(GdkColor, TOTAL_SHADES + 1);
1557             shadeColors(&opts.customProgressColor, qtcPalette.progress);
1558         }
1559         break;
1560     case SHADE_BLEND_SELECTED:
1561         if (opts.shadeSliders == SHADE_BLEND_SELECTED) {
1562             qtcPalette.progress = qtcPalette.slider;
1563         } else if (opts.comboBtn == SHADE_BLEND_SELECTED) {
1564             qtcPalette.progress = qtcPalette.combobtn;
1565         } else if (opts.sortedLv == SHADE_BLEND_SELECTED) {
1566             qtcPalette.progress = qtcPalette.sortedlv;
1567         } else if (opts.crColor == SHADE_BLEND_SELECTED) {
1568             qtcPalette.progress = qtcPalette.selectedcr;
1569         } else {
1570             GdkColor mid =
1571                 midColor(&qtcPalette.highlight[ORIGINAL_SHADE],
1572                          &qtcPalette.background[ORIGINAL_SHADE]);
1573             qtcPalette.progress = qtcNew(GdkColor, TOTAL_SHADES + 1);
1574             shadeColors(&mid, qtcPalette.progress);
1575         }
1576     }
1577 }
1578 
1579 GdkColor*
1580 getCheckRadioCol(GtkStyle *style, GtkStateType state, bool mnu)
1581 {
1582     return (!qtSettings.qt4 && mnu ? &style->text[state] :
1583             state == GTK_STATE_INSENSITIVE ?
1584             &qtSettings.colors[PAL_DISABLED][opts.crButton ? COLOR_BUTTON_TEXT :
1585                                              COLOR_TEXT] :
1586             qtcPalette.check_radio);
1587 }
1588 
1589 bool
1590 objectIsA(const GObject *object, const char *type_name)
1591 {
1592     if (object) {
1593         GType tmp = g_type_from_name(type_name);
1594         if (tmp) {
1595             return g_type_check_instance_is_a((GTypeInstance*)object, tmp);
1596         }
1597     }
1598     return false;
1599 }
1600 
1601 }