]> Pileus Git - ~andy/gtk/blob - gtk/gtksizerequestcache.c
sizerequestcache: Make code an array
[~andy/gtk] / gtk / gtksizerequestcache.c
1 /* gtksizerequest.c
2  * Copyright (C) 2007-2010 Openismus GmbH
3  *
4  * Authors:
5  *      Mathias Hasselmann <mathias@openismus.com>
6  *      Tristan Van Berkom <tristan.van.berkom@gmail.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library 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  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <config.h>
23
24 #include "gtksizerequestcacheprivate.h"
25
26 #include <string.h>
27
28 void
29 _gtk_size_request_cache_init (SizeRequestCache *cache)
30 {
31   memset (cache, 0, sizeof (SizeRequestCache));
32 }
33
34 static void
35 free_sizes (SizeRequest **sizes)
36 {
37   gint i;
38
39   for (i = 0; i < GTK_SIZE_REQUEST_CACHED_SIZES && sizes[i] != NULL; i++)
40     g_slice_free (SizeRequest, sizes[i]);
41       
42   g_slice_free1 (sizeof (SizeRequest *) * GTK_SIZE_REQUEST_CACHED_SIZES, sizes);
43 }
44
45 void
46 _gtk_size_request_cache_free (SizeRequestCache *cache)
47 {
48   if (cache->widths)
49     free_sizes (cache->widths);
50   if (cache->heights)
51     free_sizes (cache->heights);
52 }
53
54 void
55 _gtk_size_request_cache_clear (SizeRequestCache *cache)
56                                
57 {
58   _gtk_size_request_cache_free (cache);
59   _gtk_size_request_cache_init (cache);
60 }
61
62 void
63 _gtk_size_request_cache_commit (SizeRequestCache *cache,
64                                 GtkOrientation    orientation,
65                                 gint              for_size,
66                                 gint              minimum_size,
67                                 gint              natural_size)
68 {
69   SizeRequest      **cached_sizes;
70   guint              i, n_sizes;
71
72   /* First handle caching of the base requests */
73   if (for_size < 0)
74     {
75       cache->cached_size[orientation].minimum_size = minimum_size;
76       cache->cached_size[orientation].natural_size = natural_size;
77       cache->flags[orientation].cached_size_valid = TRUE;
78       return;
79     }
80
81   /* Check if the minimum_size and natural_size is already
82    * in the cache and if this result can be used to extend
83    * that cache entry 
84    */
85   if (orientation == GTK_ORIENTATION_HORIZONTAL)
86     {
87       cached_sizes = cache->widths;
88       n_sizes = cache->cached_widths;
89     }
90   else
91     {
92       cached_sizes = cache->heights;
93       n_sizes = cache->cached_heights;
94     }
95
96   for (i = 0; i < n_sizes; i++)
97     {
98       if (cached_sizes[i]->cached_size.minimum_size == minimum_size &&
99           cached_sizes[i]->cached_size.natural_size == natural_size)
100         {
101           cached_sizes[i]->lower_for_size = MIN (cached_sizes[i]->lower_for_size, for_size);
102           cached_sizes[i]->upper_for_size = MAX (cached_sizes[i]->upper_for_size, for_size);
103           return;
104         }
105     }
106
107   /* If not found, pull a new size from the cache, the returned size cache
108    * will immediately be used to cache the new computed size so we go ahead
109    * and increment the last_cached_width/height right away */
110   if (orientation == GTK_ORIENTATION_HORIZONTAL)
111     {
112       if (cache->cached_widths < GTK_SIZE_REQUEST_CACHED_SIZES)
113         {
114           cache->cached_widths++;
115           cache->last_cached_width = cache->cached_widths - 1;
116         }
117       else
118         {
119           if (++cache->last_cached_width == GTK_SIZE_REQUEST_CACHED_SIZES)
120             cache->last_cached_width = 0;
121         }
122
123       if (!cache->widths)
124         cache->widths = g_slice_alloc0 (sizeof (SizeRequest *) * GTK_SIZE_REQUEST_CACHED_SIZES);
125
126       if (!cache->widths[cache->last_cached_width])
127         cache->widths[cache->last_cached_width] = g_slice_new (SizeRequest);
128
129       cache->widths[cache->last_cached_width]->lower_for_size = for_size;
130       cache->widths[cache->last_cached_width]->upper_for_size = for_size;
131       cache->widths[cache->last_cached_width]->cached_size.minimum_size = minimum_size;
132       cache->widths[cache->last_cached_width]->cached_size.natural_size = natural_size;
133     }
134   else /* GTK_ORIENTATION_VERTICAL */
135     {
136       if (cache->cached_heights < GTK_SIZE_REQUEST_CACHED_SIZES)
137         {
138           cache->cached_heights++;
139           cache->last_cached_height = cache->cached_heights - 1;
140         }
141       else
142         {
143           if (++cache->last_cached_height == GTK_SIZE_REQUEST_CACHED_SIZES)
144             cache->last_cached_height = 0;
145         }
146
147       if (!cache->heights)
148         cache->heights = g_slice_alloc0 (sizeof (SizeRequest *) * GTK_SIZE_REQUEST_CACHED_SIZES);
149
150       if (!cache->heights[cache->last_cached_height])
151         cache->heights[cache->last_cached_height] = g_slice_new (SizeRequest);
152
153       cache->heights[cache->last_cached_height]->lower_for_size = for_size;
154       cache->heights[cache->last_cached_height]->upper_for_size = for_size;
155       cache->heights[cache->last_cached_height]->cached_size.minimum_size = minimum_size;
156       cache->heights[cache->last_cached_height]->cached_size.natural_size = natural_size;
157     }
158 }
159
160 /* looks for a cached size request for this for_size.
161  *
162  * Note that this caching code was originally derived from
163  * the Clutter toolkit but has evolved for other GTK+ requirements.
164  */
165 gboolean
166 _gtk_size_request_cache_lookup (SizeRequestCache *cache,
167                                 GtkOrientation    orientation,
168                                 gint              for_size,
169                                 gint             *minimum,
170                                 gint             *natural)
171 {
172   CachedSize *result = NULL;
173
174   if (for_size < 0)
175     {
176       if (cache->flags[orientation].cached_size_valid)
177         result = &cache->cached_size[orientation];
178     }
179   else
180     {
181       SizeRequest      **cached_sizes;
182       guint              i, n_sizes;
183
184       if (orientation == GTK_ORIENTATION_HORIZONTAL)
185         {
186           cached_sizes = cache->widths;
187           n_sizes      = cache->cached_widths;
188         }
189       else
190         {
191           cached_sizes = cache->heights;
192           n_sizes      = cache->cached_heights;
193         }
194
195       /* Search for an already cached size */
196       for (i = 0; i < n_sizes; i++)
197         {
198           if (cached_sizes[i]->lower_for_size <= for_size &&
199               cached_sizes[i]->upper_for_size >= for_size)
200             {
201               result = &cached_sizes[i]->cached_size;
202               break;
203             }
204         }
205     }
206
207   if (result)
208     {
209       *minimum = result->minimum_size;
210       *natural = result->natural_size;
211       return TRUE;
212     }
213   else
214     return FALSE;
215 }
216