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