1 /*
2 * support.c
3 * This file is part of gtk-nodoka-engine
4 *
5 * Copyright (C) 2007, 2008 - Martin Sourada, Daniel Geiger
6 *
7 * gtk-nodoka-engine is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * gtk-nodoka-engine is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with gtk-nodoka-engine; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301 USA
21 */
22
23 #include "support.h"
24
25 GtkTextDirection
nodoka_get_direction(GtkWidget * widget)26 nodoka_get_direction (GtkWidget * widget)
27 {
28 GtkTextDirection dir;
29
30 if (widget)
31 dir = gtk_widget_get_direction (widget);
32 else
33 dir = GTK_TEXT_DIR_LTR;
34
35 return dir;
36 }
37
38 G_GNUC_INTERNAL void
nodoka_rgb_to_hls(gdouble * r,gdouble * g,gdouble * b)39 nodoka_rgb_to_hls (gdouble * r, gdouble * g, gdouble * b)
40 {
41 gdouble min;
42 gdouble max;
43 gdouble red;
44 gdouble green;
45 gdouble blue;
46 gdouble h, l, s;
47 gdouble delta;
48
49 red = *r;
50 green = *g;
51 blue = *b;
52
53 if (red > green)
54 {
55 if (red > blue)
56 max = red;
57 else
58 max = blue;
59
60 if (green < blue)
61 min = green;
62 else
63 min = blue;
64 }
65 else
66 {
67 if (green > blue)
68 max = green;
69 else
70 max = blue;
71
72 if (red < blue)
73 min = red;
74 else
75 min = blue;
76 }
77
78 l = (max + min) / 2;
79 s = 0;
80 h = 0;
81
82 if (max != min)
83 {
84 if (l <= 0.5)
85 s = (max - min) / (max + min);
86 else
87 s = (max - min) / (2 - max - min);
88
89 delta = max - min;
90 if (red == max)
91 h = (green - blue) / delta;
92 else if (green == max)
93 h = 2 + (blue - red) / delta;
94 else if (blue == max)
95 h = 4 + (red - green) / delta;
96
97 h *= 60;
98 if (h < 0.0)
99 h += 360;
100 }
101
102 *r = h;
103 *g = l;
104 *b = s;
105 }
106
107 G_GNUC_INTERNAL void
nodoka_hls_to_rgb(gdouble * h,gdouble * l,gdouble * s)108 nodoka_hls_to_rgb (gdouble * h, gdouble * l, gdouble * s)
109 {
110 gdouble hue;
111 gdouble lightness;
112 gdouble saturation;
113 gdouble m1, m2;
114 gdouble r, g, b;
115
116 lightness = *l;
117 saturation = *s;
118
119 if (lightness <= 0.5)
120 m2 = lightness * (1 + saturation);
121 else
122 m2 = lightness + saturation - lightness * saturation;
123
124 m1 = 2 * lightness - m2;
125
126 if (saturation == 0)
127 {
128 *h = lightness;
129 *l = lightness;
130 *s = lightness;
131 }
132 else
133 {
134 hue = *h + 120;
135 while (hue > 360)
136 hue -= 360;
137 while (hue < 0)
138 hue += 360;
139
140 if (hue < 60)
141 r = m1 + (m2 - m1) * hue / 60;
142 else if (hue < 180)
143 r = m2;
144 else if (hue < 240)
145 r = m1 + (m2 - m1) * (240 - hue) / 60;
146 else
147 r = m1;
148
149 hue = *h;
150 while (hue > 360)
151 hue -= 360;
152 while (hue < 0)
153 hue += 360;
154
155 if (hue < 60)
156 g = m1 + (m2 - m1) * hue / 60;
157 else if (hue < 180)
158 g = m2;
159 else if (hue < 240)
160 g = m1 + (m2 - m1) * (240 - hue) / 60;
161 else
162 g = m1;
163
164 hue = *h - 120;
165 while (hue > 360)
166 hue -= 360;
167 while (hue < 0)
168 hue += 360;
169
170 if (hue < 60)
171 b = m1 + (m2 - m1) * hue / 60;
172 else if (hue < 180)
173 b = m2;
174 else if (hue < 240)
175 b = m1 + (m2 - m1) * (240 - hue) / 60;
176 else
177 b = m1;
178
179 *h = r;
180 *l = g;
181 *s = b;
182 }
183 }
184
185 void
nodoka_shade(const NodokaRGB * a,NodokaRGB * b,float k)186 nodoka_shade (const NodokaRGB * a, NodokaRGB * b, float k)
187 {
188 double red;
189 double green;
190 double blue;
191
192 red = a->r;
193 green = a->g;
194 blue = a->b;
195
196 nodoka_rgb_to_hls (&red, &green, &blue);
197
198 green *= k;
199 if (green > 1.0)
200 green = 1.0;
201 else if (green < 0.0)
202 green = 0.0;
203
204 blue *= k;
205 if (blue > 1.0)
206 blue = 1.0;
207 else if (blue < 0.0)
208 blue = 0.0;
209
210 nodoka_hls_to_rgb (&red, &green, &blue);
211
212 b->r = red;
213 b->g = green;
214 b->b = blue;
215 }
216
217
218 void
nodoka_gtk_treeview_get_header_index(GtkTreeView * tv,GtkWidget * header,gint * column_index,gint * columns,gboolean * resizable)219 nodoka_gtk_treeview_get_header_index (GtkTreeView * tv, GtkWidget * header,
220 gint * column_index, gint * columns,
221 gboolean * resizable)
222 {
223 GList *list, *list_start;
224 *column_index = *columns = 0;
225 list_start = list = gtk_tree_view_get_columns (tv);
226
227 do
228 {
229 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (list->data);
230 if (gtk_tree_view_column_get_widget (column) == header)
231 {
232 *column_index = *columns;
233 *resizable = gtk_tree_view_column_get_resizable (column);
234 }
235 if (gtk_tree_view_column_get_visible (column))
236 (*columns)++;
237 }
238 while ((list = g_list_next (list)));
239
240 g_list_free (list_start);
241 }
242
243 #if GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 90 && !defined(GTK_DISABLE_DEPRECATED)
244 void
nodoka_gtk_clist_get_header_index(GtkCList * clist,GtkWidget * button,gint * column_index,gint * columns)245 nodoka_gtk_clist_get_header_index (GtkCList * clist, GtkWidget * button,
246 gint * column_index, gint * columns)
247 {
248 int i;
249 *columns = clist->columns;
250
251 for (i = 0; i < *columns; i++)
252 {
253 if (clist->column[i].button == button)
254 {
255 *column_index = i;
256 break;
257 }
258 }
259 }
260 #endif
261
262 gboolean
nodoka_sanitize_size(GdkWindow * window,gint * width,gint * height)263 nodoka_sanitize_size (GdkWindow * window, gint * width, gint * height)
264 {
265 gboolean set_bg = FALSE;
266
267 if ((*width == -1) && (*height == -1))
268 {
269 set_bg = GDK_IS_WINDOW (window);
270 gdk_drawable_get_size (window, width, height);
271 }
272 else if (*width == -1)
273 gdk_drawable_get_size (window, width, NULL);
274 else if (*height == -1)
275 gdk_drawable_get_size (window, NULL, height);
276
277 return set_bg;
278 }
279
280 static GtkRequisition default_option_indicator_size = { 7, 13 };
281 static GtkBorder default_option_indicator_spacing = { 7, 5, 2, 2 };
282
283 void
nodoka_option_menu_get_props(GtkWidget * widget,GtkRequisition * indicator_size,GtkBorder * indicator_spacing)284 nodoka_option_menu_get_props (GtkWidget * widget,
285 GtkRequisition * indicator_size,
286 GtkBorder * indicator_spacing)
287 {
288 GtkRequisition *tmp_size = NULL;
289 GtkBorder *tmp_spacing = NULL;
290
291 if (widget)
292 gtk_widget_style_get (widget, "indicator_size", &tmp_size,
293 "indicator_spacing", &tmp_spacing, NULL);
294
295 if (tmp_size)
296 {
297 *indicator_size = *tmp_size;
298 g_free (tmp_size);
299 }
300 else
301 *indicator_size = default_option_indicator_size;
302
303 if (tmp_spacing)
304 {
305 *indicator_spacing = *tmp_spacing;
306 gtk_border_free (tmp_spacing);
307 }
308 else
309 *indicator_spacing = default_option_indicator_spacing;
310 }
311
312 GtkWidget *
nodoka_special_get_ancestor(GtkWidget * widget,GType widget_type)313 nodoka_special_get_ancestor (GtkWidget * widget, GType widget_type)
314 {
315 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
316
317 while (widget && gtk_widget_get_parent (widget)
318 && !g_type_is_a (G_OBJECT_TYPE (gtk_widget_get_parent (widget)), widget_type))
319 widget = gtk_widget_get_parent (widget);
320
321 if (!
322 (widget && gtk_widget_get_parent (widget)
323 && g_type_is_a (G_OBJECT_TYPE (gtk_widget_get_parent (widget)), widget_type)))
324 return NULL;
325
326 return widget;
327 }
328
329 GtkWidget *
nodoka_get_parent_window(GtkWidget * widget)330 nodoka_get_parent_window (GtkWidget * widget)
331 {
332 GtkWidget *parent = gtk_widget_get_parent (widget);
333
334 while (parent && !gtk_widget_get_has_window (parent))
335 parent = gtk_widget_get_parent (parent);
336
337 return parent;
338 }
339
340 GdkColor *
nodoka_get_parent_bgcolor(GtkWidget * widget)341 nodoka_get_parent_bgcolor (GtkWidget * widget)
342 {
343 GtkWidget *parent = nodoka_get_parent_window (widget);
344
345 if (parent && gtk_widget_get_style (parent))
346 return >k_widget_get_style (parent)->bg[GTK_STATE_NORMAL];
347
348 return NULL;
349 }
350
351 GtkWidget *
ndk_find_combo_box_widget(GtkWidget * widget)352 ndk_find_combo_box_widget (GtkWidget * widget)
353 {
354 GtkWidget *result = NULL;
355
356 if (widget && !GTK_IS_COMBO_BOX_ENTRY (widget))
357 {
358 if (GTK_IS_COMBO_BOX (widget))
359 result = widget;
360 else
361 result = ndk_find_combo_box_widget (gtk_widget_get_parent (widget));
362 }
363
364 return result;
365 }
366
367 gboolean
ndk_is_combo_box(GtkWidget * widget)368 ndk_is_combo_box (GtkWidget * widget)
369 {
370 return (ndk_find_combo_box_widget (widget) != NULL);
371 }
372
373 void
nodoka_gdk_color_to_rgb(GdkColor * c,double * r,double * g,double * b)374 nodoka_gdk_color_to_rgb (GdkColor * c, double *r, double *g, double *b)
375 {
376 *r = (double) c->red / (double) 65535;
377 *g = (double) c->green / (double) 65535;
378 *b = (double) c->blue / (double) 65535;
379 }
380
381 void
nodoka_get_parent_bg(const GtkWidget * widget,NodokaRGB * color)382 nodoka_get_parent_bg (const GtkWidget * widget, NodokaRGB * color)
383 {
384 GtkStateType state_type;
385 const GtkWidget *parent;
386 GdkColor *gcolor;
387
388 if (widget == NULL)
389 {
390 color->r = color->g = color->b = 255;
391 return;
392 }
393
394 parent = gtk_widget_get_parent ((GtkWidget *) widget);
395
396 while (parent && !gtk_widget_get_has_window ((GtkWidget *) parent))
397 parent = gtk_widget_get_parent ((GtkWidget *) parent);
398
399 if (parent == NULL)
400 parent = widget;
401
402 state_type = gtk_widget_get_state ((GtkWidget *) parent);
403
404 gcolor = >k_widget_get_style ((GtkWidget *) parent)->bg[state_type];
405
406 nodoka_gdk_color_to_rgb (gcolor, &color->r, &color->g, &color->b);
407 }
408
409 NodokaStepper
nodoka_scrollbar_get_stepper(GtkWidget * widget,GdkRectangle * stepper)410 nodoka_scrollbar_get_stepper (GtkWidget * widget, GdkRectangle * stepper)
411 {
412 NodokaStepper value = NDK_STEPPER_UNKNOWN;
413 GdkRectangle tmp;
414 GdkRectangle check_rectangle;
415 GtkOrientation orientation;
416 GtkAllocation allocation;
417
418 g_return_val_if_fail (GTK_IS_RANGE (widget), NDK_STEPPER_UNKNOWN);
419 gtk_widget_get_allocation (widget, &allocation);
420
421 check_rectangle.x = allocation.x;
422 check_rectangle.y = allocation.y;
423 check_rectangle.width = stepper->width;
424 check_rectangle.height = stepper->height;
425
426 if (GTK_IS_HSCROLLBAR (widget))
427 orientation = GTK_ORIENTATION_HORIZONTAL;
428 else
429 orientation = GTK_ORIENTATION_VERTICAL;
430
431 if (allocation.x == -1 && allocation.y == -1)
432 return NDK_STEPPER_UNKNOWN;
433
434 if (gdk_rectangle_intersect (stepper, &check_rectangle, &tmp))
435 value = NDK_STEPPER_A;
436
437 if (value == NDK_STEPPER_UNKNOWN) /* Haven't found a match */
438 {
439 if (orientation == GTK_ORIENTATION_HORIZONTAL)
440 check_rectangle.x = allocation.x + stepper->width;
441 else
442 check_rectangle.y = allocation.y + stepper->height;
443
444 if (gdk_rectangle_intersect (stepper, &check_rectangle, &tmp))
445 value = NDK_STEPPER_B;
446 }
447
448 if (value == NDK_STEPPER_UNKNOWN) /* Still haven't found a match */
449 {
450 if (orientation == GTK_ORIENTATION_HORIZONTAL)
451 check_rectangle.x =
452 allocation.x + allocation.width -
453 (stepper->width * 2);
454 else
455 check_rectangle.y =
456 allocation.y + allocation.height -
457 (stepper->height * 2);
458
459 if (gdk_rectangle_intersect (stepper, &check_rectangle, &tmp))
460 value = NDK_STEPPER_C;
461 }
462
463 if (value == NDK_STEPPER_UNKNOWN) /* STILL haven't found a match */
464 {
465 if (orientation == GTK_ORIENTATION_HORIZONTAL)
466 check_rectangle.x =
467 allocation.x + allocation.width -
468 stepper->width;
469 else
470 check_rectangle.y =
471 allocation.y + allocation.height -
472 stepper->height;
473
474 if (gdk_rectangle_intersect (stepper, &check_rectangle, &tmp))
475 value = NDK_STEPPER_D;
476 }
477
478 return value;
479 }
480
481 NodokaStepper
nodoka_scrollbar_visible_steppers(GtkWidget * widget)482 nodoka_scrollbar_visible_steppers (GtkWidget * widget)
483 {
484 NodokaStepper steppers = 0;
485
486 g_return_val_if_fail (GTK_IS_SCROLLBAR (widget), NDK_STEPPER_UNKNOWN);
487
488 gboolean has_stepper_a;
489 gboolean has_stepper_b;
490 gboolean has_stepper_c;
491 gboolean has_stepper_d;
492
493 gtk_widget_style_get (widget, "has-backward-stepper", &has_stepper_a,
494 "has-secondary-forward-stepper", &has_stepper_b,
495 "has-secondary-backward-stepper", &has_stepper_c,
496 "has-forward-stepper", &has_stepper_d, NULL);
497
498 if (has_stepper_a)
499 steppers |= NDK_STEPPER_A;
500
501 if (has_stepper_b)
502 steppers |= NDK_STEPPER_B;
503
504 if (has_stepper_c)
505 steppers |= NDK_STEPPER_C;
506
507 if (has_stepper_d)
508 steppers |= NDK_STEPPER_D;
509
510 return (steppers);
511 }
512
513 NodokaJunction
nodoka_scrollbar_get_junction(GtkWidget * widget)514 nodoka_scrollbar_get_junction (GtkWidget * widget)
515 {
516 GtkAdjustment *adj;
517 NodokaJunction junction = NDK_JUNCTION_NONE;
518
519 g_return_val_if_fail (GTK_IS_SCROLLBAR (widget), NDK_JUNCTION_NONE);
520
521 adj = gtk_range_get_adjustment (GTK_RANGE (widget));
522
523 gboolean has_stepper_a;
524 gboolean has_stepper_b;
525 gboolean has_stepper_c;
526 gboolean has_stepper_d;
527
528 gtk_widget_style_get (widget, "has-backward-stepper", &has_stepper_a,
529 "has-secondary-forward-stepper", &has_stepper_b,
530 "has-secondary-backward-stepper", &has_stepper_c,
531 "has-forward-stepper", &has_stepper_d, NULL);
532
533 if (gtk_adjustment_get_value (adj) <= gtk_adjustment_get_lower (adj) &&
534 (has_stepper_a
535 || has_stepper_b))
536 {
537 junction |= NDK_JUNCTION_BEGIN;
538 }
539
540 if (gtk_adjustment_get_value (adj) >= gtk_adjustment_get_upper (adj) - gtk_adjustment_get_page_size (adj) &&
541 (has_stepper_c
542 || has_stepper_d))
543 {
544 junction |= NDK_JUNCTION_END;
545 }
546
547 return junction;
548 }
549
550 gboolean
ndk_is_panel_widget(GtkWidget * widget)551 ndk_is_panel_widget (GtkWidget * widget)
552 {
553 return widget && (strcmp (G_OBJECT_TYPE_NAME (widget), "PanelApplet") == 0
554 || strcmp (G_OBJECT_TYPE_NAME (widget),
555 "PanelWidget") == 0);
556 }
557
558 gboolean
ndk_object_is_a(const GObject * object,const gchar * type_name)559 ndk_object_is_a (const GObject * object, const gchar * type_name)
560 {
561 gboolean result = FALSE;
562
563 if ((object))
564 {
565 GType tmp = g_type_from_name (type_name);
566
567 if (tmp)
568 result = g_type_check_instance_is_a ((GTypeInstance *) object, tmp);
569 }
570
571 return result;
572 }
573
574