1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpcomponenteditor.c
5  * Copyright (C) 2003-2005 Michael Natterer <mitch@gimp.org>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program 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
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #include <gegl.h>
24 #include <gtk/gtk.h>
25 
26 #include "libgimpbase/gimpbase.h"
27 #include "libgimpwidgets/gimpwidgets.h"
28 
29 #include "widgets-types.h"
30 
31 #include "core/gimpchannel.h"
32 #include "core/gimpimage.h"
33 
34 #include "gimpcellrendererviewable.h"
35 #include "gimpcomponenteditor.h"
36 #include "gimpdnd.h"
37 #include "gimpdocked.h"
38 #include "gimpmenufactory.h"
39 #include "gimpviewrendererimage.h"
40 #include "gimpwidgets-utils.h"
41 
42 #include "gimp-intl.h"
43 
44 
45 enum
46 {
47   COLUMN_CHANNEL,
48   COLUMN_VISIBLE,
49   COLUMN_RENDERER,
50   COLUMN_NAME,
51   N_COLUMNS
52 };
53 
54 
55 static void gimp_component_editor_docked_iface_init (GimpDockedInterface *iface);
56 
57 static void gimp_component_editor_set_context       (GimpDocked          *docked,
58                                                      GimpContext         *context);
59 
60 static void gimp_component_editor_set_image         (GimpImageEditor     *editor,
61                                                      GimpImage           *image);
62 
63 static void gimp_component_editor_create_components (GimpComponentEditor *editor);
64 static void gimp_component_editor_clear_components  (GimpComponentEditor *editor);
65 static void gimp_component_editor_clicked         (GtkCellRendererToggle *cellrenderertoggle,
66                                                    gchar                 *path,
67                                                    GdkModifierType        state,
68                                                    GimpComponentEditor   *editor);
69 static gboolean gimp_component_editor_select        (GtkTreeSelection    *selection,
70                                                      GtkTreeModel        *model,
71                                                      GtkTreePath         *path,
72                                                      gboolean             path_currently_selected,
73                                                      gpointer             data);
74 static gboolean gimp_component_editor_button_press  (GtkWidget           *widget,
75                                                      GdkEventButton      *bevent,
76                                                      GimpComponentEditor *editor);
77 static void gimp_component_editor_renderer_update   (GimpViewRenderer    *renderer,
78                                                      GimpComponentEditor *editor);
79 static void gimp_component_editor_mode_changed      (GimpImage           *image,
80                                                      GimpComponentEditor *editor);
81 static void gimp_component_editor_alpha_changed     (GimpImage           *image,
82                                                      GimpComponentEditor *editor);
83 static void gimp_component_editor_visibility_changed(GimpImage           *image,
84                                                      GimpChannelType      channel,
85                                                      GimpComponentEditor *editor);
86 static void gimp_component_editor_active_changed    (GimpImage           *image,
87                                                      GimpChannelType      channel,
88                                                      GimpComponentEditor *editor);
89 static GimpImage * gimp_component_editor_drag_component (GtkWidget       *widget,
90                                                          GimpContext    **context,
91                                                          GimpChannelType *channel,
92                                                          gpointer         data);
93 
94 
95 G_DEFINE_TYPE_WITH_CODE (GimpComponentEditor, gimp_component_editor,
96                          GIMP_TYPE_IMAGE_EDITOR,
97                          G_IMPLEMENT_INTERFACE (GIMP_TYPE_DOCKED,
98                                                 gimp_component_editor_docked_iface_init))
99 
100 #define parent_class gimp_component_editor_parent_class
101 
102 static GimpDockedInterface *parent_docked_iface = NULL;
103 
104 
105 static void
gimp_component_editor_class_init(GimpComponentEditorClass * klass)106 gimp_component_editor_class_init (GimpComponentEditorClass *klass)
107 {
108   GimpImageEditorClass *image_editor_class = GIMP_IMAGE_EDITOR_CLASS (klass);
109 
110   image_editor_class->set_image = gimp_component_editor_set_image;
111 }
112 
113 static void
gimp_component_editor_init(GimpComponentEditor * editor)114 gimp_component_editor_init (GimpComponentEditor *editor)
115 {
116   GtkWidget    *frame;
117   GtkListStore *list;
118 
119   frame = gtk_frame_new (NULL);
120   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
121   gtk_box_pack_start (GTK_BOX (editor), frame, FALSE, FALSE, 0);
122   gtk_widget_show (frame);
123 
124   list = gtk_list_store_new (N_COLUMNS,
125                              G_TYPE_INT,
126                              G_TYPE_BOOLEAN,
127                              GIMP_TYPE_VIEW_RENDERER,
128                              G_TYPE_STRING);
129   editor->model = GTK_TREE_MODEL (list);
130 
131   editor->view = GTK_TREE_VIEW (gtk_tree_view_new_with_model (editor->model));
132   g_object_unref (list);
133 
134   gtk_tree_view_set_headers_visible (editor->view, FALSE);
135 
136   editor->eye_column = gtk_tree_view_column_new ();
137   gtk_tree_view_append_column (editor->view, editor->eye_column);
138 
139   editor->eye_cell = gimp_cell_renderer_toggle_new (GIMP_ICON_VISIBLE);
140   gtk_tree_view_column_pack_start (editor->eye_column, editor->eye_cell,
141                                    FALSE);
142   gtk_tree_view_column_set_attributes (editor->eye_column, editor->eye_cell,
143                                        "active", COLUMN_VISIBLE,
144                                        NULL);
145 
146   g_signal_connect (editor->eye_cell, "clicked",
147                     G_CALLBACK (gimp_component_editor_clicked),
148                     editor);
149 
150   editor->renderer_cell = gimp_cell_renderer_viewable_new ();
151   gtk_tree_view_insert_column_with_attributes (editor->view,
152                                                -1, NULL,
153                                                editor->renderer_cell,
154                                                "renderer", COLUMN_RENDERER,
155                                                NULL);
156 
157   gtk_tree_view_insert_column_with_attributes (editor->view,
158                                                -1, NULL,
159                                                gtk_cell_renderer_text_new (),
160                                                "text", COLUMN_NAME,
161                                                NULL);
162 
163   gtk_container_add (GTK_CONTAINER (frame), GTK_WIDGET (editor->view));
164   gtk_widget_show (GTK_WIDGET (editor->view));
165 
166   g_signal_connect (editor->view, "button-press-event",
167                     G_CALLBACK (gimp_component_editor_button_press),
168                     editor);
169 
170   editor->selection = gtk_tree_view_get_selection (editor->view);
171   gtk_tree_selection_set_mode (editor->selection, GTK_SELECTION_MULTIPLE);
172 
173   gtk_tree_selection_set_select_function (editor->selection,
174                                           gimp_component_editor_select,
175                                           editor, NULL);
176 
177   gimp_dnd_component_source_add (GTK_WIDGET (editor->view),
178                                  gimp_component_editor_drag_component,
179                                  editor);
180 }
181 
182 static void
gimp_component_editor_docked_iface_init(GimpDockedInterface * iface)183 gimp_component_editor_docked_iface_init (GimpDockedInterface *iface)
184 {
185   parent_docked_iface = g_type_interface_peek_parent (iface);
186 
187   if (! parent_docked_iface)
188     parent_docked_iface = g_type_default_interface_peek (GIMP_TYPE_DOCKED);
189 
190   iface->set_context = gimp_component_editor_set_context;
191 }
192 
193 static void
gimp_component_editor_set_context(GimpDocked * docked,GimpContext * context)194 gimp_component_editor_set_context (GimpDocked  *docked,
195                                    GimpContext *context)
196 {
197   GimpComponentEditor *editor = GIMP_COMPONENT_EDITOR (docked);
198   GtkTreeIter          iter;
199   gboolean             iter_valid;
200 
201   parent_docked_iface->set_context (docked, context);
202 
203   for (iter_valid = gtk_tree_model_get_iter_first (editor->model, &iter);
204        iter_valid;
205        iter_valid = gtk_tree_model_iter_next (editor->model, &iter))
206     {
207       GimpViewRenderer *renderer;
208 
209       gtk_tree_model_get (editor->model, &iter,
210                           COLUMN_RENDERER, &renderer,
211                           -1);
212 
213       gimp_view_renderer_set_context (renderer, context);
214       g_object_unref (renderer);
215     }
216 }
217 
218 static void
gimp_component_editor_set_image(GimpImageEditor * editor,GimpImage * image)219 gimp_component_editor_set_image (GimpImageEditor *editor,
220                                  GimpImage       *image)
221 {
222   GimpComponentEditor *component_editor = GIMP_COMPONENT_EDITOR (editor);
223 
224   if (editor->image)
225     {
226       gimp_component_editor_clear_components (component_editor);
227 
228       g_signal_handlers_disconnect_by_func (editor->image,
229                                             gimp_component_editor_mode_changed,
230                                             component_editor);
231       g_signal_handlers_disconnect_by_func (editor->image,
232                                             gimp_component_editor_alpha_changed,
233                                             component_editor);
234       g_signal_handlers_disconnect_by_func (editor->image,
235                                             gimp_component_editor_visibility_changed,
236                                             component_editor);
237       g_signal_handlers_disconnect_by_func (editor->image,
238                                             gimp_component_editor_active_changed,
239                                             component_editor);
240     }
241 
242   GIMP_IMAGE_EDITOR_CLASS (parent_class)->set_image (editor, image);
243 
244   if (editor->image)
245     {
246       gimp_component_editor_create_components (component_editor);
247 
248       g_signal_connect (editor->image, "mode-changed",
249                         G_CALLBACK (gimp_component_editor_mode_changed),
250                         component_editor);
251       g_signal_connect (editor->image, "alpha-changed",
252                         G_CALLBACK (gimp_component_editor_alpha_changed),
253                         component_editor);
254       g_signal_connect (editor->image, "component-visibility-changed",
255                         G_CALLBACK (gimp_component_editor_visibility_changed),
256                         component_editor);
257       g_signal_connect (editor->image, "component-active-changed",
258                         G_CALLBACK (gimp_component_editor_active_changed),
259                         component_editor);
260     }
261 }
262 
263 GtkWidget *
gimp_component_editor_new(gint view_size,GimpMenuFactory * menu_factory)264 gimp_component_editor_new (gint             view_size,
265                            GimpMenuFactory *menu_factory)
266 {
267   GimpComponentEditor *editor;
268 
269   g_return_val_if_fail (view_size > 0 &&
270                         view_size <= GIMP_VIEWABLE_MAX_PREVIEW_SIZE, NULL);
271   g_return_val_if_fail (GIMP_IS_MENU_FACTORY (menu_factory), NULL);
272 
273   editor = g_object_new (GIMP_TYPE_COMPONENT_EDITOR,
274                          "menu-factory",    menu_factory,
275                          "menu-identifier", "<Channels>",
276                          "ui-path",         "/channels-popup",
277                          NULL);
278 
279   gimp_component_editor_set_view_size (editor, view_size);
280 
281   return GTK_WIDGET (editor);
282 }
283 
284 void
gimp_component_editor_set_view_size(GimpComponentEditor * editor,gint view_size)285 gimp_component_editor_set_view_size (GimpComponentEditor *editor,
286                                      gint                 view_size)
287 {
288   GtkWidget   *tree_widget;
289   GtkStyle    *tree_style;
290   GtkIconSize  icon_size;
291   GtkTreeIter  iter;
292   gboolean     iter_valid;
293 
294   g_return_if_fail (GIMP_IS_COMPONENT_EDITOR (editor));
295   g_return_if_fail (view_size >  0 &&
296                     view_size <= GIMP_VIEWABLE_MAX_PREVIEW_SIZE);
297 
298   tree_widget = GTK_WIDGET (editor->view);
299   tree_style  = gtk_widget_get_style (tree_widget);
300 
301   icon_size = gimp_get_icon_size (tree_widget,
302                                   GIMP_ICON_VISIBLE,
303                                   GTK_ICON_SIZE_BUTTON,
304                                   view_size -
305                                   2 * tree_style->xthickness,
306                                   view_size -
307                                   2 * tree_style->ythickness);
308 
309   g_object_set (editor->eye_cell,
310                 "stock-size", icon_size,
311                 NULL);
312 
313   for (iter_valid = gtk_tree_model_get_iter_first (editor->model, &iter);
314        iter_valid;
315        iter_valid = gtk_tree_model_iter_next (editor->model, &iter))
316     {
317       GimpViewRenderer *renderer;
318 
319       gtk_tree_model_get (editor->model, &iter,
320                           COLUMN_RENDERER, &renderer,
321                           -1);
322 
323       gimp_view_renderer_set_size (renderer, view_size, 1);
324       g_object_unref (renderer);
325     }
326 
327   editor->view_size = view_size;
328 
329   gtk_tree_view_columns_autosize (editor->view);
330 }
331 
332 static void
gimp_component_editor_create_components(GimpComponentEditor * editor)333 gimp_component_editor_create_components (GimpComponentEditor *editor)
334 {
335   GimpImage       *image        = GIMP_IMAGE_EDITOR (editor)->image;
336   gint             n_components = 0;
337   GimpChannelType  components[MAX_CHANNELS];
338   GEnumClass      *enum_class;
339   gint             i;
340 
341   switch (gimp_image_get_base_type (image))
342     {
343     case GIMP_RGB:
344       n_components  = 3;
345       components[0] = GIMP_CHANNEL_RED;
346       components[1] = GIMP_CHANNEL_GREEN;
347       components[2] = GIMP_CHANNEL_BLUE;
348       break;
349 
350     case GIMP_GRAY:
351       n_components  = 1;
352       components[0] = GIMP_CHANNEL_GRAY;
353       break;
354 
355     case GIMP_INDEXED:
356       n_components  = 1;
357       components[0] = GIMP_CHANNEL_INDEXED;
358       break;
359     }
360 
361   if (gimp_image_has_alpha (image))
362     components[n_components++] = GIMP_CHANNEL_ALPHA;
363 
364   enum_class = g_type_class_ref (GIMP_TYPE_CHANNEL_TYPE);
365 
366   for (i = 0; i < n_components; i++)
367     {
368       GimpViewRenderer *renderer;
369       GtkTreeIter       iter;
370       GEnumValue       *enum_value;
371       const gchar      *desc;
372       gboolean          visible;
373 
374       visible = gimp_image_get_component_visible (image, components[i]);
375 
376       renderer = gimp_view_renderer_new (GIMP_IMAGE_EDITOR (editor)->context,
377                                          G_TYPE_FROM_INSTANCE (image),
378                                          editor->view_size, 1, FALSE);
379       gimp_view_renderer_set_viewable (renderer, GIMP_VIEWABLE (image));
380       gimp_view_renderer_remove_idle (renderer);
381 
382       GIMP_VIEW_RENDERER_IMAGE (renderer)->channel = components[i];
383 
384       g_signal_connect (renderer, "update",
385                         G_CALLBACK (gimp_component_editor_renderer_update),
386                         editor);
387 
388       enum_value = g_enum_get_value (enum_class, components[i]);
389       desc = gimp_enum_value_get_desc (enum_class, enum_value);
390 
391       gtk_list_store_append (GTK_LIST_STORE (editor->model), &iter);
392 
393       gtk_list_store_set (GTK_LIST_STORE (editor->model), &iter,
394                           COLUMN_CHANNEL,  components[i],
395                           COLUMN_VISIBLE,  visible,
396                           COLUMN_RENDERER, renderer,
397                           COLUMN_NAME,     desc,
398                           -1);
399 
400       g_object_unref (renderer);
401 
402       if (gimp_image_get_component_active (image, components[i]))
403         gtk_tree_selection_select_iter (editor->selection, &iter);
404     }
405 
406   g_type_class_unref (enum_class);
407 }
408 
409 static void
gimp_component_editor_clear_components(GimpComponentEditor * editor)410 gimp_component_editor_clear_components (GimpComponentEditor *editor)
411 {
412   gtk_list_store_clear (GTK_LIST_STORE (editor->model));
413 
414   /*  Clear the renderer so that it don't reference the viewable.
415    *  See bug #149906.
416    */
417   g_object_set (editor->renderer_cell, "renderer", NULL, NULL);
418 }
419 
420 static void
gimp_component_editor_clicked(GtkCellRendererToggle * cellrenderertoggle,gchar * path_str,GdkModifierType state,GimpComponentEditor * editor)421 gimp_component_editor_clicked (GtkCellRendererToggle *cellrenderertoggle,
422                                gchar                 *path_str,
423                                GdkModifierType        state,
424                                GimpComponentEditor   *editor)
425 {
426   GtkTreePath *path;
427   GtkTreeIter  iter;
428 
429   path = gtk_tree_path_new_from_string (path_str);
430 
431   if (gtk_tree_model_get_iter (editor->model, &iter, path))
432     {
433       GimpImage       *image = GIMP_IMAGE_EDITOR (editor)->image;
434       GimpChannelType  channel;
435       gboolean         active;
436 
437       gtk_tree_model_get (editor->model, &iter,
438                           COLUMN_CHANNEL, &channel,
439                           -1);
440       g_object_get (cellrenderertoggle,
441                     "active", &active,
442                     NULL);
443 
444       gimp_image_set_component_visible (image, channel, !active);
445       gimp_image_flush (image);
446     }
447 
448   gtk_tree_path_free (path);
449 }
450 
451 static gboolean
gimp_component_editor_select(GtkTreeSelection * selection,GtkTreeModel * model,GtkTreePath * path,gboolean path_currently_selected,gpointer data)452 gimp_component_editor_select (GtkTreeSelection *selection,
453                               GtkTreeModel     *model,
454                               GtkTreePath      *path,
455                               gboolean          path_currently_selected,
456                               gpointer          data)
457 {
458   GimpComponentEditor *editor = GIMP_COMPONENT_EDITOR (data);
459   GtkTreeIter          iter;
460   GimpChannelType      channel;
461   gboolean             active;
462 
463   gtk_tree_model_get_iter (editor->model, &iter, path);
464   gtk_tree_model_get (editor->model, &iter,
465                       COLUMN_CHANNEL, &channel,
466                       -1);
467 
468   active = gimp_image_get_component_active (GIMP_IMAGE_EDITOR (editor)->image,
469                                             channel);
470 
471   return active != path_currently_selected;
472 }
473 
474 static gboolean
gimp_component_editor_button_press(GtkWidget * widget,GdkEventButton * bevent,GimpComponentEditor * editor)475 gimp_component_editor_button_press (GtkWidget           *widget,
476                                     GdkEventButton      *bevent,
477                                     GimpComponentEditor *editor)
478 {
479   GtkTreeViewColumn *column;
480   GtkTreePath       *path;
481 
482   editor->clicked_component = -1;
483 
484   if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
485                                      bevent->x,
486                                      bevent->y,
487                                      &path, &column, NULL, NULL))
488     {
489       GtkTreeIter     iter;
490       GimpChannelType channel;
491       gboolean        active;
492 
493       active = gtk_tree_selection_path_is_selected (editor->selection, path);
494 
495       gtk_tree_model_get_iter (editor->model, &iter, path);
496 
497       gtk_tree_path_free (path);
498 
499       gtk_tree_model_get (editor->model, &iter,
500                           COLUMN_CHANNEL, &channel,
501                           -1);
502 
503       editor->clicked_component = channel;
504 
505       if (gdk_event_triggers_context_menu ((GdkEvent *) bevent))
506         {
507           gimp_editor_popup_menu (GIMP_EDITOR (editor), NULL, NULL);
508         }
509       else if (bevent->type == GDK_BUTTON_PRESS && bevent->button == 1 &&
510                column != editor->eye_column)
511         {
512           GimpImage *image = GIMP_IMAGE_EDITOR (editor)->image;
513 
514           gimp_image_set_component_active (image, channel, ! active);
515           gimp_image_flush (image);
516         }
517     }
518 
519   return FALSE;
520 }
521 
522 static gboolean
gimp_component_editor_get_iter(GimpComponentEditor * editor,GimpChannelType channel,GtkTreeIter * iter)523 gimp_component_editor_get_iter (GimpComponentEditor *editor,
524                                 GimpChannelType      channel,
525                                 GtkTreeIter         *iter)
526 {
527   gint index;
528 
529   index = gimp_image_get_component_index (GIMP_IMAGE_EDITOR (editor)->image,
530                                           channel);
531 
532   if (index != -1)
533     return gtk_tree_model_iter_nth_child (editor->model, iter, NULL, index);
534 
535   return FALSE;
536 }
537 
538 static void
gimp_component_editor_renderer_update(GimpViewRenderer * renderer,GimpComponentEditor * editor)539 gimp_component_editor_renderer_update (GimpViewRenderer    *renderer,
540                                        GimpComponentEditor *editor)
541 {
542   GimpChannelType channel = GIMP_VIEW_RENDERER_IMAGE (renderer)->channel;
543   GtkTreeIter     iter;
544 
545   if (gimp_component_editor_get_iter (editor, channel, &iter))
546     {
547       GtkTreePath *path;
548 
549       path = gtk_tree_model_get_path (editor->model, &iter);
550       gtk_tree_model_row_changed (editor->model, path, &iter);
551       gtk_tree_path_free (path);
552     }
553 }
554 
555 static void
gimp_component_editor_mode_changed(GimpImage * image,GimpComponentEditor * editor)556 gimp_component_editor_mode_changed (GimpImage           *image,
557                                     GimpComponentEditor *editor)
558 {
559   gimp_component_editor_clear_components (editor);
560   gimp_component_editor_create_components (editor);
561 }
562 
563 static void
gimp_component_editor_alpha_changed(GimpImage * image,GimpComponentEditor * editor)564 gimp_component_editor_alpha_changed (GimpImage           *image,
565                                      GimpComponentEditor *editor)
566 {
567   gimp_component_editor_clear_components (editor);
568   gimp_component_editor_create_components (editor);
569 }
570 
571 static void
gimp_component_editor_visibility_changed(GimpImage * image,GimpChannelType channel,GimpComponentEditor * editor)572 gimp_component_editor_visibility_changed (GimpImage           *image,
573                                           GimpChannelType      channel,
574                                           GimpComponentEditor *editor)
575 {
576   GtkTreeIter iter;
577 
578   if (gimp_component_editor_get_iter (editor, channel, &iter))
579     {
580       gboolean visible = gimp_image_get_component_visible (image, channel);
581 
582       gtk_list_store_set (GTK_LIST_STORE (editor->model), &iter,
583                           COLUMN_VISIBLE, visible,
584                           -1);
585     }
586 }
587 
588 static void
gimp_component_editor_active_changed(GimpImage * image,GimpChannelType channel,GimpComponentEditor * editor)589 gimp_component_editor_active_changed (GimpImage           *image,
590                                       GimpChannelType      channel,
591                                       GimpComponentEditor *editor)
592 {
593   GtkTreeIter iter;
594 
595   if (gimp_component_editor_get_iter (editor, channel, &iter))
596     {
597       gboolean active = gimp_image_get_component_active (image, channel);
598 
599       if (gtk_tree_selection_iter_is_selected (editor->selection, &iter) !=
600           active)
601         {
602           if (active)
603             gtk_tree_selection_select_iter (editor->selection, &iter);
604           else
605             gtk_tree_selection_unselect_iter (editor->selection, &iter);
606         }
607     }
608 }
609 
610 static GimpImage *
gimp_component_editor_drag_component(GtkWidget * widget,GimpContext ** context,GimpChannelType * channel,gpointer data)611 gimp_component_editor_drag_component (GtkWidget        *widget,
612                                       GimpContext     **context,
613                                       GimpChannelType  *channel,
614                                       gpointer          data)
615 {
616   GimpComponentEditor *editor = GIMP_COMPONENT_EDITOR (data);
617 
618   if (GIMP_IMAGE_EDITOR (editor)->image &&
619       editor->clicked_component != -1)
620     {
621       if (channel)
622         *channel = editor->clicked_component;
623 
624       if (context)
625         *context = GIMP_IMAGE_EDITOR (editor)->context;
626 
627       return GIMP_IMAGE_EDITOR (editor)->image;
628     }
629 
630   return NULL;
631 }
632