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 &gtk_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 = &gtk_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