1848b8605Smrg/*
2848b8605Smrg Copyright (c) 2008, 2009 Apple Inc.
3848b8605Smrg
4848b8605Smrg Permission is hereby granted, free of charge, to any person
5848b8605Smrg obtaining a copy of this software and associated documentation files
6848b8605Smrg (the "Software"), to deal in the Software without restriction,
7848b8605Smrg including without limitation the rights to use, copy, modify, merge,
8848b8605Smrg publish, distribute, sublicense, and/or sell copies of the Software,
9848b8605Smrg and to permit persons to whom the Software is furnished to do so,
10848b8605Smrg subject to the following conditions:
11848b8605Smrg
12848b8605Smrg The above copyright notice and this permission notice shall be
13848b8605Smrg included in all copies or substantial portions of the Software.
14848b8605Smrg
15848b8605Smrg THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16848b8605Smrg EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17848b8605Smrg MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18848b8605Smrg NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
19848b8605Smrg HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20848b8605Smrg WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21848b8605Smrg OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22848b8605Smrg DEALINGS IN THE SOFTWARE.
23848b8605Smrg
24848b8605Smrg Except as contained in this notice, the name(s) of the above
25848b8605Smrg copyright holders shall not be used in advertising or otherwise to
26848b8605Smrg promote the sale, use or other dealings in this Software without
27848b8605Smrg prior written authorization.
28848b8605Smrg*/
29848b8605Smrg
30848b8605Smrg#include <stdbool.h>
31848b8605Smrg#include <stdio.h>
32848b8605Smrg#include <stdlib.h>
33848b8605Smrg#include <assert.h>
34848b8605Smrg#include <pthread.h>
35848b8605Smrg#include <string.h>
36848b8605Smrg#include "apple_glx.h"
37848b8605Smrg#include "apple_glx_context.h"
38848b8605Smrg#include "apple_glx_drawable.h"
39848b8605Smrg#include "appledri.h"
40848b8605Smrg
41848b8605Smrgstatic pthread_mutex_t drawables_lock = PTHREAD_MUTEX_INITIALIZER;
42848b8605Smrgstatic struct apple_glx_drawable *drawables_list = NULL;
43848b8605Smrg
44848b8605Smrgstatic void
45848b8605Smrglock_drawables_list(void)
46848b8605Smrg{
47848b8605Smrg   int err;
48848b8605Smrg
49848b8605Smrg   err = pthread_mutex_lock(&drawables_lock);
50848b8605Smrg
51848b8605Smrg   if (err) {
52848b8605Smrg      fprintf(stderr, "pthread_mutex_lock failure in %s: %s\n",
53848b8605Smrg              __func__, strerror(err));
54848b8605Smrg      abort();
55848b8605Smrg   }
56848b8605Smrg}
57848b8605Smrg
58848b8605Smrgstatic void
59848b8605Smrgunlock_drawables_list(void)
60848b8605Smrg{
61848b8605Smrg   int err;
62848b8605Smrg
63848b8605Smrg   err = pthread_mutex_unlock(&drawables_lock);
64848b8605Smrg
65848b8605Smrg   if (err) {
66848b8605Smrg      fprintf(stderr, "pthread_mutex_unlock failure in %s: %s\n",
67848b8605Smrg              __func__, strerror(err));
68848b8605Smrg      abort();
69848b8605Smrg   }
70848b8605Smrg}
71848b8605Smrg
72848b8605Smrgstruct apple_glx_drawable *
73848b8605Smrgapple_glx_find_drawable(Display * dpy, GLXDrawable drawable)
74848b8605Smrg{
75848b8605Smrg   struct apple_glx_drawable *i, *agd = NULL;
76848b8605Smrg
77848b8605Smrg   lock_drawables_list();
78848b8605Smrg
79848b8605Smrg   for (i = drawables_list; i; i = i->next) {
80848b8605Smrg      if (i->drawable == drawable) {
81848b8605Smrg         agd = i;
82848b8605Smrg         break;
83848b8605Smrg      }
84848b8605Smrg   }
85848b8605Smrg
86848b8605Smrg   unlock_drawables_list();
87848b8605Smrg
88848b8605Smrg   return agd;
89848b8605Smrg}
90848b8605Smrg
91848b8605Smrgstatic void
92848b8605Smrgdrawable_lock(struct apple_glx_drawable *agd)
93848b8605Smrg{
94848b8605Smrg   int err;
95848b8605Smrg
96848b8605Smrg   err = pthread_mutex_lock(&agd->mutex);
97848b8605Smrg
98848b8605Smrg   if (err) {
99848b8605Smrg      fprintf(stderr, "pthread_mutex_lock error: %s\n", strerror(err));
100848b8605Smrg      abort();
101848b8605Smrg   }
102848b8605Smrg}
103848b8605Smrg
104848b8605Smrgstatic void
105848b8605Smrgdrawable_unlock(struct apple_glx_drawable *d)
106848b8605Smrg{
107848b8605Smrg   int err;
108848b8605Smrg
109848b8605Smrg   err = pthread_mutex_unlock(&d->mutex);
110848b8605Smrg
111848b8605Smrg   if (err) {
112848b8605Smrg      fprintf(stderr, "pthread_mutex_unlock error: %s\n", strerror(err));
113848b8605Smrg      abort();
114848b8605Smrg   }
115848b8605Smrg}
116848b8605Smrg
117848b8605Smrg
118848b8605Smrgstatic void
119848b8605Smrgreference_drawable(struct apple_glx_drawable *d)
120848b8605Smrg{
121848b8605Smrg   d->lock(d);
122848b8605Smrg   d->reference_count++;
123848b8605Smrg   d->unlock(d);
124848b8605Smrg}
125848b8605Smrg
126848b8605Smrgstatic void
127848b8605Smrgrelease_drawable(struct apple_glx_drawable *d)
128848b8605Smrg{
129848b8605Smrg   d->lock(d);
130848b8605Smrg   d->reference_count--;
131848b8605Smrg   d->unlock(d);
132848b8605Smrg}
133848b8605Smrg
134848b8605Smrg/* The drawables list must be locked prior to calling this. */
135848b8605Smrg/* Return true if the drawable was destroyed. */
136848b8605Smrgstatic bool
137848b8605Smrgdestroy_drawable(struct apple_glx_drawable *d)
138848b8605Smrg{
139848b8605Smrg   int err;
140848b8605Smrg
141848b8605Smrg   d->lock(d);
142848b8605Smrg
143848b8605Smrg   if (d->reference_count > 0) {
144848b8605Smrg      d->unlock(d);
145848b8605Smrg      return false;
146848b8605Smrg   }
147848b8605Smrg
148848b8605Smrg   d->unlock(d);
149848b8605Smrg
150848b8605Smrg   if (d->previous) {
151848b8605Smrg      d->previous->next = d->next;
152848b8605Smrg   }
153848b8605Smrg   else {
154848b8605Smrg      /*
155848b8605Smrg       * The item must be at the head of the list, if it
156848b8605Smrg       * has no previous pointer.
157848b8605Smrg       */
158848b8605Smrg      drawables_list = d->next;
159848b8605Smrg   }
160848b8605Smrg
161848b8605Smrg   if (d->next)
162848b8605Smrg      d->next->previous = d->previous;
163848b8605Smrg
164848b8605Smrg   unlock_drawables_list();
165848b8605Smrg
166848b8605Smrg   if (d->callbacks.destroy) {
167848b8605Smrg      /*
168848b8605Smrg       * Warning: this causes other routines to be called (potentially)
169848b8605Smrg       * from surface_notify_handler.  It's probably best to not have
170848b8605Smrg       * any locks at this point locked.
171848b8605Smrg       */
172848b8605Smrg      d->callbacks.destroy(d->display, d);
173848b8605Smrg   }
174848b8605Smrg
175848b8605Smrg   apple_glx_diagnostic("%s: freeing %p\n", __func__, (void *) d);
176848b8605Smrg
177848b8605Smrg   /* Stupid recursive locks */
178848b8605Smrg   while (pthread_mutex_unlock(&d->mutex) == 0);
179848b8605Smrg
180848b8605Smrg   err = pthread_mutex_destroy(&d->mutex);
181848b8605Smrg   if (err) {
182848b8605Smrg      fprintf(stderr, "pthread_mutex_destroy error: %s\n", strerror(err));
183848b8605Smrg      abort();
184848b8605Smrg   }
185848b8605Smrg
186848b8605Smrg   free(d);
187848b8605Smrg
188848b8605Smrg   /* So that the locks are balanced and the caller correctly unlocks. */
189848b8605Smrg   lock_drawables_list();
190848b8605Smrg
191848b8605Smrg   return true;
192848b8605Smrg}
193848b8605Smrg
194848b8605Smrg/*
195848b8605Smrg * This is typically called when a context is destroyed or the current
196848b8605Smrg * drawable is made None.
197848b8605Smrg */
198848b8605Smrgstatic bool
199848b8605Smrgdestroy_drawable_callback(struct apple_glx_drawable *d)
200848b8605Smrg{
201848b8605Smrg   bool result;
202848b8605Smrg
203848b8605Smrg   d->lock(d);
204848b8605Smrg
205848b8605Smrg   apple_glx_diagnostic("%s: %p ->reference_count before -- %d\n", __func__,
206848b8605Smrg                        (void *) d, d->reference_count);
207848b8605Smrg
208848b8605Smrg   d->reference_count--;
209848b8605Smrg
210848b8605Smrg   if (d->reference_count > 0) {
211848b8605Smrg      d->unlock(d);
212848b8605Smrg      return false;
213848b8605Smrg   }
214848b8605Smrg
215848b8605Smrg   d->unlock(d);
216848b8605Smrg
217848b8605Smrg   lock_drawables_list();
218848b8605Smrg
219848b8605Smrg   result = destroy_drawable(d);
220848b8605Smrg
221848b8605Smrg   unlock_drawables_list();
222848b8605Smrg
223848b8605Smrg   return result;
224848b8605Smrg}
225848b8605Smrg
226848b8605Smrgstatic bool
227848b8605Smrgis_pbuffer(struct apple_glx_drawable *d)
228848b8605Smrg{
229848b8605Smrg   return APPLE_GLX_DRAWABLE_PBUFFER == d->type;
230848b8605Smrg}
231848b8605Smrg
232848b8605Smrgstatic bool
233848b8605Smrgis_pixmap(struct apple_glx_drawable *d)
234848b8605Smrg{
235848b8605Smrg   return APPLE_GLX_DRAWABLE_PIXMAP == d->type;
236848b8605Smrg}
237848b8605Smrg
238848b8605Smrgstatic void
239848b8605Smrgcommon_init(Display * dpy, GLXDrawable drawable, struct apple_glx_drawable *d)
240848b8605Smrg{
241848b8605Smrg   int err;
242848b8605Smrg   pthread_mutexattr_t attr;
243848b8605Smrg
244848b8605Smrg   d->display = dpy;
245848b8605Smrg   d->reference_count = 0;
246848b8605Smrg   d->drawable = drawable;
247848b8605Smrg   d->type = -1;
248848b8605Smrg
249848b8605Smrg   err = pthread_mutexattr_init(&attr);
250848b8605Smrg
251848b8605Smrg   if (err) {
252848b8605Smrg      fprintf(stderr, "pthread_mutexattr_init error: %s\n", strerror(err));
253848b8605Smrg      abort();
254848b8605Smrg   }
255848b8605Smrg
256848b8605Smrg   /*
257848b8605Smrg    * There are some patterns that require a recursive mutex,
258848b8605Smrg    * when working with locks that protect the apple_glx_drawable,
259848b8605Smrg    * and reference functions like ->reference, and ->release.
260848b8605Smrg    */
261848b8605Smrg   err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
262848b8605Smrg
263848b8605Smrg   if (err) {
264848b8605Smrg      fprintf(stderr, "error: setting pthread mutex type: %s\n", strerror(err));
265848b8605Smrg      abort();
266848b8605Smrg   }
267848b8605Smrg
268848b8605Smrg   err = pthread_mutex_init(&d->mutex, &attr);
269848b8605Smrg
270848b8605Smrg   if (err) {
271848b8605Smrg      fprintf(stderr, "pthread_mutex_init error: %s\n", strerror(err));
272848b8605Smrg      abort();
273848b8605Smrg   }
274848b8605Smrg
275848b8605Smrg   (void) pthread_mutexattr_destroy(&attr);
276848b8605Smrg
277848b8605Smrg   d->lock = drawable_lock;
278848b8605Smrg   d->unlock = drawable_unlock;
279848b8605Smrg
280848b8605Smrg   d->reference = reference_drawable;
281848b8605Smrg   d->release = release_drawable;
282848b8605Smrg
283848b8605Smrg   d->destroy = destroy_drawable_callback;
284848b8605Smrg
285848b8605Smrg   d->is_pbuffer = is_pbuffer;
286848b8605Smrg   d->is_pixmap = is_pixmap;
287848b8605Smrg
288848b8605Smrg   d->width = -1;
289848b8605Smrg   d->height = -1;
290848b8605Smrg   d->row_bytes = 0;
291848b8605Smrg   d->path[0] = '\0';
292848b8605Smrg   d->fd = -1;
293848b8605Smrg   d->buffer = NULL;
294848b8605Smrg   d->buffer_length = 0;
295848b8605Smrg
296848b8605Smrg   d->previous = NULL;
297848b8605Smrg   d->next = NULL;
298848b8605Smrg}
299848b8605Smrg
300848b8605Smrgstatic void
301848b8605Smrglink_tail(struct apple_glx_drawable *agd)
302848b8605Smrg{
303848b8605Smrg   lock_drawables_list();
304848b8605Smrg
305848b8605Smrg   /* Link the new drawable into the global list. */
306848b8605Smrg   agd->next = drawables_list;
307848b8605Smrg
308848b8605Smrg   if (drawables_list)
309848b8605Smrg      drawables_list->previous = agd;
310848b8605Smrg
311848b8605Smrg   drawables_list = agd;
312848b8605Smrg
313848b8605Smrg   unlock_drawables_list();
314848b8605Smrg}
315848b8605Smrg
316848b8605Smrg/*WARNING: this returns a locked and referenced object. */
317848b8605Smrgbool
318848b8605Smrgapple_glx_drawable_create(Display * dpy,
319848b8605Smrg                          int screen,
320848b8605Smrg                          GLXDrawable drawable,
321848b8605Smrg                          struct apple_glx_drawable **agdResult,
322848b8605Smrg                          struct apple_glx_drawable_callbacks *callbacks)
323848b8605Smrg{
324848b8605Smrg   struct apple_glx_drawable *d;
325848b8605Smrg
326848b8605Smrg   d = calloc(1, sizeof *d);
327848b8605Smrg
328848b8605Smrg   if (NULL == d) {
329848b8605Smrg      perror("malloc");
330848b8605Smrg      return true;
331848b8605Smrg   }
332848b8605Smrg
333848b8605Smrg   common_init(dpy, drawable, d);
334848b8605Smrg   d->type = callbacks->type;
335848b8605Smrg   d->callbacks = *callbacks;
336848b8605Smrg
337848b8605Smrg   d->reference(d);
338848b8605Smrg   d->lock(d);
339848b8605Smrg
340848b8605Smrg   link_tail(d);
341848b8605Smrg
342848b8605Smrg   apple_glx_diagnostic("%s: new drawable %p\n", __func__, (void *) d);
343848b8605Smrg
344848b8605Smrg   *agdResult = d;
345848b8605Smrg
346848b8605Smrg   return false;
347848b8605Smrg}
348848b8605Smrg
349848b8605Smrgstatic int error_count = 0;
350848b8605Smrg
351848b8605Smrgstatic int
352848b8605Smrgerror_handler(Display * dpy, XErrorEvent * err)
353848b8605Smrg{
354848b8605Smrg   if (err->error_code == BadWindow) {
355848b8605Smrg      ++error_count;
356848b8605Smrg   }
357848b8605Smrg
358848b8605Smrg   return 0;
359848b8605Smrg}
360848b8605Smrg
361848b8605Smrgvoid
362848b8605Smrgapple_glx_garbage_collect_drawables(Display * dpy)
363848b8605Smrg{
364848b8605Smrg   struct apple_glx_drawable *d, *dnext;
365848b8605Smrg   Window root;
366848b8605Smrg   int x, y;
367848b8605Smrg   unsigned int width, height, bd, depth;
368848b8605Smrg   int (*old_handler) (Display *, XErrorEvent *);
369848b8605Smrg
370848b8605Smrg
371848b8605Smrg   if (NULL == drawables_list)
372848b8605Smrg      return;
373848b8605Smrg
374848b8605Smrg   old_handler = XSetErrorHandler(error_handler);
375848b8605Smrg
376848b8605Smrg   XSync(dpy, False);
377848b8605Smrg
378848b8605Smrg   lock_drawables_list();
379848b8605Smrg
380848b8605Smrg   for (d = drawables_list; d;) {
381848b8605Smrg      dnext = d->next;
382848b8605Smrg
383848b8605Smrg      d->lock(d);
384848b8605Smrg
385848b8605Smrg      if (d->reference_count > 0) {
386848b8605Smrg         /*
387848b8605Smrg          * Skip this, because some context still retains a reference
388848b8605Smrg          * to the drawable.
389848b8605Smrg          */
390848b8605Smrg         d->unlock(d);
391848b8605Smrg         d = dnext;
392848b8605Smrg         continue;
393848b8605Smrg      }
394848b8605Smrg
395848b8605Smrg      d->unlock(d);
396848b8605Smrg
397848b8605Smrg      error_count = 0;
398848b8605Smrg
399848b8605Smrg      /*
400848b8605Smrg       * Mesa uses XGetWindowAttributes, but some of these things are
401848b8605Smrg       * most definitely not Windows, and that's against the rules.
402848b8605Smrg       * XGetGeometry on the other hand is legal with a Pixmap and Window.
403848b8605Smrg       */
404848b8605Smrg      XGetGeometry(dpy, d->drawable, &root, &x, &y, &width, &height, &bd,
405848b8605Smrg                   &depth);
406848b8605Smrg
407848b8605Smrg      if (error_count > 0) {
408848b8605Smrg         /*
409848b8605Smrg          * Note: this may not actually destroy the drawable.
410848b8605Smrg          * If another context retains a reference to the drawable
411848b8605Smrg          * after the reference count test above.
412848b8605Smrg          */
413848b8605Smrg         (void) destroy_drawable(d);
414848b8605Smrg         error_count = 0;
415848b8605Smrg      }
416848b8605Smrg
417848b8605Smrg      d = dnext;
418848b8605Smrg   }
419848b8605Smrg
420848b8605Smrg   XSetErrorHandler(old_handler);
421848b8605Smrg
422848b8605Smrg   unlock_drawables_list();
423848b8605Smrg}
424848b8605Smrg
425848b8605Smrgunsigned int
426848b8605Smrgapple_glx_get_drawable_count(void)
427848b8605Smrg{
428848b8605Smrg   unsigned int result = 0;
429848b8605Smrg   struct apple_glx_drawable *d;
430848b8605Smrg
431848b8605Smrg   lock_drawables_list();
432848b8605Smrg
433848b8605Smrg   for (d = drawables_list; d; d = d->next)
434848b8605Smrg      ++result;
435848b8605Smrg
436848b8605Smrg   unlock_drawables_list();
437848b8605Smrg
438848b8605Smrg   return result;
439848b8605Smrg}
440848b8605Smrg
441848b8605Smrgstruct apple_glx_drawable *
442848b8605Smrgapple_glx_drawable_find_by_type(GLXDrawable drawable, int type, int flags)
443848b8605Smrg{
444848b8605Smrg   struct apple_glx_drawable *d;
445848b8605Smrg
446848b8605Smrg   lock_drawables_list();
447848b8605Smrg
448848b8605Smrg   for (d = drawables_list; d; d = d->next) {
449848b8605Smrg      if (d->type == type && d->drawable == drawable) {
450848b8605Smrg         if (flags & APPLE_GLX_DRAWABLE_REFERENCE)
451848b8605Smrg            d->reference(d);
452848b8605Smrg
453848b8605Smrg         if (flags & APPLE_GLX_DRAWABLE_LOCK)
454848b8605Smrg            d->lock(d);
455848b8605Smrg
456848b8605Smrg         unlock_drawables_list();
457848b8605Smrg
458848b8605Smrg         return d;
459848b8605Smrg      }
460848b8605Smrg   }
461848b8605Smrg
462848b8605Smrg   unlock_drawables_list();
463848b8605Smrg
464848b8605Smrg   return NULL;
465848b8605Smrg}
466848b8605Smrg
467848b8605Smrgstruct apple_glx_drawable *
468848b8605Smrgapple_glx_drawable_find(GLXDrawable drawable, int flags)
469848b8605Smrg{
470848b8605Smrg   struct apple_glx_drawable *d;
471848b8605Smrg
472848b8605Smrg   lock_drawables_list();
473848b8605Smrg
474848b8605Smrg   for (d = drawables_list; d; d = d->next) {
475848b8605Smrg      if (d->drawable == drawable) {
476848b8605Smrg         if (flags & APPLE_GLX_DRAWABLE_REFERENCE)
477848b8605Smrg            d->reference(d);
478848b8605Smrg
479848b8605Smrg         if (flags & APPLE_GLX_DRAWABLE_LOCK)
480848b8605Smrg            d->lock(d);
481848b8605Smrg
482848b8605Smrg         unlock_drawables_list();
483848b8605Smrg
484848b8605Smrg         return d;
485848b8605Smrg      }
486848b8605Smrg   }
487848b8605Smrg
488848b8605Smrg   unlock_drawables_list();
489848b8605Smrg
490848b8605Smrg   return NULL;
491848b8605Smrg}
492848b8605Smrg
493848b8605Smrg/* Return true if the type is valid for the drawable. */
494848b8605Smrgbool
495848b8605Smrgapple_glx_drawable_destroy_by_type(Display * dpy,
496848b8605Smrg                                   GLXDrawable drawable, int type)
497848b8605Smrg{
498848b8605Smrg   struct apple_glx_drawable *d;
499848b8605Smrg
500848b8605Smrg   lock_drawables_list();
501848b8605Smrg
502848b8605Smrg   for (d = drawables_list; d; d = d->next) {
503848b8605Smrg      if (drawable == d->drawable && type == d->type) {
504848b8605Smrg         /*
505848b8605Smrg          * The user has requested that we destroy this resource.
506848b8605Smrg          * However, there may be references in the contexts to it, so
507848b8605Smrg          * release it, and call destroy_drawable which doesn't destroy
508848b8605Smrg          * if the reference_count is > 0.
509848b8605Smrg          */
510848b8605Smrg         d->release(d);
511848b8605Smrg
512848b8605Smrg         apple_glx_diagnostic("%s d->reference_count %d\n",
513848b8605Smrg                              __func__, d->reference_count);
514848b8605Smrg
515848b8605Smrg         destroy_drawable(d);
516848b8605Smrg         unlock_drawables_list();
517848b8605Smrg         return true;
518848b8605Smrg      }
519848b8605Smrg   }
520848b8605Smrg
521848b8605Smrg   unlock_drawables_list();
522848b8605Smrg
523848b8605Smrg   return false;
524848b8605Smrg}
525848b8605Smrg
526848b8605Smrgstruct apple_glx_drawable *
527848b8605Smrgapple_glx_drawable_find_by_uid(unsigned int uid, int flags)
528848b8605Smrg{
529848b8605Smrg   struct apple_glx_drawable *d;
530848b8605Smrg
531848b8605Smrg   lock_drawables_list();
532848b8605Smrg
533848b8605Smrg   for (d = drawables_list; d; d = d->next) {
534848b8605Smrg      /* Only surfaces have a uid. */
535848b8605Smrg      if (APPLE_GLX_DRAWABLE_SURFACE == d->type) {
536848b8605Smrg         if (d->types.surface.uid == uid) {
537848b8605Smrg            if (flags & APPLE_GLX_DRAWABLE_REFERENCE)
538848b8605Smrg               d->reference(d);
539848b8605Smrg
540848b8605Smrg            if (flags & APPLE_GLX_DRAWABLE_LOCK)
541848b8605Smrg               d->lock(d);
542848b8605Smrg
543848b8605Smrg            unlock_drawables_list();
544848b8605Smrg
545848b8605Smrg            return d;
546848b8605Smrg         }
547848b8605Smrg      }
548848b8605Smrg   }
549848b8605Smrg
550848b8605Smrg   unlock_drawables_list();
551848b8605Smrg
552848b8605Smrg   return NULL;
553848b8605Smrg}
554