1 /*****************************************************************************
2  *   Copyright 2003 - 2010 Craig Drummond <craig.p.drummond@gmail.com>       *
3  *   Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com>                     *
4  *                                                                           *
5  *   This program is free software; you can redistribute it and/or modify    *
6  *   it under the terms of the GNU Lesser General Public License as          *
7  *   published by the Free Software Foundation; either version 2.1 of the    *
8  *   License, or (at your option) version 3, or any later version accepted   *
9  *   by the membership of KDE e.V. (or its successor approved by the         *
10  *   membership of KDE e.V.), which shall act as a proxy defined in          *
11  *   Section 6 of version 3 of the license.                                  *
12  *                                                                           *
13  *   This program is distributed in the hope that it will be useful,         *
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *
16  *   Lesser General Public License for more details.                         *
17  *                                                                           *
18  *   You should have received a copy of the GNU Lesser General Public        *
19  *   License along with this library. If not,                                *
20  *   see <http://www.gnu.org/licenses/>.                                     *
21  *****************************************************************************/
22 
23 #include "helpers.h"
24 
25 #include <qtcurve-utils/gtkprops.h>
26 #include <qtcurve-utils/x11blur.h>
27 #include <qtcurve-utils/color.h>
28 #include <qtcurve-utils/log.h>
29 #include <qtcurve-utils/strs.h>
30 
31 #include "qt_settings.h"
32 #include <gdk/gdkx.h>
33 
34 namespace QtCurve {
35 
36 void
debugDisplayWidget(GtkWidget * widget,int level)37 debugDisplayWidget(GtkWidget *widget, int level)
38 {
39     if (Log::level() > LogLevel::Debug)
40         return;
41     if (level < 0 || !widget) {
42         printf("\n");
43         return;
44     }
45     const char *widget_name = gtk_widget_get_name(widget);
46     qtcDebug("%s(%s)[%p] ", gTypeName(widget),
47              widget_name ? widget_name : "NULL", widget);
48     debugDisplayWidget(gtk_widget_get_parent(widget), level - 1);
49 }
50 
51 bool
haveAlternateListViewCol()52 haveAlternateListViewCol()
53 {
54     return (qtSettings.colors[PAL_ACTIVE][COLOR_LV].red != 0 ||
55             qtSettings.colors[PAL_ACTIVE][COLOR_LV].green != 0 ||
56             qtSettings.colors[PAL_ACTIVE][COLOR_LV].blue != 0);
57 }
58 
59 GdkColor*
menuColors(bool active)60 menuColors(bool active)
61 {
62     return (SHADE_WINDOW_BORDER == opts.shadeMenubars ?
63             qtcPalette.wborder[active ? 1 : 0] :
64             SHADE_NONE == opts.shadeMenubars ||
65             (opts.shadeMenubarOnlyWhenActive && !active) ?
66             qtcPalette.background : qtcPalette.menubar);
67 }
68 
69 EBorder
shadowToBorder(GtkShadowType shadow)70 shadowToBorder(GtkShadowType shadow)
71 {
72     switch (shadow) {
73     default:
74     case GTK_SHADOW_NONE:
75         return BORDER_FLAT;
76     case GTK_SHADOW_IN:
77     case GTK_SHADOW_ETCHED_IN:
78         return BORDER_SUNKEN;
79     case GTK_SHADOW_OUT:
80     case GTK_SHADOW_ETCHED_OUT:
81         return BORDER_RAISED;
82     }
83 }
84 
85 bool
useButtonColor(const char * detail)86 useButtonColor(const char *detail)
87 {
88     return (detail &&
89             (oneOf(detail, "optionmenu", "button", "buttondefault",
90                    "togglebuttondefault", "togglebutton", "hscale", "vscale",
91                    "spinbutton", "spinbutton_up", "spinbutton_down", "slider",
92                    "qtc-slider", "stepper") ||
93              (detail[0] && Str::startsWith(detail + 1, "scrollbar"))));
94 }
95 
96 void
shadeColors(const GdkColor * base,GdkColor * vals)97 shadeColors(const GdkColor *base, GdkColor *vals)
98 {
99     bool useCustom = USE_CUSTOM_SHADES(opts);
100     double hl = TO_FACTOR(opts.highlightFactor);
101 
102     for (int i = 0;i < QTC_NUM_STD_SHADES;i++) {
103         qtcShade(base, &vals[i], useCustom ? opts.customShades[i] :
104                  qtcShadeGetIntern(opts.contrast, i, opts.darkerBorders,
105                                    opts.shading), opts.shading);
106     }
107     qtcShade(base, &vals[SHADE_ORIG_HIGHLIGHT], hl, opts.shading);
108     qtcShade(&vals[4], &vals[SHADE_4_HIGHLIGHT], hl, opts.shading);
109     qtcShade(&vals[2], &vals[SHADE_2_HIGHLIGHT], hl, opts.shading);
110     vals[ORIGINAL_SHADE] = *base;
111 }
112 
113 bool
isSortColumn(GtkWidget * button)114 isSortColumn(GtkWidget *button)
115 {
116     GtkWidget *parent = nullptr;
117     if (button && (parent = gtk_widget_get_parent(button)) &&
118         GTK_IS_TREE_VIEW(parent)) {
119 #if GTK_CHECK_VERSION(2, 90, 0)
120         GtkWidget *box = (GTK_IS_BUTTON(button) ?
121                           gtk_bin_get_child(GTK_BIN(button)) : nullptr);
122 
123         if (box && GTK_IS_BOX(box)) {
124             GList *children = gtk_container_get_children(GTK_CONTAINER(box));
125             bool found = false;
126             for (GList *child = children;child && !found;
127                  child = g_list_next(child)) {
128                 if (GTK_IS_ARROW(child->data)) {
129                     int val;
130                     g_object_get(child->data, "arrow-type", &val, nullptr);
131                     if (GTK_ARROW_NONE != val) {
132                         found = true;
133                     }
134                 }
135             }
136             if (children) {
137                 g_list_free(children);
138             }
139             return found;
140         }
141 #else
142         GtkWidget *sort = nullptr;
143         GList *columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(parent));
144         for (GList *column = columns;column && !sort && sort != button;
145              column = g_list_next(column)) {
146             if (GTK_IS_TREE_VIEW_COLUMN(column->data)) {
147                 GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN(column->data);
148                 if (gtk_tree_view_column_get_sort_indicator(c)) {
149                     sort = c->button;
150                 }
151             }
152         }
153 
154         if (columns) {
155             g_list_free(columns);
156         }
157         return sort == button;
158 #endif
159     }
160     return false;
161 };
162 
163 GdkColor*
getCellCol(GdkColor * std,const char * detail)164 getCellCol(GdkColor *std, const char *detail)
165 {
166     if (!qtSettings.shadeSortedList || !strstr(detail, "_sorted"))
167         return std;
168 
169     static GdkColor shaded;
170     shaded = *std;
171 
172     if (isBlack(shaded)) {
173         shaded.red = shaded.green = shaded.blue = 55 << 8;
174     } else {
175         double r = shaded.red / 65535.0;
176         double g = shaded.green / 65535.0;
177         double b = shaded.blue / 65535.0;
178         double h, s, v;
179 
180         qtcRgbToHsv(r, g, b, &h, &s, &v);
181 
182         if (v > 175.0 / 255.0) {
183             v *= 100.0 / 104.0;
184         } else {
185             v *= 120.0 / 100.0;
186         }
187 
188         if (v > 1.0) {
189             s = qtcMax(0, s - (v - 1.0));
190             v = 1.0;
191         }
192 
193         qtcHsvToRgb(&r, &g, &b, h, s, v);
194         shaded.red = r * 65535.0;
195         shaded.green = g * 65535.0;
196         shaded.blue = b * 65535.0;
197     }
198     return &shaded;
199 }
200 
201 bool
reverseLayout(GtkWidget * widget)202 reverseLayout(GtkWidget *widget)
203 {
204     if (widget) {
205         return gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL;
206     }
207     return false;
208 }
209 
210 bool
isOnToolbar(GtkWidget * widget,bool * horiz,int level)211 isOnToolbar(GtkWidget *widget, bool *horiz, int level)
212 {
213     if (widget) {
214         if (GTK_IS_TOOLBAR(widget)) {
215             qtcAssign(horiz, Widget::isHorizontal(widget));
216             return true;
217         } else if (level < 4) {
218             return isOnToolbar(gtk_widget_get_parent(widget), horiz, level + 1);
219         }
220     }
221     return false;
222 }
223 
224 bool
isOnHandlebox(GtkWidget * widget,bool * horiz,int level)225 isOnHandlebox(GtkWidget *widget, bool *horiz, int level)
226 {
227     if (widget) {
228         if (GTK_IS_HANDLE_BOX(widget)) {
229             qtcAssign(horiz, oneOf(gtk_handle_box_get_handle_position(
230                                        GTK_HANDLE_BOX(widget)),
231                                    GTK_POS_LEFT, GTK_POS_RIGHT));
232             return true;
233         } else if (level < 4) {
234             return isOnHandlebox(gtk_widget_get_parent(widget), horiz,
235                                  level + 1);
236         }
237     }
238     return false;
239 }
240 
241 bool
isButtonOnToolbar(GtkWidget * widget,bool * horiz)242 isButtonOnToolbar(GtkWidget *widget, bool *horiz)
243 {
244     GtkWidget *parent = nullptr;
245     if (widget && (parent = gtk_widget_get_parent(widget)) &&
246         GTK_IS_BUTTON(widget)) {
247         return isOnToolbar(parent, horiz, 0);
248     }
249     return false;
250 }
251 
252 bool
isButtonOnHandlebox(GtkWidget * widget,bool * horiz)253 isButtonOnHandlebox(GtkWidget *widget, bool *horiz)
254 {
255     GtkWidget *parent = nullptr;
256     if (widget && (parent = gtk_widget_get_parent(widget)) &&
257         GTK_IS_BUTTON(widget)) {
258         return isOnHandlebox(parent, horiz, 0);
259     }
260     return false;
261 }
262 
263 bool
isOnStatusBar(GtkWidget * widget,int level)264 isOnStatusBar(GtkWidget *widget, int level)
265 {
266     GtkWidget *parent = gtk_widget_get_parent(widget);
267     if (parent) {
268         if (GTK_IS_STATUSBAR(parent)) {
269             return true;
270         } else if (level < 4) {
271             return isOnStatusBar(parent, level + 1);
272         }
273     }
274     return false;
275 }
276 
277 bool
isList(GtkWidget * widget)278 isList(GtkWidget *widget)
279 {
280     return widget && (GTK_IS_TREE_VIEW(widget) ||
281 #if !GTK_CHECK_VERSION(2, 90, 0)
282                       GTK_IS_CLIST(widget) || GTK_IS_LIST(widget) ||
283 #ifdef GTK_ENABLE_BROKEN
284                       GTK_IS_TREE(widget) ||
285 #endif
286                       GTK_IS_CTREE(widget) ||
287 #endif
288                       oneOf(gTypeName(widget), "GtkSCTree"));
289 }
290 
291 bool
isListViewHeader(GtkWidget * widget)292 isListViewHeader(GtkWidget *widget)
293 {
294     GtkWidget *parent = nullptr;
295     return widget && GTK_IS_BUTTON(widget) && (parent=gtk_widget_get_parent(widget)) &&
296            (isList(parent) ||
297             (GTK_APP_GIMP == qtSettings.app && GTK_IS_BOX(parent) &&
298              (parent=gtk_widget_get_parent(parent)) &&
299              GTK_IS_EVENT_BOX(parent) &&
300              (parent=gtk_widget_get_parent(parent)) &&
301              oneOf(gTypeName(parent), "GimpThumbBox")));
302 }
303 
304 bool
isEvolutionListViewHeader(GtkWidget * widget,const char * detail)305 isEvolutionListViewHeader(GtkWidget *widget, const char *detail)
306 {
307     GtkWidget *parent = nullptr;
308     return ((qtSettings.app == GTK_APP_EVOLUTION) && widget &&
309             oneOf(detail, "button") &&
310             oneOf(gTypeName(widget), "ECanvas") &&
311             (parent = gtk_widget_get_parent(widget)) &&
312             (parent = gtk_widget_get_parent(parent)) &&
313             GTK_IS_SCROLLED_WINDOW(parent));
314 }
315 
isOnListViewHeader(GtkWidget * w,int level)316 bool isOnListViewHeader(GtkWidget *w, int level)
317 {
318     if (w) {
319         if (isListViewHeader(w)) {
320             return true;
321         } else if (level < 4) {
322             return isOnListViewHeader(gtk_widget_get_parent(w), level + 1);
323         }
324     }
325     return false;
326 }
327 
328 bool
isPathButton(GtkWidget * widget)329 isPathButton(GtkWidget *widget)
330 {
331     return (widget && GTK_IS_BUTTON(widget) &&
332             oneOf(gTypeName(gtk_widget_get_parent(widget)), "GtkPathBar"));
333 }
334 
335 // static gboolean isTabButton(GtkWidget *widget)
336 // {
337 //     return widget && GTK_IS_BUTTON(widget) && gtk_widget_get_parent(widget) &&
338 //            (GTK_IS_NOTEBOOK(gtk_widget_get_parent(widget)) ||
339 //             (gtk_widget_get_parent(widget)->parent && GTK_IS_BOX(gtk_widget_get_parent(widget)) && GTK_IS_NOTEBOOK(gtk_widget_get_parent(widget)->parent)));
340 // }
341 
342 GtkWidget*
getComboEntry(GtkWidget * widget)343 getComboEntry(GtkWidget *widget)
344 {
345     GList *children = gtk_container_get_children(GTK_CONTAINER(widget));
346     GtkWidget *rv = nullptr;
347     for (GList *child = children;child && !rv;child = child->next) {
348         GtkWidget *boxChild = (GtkWidget *)child->data;
349         if (GTK_IS_ENTRY(boxChild)) {
350             rv = (GtkWidget*)boxChild;
351         }
352     }
353     if (children) {
354         g_list_free(children);
355     }
356     return rv;
357 }
358 
359 GtkWidget*
getComboButton(GtkWidget * widget)360 getComboButton(GtkWidget *widget)
361 {
362     GList *children = gtk_container_get_children(GTK_CONTAINER(widget));
363     GtkWidget *rv = nullptr;
364     for (GList *child = children;child && !rv;child = child->next) {
365         GtkWidget *boxChild = (GtkWidget*)child->data;
366         if (GTK_IS_BUTTON(boxChild)) {
367             rv = (GtkWidget*)boxChild;
368         }
369     }
370     if (children) {
371         g_list_free(children);
372     }
373     return rv;
374 }
375 
isSideBarBtn(GtkWidget * widget)376 bool isSideBarBtn(GtkWidget *widget)
377 {
378     return widget && oneOf(gTypeName(gtk_widget_get_parent(widget)),
379                            "GdlDockBar", "GdlSwitcher");
380 }
381 
isComboBoxButton(GtkWidget * widget)382 bool isComboBoxButton(GtkWidget *widget)
383 {
384     GtkWidget *parent = nullptr;
385     return widget && GTK_IS_BUTTON(widget) && (parent=gtk_widget_get_parent(widget)) &&
386            (QTC_COMBO_ENTRY(parent) || QTC_IS_COMBO(parent));
387 }
388 
isComboBox(GtkWidget * widget)389 bool isComboBox(GtkWidget *widget)
390 {
391     GtkWidget *parent=nullptr;
392     return widget && GTK_IS_BUTTON(widget) && (parent=gtk_widget_get_parent(widget)) &&
393            !QTC_COMBO_ENTRY(parent) && (GTK_IS_COMBO_BOX(parent) || QTC_IS_COMBO(parent));
394 }
395 
isComboBoxEntry(GtkWidget * widget)396 bool isComboBoxEntry(GtkWidget *widget)
397 {
398     GtkWidget *parent=nullptr;
399     return widget && GTK_IS_ENTRY(widget) && (parent=gtk_widget_get_parent(widget)) &&
400            (QTC_COMBO_ENTRY(parent) || QTC_IS_COMBO(parent));
401 }
402 
isComboBoxEntryButton(GtkWidget * widget)403 bool isComboBoxEntryButton(GtkWidget *widget)
404 {
405     GtkWidget *parent=nullptr;
406     return widget && (parent=gtk_widget_get_parent(widget)) && GTK_IS_TOGGLE_BUTTON(widget) && QTC_COMBO_ENTRY(parent);
407 }
408 
409 /*
410 static gboolean isSwtComboBoxEntry(GtkWidget *widget)
411 {
412     return GTK_APP_JAVA_SWT == qtSettings.app &&
413            isComboBoxEntry(widget) &&
414            gtk_widget_get_parent(widget)->parent && 0 == strcmp(g_type_name(G_OBJECT_TYPE(gtk_widget_get_parent(widget)->parent)), "SwtFixed");
415 }
416 */
417 
isGimpCombo(GtkWidget * widget)418 bool isGimpCombo(GtkWidget *widget)
419 {
420     return (qtSettings.app == GTK_APP_GIMP && widget &&
421             GTK_IS_TOGGLE_BUTTON(widget) &&
422             oneOf(gTypeName(gtk_widget_get_parent(widget)),
423                   "GimpEnumComboBox"));
424 }
425 
426 bool
isOnComboEntry(GtkWidget * w,int level)427 isOnComboEntry(GtkWidget *w, int level)
428 {
429     if (w) {
430         if (QTC_COMBO_ENTRY(w)) {
431             return true;
432         } else if (level < 4) {
433             return isOnComboEntry(gtk_widget_get_parent(w), level + 1);
434         }
435     }
436     return false;
437 }
438 
439 bool
isOnComboBox(GtkWidget * w,int level)440 isOnComboBox(GtkWidget *w, int level)
441 {
442     if (w) {
443         if (GTK_IS_COMBO_BOX(w)) {
444             return true;
445         } else if (level < 4) {
446             return isOnComboBox(gtk_widget_get_parent(w), level + 1);
447         }
448     }
449     return false;
450 }
451 
452 bool
isOnCombo(GtkWidget * w,int level)453 isOnCombo(GtkWidget *w, int level)
454 {
455     if (w) {
456         if (QTC_IS_COMBO(w)) {
457             return true;
458         } else if (level < 4) {
459             return isOnCombo(gtk_widget_get_parent(w), level + 1);
460         }
461     }
462     return false;
463 }
464 
465 #if !GTK_CHECK_VERSION(2, 90, 0)
isOnOptionMenu(GtkWidget * w,int level)466 bool isOnOptionMenu(GtkWidget *w, int level)
467 {
468     if (w) {
469         if (GTK_IS_OPTION_MENU(w)) {
470             return true;
471         } else if (level < 4) {
472             return isOnOptionMenu(gtk_widget_get_parent(w), level + 1);
473         }
474     }
475     return false;
476 }
477 
isActiveOptionMenu(GtkWidget * widget)478 bool isActiveOptionMenu(GtkWidget *widget)
479 {
480     if (GTK_IS_OPTION_MENU(widget)) {
481         GtkWidget *menu = gtk_option_menu_get_menu(GTK_OPTION_MENU(widget));
482         if(menu && gtk_widget_get_visible(menu) &&
483            gtk_widget_get_realized(menu)) {
484             return true;
485         }
486     }
487     return false;
488 }
489 #endif
490 
isOnMenuItem(GtkWidget * w,int level)491 bool isOnMenuItem(GtkWidget *w, int level)
492 {
493     if(w)
494     {
495         if(GTK_IS_MENU_ITEM(w))
496             return true;
497         else if(level<4)
498             return isOnMenuItem(gtk_widget_get_parent(w), ++level);
499     }
500     return false;
501 }
502 
isSpinButton(GtkWidget * widget)503 bool isSpinButton(GtkWidget *widget)
504 {
505     return widget && GTK_IS_SPIN_BUTTON(widget);
506 }
507 
isStatusBarFrame(GtkWidget * widget)508 bool isStatusBarFrame(GtkWidget *widget)
509 {
510     GtkWidget *parent=nullptr;
511     return widget && (parent=gtk_widget_get_parent(widget)) && GTK_IS_FRAME(widget) &&
512            (GTK_IS_STATUSBAR(parent) || ((parent=gtk_widget_get_parent(parent)) && GTK_IS_STATUSBAR(parent)));
513 }
514 
isMenubar(GtkWidget * w,int level)515 GtkMenuBar * isMenubar(GtkWidget *w, int level)
516 {
517     if(w)
518     {
519         if(GTK_IS_MENU_BAR(w))
520             return (GtkMenuBar*)w;
521         else if(level<3)
522             return isMenubar(gtk_widget_get_parent(w), level++);
523     }
524 
525     return nullptr;
526 }
527 
isMenuitem(GtkWidget * w,int level)528 bool isMenuitem(GtkWidget *w, int level)
529 {
530     if(w)
531     {
532         if(GTK_IS_MENU_ITEM(w))
533             return true;
534         else if(level<3)
535             return isMenuitem(gtk_widget_get_parent(w), level++);
536     }
537 
538     return false;
539 }
540 
isMenuWindow(GtkWidget * w)541 bool isMenuWindow(GtkWidget *w)
542 {
543     GtkWidget *def = gtk_window_get_default_widget(GTK_WINDOW(w));
544 
545     return def && GTK_IS_MENU(def);
546 }
547 
isInGroupBox(GtkWidget * w,int level)548 bool isInGroupBox(GtkWidget *w, int level)
549 {
550     if(w)
551     {
552         if(IS_GROUP_BOX(w))
553             return true;
554         else if(level<5)
555             return isInGroupBox(gtk_widget_get_parent(w), level++);
556     }
557 
558     return false;
559 }
560 
isOnButton(GtkWidget * w,int level,bool * def)561 bool isOnButton(GtkWidget *w, int level, bool *def)
562 {
563     if (w) {
564         if ((GTK_IS_BUTTON(w) || GTK_IS_OPTION_MENU(w)) &&
565             (!(GTK_IS_RADIO_BUTTON(w) || GTK_IS_CHECK_BUTTON(w)))) {
566             if (def) {
567                 *def = gtk_widget_has_default(w);
568             }
569             return true;
570         } else if (level < 3) {
571             return isOnButton(gtk_widget_get_parent(w), level++, def);
572         }
573     }
574     return false;
575 }
576 
577 static GtkRequisition defaultOptionIndicatorSize = {6, 13};
578 static GtkBorder defaultOptionIndicatorSpacing = {7, 5, 1, 1};
579 
580 void
optionMenuGetProps(GtkWidget * widget,GtkRequisition * indicator_size,GtkBorder * indicator_spacing)581 optionMenuGetProps(GtkWidget *widget, GtkRequisition *indicator_size,
582                    GtkBorder *indicator_spacing)
583 {
584     GtkRequisition *tmp_size = nullptr;
585     GtkBorder *tmp_spacing = nullptr;
586 
587     if (widget)
588         gtk_widget_style_get(widget, "indicator_size", &tmp_size,
589                              "indicator_spacing", &tmp_spacing,
590                              nullptr);
591     *indicator_size= tmp_size ? *tmp_size : defaultOptionIndicatorSize;
592     *indicator_spacing = (tmp_spacing ? *tmp_spacing :
593                           defaultOptionIndicatorSpacing);
594 
595     if (tmp_size) {
596         gtk_requisition_free(tmp_size);
597     }
598     if (tmp_spacing) {
599         gtk_border_free(tmp_spacing);
600     }
601 }
602 
603 EStepper
getStepper(GtkWidget * widget,int x,int y,int width,int height)604 getStepper(GtkWidget *widget, int x, int y, int width, int height)
605 {
606     if (widget && GTK_IS_RANGE(widget)) {
607         const QtcRect stepper = {x, y, width, height};
608         GtkOrientation orientation = Widget::getOrientation(widget);
609         QtcRect alloc = Widget::getAllocation(widget);
610         QtcRect check_rectangle = {alloc.x, alloc.y,
611                                    stepper.width, stepper.height};
612 
613         if (alloc.x == -1 && alloc.y == -1) {
614             return STEPPER_NONE;
615         }
616         if (Rect::intersect(&stepper, &check_rectangle, nullptr)) {
617             return STEPPER_A;
618         }
619 
620         if (orientation == GTK_ORIENTATION_HORIZONTAL) {
621             check_rectangle.x = alloc.x + stepper.width;
622         } else {
623             check_rectangle.y = alloc.y + stepper.height;
624         }
625         if (Rect::intersect(&stepper, &check_rectangle, nullptr)) {
626             return STEPPER_B;
627         }
628 
629         if (orientation == GTK_ORIENTATION_HORIZONTAL) {
630             check_rectangle.x = alloc.x + alloc.width - stepper.width * 2;
631         } else {
632             check_rectangle.y = alloc.y + alloc.height - stepper.height * 2;
633         }
634         if (Rect::intersect(&stepper, &check_rectangle, nullptr)) {
635             return STEPPER_C;
636         }
637 
638         if (orientation == GTK_ORIENTATION_HORIZONTAL) {
639             check_rectangle.x = alloc.x + alloc.width - stepper.width;
640         } else {
641             check_rectangle.y = alloc.y + alloc.height - stepper.height;
642         }
643         if (Rect::intersect(&stepper, &check_rectangle, nullptr)) {
644             return STEPPER_D;
645         }
646     }
647     return STEPPER_NONE;
648 }
649 
650 #if GTK_CHECK_VERSION(2, 90, 0)
gdk_drawable_get_size(GdkWindow * window,int * width,int * height)651 void gdk_drawable_get_size(GdkWindow *window, int *width, int *height)
652 {
653     *width = gdk_window_get_width(window);
654     *height = gdk_window_get_height(window);
655 }
656 
sanitizeSizeReal(GtkWidget * widget,int * width,int * height)657 void sanitizeSizeReal(GtkWidget *widget, int *width, int *height)
658 {
659     if (*width == -1 || *height == -1) {
660         GdkWindow *window = gtk_widget_get_window(widget);
661         if (window) {
662             if (*width == -1) {
663                 *width = gdk_window_get_width(window);
664             }
665             if (*height == -1) {
666                 *height = gdk_window_get_height(window);
667             }
668         }
669     }
670 }
671 #else
sanitizeSize(GdkWindow * window,int * width,int * height)672 void sanitizeSize(GdkWindow *window, int *width, int *height)
673 {
674     if (*width == -1 && *height == -1) {
675         gdk_window_get_size(window, width, height);
676     } else if (*width == -1) {
677         gdk_window_get_size(window, width, nullptr);
678     } else if (*height == -1) {
679         gdk_window_get_size(window, nullptr, height);
680     }
681 }
682 #endif
683 
684 int
getFill(GtkStateType state,bool set,bool darker)685 getFill(GtkStateType state, bool set, bool darker)
686 {
687     if (state == GTK_STATE_INSENSITIVE) {
688         return darker ? 2 : ORIGINAL_SHADE;
689     } else if (state == GTK_STATE_PRELIGHT) {
690         if (set) {
691             return darker ? 3 : SHADE_4_HIGHLIGHT;
692         } else {
693             return darker ? SHADE_2_HIGHLIGHT : SHADE_ORIG_HIGHLIGHT;
694         }
695     } else if (set || state == GTK_STATE_ACTIVE) {
696         return darker ? 5 : 4;
697     } else {
698         return darker ? 2 : ORIGINAL_SHADE;
699     }
700 }
701 
702 bool
isSbarDetail(const char * detail)703 isSbarDetail(const char *detail)
704 {
705     return (detail && detail[0] && (oneOf(detail, "stepper") ||
706                                     Str::startsWith(detail + 1, "scrollbar")));
707 }
708 
709 ECornerBits
getRound(const char * detail,GtkWidget * widget,bool rev)710 getRound(const char *detail, GtkWidget *widget, bool rev)
711 {
712     if (detail) {
713         if (oneOf(detail, "slider")) {
714 #ifndef SIMPLE_SCROLLBARS
715             if (!(opts.square & SQUARE_SB_SLIDER) &&
716                 (opts.scrollbarType == SCROLLBAR_NONE ||
717                  opts.flatSbarButtons)) {
718                 return ROUNDED_ALL;
719             }
720 #endif
721             return ROUNDED_NONE;
722         } else if (oneOf(detail, "qtc-slider")) {
723             return opts.square&SQUARE_SLIDER && (SLIDER_PLAIN == opts.sliderStyle || SLIDER_PLAIN_ROTATED == opts.sliderStyle)
724                 ? ROUNDED_NONE : ROUNDED_ALL;
725         } else if (oneOf(detail, "splitter", "optionmenu", "togglebutton",
726                          "hscale", "vscale")) {
727             return ROUNDED_ALL;
728         } else if (oneOf(detail, "spinbutton_up"))
729             return rev ? ROUNDED_TOPLEFT : ROUNDED_TOPRIGHT;
730         else if(oneOf(detail, "spinbutton_down"))
731             return rev ? ROUNDED_BOTTOMLEFT : ROUNDED_BOTTOMRIGHT;
732         else if (isSbarDetail(detail)) {
733             // Requires `GtkRange::stepper-position-details = 1`
734             if (Str::endsWith(detail, "_start")) {
735                 return detail[0] == 'h' ? ROUNDED_LEFT : ROUNDED_TOP;
736             } else if (Str::endsWith(detail, "_end")) {
737                 return detail[0] == 'v' ? ROUNDED_BOTTOM : ROUNDED_RIGHT;
738             }
739             return ROUNDED_NONE;
740         } else if (oneOf(detail, "button")) {
741             if(isListViewHeader(widget))
742                 return ROUNDED_NONE;
743             else if(isComboBoxButton(widget))
744                 return rev ? ROUNDED_LEFT : ROUNDED_RIGHT;
745             else
746                 return ROUNDED_ALL;
747         }
748     }
749 
750     return ROUNDED_NONE;
751 }
752 
753 bool
isHorizontalProgressbar(GtkWidget * widget)754 isHorizontalProgressbar(GtkWidget *widget)
755 {
756     if (!widget || isMozilla() || !GTK_IS_PROGRESS_BAR(widget))
757         return true;
758 #if GTK_CHECK_VERSION(2, 90, 0)
759     return Widget::isHorizontal(widget);
760 #else
761     switch (GTK_PROGRESS_BAR(widget)->orientation) {
762     default:
763     case GTK_PROGRESS_LEFT_TO_RIGHT:
764     case GTK_PROGRESS_RIGHT_TO_LEFT:
765         return true;
766     case GTK_PROGRESS_BOTTOM_TO_TOP:
767     case GTK_PROGRESS_TOP_TO_BOTTOM:
768         return false;
769     }
770 #endif
771 }
772 
773 bool
isComboBoxPopupWindow(GtkWidget * widget,int level)774 isComboBoxPopupWindow(GtkWidget *widget, int level)
775 {
776     if (widget) {
777         if (GTK_IS_WINDOW(widget) && oneOf(gtk_widget_get_name(widget),
778                                            "gtk-combobox-popup-window")) {
779             return true;
780         } else if (level < 4) {
781             return isComboBoxPopupWindow(gtk_widget_get_parent(widget),
782                                          level + 1);
783         }
784     }
785     return false;
786 }
787 
isComboBoxList(GtkWidget * widget)788 bool isComboBoxList(GtkWidget *widget)
789 {
790     GtkWidget *parent=nullptr;
791     return widget && (parent=gtk_widget_get_parent(widget)) && /*GTK_IS_FRAME(widget) && */isComboBoxPopupWindow(parent, 0);
792 }
793 
794 bool
isComboPopupWindow(GtkWidget * widget,int level)795 isComboPopupWindow(GtkWidget *widget, int level)
796 {
797     if (widget) {
798         if (GTK_IS_WINDOW(widget) && oneOf(gtk_widget_get_name(widget),
799                                            "gtk-combo-popup-window")) {
800             return true;
801         } else if (level < 4) {
802             return isComboPopupWindow(gtk_widget_get_parent(widget), level + 1);
803         }
804     }
805     return false;
806 }
807 
isComboList(GtkWidget * widget)808 bool isComboList(GtkWidget *widget)
809 {
810     return widget && isComboPopupWindow(gtk_widget_get_parent(widget), 0);
811 }
812 
813 bool
isComboMenu(GtkWidget * widget)814 isComboMenu(GtkWidget *widget)
815 {
816     if (widget && gtk_widget_get_name(widget) && GTK_IS_MENU(widget) &&
817         oneOf(gtk_widget_get_name(widget), "gtk-combobox-popup-menu")) {
818         return true;
819     } else {
820         GtkWidget *top = gtk_widget_get_toplevel(widget);
821         GtkWidget *topChild = top ? gtk_bin_get_child(GTK_BIN(top)) : nullptr;
822         GtkWidget *transChild = nullptr;
823         GtkWindow *trans = nullptr;
824 
825         return (topChild &&
826                 (isComboBoxPopupWindow(topChild, 0) ||
827                  (GTK_IS_WINDOW(top) &&
828                   (trans = gtk_window_get_transient_for(GTK_WINDOW(top))) &&
829                   (transChild = gtk_bin_get_child(GTK_BIN(trans))) &&
830                   isComboMenu(transChild))));
831     }
832 }
833 
isComboFrame(GtkWidget * widget)834 bool isComboFrame(GtkWidget *widget)
835 {
836     GtkWidget *parent=nullptr;
837     return !QTC_COMBO_ENTRY(widget) && GTK_IS_FRAME(widget) && (parent=gtk_widget_get_parent(widget)) && GTK_IS_COMBO_BOX(parent);
838 }
839 
isFixedWidget(GtkWidget * widget)840 bool isFixedWidget(GtkWidget *widget)
841 {
842     GtkWidget *parent = nullptr;
843     return (widget && (parent = gtk_widget_get_parent(widget)) &&
844             GTK_IS_FIXED(parent) &&
845             (parent = gtk_widget_get_parent(parent)) && GTK_IS_WINDOW(parent));
846 }
847 
isGimpDockable(GtkWidget * widget)848 bool isGimpDockable(GtkWidget *widget)
849 {
850     if (qtSettings.app == GTK_APP_GIMP) {
851         for (GtkWidget *wid = widget;wid;wid = gtk_widget_get_parent(wid)) {
852             if (oneOf(gTypeName(wid), "GimpDockable", "GimpToolbox")) {
853                 return true;
854             }
855         }
856     }
857     return false;
858 }
859 
860 GdkColor*
getParentBgCol(GtkWidget * widget)861 getParentBgCol(GtkWidget *widget)
862 {
863     if (GTK_IS_SCROLLBAR(widget)) {
864         widget = gtk_widget_get_parent(widget);
865     }
866     if (widget) {
867         widget = gtk_widget_get_parent(widget);
868         while (widget && GTK_IS_BOX(widget)) {
869             widget = gtk_widget_get_parent(widget);
870         }
871     }
872 
873     GtkStyle *style = widget ? gtk_widget_get_style(widget) : nullptr;
874     return style ? &style->bg[gtk_widget_get_state(widget)] : nullptr;
875 }
876 
877 int
getOpacity(GtkWidget * widget)878 getOpacity(GtkWidget *widget)
879 {
880     if (opts.bgndOpacity == opts.dlgOpacity)
881         return opts.bgndOpacity;
882 
883     if (opts.bgndOpacity != 100 || opts.dlgOpacity != 100) {
884         if (!widget) {
885             return opts.bgndOpacity;
886         } else {
887             GtkWidget *top = gtk_widget_get_toplevel(widget);
888             return (top && GTK_IS_DIALOG(top) ? opts.dlgOpacity :
889                     opts.bgndOpacity);
890         }
891     }
892     return 100;
893 }
894 
setLowerEtchCol(cairo_t * cr,GtkWidget * widget)895 void setLowerEtchCol(cairo_t *cr, GtkWidget *widget)
896 {
897     if(USE_CUSTOM_ALPHAS(opts))
898         cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, opts.customAlphas[ALPHA_ETCH_LIGHT]);
899     else if(qtcIsFlatBgnd(opts.bgndAppearance) && (!widget || !g_object_get_data(G_OBJECT (widget), "transparent-bg-hint")))
900     {
901         GdkColor *parentBg=getParentBgCol(widget);
902 
903         if (parentBg) {
904             GdkColor col;
905             qtcShade(parentBg, &col, 1.06, opts.shading);
906             Cairo::setColor(cr, &col);
907         } else {
908             cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.1); // 0.25);
909         }
910     } else {
911         cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.1); // 0.4);
912     }
913 }
914 
915 GdkColor
shadeColor(const GdkColor * orig,double mod)916 shadeColor(const GdkColor *orig, double mod)
917 {
918     if (!qtcEqual(mod, 0.0)) {
919         GdkColor modified;
920         qtcShade(orig, &modified, mod, opts.shading);
921         return modified;
922     }
923     return *orig;
924 }
925 
926 gboolean
windowEvent(GtkWidget *,GdkEvent * event,void * user_data)927 windowEvent(GtkWidget*, GdkEvent *event, void *user_data)
928 {
929     if (GDK_FOCUS_CHANGE == event->type)
930         gtk_widget_queue_draw((GtkWidget*)user_data);
931     return false;
932 }
933 
934 void
adjustToolbarButtons(GtkWidget * widget,int * x,int * y,int * width,int * height,ECornerBits * round,bool horiz)935 adjustToolbarButtons(GtkWidget *widget, int *x, int *y, int *width,
936                      int *height, ECornerBits *round, bool horiz)
937 {
938     GtkToolbar *toolbar = nullptr;
939     GtkToolItem *toolitem = nullptr;
940     GtkWidget *w = widget;
941 
942     for (int i = 0;i < 5 && w && (!toolbar || !toolitem);++i) {
943         if (GTK_IS_TOOLBAR(w)) {
944             toolbar = GTK_TOOLBAR(w);
945         } else if (GTK_IS_TOOL_ITEM(w)) {
946             toolitem = GTK_TOOL_ITEM(w);
947         }
948         w = gtk_widget_get_parent(w);
949     }
950 
951     if (toolbar && toolitem) {
952         int num = gtk_toolbar_get_n_items(toolbar);
953         if (num > 1) {
954             int index = gtk_toolbar_get_item_index(toolbar, toolitem);
955             GtkToolItem *prev =
956                 (index ? gtk_toolbar_get_nth_item(toolbar, index - 1) : nullptr);
957             GtkToolItem *next =
958                 (index < num - 1 ?
959                  gtk_toolbar_get_nth_item(toolbar, index + 1) : nullptr);
960             GtkWidget *parent = nullptr;
961             bool roundLeft = !prev || !GTK_IS_TOOL_BUTTON(prev);
962             bool roundRight = !next || !GTK_IS_TOOL_BUTTON(next);
963             bool isMenuButton =
964                 (widget && GTK_IS_BUTTON(widget) &&
965                  (parent = gtk_widget_get_parent(widget)) &&
966                  GTK_IS_BOX(parent) &&
967                  (parent = gtk_widget_get_parent(parent)) &&
968                  GTK_IS_MENU_TOOL_BUTTON(parent));
969             bool isArrowButton = isMenuButton && GTK_IS_TOGGLE_BUTTON(widget);
970             int *pos = horiz ? x : y;
971             int *size = horiz ? width : height;
972 
973             if (isArrowButton) {
974                 *pos -= 4;
975                 if (roundLeft && roundRight) {
976                     *round = horiz ? ROUNDED_RIGHT : ROUNDED_BOTTOM;
977                     *size += 4;
978                 } else if (roundLeft) {
979                     *round = ROUNDED_NONE;
980                     *size += 8;
981                 } else if (roundRight) {
982                     *round = horiz ? ROUNDED_RIGHT : ROUNDED_BOTTOM;
983                     *size += 4;
984                 } else {
985                     *round = ROUNDED_NONE;
986                     *size += 8;
987                 }
988             } else if (isMenuButton) {
989                 if (roundLeft && roundRight) {
990                     *round = horiz ? ROUNDED_LEFT : ROUNDED_TOP;
991                     *size += 4;
992                 } else if (roundLeft) {
993                     *round = horiz ? ROUNDED_LEFT : ROUNDED_TOP;
994                     *size += 4;
995                 } else if(roundRight) {
996                     *round = ROUNDED_NONE;
997                     *pos -= 4;
998                     *size += 8;
999                 } 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
getEntryParentBgCol(GtkWidget * widget,GdkColor * color)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
compositingActive(GtkWidget * widget)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
isRgbaWidget(GtkWidget * widget)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
enableBlurBehind(GtkWidget * w,bool enable)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
getTopLevelSize(GdkWindow * window,int * w,int * h)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
getTopLevelOrigin(GdkWindow * window,int * x,int * y)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
mapToTopLevel(GdkWindow * window,GtkWidget * widget,int * x,int * y,int * w,int * h)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
treeViewCellHasChildren(GtkTreeView * treeView,GtkTreePath * path)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
treeViewCellIsLast(GtkTreeView * treeView,GtkTreePath * path)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*
treeViewPathParent(GtkTreeView *,GtkTreePath * path)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
generateColors()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*
getCheckRadioCol(GtkStyle * style,GtkStateType state,bool mnu)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
objectIsA(const GObject * object,const char * type_name)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 }
1602