Fix object lifecycle errors.
[platform/core/uifw/at-spi2-atk.git] / atk-adaptor / accessible-leasing.c
1 /*
2  * AT-SPI - Assistive Technology Service Provider Interface
3  * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
4  *
5  * Copyright 2009, 2010 Codethink Ltd.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library 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 GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "accessible-leasing.h"
28
29 #ifdef SPI_ATK_DEBUG
30 #include "accessible-cache.h"
31 #endif
32
33 /*---------------------------------------------------------------------------*/
34
35 SpiLeasing *spi_global_leasing;
36
37 typedef struct _ExpiryElement
38 {
39   guint expiry_s;
40   GObject *object;
41 } ExpiryElement;
42
43 static void spi_leasing_dispose (GObject * object);
44
45 static void spi_leasing_finalize (GObject * object);
46
47 static void add_expiry_timeout (SpiLeasing * leasing);
48
49 /*---------------------------------------------------------------------------*/
50
51 G_DEFINE_TYPE (SpiLeasing, spi_leasing, G_TYPE_OBJECT)
52
53 static void spi_leasing_class_init (SpiLeasingClass * klass)
54 {
55   GObjectClass *object_class = (GObjectClass *) klass;
56
57   spi_leasing_parent_class = g_type_class_ref (G_TYPE_OBJECT);
58
59   object_class->finalize = spi_leasing_finalize;
60   object_class->dispose = spi_leasing_dispose;
61 }
62
63 static void
64 spi_leasing_init (SpiLeasing * leasing)
65 {
66   leasing->expiry_queue = g_queue_new ();
67   leasing->expiry_func_id = 0;
68 }
69
70 static void
71 spi_leasing_finalize (GObject * object)
72 {
73   SpiLeasing *leasing = SPI_LEASING (object);
74
75   g_free (leasing->expiry_queue);
76   G_OBJECT_CLASS (spi_leasing_parent_class)->finalize (object);
77 }
78
79 static void
80 spi_leasing_dispose (GObject * object)
81 {
82   SpiLeasing *leasing = SPI_LEASING (object);
83
84   ExpiryElement *head;
85   while (head = g_queue_pop_head (leasing->expiry_queue))
86     {
87       g_object_unref (head->object);
88       g_slice_free (ExpiryElement, head);
89     }
90   G_OBJECT_CLASS (spi_leasing_parent_class)->dispose (object);
91 }
92
93 /*---------------------------------------------------------------------------*/
94
95 /*
96   End the lease on all objects whose expiry time has passed.
97  
98   Check when the next event is and set the next expiry func.
99 */
100 static gboolean
101 expiry_func (gpointer data)
102 {
103   SpiLeasing *leasing = SPI_LEASING (data);
104
105   ExpiryElement *head, *current;
106   GTimeVal t;
107
108   g_get_current_time (&t);
109
110   head = g_queue_peek_head (leasing->expiry_queue);
111   while (head != NULL && head->expiry_s <= t.tv_sec)
112     {
113       current = g_queue_pop_head (leasing->expiry_queue);
114
115 #ifdef SPI_ATK_DEBUG
116       g_debug ("REVOKE - ");
117       spi_cache_print_info (current->object);
118 #endif
119
120       g_object_unref (current->object);
121       g_slice_free (ExpiryElement, current);
122
123       head = g_queue_peek_head (leasing->expiry_queue);
124     }
125
126   leasing->expiry_func_id = 0;
127   add_expiry_timeout (leasing);
128
129   return FALSE;
130 }
131
132 /*---------------------------------------------------------------------------*/
133
134 /*
135   Checks if an expiry timeout is already scheduled, if so returns.
136   This is becasue events will always be added to the end of the queue.
137   Events are always later in time to previoulsy added events.
138
139   Otherwise calculate the next wake time using the top of the queue
140   and add the next expiry function.
141
142   This function is called when a lease is added or at the end of the
143   expiry function to add the next expiry timeout.
144 */
145 static void
146 add_expiry_timeout (SpiLeasing * leasing)
147 {
148   ExpiryElement *elem;
149   GTimeVal t;
150   guint next_expiry;
151
152   if (leasing->expiry_func_id != 0)
153     return;
154
155   elem = (ExpiryElement *) g_queue_peek_head (leasing->expiry_queue);
156   if (elem == NULL)
157     return;
158
159   /* The current time is implicitly rounded down here by ignoring the us */
160   g_get_current_time (&t);
161   next_expiry = elem->expiry_s - t.tv_sec;
162   leasing->expiry_func_id = g_timeout_add_seconds (next_expiry,
163                                                    expiry_func, leasing);
164 }
165
166 /*---------------------------------------------------------------------------*/
167
168 /*
169   The lease time is expected to be in seconds, the rounding is going to be to
170   intervals of 1 second.
171
172   The lease time is going to be rounded up, as the lease time should be
173   considered a MINIMUM that the object will be leased for.
174 */
175 #define LEASE_TIME_S 3
176 #define EXPIRY_TIME_S (LEASE_TIME_S + 1)
177
178 GObject *
179 spi_leasing_take (SpiLeasing * leasing, GObject * object)
180 {
181   /*
182      Get the current time.
183      Quantize the time.
184      Add the release event to the queue.
185      Check the next expiry.
186    */
187
188   GTimeVal t;
189   guint expiry_s;
190
191   ExpiryElement *elem;
192
193   g_get_current_time (&t);
194   expiry_s = t.tv_sec + EXPIRY_TIME_S;
195
196   elem = g_slice_new (ExpiryElement);
197   elem->expiry_s = expiry_s;
198   elem->object = g_object_ref (object);
199
200   g_queue_push_tail (leasing->expiry_queue, elem);
201
202   add_expiry_timeout (leasing);
203
204 #ifdef SPI_ATK_DEBUG
205   g_debug ("LEASE - ");
206   spi_cache_print_info (object);
207 #endif
208
209   return object;
210 }
211
212 /*END------------------------------------------------------------------------*/