]> Pileus Git - ~andy/gtk/blob - gtk/gtksizerequestcache.c
sizerequest: Use GtkOrientation
[~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       if (orientation == GTK_ORIENTATION_HORIZONTAL)
76         {
77           cache->cached_width.minimum_size = minimum_size;
78           cache->cached_width.natural_size = natural_size;
79           cache->cached_base_width = TRUE;
80         }
81       else
82         {
83           cache->cached_height.minimum_size = minimum_size;
84           cache->cached_height.natural_size = natural_size;
85           cache->cached_base_height = TRUE;
86         }
87       return;
88     }
89
90   /* Check if the minimum_size and natural_size is already
91    * in the cache and if this result can be used to extend
92    * that cache entry 
93    */
94   if (orientation == GTK_ORIENTATION_HORIZONTAL)
95     {
96       cached_sizes = cache->widths;
97       n_sizes = cache->cached_widths;
98     }
99   else
100     {
101       cached_sizes = cache->heights;
102       n_sizes = cache->cached_heights;
103     }
104
105   for (i = 0; i < n_sizes; i++)
106     {
107       if (cached_sizes[i]->cached_size.minimum_size == minimum_size &&
108           cached_sizes[i]->cached_size.natural_size == natural_size)
109         {
110           cached_sizes[i]->lower_for_size = MIN (cached_sizes[i]->lower_for_size, for_size);
111           cached_sizes[i]->upper_for_size = MAX (cached_sizes[i]->upper_for_size, for_size);
112           return;
113         }
114     }
115
116   /* If not found, pull a new size from the cache, the returned size cache
117    * will immediately be used to cache the new computed size so we go ahead
118    * and increment the last_cached_width/height right away */
119   if (orientation == GTK_ORIENTATION_HORIZONTAL)
120     {
121       if (cache->cached_widths < GTK_SIZE_REQUEST_CACHED_SIZES)
122         {
123           cache->cached_widths++;
124           cache->last_cached_width = cache->cached_widths - 1;
125         }
126       else
127         {
128           if (++cache->last_cached_width == GTK_SIZE_REQUEST_CACHED_SIZES)
129             cache->last_cached_width = 0;
130         }
131
132       if (!cache->widths)
133         cache->widths = g_slice_alloc0 (sizeof (SizeRequest *) * GTK_SIZE_REQUEST_CACHED_SIZES);
134
135       if (!cache->widths[cache->last_cached_width])
136         cache->widths[cache->last_cached_width] = g_slice_new (SizeRequest);
137
138       cache->widths[cache->last_cached_width]->lower_for_size = for_size;
139       cache->widths[cache->last_cached_width]->upper_for_size = for_size;
140       cache->widths[cache->last_cached_width]->cached_size.minimum_size = minimum_size;
141       cache->widths[cache->last_cached_width]->cached_size.natural_size = natural_size;
142     }
143   else /* GTK_ORIENTATION_VERTICAL */
144     {
145       if (cache->cached_heights < GTK_SIZE_REQUEST_CACHED_SIZES)
146         {
147           cache->cached_heights++;
148           cache->last_cached_height = cache->cached_heights - 1;
149         }
150       else
151         {
152           if (++cache->last_cached_height == GTK_SIZE_REQUEST_CACHED_SIZES)
153             cache->last_cached_height = 0;
154         }
155
156       if (!cache->heights)
157         cache->heights = g_slice_alloc0 (sizeof (SizeRequest *) * GTK_SIZE_REQUEST_CACHED_SIZES);
158
159       if (!cache->heights[cache->last_cached_height])
160         cache->heights[cache->last_cached_height] = g_slice_new (SizeRequest);
161
162       cache->heights[cache->last_cached_height]->lower_for_size = for_size;
163       cache->heights[cache->last_cached_height]->upper_for_size = for_size;
164       cache->heights[cache->last_cached_height]->cached_size.minimum_size = minimum_size;
165       cache->heights[cache->last_cached_height]->cached_size.natural_size = natural_size;
166     }
167 }
168
169 /* looks for a cached size request for this for_size.
170  *
171  * Note that this caching code was originally derived from
172  * the Clutter toolkit but has evolved for other GTK+ requirements.
173  */
174 gboolean
175 _gtk_size_request_cache_lookup (SizeRequestCache *cache,
176                                 GtkOrientation    orientation,
177                                 gint              for_size,
178                                 gint             *minimum,
179                                 gint             *natural)
180 {
181   CachedSize *result = NULL;
182
183   if (for_size < 0)
184     {
185       if (orientation == GTK_ORIENTATION_HORIZONTAL)
186         {
187           if (cache->cached_base_width)
188             result = &cache->cached_width;
189         }
190       else
191         {
192           if (cache->cached_base_height)
193             result = &cache->cached_height;
194         }
195     }
196   else
197     {
198       SizeRequest      **cached_sizes;
199       guint              i, n_sizes;
200
201       if (orientation == GTK_ORIENTATION_HORIZONTAL)
202         {
203           cached_sizes = cache->widths;
204           n_sizes      = cache->cached_widths;
205         }
206       else
207         {
208           cached_sizes = cache->heights;
209           n_sizes      = cache->cached_heights;
210         }
211
212       /* Search for an already cached size */
213       for (i = 0; i < n_sizes; i++)
214         {
215           if (cached_sizes[i]->lower_for_size <= for_size &&
216               cached_sizes[i]->upper_for_size >= for_size)
217             {
218               result = &cached_sizes[i]->cached_size;
219               break;
220             }
221         }
222     }
223
224   if (result)
225     {
226       *minimum = result->minimum_size;
227       *natural = result->natural_size;
228       return TRUE;
229     }
230   else
231     return FALSE;
232 }
233