* fixed memory allocation bugs
[ardour.git] / libs / clearlooks / support.c
1 /* Clearlooks theme engine
2  * Copyright (C) 2005 Richard Stellingwerff.
3  * Copyright (C) 2007 Benjamin Berg <benjamin@sipsolutions.net>.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  */
21
22 #include "support.h"
23
24 void clearlooks_treeview_get_header_index (GtkTreeView *tv, GtkWidget *header,
25                                     gint *column_index, gint *columns,
26                                     gboolean *resizable)
27 {
28         GList *list, *list_start;
29         *column_index = *columns = 0;
30         list_start = list = gtk_tree_view_get_columns (tv);
31
32         do
33         {
34                 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(list->data);
35                 if ( column->button == header )
36                 {
37                         *column_index = *columns;
38                         *resizable = column->resizable;
39                 }
40                 if ( column->visible )
41                         (*columns)++;
42         } while ((list = g_list_next(list)));
43
44         g_list_free (list_start);
45 }
46
47 void clearlooks_clist_get_header_index (GtkCList *clist, GtkWidget *button,
48                                  gint *column_index, gint *columns)
49 {
50         int i;
51         *columns = clist->columns;
52         
53         for (i=0; i<*columns; i++)
54         {
55                 if (clist->column[i].button == button)
56                 {
57                         *column_index = i;
58                         break;
59                 }
60         }
61 }
62
63 void
64 clearlooks_get_parent_bg (const GtkWidget *widget, CairoColor *color)
65 {
66         GtkStateType state_type;
67         const GtkWidget *parent;
68         GdkColor *gcolor;
69         gboolean stop;
70         
71         if (widget == NULL)
72                 return;
73         
74         parent = widget->parent;
75         stop = FALSE;
76         
77         while (parent && !stop)
78         {
79                 stop = FALSE;
80
81                 stop |= !GTK_WIDGET_NO_WINDOW (parent);
82                 stop |= GTK_IS_NOTEBOOK (parent) &&
83                         gtk_notebook_get_show_tabs (GTK_NOTEBOOK (parent)) &&
84                         gtk_notebook_get_show_border (GTK_NOTEBOOK (parent));
85
86                 if (GTK_IS_TOOLBAR (parent))
87                 {
88                         GtkShadowType shadow = GTK_SHADOW_OUT;
89                         gtk_widget_style_get (GTK_WIDGET (parent), "shadow-type", &shadow, NULL);
90                         
91                         stop |= (shadow != GTK_SHADOW_NONE);
92                 }
93
94                 if (!stop)
95                         parent = parent->parent;
96         }
97
98         if (parent == NULL)
99                 return;
100         
101         state_type = GTK_WIDGET_STATE (parent);
102         
103         gcolor = &parent->style->bg[state_type];
104         
105         ge_gdk_color_to_cairo (gcolor, color);
106 }
107
108 ClearlooksStepper
109 clearlooks_scrollbar_get_stepper (GtkWidget    *widget,
110                        GdkRectangle *stepper)
111 {
112         ClearlooksStepper value = CL_STEPPER_UNKNOWN;
113         GdkRectangle tmp;
114         GdkRectangle check_rectangle;
115         GtkOrientation orientation;
116
117         if (!GE_IS_RANGE (widget))
118                 return CL_STEPPER_UNKNOWN;
119
120         check_rectangle.x      = widget->allocation.x;
121         check_rectangle.y      = widget->allocation.y;
122         check_rectangle.width  = stepper->width;
123         check_rectangle.height = stepper->height;
124         
125         orientation = GTK_RANGE (widget)->orientation;
126         
127         if (widget->allocation.x == -1 && widget->allocation.y == -1)
128                 return CL_STEPPER_UNKNOWN;
129                 
130         if (gdk_rectangle_intersect (stepper, &check_rectangle, &tmp))
131                 value = CL_STEPPER_A;
132
133         if (value == CL_STEPPER_UNKNOWN) /* Haven't found a match */
134         {
135                 if (orientation == GTK_ORIENTATION_HORIZONTAL)
136                         check_rectangle.x = widget->allocation.x + stepper->width;
137                 else
138                         check_rectangle.y = widget->allocation.y + stepper->height;
139                 
140                 if (gdk_rectangle_intersect (stepper, &check_rectangle, &tmp))
141                         value = CL_STEPPER_B;
142         }
143
144         if (value == CL_STEPPER_UNKNOWN) /* Still haven't found a match */
145         {
146                 if (orientation == GTK_ORIENTATION_HORIZONTAL)
147                         check_rectangle.x = widget->allocation.x + widget->allocation.width - (stepper->width * 2);
148                 else
149                         check_rectangle.y = widget->allocation.y + widget->allocation.height - (stepper->height * 2);
150                 
151                 if (gdk_rectangle_intersect (stepper, &check_rectangle, &tmp))
152                         value = CL_STEPPER_C;
153         }
154
155         if (value == CL_STEPPER_UNKNOWN) /* STILL haven't found a match */
156         {
157                 if (orientation == GTK_ORIENTATION_HORIZONTAL)
158                         check_rectangle.x = widget->allocation.x + widget->allocation.width - stepper->width;
159                 else
160                         check_rectangle.y = widget->allocation.y + widget->allocation.height - stepper->height;
161                 
162                 if (gdk_rectangle_intersect (stepper, &check_rectangle, &tmp))
163                         value = CL_STEPPER_D;
164         }
165         
166         return value;
167 }
168
169 ClearlooksStepper
170 clearlooks_scrollbar_visible_steppers (GtkWidget *widget)
171 {
172         ClearlooksStepper steppers = 0;
173         
174         /* If this is not a range widget, assume that the primary steppers
175          * are present. */
176         if (!GE_IS_RANGE (widget))
177                 return CL_STEPPER_A | CL_STEPPER_D;
178         
179         if (GTK_RANGE (widget)->has_stepper_a)
180                 steppers |= CL_STEPPER_A;
181         
182         if (GTK_RANGE (widget)->has_stepper_b)
183                 steppers |= CL_STEPPER_B;
184
185         if (GTK_RANGE (widget)->has_stepper_c)
186                 steppers |= CL_STEPPER_C;
187
188         if (GTK_RANGE (widget)->has_stepper_d)
189                 steppers |= CL_STEPPER_D;
190
191         return steppers;
192 }
193
194 ClearlooksJunction
195 clearlooks_scrollbar_get_junction (GtkWidget    *widget)
196 {       
197         GtkAdjustment *adj;
198         ClearlooksJunction junction = CL_JUNCTION_NONE;
199         
200         if (!GE_IS_RANGE (widget))
201                 return CL_JUNCTION_NONE;
202
203         adj = GTK_RANGE (widget)->adjustment;
204         
205         if (adj->value <= adj->lower &&
206                 (GTK_RANGE (widget)->has_stepper_a || GTK_RANGE (widget)->has_stepper_b))
207         {
208                 if (!gtk_range_get_inverted (GTK_RANGE (widget)))
209                         junction |= CL_JUNCTION_BEGIN;
210                 else
211                         junction |= CL_JUNCTION_END;
212         }
213         
214         if (adj->value >= adj->upper - adj->page_size &&
215                 (GTK_RANGE (widget)->has_stepper_c || GTK_RANGE (widget)->has_stepper_d))
216         {
217                 if (!gtk_range_get_inverted (GTK_RANGE (widget)))
218                         junction |= CL_JUNCTION_END;
219                 else
220                         junction |= CL_JUNCTION_BEGIN;
221         }
222         
223         return junction;
224 }
225
226 void
227 clearlooks_set_toolbar_parameters (ToolbarParameters *toolbar,
228                                    GtkWidget *widget,
229                                    GdkWindow *window,
230                                    gint x, gint y)
231 {
232         toolbar->topmost = FALSE;
233
234         if (x == 0 && y == 0) {
235                 if (widget && widget->allocation.x == 0 && widget->allocation.y == 0)
236                 {
237                         if (widget->window == window && GE_IS_TOOLBAR (widget))
238                         {
239                                 toolbar->topmost = TRUE;
240                         }
241                 }
242         }
243 }
244
245 void
246 clearlooks_get_notebook_tab_position (GtkWidget *widget,
247                                       gboolean  *start,
248                                       gboolean  *end)
249 {
250         /* default value */
251         *start = TRUE;
252         *end = FALSE;
253
254         if (GE_IS_NOTEBOOK (widget)) {
255                 gboolean found_tabs = FALSE;
256                 gint i, n_pages;
257                 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
258
259                 /* got a notebook, so walk over all the tabs and decide based
260                  * on that ...
261                  * It works like this:
262                  *   - If there is any visible tab that is expanded, set both.
263                  *   - Set start/end if there is any visible tab that is at
264                  *     the start/end.
265                  *   - If one has the child_visibility set to false, arrows
266                  *     are present; so none
267                  * The heuristic falls over if there is a notebook that just
268                  * happens to fill up all the available space. ie. All tabs
269                  * are left aligned, but it does not require scrolling.
270                  * (a more complex heuristic could calculate the tabs width
271                  * and add them all up) */
272
273                 n_pages = gtk_notebook_get_n_pages (notebook);
274                 for (i = 0; i < n_pages; i++) {
275                         GtkWidget *tab_child;
276                         GtkWidget *tab_label;
277                         gboolean expand;
278                         GtkPackType pack_type;
279                                                 
280                         tab_child = gtk_notebook_get_nth_page (notebook, i);
281
282                         /* Skip invisible tabs */
283                         tab_label = gtk_notebook_get_tab_label (notebook, tab_child);
284                         if (!tab_label || !GTK_WIDGET_VISIBLE (tab_label))
285                                 continue;
286                         /* This is the same what the notebook does internally. */
287                         if (tab_label && !gtk_widget_get_child_visible (tab_label)) {
288                                 /* One child is hidden because scroll arrows are present.
289                                  * So both corners are rounded. */
290                                 *start = FALSE;
291                                 *end = FALSE;
292                                 return;
293                         }
294
295                         gtk_notebook_query_tab_label_packing (notebook, tab_child,
296                                                               &expand,
297                                                               NULL, /* don't need fill */
298                                                               &pack_type);
299
300                         if (!found_tabs) {
301                                 found_tabs = TRUE;
302                                 *start = FALSE;
303                                 *end = FALSE;
304                         }
305
306                         if (expand) {
307                                 *start = TRUE;
308                                 *end = TRUE;
309                         } else if (pack_type == GTK_PACK_START) {
310                                 *start = TRUE;
311                         } else {
312                                 *end = TRUE;
313                         }
314                 }
315         }
316 }
317
318