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
28void
29_gtk_size_request_cache_init (SizeRequestCache *cache)
30{
31 memset (s: cache, c: 0, n: sizeof (SizeRequestCache));
32}
33
34static void
35free_sizes_x (SizeRequestX **sizes)
36{
37 int i;
38
39 for (i = 0; i < GTK_SIZE_REQUEST_CACHED_SIZES && sizes[i] != NULL; i++)
40 g_slice_free (SizeRequestX, sizes[i]);
41
42 g_slice_free1 (block_size: sizeof (SizeRequestY *) * GTK_SIZE_REQUEST_CACHED_SIZES, mem_block: sizes);
43}
44
45static void
46free_sizes_y (SizeRequestY **sizes)
47{
48 int i;
49
50 for (i = 0; i < GTK_SIZE_REQUEST_CACHED_SIZES && sizes[i] != NULL; i++)
51 g_slice_free (SizeRequestY, sizes[i]);
52
53 g_slice_free1 (block_size: sizeof (SizeRequestY *) * GTK_SIZE_REQUEST_CACHED_SIZES, mem_block: sizes);
54}
55
56void
57_gtk_size_request_cache_free (SizeRequestCache *cache)
58{
59 if (cache->requests_x)
60 free_sizes_x (sizes: cache->requests_x);
61 if (cache->requests_y)
62 free_sizes_y (sizes: cache->requests_y);
63}
64
65void
66_gtk_size_request_cache_clear (SizeRequestCache *cache)
67{
68 _gtk_size_request_cache_free (cache);
69 _gtk_size_request_cache_init (cache);
70}
71
72void
73_gtk_size_request_cache_commit (SizeRequestCache *cache,
74 GtkOrientation orientation,
75 int for_size,
76 int minimum_size,
77 int natural_size,
78 int minimum_baseline,
79 int natural_baseline)
80{
81 guint i, n_sizes;
82
83 if (orientation == GTK_ORIENTATION_HORIZONTAL)
84 {
85 g_assert (minimum_baseline == -1);
86 g_assert (natural_baseline == -1);
87 }
88
89 /* First handle caching of the base requests */
90 if (for_size < 0)
91 {
92 if (orientation == GTK_ORIENTATION_HORIZONTAL)
93 {
94 cache->cached_size_x.minimum_size = minimum_size;
95 cache->cached_size_x.natural_size = natural_size;
96 }
97 else
98 {
99 cache->cached_size_y.minimum_size = minimum_size;
100 cache->cached_size_y.natural_size = natural_size;
101 cache->cached_size_y.minimum_baseline = minimum_baseline;
102 cache->cached_size_y.natural_baseline = natural_baseline;
103 }
104
105 cache->flags[orientation].cached_size_valid = TRUE;
106 return;
107 }
108
109 /* Check if the minimum_size and natural_size is already
110 * in the cache and if this result can be used to extend
111 * that cache entry
112 */
113 n_sizes = cache->flags[orientation].n_cached_requests;
114
115
116 if (orientation == GTK_ORIENTATION_HORIZONTAL)
117 {
118 SizeRequestX **cached_sizes = cache->requests_x;
119 SizeRequestX *cached_size;
120
121 for (i = 0; i < n_sizes; i++)
122 {
123 if (cached_sizes[i]->cached_size.minimum_size == minimum_size &&
124 cached_sizes[i]->cached_size.natural_size == natural_size)
125 {
126 cached_sizes[i]->lower_for_size = MIN (cached_sizes[i]->lower_for_size, for_size);
127 cached_sizes[i]->upper_for_size = MAX (cached_sizes[i]->upper_for_size, for_size);
128 return;
129 }
130 }
131
132 /* If not found, pull a new size from the cache, the returned size cache
133 * will immediately be used to cache the new computed size so we go ahead
134 * and increment the last_cached_request right away */
135 if (n_sizes < GTK_SIZE_REQUEST_CACHED_SIZES)
136 {
137 cache->flags[orientation].n_cached_requests++;
138 cache->flags[orientation].last_cached_request = cache->flags[orientation].n_cached_requests - 1;
139 }
140 else
141 {
142 if (++cache->flags[orientation].last_cached_request == GTK_SIZE_REQUEST_CACHED_SIZES)
143 cache->flags[orientation].last_cached_request = 0;
144 }
145
146 if (cache->requests_x == NULL)
147 cache->requests_x = g_slice_alloc0 (block_size: sizeof (SizeRequestX *) * GTK_SIZE_REQUEST_CACHED_SIZES);
148
149 if (cache->requests_x[cache->flags[orientation].last_cached_request] == NULL)
150 cache->requests_x[cache->flags[orientation].last_cached_request] = g_slice_new (SizeRequestX);
151
152 cached_size = cache->requests_x[cache->flags[orientation].last_cached_request];
153 cached_size->lower_for_size = for_size;
154 cached_size->upper_for_size = for_size;
155 cached_size->cached_size.minimum_size = minimum_size;
156 cached_size->cached_size.natural_size = natural_size;
157 }
158 else
159 {
160 SizeRequestY **cached_sizes = cache->requests_y;
161 SizeRequestY *cached_size;
162
163 for (i = 0; i < n_sizes; i++)
164 {
165 if (cached_sizes[i]->cached_size.minimum_size == minimum_size &&
166 cached_sizes[i]->cached_size.natural_size == natural_size &&
167 cached_sizes[i]->cached_size.minimum_baseline == minimum_baseline &&
168 cached_sizes[i]->cached_size.natural_baseline == natural_baseline)
169 {
170 cached_sizes[i]->lower_for_size = MIN (cached_sizes[i]->lower_for_size, for_size);
171 cached_sizes[i]->upper_for_size = MAX (cached_sizes[i]->upper_for_size, for_size);
172 return;
173 }
174 }
175
176 /* If not found, pull a new size from the cache, the returned size cache
177 * will immediately be used to cache the new computed size so we go ahead
178 * and increment the last_cached_request right away */
179 if (n_sizes < GTK_SIZE_REQUEST_CACHED_SIZES)
180 {
181 cache->flags[orientation].n_cached_requests++;
182 cache->flags[orientation].last_cached_request = cache->flags[orientation].n_cached_requests - 1;
183 }
184 else
185 {
186 if (++cache->flags[orientation].last_cached_request == GTK_SIZE_REQUEST_CACHED_SIZES)
187 cache->flags[orientation].last_cached_request = 0;
188 }
189
190 if (cache->requests_y == NULL)
191 cache->requests_y = g_slice_alloc0 (block_size: sizeof (SizeRequestY *) * GTK_SIZE_REQUEST_CACHED_SIZES);
192
193 if (cache->requests_y[cache->flags[orientation].last_cached_request] == NULL)
194 cache->requests_y[cache->flags[orientation].last_cached_request] = g_slice_new (SizeRequestY);
195
196 cached_size = cache->requests_y[cache->flags[orientation].last_cached_request];
197 cached_size->lower_for_size = for_size;
198 cached_size->upper_for_size = for_size;
199 cached_size->cached_size.minimum_size = minimum_size;
200 cached_size->cached_size.natural_size = natural_size;
201 cached_size->cached_size.minimum_baseline = minimum_baseline;
202 cached_size->cached_size.natural_baseline = natural_baseline;
203 }
204}
205
206/* looks for a cached size request for this for_size.
207 *
208 * Note that this caching code was originally derived from
209 * the Clutter toolkit but has evolved for other GTK requirements.
210 */
211gboolean
212_gtk_size_request_cache_lookup (const SizeRequestCache *cache,
213 GtkOrientation orientation,
214 int for_size,
215 int *minimum,
216 int *natural,
217 int *minimum_baseline,
218 int *natural_baseline)
219{
220 guint i, p;
221
222 if (orientation == GTK_ORIENTATION_HORIZONTAL)
223 {
224 if (for_size < 0)
225 {
226 if (cache->flags[GTK_ORIENTATION_HORIZONTAL].cached_size_valid)
227 {
228 const CachedSizeX *result = &cache->cached_size_x;
229
230 *minimum = result->minimum_size;
231 *natural = result->natural_size;
232 return TRUE;
233 }
234
235 return FALSE;
236 }
237 else
238 {
239 /* Search for an already cached size */
240 for (i = 0, p = cache->flags[GTK_ORIENTATION_HORIZONTAL].n_cached_requests; i < p; i++)
241 {
242 const SizeRequestX *cur = cache->requests_x[i];
243
244 if (cur->lower_for_size <= for_size &&
245 cur->upper_for_size >= for_size)
246 {
247 const CachedSizeX *result = &cur->cached_size;
248
249 *minimum = result->minimum_size;
250 *natural = result->natural_size;
251
252 return TRUE;
253 }
254 }
255
256 return FALSE;
257 }
258 }
259 else
260 {
261 if (for_size < 0)
262 {
263 if (cache->flags[GTK_ORIENTATION_VERTICAL].cached_size_valid)
264 {
265 const CachedSizeY *result = &cache->cached_size_y;
266
267 *minimum = result->minimum_size;
268 *natural = result->natural_size;
269 *minimum_baseline = result->minimum_baseline;
270 *natural_baseline = result->natural_baseline;
271 return TRUE;
272 }
273
274 return FALSE;
275 }
276 else
277 {
278 /* Search for an already cached size */
279 for (i = 0, p = cache->flags[GTK_ORIENTATION_VERTICAL].n_cached_requests; i < p; i++)
280 {
281 const SizeRequestY *cur = cache->requests_y[i];
282
283 if (cur->lower_for_size <= for_size &&
284 cur->upper_for_size >= for_size)
285 {
286 const CachedSizeY *result = &cur->cached_size;
287
288 *minimum = result->minimum_size;
289 *natural = result->natural_size;
290 *minimum_baseline = result->minimum_baseline;
291 *natural_baseline = result->natural_baseline;
292 return TRUE;
293 }
294 }
295
296 return FALSE;
297 }
298 }
299}
300
301

source code of gtk/gtk/gtksizerequestcache.c