[gimp-gap/gap-2-8] LAYER GROUP Support in animated filtercalls and filtermacros



commit 4b1cd364a37a28e76e484d64bb805895cc9e234d
Author: Wolfgang Hofer <wolfgangh svn gnome org>
Date:   Sat Feb 22 09:29:50 2014 +0100

    LAYER GROUP Support in animated filtercalls and filtermacros

 ChangeLog                                      |   85 ++++++
 gap/gap_blend_fill_main.c                      |    2 +-
 gap/gap_dbbrowser_utils.c                      |  305 +++++++++++++++------
 gap/gap_dbbrowser_utils.h                      |   14 +-
 gap/gap_edge_detection.c                       |    2 +-
 gap/gap_fg_matting_dialog.c                    |    8 +-
 gap/gap_filter_foreach.c                       |  296 ++++++++++++++-------
 gap/gap_filter_iterators.c                     |   54 +++-
 gap/gap_fire_pattern.c                         |   20 +-
 gap/gap_fmac_base.c                            |    2 +-
 gap/gap_fmac_context.c                         |   94 +++++--
 gap/gap_fmac_context.h                         |    8 +-
 gap/gap_frame_fetcher.c                        |  205 ++++++++-------
 gap/gap_frame_fetcher.h                        |   18 +-
 gap/gap_image.c                                |  267 ++++++++++++++++++-
 gap/gap_image.h                                |    9 +
 gap/gap_mod_layer.c                            |  352 +++++++++++++++++++-----
 gap/gap_player_cache.c                         |    3 -
 gap/gap_water_pattern.c                        |   16 +-
 gap/iter_ALT/mod/plug_in_bump_map_iter_ALT.inc |   43 ++--
 20 files changed, 1357 insertions(+), 446 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 169984b..021cdfa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,88 @@
+2014-02-22 Wolfgang Hofer <hof gimp org>
+- extended filtermacro reference sidecar filformat (.fmref)
+  .fmref files do describe persistent layer ids and 
+  allow succesful applying a filter that requires additional layers
+  (such as bumpmap that needs a layer for the map)
+  with recorded lastvlues buffer in the next gimp session.
+
+  The old format describes layer rference by imagname and stackposition.
+  In case of nested layer this is not sufficient.
+  
+  Therefore the fileformat was exteded with keyword "parentstack:",
+  followed by a list of integer stack positions of all parent group layers 
+  concatenated by the "/" delimiter character.
+  
+  Note that toplevel layers are still refered without the new parentstack
+  (== compatible to the old format) 
+
+  id:800003 frameNr:000000 stack:02 track:-1 mtime:01392968915  type:3 file:"/home/hof/testimage.xcf" 
parentstack:2/0
+
+
+
+- replaced deprecated gimp_drawable_is_valid calls by gimp_item_is_valid
+
+- Filter All Layers feature now has options how to handle applying a filter to a group layer.
+  The GAP filter db browser dialog provides radio buttons how to handle group layers.
+    - normal mode (enables filter calls on group layer items)
+    - merge group items before calling a filter
+    - skip filtercalls on group items
+
+  This feature is mainly a workaround for the fact, that many plug-in filters
+  of the GIMP-2.8.10 release fail on attempt to process a group layer.
+  
+  Example: the  whirl-pinch plugin fails with the message:
+  Calling error for procedure 'gimp-drawable-merge-shadow':
+                  Item 'GR-1' (20) cannot be modified because it is a group item
+
+- fixed issuses for the "FramesModify" feature
+  when function "Apply filter on layer(s)" is selected.
+  Support skip and automatical merge on selected group layers in the processed frames
+  for this modify function.
+  Notes:
+    for filter apply with constant values (acceleration characteristic value == 0)
+    the first processed frame must contain at least one layer 
+    that matches the selection criteria.
+    
+    for filter apply with varying values both 
+    the first and the last processed frame
+    must contain at least one layer 
+    that matches the selection criteria.
+    
+    This is required for the interactive filtercalls to record the
+    last values buffer(s) for the called filter pdb procedure.
+    
+
+- dropped support for GAP_FILTER_PITSTOP environment variable
+  the pitstop dialog is now configurable via gimprc parameters:
+    (gap-filterall-enable-pitstop-dialog "no")
+    (gap-modify-enable-pitstop-dialog "no")
+  
+  Both pitstop dialogs now have an option "do not show this dialog again"
+  to disable those (optional) dialogs in the future (in this and further sessions).
+  
+
+  * gap/gap_blend_fill_main.c
+  * gap/gap_dbbrowser_utils.c
+  * gap/gap_dbbrowser_utils.h
+  * gap/gap_edge_detection.c
+  * gap/gap_fg_matting_dialog.c
+  * gap/gap_filter_foreach.c
+  * gap/gap_filter_iterators.c
+  * gap/gap_fire_pattern.c
+  * gap/gap_fmac_base.c
+  * gap/gap_fmac_context.c
+  * gap/gap_fmac_context.h
+  * gap/gap_frame_fetcher.c
+  * gap/gap_frame_fetcher.h
+  * gap/gap_image.c
+  * gap/gap_image.h
+  * gap/gap_mod_layer.c
+  * gap/gap_player_cache.c
+  * gap/gap_water_pattern.c
+  * gap/iter_ALT/mod/plug_in_bump_map_iter_ALT.inc
+
+
+
 2014-02-15 Wolfgang Hofer <hof gimp org>
 
 - applied fix for the foreground matting feature as suggested at bug #723818
diff --git a/gap/gap_blend_fill_main.c b/gap/gap_blend_fill_main.c
index bb5b0ac..a054767 100644
--- a/gap/gap_blend_fill_main.c
+++ b/gap/gap_blend_fill_main.c
@@ -1935,7 +1935,7 @@ gap_blend_fill_dialog (FilterVals *fiVals, gint32 drawable_id)
   {
     initalComboElem = SELECTION_FROM_SVG_FILE;
   }
-  else if(gimp_drawable_is_valid(fiVals->altSelection) == TRUE)
+  else if(gimp_item_is_valid(fiVals->altSelection) == TRUE)
   {
     initalComboElem = fiVals->altSelection;
   }
diff --git a/gap/gap_dbbrowser_utils.c b/gap/gap_dbbrowser_utils.c
index cab0eba..afdd283 100644
--- a/gap/gap_dbbrowser_utils.c
+++ b/gap/gap_dbbrowser_utils.c
@@ -1,5 +1,5 @@
-/* 
- *  gap_dbbrowser_utils.c (most parts of the code are copied from 
+/*
+ *  gap_dbbrowser_utils.c (most parts of the code are copied from
  *  GIMP DB-Browser Code by Thomas NOEL <thomas minet net>
  */
 /* The GIMP -- an image manipulation program
@@ -34,10 +34,10 @@
  * 27. jan .1999   hof: update for GIMP 1.1.1 (show help)
  * 09. dec .1998   hof: update for GIMP 1.1
  * 12. jan .1998   hof: added "Gen Code" button
- *  
+ *
  * 23. dec .1997   hof: created GAP specific variant of DBbrowser
  *                       removed apply_callback
- *                       added constraint_procedure, 
+ *                       added constraint_procedure,
  *                       added 2 buttons
  *                       added return type
  */
@@ -96,7 +96,7 @@ typedef struct
   gint              selected_nparams;
   gint              selected_nreturn_vals;
   GimpParamDef     *selected_params;
-  GimpParamDef     *selected_return_vals; 
+  GimpParamDef     *selected_return_vals;
 
   /* GAP DB-Browser specific items */
   gchar            *selected_menu_path;
@@ -105,6 +105,10 @@ typedef struct
   GtkObject        *accel_adj;
   GtkWidget        *accel_spinbutton;
   GtkWidget        *accel_hbox;
+  GtkWidget        *radio_grp_hbox;
+  GtkWidget        *radio_grp_process;
+  GtkWidget        *radio_grp_skip;
+  GtkWidget        *radio_grp_merge;
 
 
   GtkWidget* menupath_button;
@@ -113,7 +117,7 @@ typedef struct
   t_constraint_func      constraint_func_sel1;
   t_constraint_func      constraint_func_sel2;
   GapDbBrowserResult *result;
-  
+
   gint                   codegen_flag;
   gint32                 current_image_id;
   const char            *help_id;
@@ -127,18 +131,20 @@ typedef struct
 
 static void         procedure_select_callback    (GtkTreeSelection  *sel,
                                                   dbbrowser_t       *dbbrowser);
-static void         dialog_search_callback       (GtkWidget         *widget, 
+static void         dialog_search_callback       (GtkWidget         *widget,
                                                   dbbrowser_t       *dbbrowser);
-static void         dialog_select                (dbbrowser_t       *dbbrowser, 
+static void         dialog_select                (dbbrowser_t       *dbbrowser,
                                                   gchar             *proc_name);
-static void         dialog_close_callback        (GtkWidget         *widget, 
+static void         dialog_close_callback        (GtkWidget         *widget,
                                                   dbbrowser_t       *dbbrowser);
-static void         dialog_help_callback         (GtkWidget         *widget, 
+static void         dialog_help_callback         (GtkWidget         *widget,
                                                   dbbrowser_t       *dbbrowser);
 static void         convert_string               (gchar             *str);
 
 /* GAP specific extra callbacks */
-static void         dialog_num_button_callback   (dbbrowser_t* dbbrowser, 
+static void         p_radio_callback(GtkWidget *wgt, gpointer user_data);
+
+static void         dialog_num_button_callback   (dbbrowser_t* dbbrowser,
                                                   gint button_nr);
 static void         dialog_button_1_callback     (GtkWidget *widget,
                                                   dbbrowser_t* dbbrowser);
@@ -146,6 +152,8 @@ static void         dialog_button_3_callback     (GtkWidget *widget,
                                                   dbbrowser_t* dbbrowser);
 static void         p_accel_spinbutton_callback  (GtkObject *obj, dbbrowser_t* dbbrowser);
 
+static void         p_create_radio_group_handling_widgets (dbbrowser_t *dbbrowser, gboolean 
showGroupHandling);
+
 static void         p_create_action_area_buttons (dbbrowser_t *dbbrowser,
                                                   char *button_1_txt,
                                                   gboolean showAccelerationCharacteristic,
@@ -153,7 +161,7 @@ static void         p_create_action_area_buttons (dbbrowser_t *dbbrowser,
                                                 );
 
 /* create and perform the dialog */
-int 
+int
 gap_db_browser_dialog(char *title_txt,
                       char *button_1_txt,
                       gboolean                 showAccelerationCharacteristic,
@@ -175,19 +183,24 @@ gap_db_browser_dialog(char *title_txt,
   gimp_ui_init ("gap-animated-filter-apply", FALSE);
 
   dbbrowser = g_new0 (dbbrowser_t, 1);
-  
-  /* store pointers to gap constraint procedures */  
+
+  /* store pointers to gap constraint procedures */
   dbbrowser->constraint_func      = constraint_func;
   dbbrowser->constraint_func_sel1 = constraint_func_sel1;
   dbbrowser->constraint_func_sel2 = constraint_func_sel2;
   dbbrowser->result  = result;
   dbbrowser->codegen_flag  = 0;   /* default: no code generation */
   dbbrowser->current_image_id = image_id;
-  
+
+  dbbrowser->radio_grp_hbox            = NULL;
+  dbbrowser->radio_grp_process         = NULL;
+  dbbrowser->radio_grp_skip            = NULL;
+  dbbrowser->radio_grp_merge           = NULL;
+
   /* the dialog box */
 
   dbbrowser->dialog = gtk_dialog_new ();
-  
+
   gtk_window_set_title (GTK_WINDOW (dbbrowser->dialog), title_txt);
   gtk_window_set_position (GTK_WINDOW (dbbrowser->dialog), GTK_WIN_POS_MOUSE);
   g_signal_connect (dbbrowser->dialog, "destroy",
@@ -197,18 +210,18 @@ gap_db_browser_dialog(char *title_txt,
   /* hpaned : left=list ; right=description */
 
   hpaned = gtk_hpaned_new ();
-  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dbbrowser->dialog)->vbox), 
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dbbrowser->dialog)->vbox),
                       hpaned, TRUE, TRUE, 0);
   gtk_widget_show (hpaned);
 
   /* left = vbox : the list and the search entry */
-  
+
   vbox = gtk_vbox_new (FALSE, 4);
   gtk_paned_pack1 (GTK_PANED (hpaned), vbox, FALSE, TRUE);
   gtk_widget_show (vbox);
 
   /* list : list in a scrolled_win */
-  
+
   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
                                        GTK_SHADOW_IN);
@@ -262,7 +275,7 @@ gap_db_browser_dialog(char *title_txt,
   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
   gtk_widget_set_size_request (scrolled_window, DBL_WIDTH - DBL_LIST_WIDTH, -1);
   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
-                                  GTK_POLICY_AUTOMATIC, 
+                                  GTK_POLICY_AUTOMATIC,
                                   GTK_POLICY_ALWAYS);
   gtk_paned_pack2 (GTK_PANED (hpaned), scrolled_window, TRUE, TRUE);
   gtk_widget_show (scrolled_window);
@@ -274,9 +287,6 @@ gap_db_browser_dialog(char *title_txt,
   gtk_widget_show (dbbrowser->descr_vbox);
 
 
-
-
-
   /* GAP specific buttons in dialog->action_aera */
   p_create_action_area_buttons(dbbrowser, button_1_txt, showAccelerationCharacteristic, help_id);
 
@@ -315,8 +325,9 @@ gap_db_browser_dialog(char *title_txt,
 
   if(gap_debug)
   {
-    printf("gap_db_browser_dialog: result accelCharacteristic:%d\n"
+    printf("gap_db_browser_dialog: result accelCharacteristic:%d groupFilterHandlingMode:%d\n"
        , (int)dbbrowser->result->accelCharacteristic
+       , (int)dbbrowser->result->groupFilterHandlingMode
        );
   }
 
@@ -324,6 +335,79 @@ gap_db_browser_dialog(char *title_txt,
 } /* end gap_db_browser_dialog */
 
 
+/* ---------------------------------------
+ * p_create_radio_group_handling_widgets
+ * ---------------------------------------
+ */
+static void
+p_create_radio_group_handling_widgets (dbbrowser_t *dbbrowser, gboolean showGroupHandling)
+{
+  GtkWidget *hbox1;
+  GtkWidget *label1;
+  GSList *grp_handling_group = NULL;
+  GtkWidget *radiobutton1;
+  GtkWidget *radiobutton2;
+  GtkWidget *radiobutton3;
+
+  hbox1 = gtk_hbox_new (FALSE, 0);
+
+  if(showGroupHandling)
+  {
+    gtk_widget_show (hbox1);
+  }
+  gtk_container_set_border_width (GTK_CONTAINER (hbox1), 4);
+
+
+  /* Layer Group handling mode the label */
+  label1 = gtk_label_new (_("Layer Group:"));
+
+  gtk_widget_show (label1);
+  gtk_box_pack_start (GTK_BOX (hbox1), label1, FALSE, FALSE, 0);
+  gtk_misc_set_alignment (GTK_MISC (label1), 0, 0.5);
+
+
+  /* GroupLayer handling mode the radio buttons */
+  radiobutton1 = gtk_radio_button_new_with_label (grp_handling_group, _("Process"));
+  grp_handling_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton1));
+  gtk_widget_show (radiobutton1);
+  gimp_help_set_help_data(radiobutton1
+       , _("group layers are processed the same way as normal layers."
+           " (this typically keeps the group structure, but the filter call will fail "
+           " for all filters that are not capable to process a group layer)")
+       , NULL);
+  gtk_box_pack_start (GTK_BOX (hbox1), radiobutton1, FALSE, FALSE, 0);
+
+  radiobutton2 = gtk_radio_button_new_with_label (grp_handling_group, _("Skip"));
+  grp_handling_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton2));
+  gtk_widget_show (radiobutton2);
+  gimp_help_set_help_data(radiobutton2
+       , _("skip processing of the selected filter for group layers.")
+       , NULL);
+  gtk_box_pack_start (GTK_BOX (hbox1), radiobutton2, FALSE, FALSE, 0);
+
+  radiobutton3 = gtk_radio_button_new_with_label (grp_handling_group, _("Merge"));
+  grp_handling_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radiobutton3));
+  gtk_widget_show (radiobutton3);
+  gimp_help_set_help_data(radiobutton3
+       , _("group layers are merged before the selected filter is applied.")
+       , NULL);
+  gtk_box_pack_start (GTK_BOX (hbox1), radiobutton3, FALSE, FALSE, 0);
+
+
+  dbbrowser->radio_grp_hbox     = hbox1;
+  dbbrowser->radio_grp_process  = radiobutton1;
+  dbbrowser->radio_grp_skip     = radiobutton2;
+  dbbrowser->radio_grp_merge    = radiobutton3;
+
+
+  /* signals */
+  g_signal_connect (G_OBJECT (dbbrowser->radio_grp_process),  "clicked",  G_CALLBACK (p_radio_callback), 
dbbrowser);
+  g_signal_connect (G_OBJECT (dbbrowser->radio_grp_skip),     "clicked",  G_CALLBACK (p_radio_callback), 
dbbrowser);
+  g_signal_connect (G_OBJECT (dbbrowser->radio_grp_merge),    "clicked",  G_CALLBACK (p_radio_callback), 
dbbrowser);
+
+}   /* end p_create_radio_group_handling_widgets */
+
+
 static void
 p_create_action_area_buttons(dbbrowser_t *dbbrowser,
                              char *button_1_txt,
@@ -335,8 +419,10 @@ p_create_action_area_buttons(dbbrowser_t *dbbrowser,
   GtkWidget       *button;
   gint             row;
   gint             cof;
-
+  gboolean         showGroupHandling;
   cof = 2;
+
+  showGroupHandling = showAccelerationCharacteristic;
   
   /* 5 cols, 3rows */
   table = gtk_table_new(1,1,TRUE);
@@ -346,8 +432,9 @@ p_create_action_area_buttons(dbbrowser_t *dbbrowser,
 
 
   row = 0;
+
   /* Button GenCode (conditional in DEBUG mode only for developers) */
-  if (gap_debug) 
+  if (gap_debug)
   {
     button = gtk_button_new_with_label ( _("Gen Code by name"));
     GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
@@ -362,13 +449,19 @@ p_create_action_area_buttons(dbbrowser_t *dbbrowser,
     row++;
   }
 
+  /* GAP specific radio buttons for group layer handling */
+  p_create_radio_group_handling_widgets (dbbrowser, showGroupHandling);
+  gtk_table_attach (GTK_TABLE (table), dbbrowser->radio_grp_hbox ,
+                    0, cof, row, row + 1,
+                    GTK_FILL, 0, 0, 0);
+
   /* Button Search by Name */
   dbbrowser->name_button = gtk_button_new_with_label ( _("Search by Name"));
   GTK_WIDGET_SET_FLAGS (dbbrowser->name_button, GTK_CAN_DEFAULT);
   g_signal_connect (G_OBJECT (dbbrowser->name_button), "clicked",
                       G_CALLBACK (dialog_search_callback), dbbrowser);
   gtk_table_attach (GTK_TABLE (table), dbbrowser->name_button,
-                    cof, cof+1, row, row + 1, 
+                    cof, cof+1, row, row + 1,
                     GTK_FILL, 0, 0, 0);
   gtk_widget_show(dbbrowser->name_button);
 
@@ -378,7 +471,7 @@ p_create_action_area_buttons(dbbrowser_t *dbbrowser,
   g_signal_connect (G_OBJECT (dbbrowser->blurb_button), "clicked",
                       G_CALLBACK (dialog_search_callback), dbbrowser);
   gtk_table_attach (GTK_TABLE (table), dbbrowser->blurb_button,
-                    cof+1, cof+2, row, row + 1, 
+                    cof+1, cof+2, row, row + 1,
                     GTK_FILL, 0, 0, 0);
   gtk_widget_show(dbbrowser->blurb_button);
 
@@ -388,7 +481,7 @@ p_create_action_area_buttons(dbbrowser_t *dbbrowser,
   g_signal_connect (G_OBJECT (dbbrowser->menupath_button), "clicked",
                       G_CALLBACK (dialog_search_callback), dbbrowser);
   gtk_table_attach (GTK_TABLE (table), dbbrowser->menupath_button,
-                    cof+2, cof+3, row, row + 1, 
+                    cof+2, cof+3, row, row + 1,
                     GTK_FILL, 0, 0, 0);
   gtk_widget_show(dbbrowser->menupath_button);
 
@@ -396,7 +489,7 @@ p_create_action_area_buttons(dbbrowser_t *dbbrowser,
   row++;
 
   /* the Acceleration characteristic value spinbutton and graph */
-  if (showAccelerationCharacteristic) 
+  if (showAccelerationCharacteristic)
   {
     GapAccelWidget  *accel_wgt;
     GtkObject       *adj;
@@ -421,7 +514,7 @@ p_create_action_area_buttons(dbbrowser_t *dbbrowser,
     accel_wgt = gap_accel_new(ACC_WGT_WIDTH, ACC_WGT_HEIGHT, accelerationCharacteristic);
     gtk_box_pack_start (GTK_BOX (dbbrowser->accel_hbox), accel_wgt->da_widget, FALSE, FALSE, 1);
     gtk_widget_show (accel_wgt->da_widget);
-  
+
     adj = accel_wgt->adj;
 
     /* the Acceleration characteristic value spinbutton */
@@ -430,7 +523,7 @@ p_create_action_area_buttons(dbbrowser_t *dbbrowser,
     dbbrowser->accel_spinbutton = spinbutton;
 
     gtk_widget_show (spinbutton);
-    
+
     gtk_box_pack_start (GTK_BOX (dbbrowser->accel_hbox), spinbutton, TRUE, TRUE, 1);
     gtk_widget_set_size_request (spinbutton, 50, -1);
     gimp_help_set_help_data (spinbutton, _("acceleration characteristic for filter apply 0=constant, 1 
varying with constant speed, positive accelerate, negative decelerate"), NULL);
@@ -443,16 +536,16 @@ p_create_action_area_buttons(dbbrowser_t *dbbrowser,
 
 
     dbbrowser->accel_wgt = accel_wgt;
-  } 
+  }
   else
-  { 
+  {
     dbbrowser->accel_adj = NULL;
     dbbrowser->accel_spinbutton = NULL;
-  
+
     dbbrowser->accel_hbox = gtk_hbox_new (FALSE, 1);
     gtk_widget_show (dbbrowser->accel_hbox);
     gtk_table_attach_defaults (GTK_TABLE(table), dbbrowser->accel_hbox, cof, cof+1, row, row + 1);
-  
+
   }
 
   /* Button1 (Apply Constant) */
@@ -462,7 +555,7 @@ p_create_action_area_buttons(dbbrowser_t *dbbrowser,
     g_signal_connect (G_OBJECT (dbbrowser->app_const_button), "clicked",
                         G_CALLBACK (dialog_button_1_callback), dbbrowser );
     gtk_table_attach (GTK_TABLE (table), dbbrowser->app_const_button,
-                      cof+1, cof+2, row, row + 1, 
+                      cof+1, cof+2, row, row + 1,
                       GTK_FILL, 0, 0, 0);
     gtk_widget_set_sensitive (dbbrowser->app_const_button, FALSE);
     gtk_widget_show (dbbrowser->app_const_button);
@@ -475,7 +568,7 @@ p_create_action_area_buttons(dbbrowser_t *dbbrowser,
   g_signal_connect (G_OBJECT (button), "clicked",
                       G_CALLBACK (dialog_close_callback), dbbrowser);
   gtk_table_attach (GTK_TABLE (table), button,
-                    cof+2, cof+3, row, row + 1, 
+                    cof+2, cof+3, row, row + 1,
                     GTK_FILL, 0, 0, 0);
   gtk_widget_show (button);
 
@@ -489,13 +582,13 @@ p_create_action_area_buttons(dbbrowser_t *dbbrowser,
     g_signal_connect (G_OBJECT (button), "clicked",
                         G_CALLBACK (dialog_help_callback), dbbrowser);
     gtk_table_attach (GTK_TABLE (table), button,
-                      0, 1, row, row + 1, 
+                      0, 1, row, row + 1,
                       GTK_FILL, 0, 0, 0);
   }
 
 
   gtk_widget_show (table);
-  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dbbrowser->dialog)->action_area), 
+  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dbbrowser->dialog)->action_area),
                         table, TRUE, TRUE, 0);
 }  /* end p_create_action_area_buttons */
 
@@ -526,8 +619,8 @@ procedure_select_callback (GtkTreeSelection *sel,
 }
 
 /* update the description box (right) */
-static void 
-dialog_select (dbbrowser_t *dbbrowser, 
+static void
+dialog_select (dbbrowser_t *dbbrowser,
                gchar       *proc_name)
 {
   GtkWidget   *old_description;
@@ -547,13 +640,13 @@ dialog_select (dbbrowser_t *dbbrowser,
   g_free (dbbrowser->selected_params);
   g_free (dbbrowser->selected_return_vals);
 
-  g_free (dbbrowser->selected_menu_path); 
+  g_free (dbbrowser->selected_menu_path);
   dbbrowser->selected_menu_path = gap_db_get_plugin_menupath(proc_name);
   if(dbbrowser->selected_menu_path == NULL)
     dbbrowser->selected_menu_path = g_strdup(_("** not available **"));
-    
 
-  gimp_procedural_db_proc_info (proc_name, 
+
+  gimp_procedural_db_proc_info (proc_name,
                                 &dbbrowser->selected_proc_blurb,
                                 &dbbrowser->selected_proc_help,
                                 &dbbrowser->selected_proc_author,
@@ -569,7 +662,7 @@ dialog_select (dbbrowser_t *dbbrowser,
   old_description = dbbrowser->description;
 
   /* render the new description */
-  dbbrowser->description = 
+  dbbrowser->description =
      gimp_proc_view_new (proc_name,
                 dbbrowser->selected_menu_path,
                 dbbrowser->selected_proc_blurb,
@@ -582,7 +675,7 @@ dialog_select (dbbrowser_t *dbbrowser,
                 dbbrowser->selected_nreturn_vals,
                 dbbrowser->selected_params,
                 dbbrowser->selected_return_vals);
-                    
+
 
 
   if (old_description)
@@ -592,32 +685,42 @@ dialog_select (dbbrowser_t *dbbrowser,
   gtk_box_pack_start (GTK_BOX (dbbrowser->descr_vbox),
                       dbbrowser->description, FALSE, FALSE, 0);
   gtk_widget_show (dbbrowser->description);
-  
 
-  /* call GAP constraint functions to check sensibility for the apply buttons */ 
+
+  /* call GAP constraint functions to check sensibility for the apply buttons */
   if(dbbrowser->app_const_button != NULL)
   {
      if(0 != (dbbrowser->constraint_func_sel1)(dbbrowser->selected_proc_name, dbbrowser->current_image_id))
-     { 
+     {
        gtk_widget_set_sensitive (dbbrowser->app_const_button, TRUE);
      }
-     else 
+     else
      {
        gtk_widget_set_sensitive (dbbrowser->app_const_button, FALSE);
      }
   }
-  if(dbbrowser->accel_spinbutton != NULL)
+  if((dbbrowser->accel_spinbutton != NULL) && (dbbrowser->accel_wgt != NULL))
   {
+  
      if(0 != (dbbrowser->constraint_func_sel2)(dbbrowser->selected_proc_name, dbbrowser->current_image_id))
-     { 
+     {
         gtk_widget_set_sensitive (dbbrowser->accel_spinbutton, TRUE);
+        if(dbbrowser->accel_wgt->da_widget != NULL)
+        {
+          gtk_widget_set_sensitive (dbbrowser->accel_wgt->da_widget, TRUE);
+        }
      }
      else
      {
         gtk_widget_set_sensitive (dbbrowser->accel_spinbutton, FALSE);
-     }
+        gtk_adjustment_set_value(GTK_ADJUSTMENT(dbbrowser->accel_adj), (gfloat)0.0);
+        if(dbbrowser->accel_wgt->da_widget != NULL)
+        {
+          gtk_widget_set_sensitive (dbbrowser->accel_wgt->da_widget, FALSE);
+        }
+    }
   }
-  
+
 }
 
 static void
@@ -646,7 +749,7 @@ dialog_show_message (dbbrowser_t *dbbrowser,
 
 /* the HELP dialog */
 static void
-dialog_help_callback (GtkWidget   *widget, 
+dialog_help_callback (GtkWidget   *widget,
                        dbbrowser_t *dbbrowser)
 {
   if(dbbrowser)
@@ -660,11 +763,11 @@ dialog_help_callback (GtkWidget   *widget,
 
 /* end of the dialog */
 static void
-dialog_close_callback (GtkWidget   *widget, 
+dialog_close_callback (GtkWidget   *widget,
                        dbbrowser_t *dbbrowser)
 {
   GtkWidget *dlg;
-  
+
   if(dbbrowser)
   {
     dlg = dbbrowser->dialog;
@@ -681,27 +784,55 @@ dialog_close_callback (GtkWidget   *widget,
   }
 }
 
+/* ---------------------------------------
+ * p_radio_callback
+ * ---------------------------------------
+ */
+static void
+p_radio_callback(GtkWidget *wgt, gpointer user_data)
+{
+  dbbrowser_t *dbbrowser;
+
+  if(gap_debug) printf("p_radio_callback: START\n");
+  dbbrowser = (dbbrowser_t *)user_data;
+  if(dbbrowser != NULL)
+  {
+    if(dbbrowser->result != NULL)
+    {
+       if(wgt == dbbrowser->radio_grp_process)  { dbbrowser->result->groupFilterHandlingMode = 
GAP_GROUP_FILTER_HANDLING_NORMAL; }
+       if(wgt == dbbrowser->radio_grp_skip)     { dbbrowser->result->groupFilterHandlingMode = 
GAP_GROUP_FILTER_HANDLING_SKIP; }
+       if(wgt == dbbrowser->radio_grp_merge)    { dbbrowser->result->groupFilterHandlingMode = 
GAP_GROUP_FILTER_HANDLING_MERGE; }
+
+       if(gap_debug)
+       {
+         printf("p:radio_callback: value: %d\n", (int)dbbrowser->result->groupFilterHandlingMode);
+       }
+    }
+  }
+}  /* end p_radio_callback */
+
+
 /* GAP dialog_num_button_callback (end of the dialog) */
-static void 
-dialog_num_button_callback (dbbrowser_t* dbbrowser, 
+static void
+dialog_num_button_callback (dbbrowser_t* dbbrowser,
                             gint button_nr)
 {
-  if (dbbrowser->selected_proc_name==NULL) 
+  if (dbbrowser->selected_proc_name==NULL)
   {
     return;
   }
 
   strcpy(dbbrowser->result->selected_proc_name, dbbrowser->selected_proc_name);
   dbbrowser->result->button_nr = button_nr;
-  
+
   gtk_widget_hide(dbbrowser->dialog);
   dialog_close_callback(NULL, dbbrowser);
-  
+
 }  /* end dialog_num_button_callback */
 
 
 /* GAP APPLY const callback */
-static void 
+static void
 dialog_button_1_callback (GtkWidget *widget, dbbrowser_t* dbbrowser)
 {
   dialog_num_button_callback(dbbrowser, 0);
@@ -709,7 +840,7 @@ dialog_button_1_callback (GtkWidget *widget, dbbrowser_t* dbbrowser)
 
 
 /* CODEGEN callback (does not close the dialog) */
-static void 
+static void
 dialog_button_3_callback (GtkWidget *widget, dbbrowser_t* dbbrowser)
 {
   gap_codegen_remove_codegen_files();      /* remove old versions of generated CODE */
@@ -744,8 +875,8 @@ p_accel_spinbutton_callback(GtkObject *obj, dbbrowser_t* dbbrowser)
 
 
 /* search in the whole db */
-static void 
-dialog_search_callback (GtkWidget   *widget, 
+static void
+dialog_search_callback (GtkWidget   *widget,
                         dbbrowser_t *dbbrowser)
 {
   gchar       **proc_list;
@@ -780,7 +911,7 @@ dialog_search_callback (GtkWidget   *widget,
         }
 
       gimp_procedural_db_query (query->str,
-                                ".*", ".*", ".*", ".*", ".*", ".*", 
+                                ".*", ".*", ".*", ".*", ".*", ".*",
                                 &num_procs, &proc_list);
 
       g_string_free (query, TRUE);
@@ -789,7 +920,7 @@ dialog_search_callback (GtkWidget   *widget,
     {
       dialog_show_message (dbbrowser, _("Searching by blurb - please wait"));
 
-      gimp_procedural_db_query (".*", 
+      gimp_procedural_db_query (".*",
                                 (gchar *) gtk_entry_get_text
                                   (GTK_ENTRY (dbbrowser->search_entry)),
                                 ".*", ".*", ".*", ".*", ".*",
@@ -806,7 +937,7 @@ dialog_search_callback (GtkWidget   *widget,
           dialog_show_message (dbbrowser, _("Searching - please wait"));
         }
 
-      gimp_procedural_db_query (".*", ".*", ".*", ".*", ".*", ".*", ".*", 
+      gimp_procedural_db_query (".*", ".*", ".*", ".*", ".*", ".*", ".*",
                                 &num_procs, &proc_list);
     }
 
@@ -815,7 +946,7 @@ dialog_search_callback (GtkWidget   *widget,
                            GTK_TREE_MODEL (dbbrowser->store));
   g_object_unref (dbbrowser->store);
 
- 
+
   pattern = NULL;
   query_text = gtk_entry_get_text (GTK_ENTRY (dbbrowser->search_entry));
   if (query_text && strlen (query_text))
@@ -825,12 +956,12 @@ dialog_search_callback (GtkWidget   *widget,
   for (i = 0; i < num_procs; i++)
     {
       gboolean pre_selection;
-      
+
       pre_selection = FALSE;
       if (widget == dbbrowser->menupath_button)
         {
           gchar *menu_path;
-          
+
           menu_path = gap_db_get_plugin_menupath(proc_list[i]);
           if(menu_path)
             {
@@ -854,12 +985,12 @@ dialog_search_callback (GtkWidget   *widget,
         }
         else
         {
-          /* for all other cases than menupath_button 
-           * the pre_selection was already done at gimp_procedural_db_query 
+          /* for all other cases than menupath_button
+           * the pre_selection was already done at gimp_procedural_db_query
            */
-          pre_selection = TRUE;  
+          pre_selection = TRUE;
         }
-        
+
       if (pre_selection)
         {
           /* the filter constraint_function checks if the
@@ -869,7 +1000,7 @@ dialog_search_callback (GtkWidget   *widget,
           if (0 != (dbbrowser->constraint_func)((char *)proc_list[i], dbbrowser->current_image_id))
             {
               i_added++;
-              
+
               if((dbbrowser->codegen_flag != 0) && (gap_debug))
                 {
                   gap_codegen_gen_forward_iter_ALT(proc_list[i]);
@@ -891,10 +1022,10 @@ dialog_search_callback (GtkWidget   *widget,
 
   g_free (proc_list);
 
-  /* now sort the store */ 
+  /* now sort the store */
   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (dbbrowser->store),
                                         0, GTK_SORT_ASCENDING);
-  
+
   if (i_added > 0)
     {
       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (dbbrowser->store), &iter);
@@ -908,7 +1039,7 @@ dialog_search_callback (GtkWidget   *widget,
 
 /* utils ... */
 
-static void 
+static void
 convert_string (gchar *str)
 {
   while (*str)
@@ -952,8 +1083,8 @@ convert_string (gchar *str)
 //     default:                   return "UNKNOWN?";
 //     }
 // }
-// 
-// 
+//
+//
 // static const gchar *
 // GimpPDBProcType_to_string (GimpPDBProcType type)
 // {
@@ -984,11 +1115,11 @@ gap_db_get_plugin_menupath (const gchar *search_text)
   gchar **types_strs;
   gchar **realname_strs;
   gint  *time_ints;
-  
+
   gchar *menu_path;
 
   menu_path = NULL;
- 
+
   if (!initialized)
     {
       /* query for all elements (only at 1.st call in this process)
@@ -1005,14 +1136,14 @@ gap_db_get_plugin_menupath (const gchar *search_text)
         {
           initialized = TRUE;
         }
-     
+
     }
 
   if (initialized)
     {
       int loop;
       int num_plugins;
-      
+
       num_plugins        = return_vals[1].data.d_int32;
       menu_strs          = return_vals[2].data.d_stringarray;
       accel_strs         = return_vals[4].data.d_stringarray;
diff --git a/gap/gap_dbbrowser_utils.h b/gap/gap_dbbrowser_utils.h
index 03c09bb..e85e68f 100644
--- a/gap/gap_dbbrowser_utils.h
+++ b/gap/gap_dbbrowser_utils.h
@@ -17,17 +17,17 @@
  */
 
 
-/* 
+/*
    gap_dbbrowser_utils.h (original code dbbrowser_utils.h by Thomas NOEL <thomas minet net>
-   
+
    09. dec .1998   hof: update for GIMP 1.1
    20. dec .1997   hof: GAP variant of DBbrowser
                         removed apply_callback
-                        added constraint_procedure, 
+                        added constraint_procedure,
                         added 2 buttons
                         added return type
 
-   0.08  26th sept 97  by Thomas NOEL <thomas minet net> 
+   0.08  26th sept 97  by Thomas NOEL <thomas minet net>
 */
 
 #ifndef _GAP_DB_BROWSER_UTILS_H
@@ -35,10 +35,16 @@
 
 #include "libgimp/gimp.h"
 
+#define GAP_GROUP_FILTER_HANDLING_NORMAL  0
+#define GAP_GROUP_FILTER_HANDLING_SKIP    1
+#define GAP_GROUP_FILTER_HANDLING_MERGE   2
+
+
 typedef struct {
    char   selected_proc_name[256];
    int    button_nr;               /* -1 on cancel, 0 .. n */
    gint32 accelCharacteristic;
+   gint32 groupFilterHandlingMode;
 } GapDbBrowserResult;
 
 /* proc to check if to add or not to add the procedure to the browsers listbox
diff --git a/gap/gap_edge_detection.c b/gap/gap_edge_detection.c
index 7695acc..cc6994f 100644
--- a/gap/gap_edge_detection.c
+++ b/gap/gap_edge_detection.c
@@ -119,7 +119,7 @@ p_get_debug_coords_from_guides(gint32 image_id, gint *cx, gint *cy)
   *cx = guideCol;
   *cy = guideRow;
 
-  //if(gap_debug)
+  if(gap_debug)
   {
     printf("image_id:%d  guideCol:%d :%d\n"
        ,(int)image_id
diff --git a/gap/gap_fg_matting_dialog.c b/gap/gap_fg_matting_dialog.c
index 7c5c830..3f5992b 100644
--- a/gap/gap_fg_matting_dialog.c
+++ b/gap/gap_fg_matting_dialog.c
@@ -123,7 +123,7 @@ p_init_widget_values(FgExtractDialogGuiStuff *guiStuffPtr)
   {
       comboInitalValue = GAP_FG_USE_LAYER_MASK;
   }
-  else if(gimp_drawable_is_valid(guiStuffPtr->vals->tri_map_drawable_id))
+  else if(gimp_item_is_valid(guiStuffPtr->vals->tri_map_drawable_id))
   {
       comboInitalValue = guiStuffPtr->vals->tri_map_drawable_id;
   }
@@ -282,11 +282,11 @@ p_tri_map_combo_constrain(gint32 image_id, gint32 drawable_id, FgExtractDialogGu
      return(TRUE);
   }
 
-  if(gimp_drawable_is_valid(drawable_id) != TRUE)
+  if(gimp_item_is_valid(drawable_id) != TRUE)
   {
      if(gap_debug)
      {
-       printf("-- drawable_id:%d gimp_drawable_is_valid --\n", (int)drawable_id); 
+       printf("-- drawable_id:%d gimp_item_is_valid --\n", (int)drawable_id); 
      }
      return(FALSE);
   }
@@ -455,7 +455,7 @@ do_dialog (FgExtractDialogGuiStuff *guiStuffPtr, GapFgExtractValues *cuvals)
     gint   comboInitalValue;
 
     comboInitalValue = -1; 
-    if(gimp_drawable_is_valid(guiStuffPtr->vals->tri_map_drawable_id))
+    if(gimp_item_is_valid(guiStuffPtr->vals->tri_map_drawable_id))
     {
       comboInitalValue = guiStuffPtr->vals->tri_map_drawable_id;
     }  
diff --git a/gap/gap_filter_foreach.c b/gap/gap_filter_foreach.c
index 0034489..6a07968 100644
--- a/gap/gap_filter_foreach.c
+++ b/gap/gap_filter_foreach.c
@@ -71,10 +71,14 @@
 #include "gap_filter_pdb.h"
 #include "gap_dbbrowser_utils.h"
 #include "gap_lib.h"
+#include "gap_base.h"
+#include "gap_image.h"
 #include "gap_accel_char.h"
 
 #define GAP_DB_BROWSER_FILTERALL_HELP_ID  "gap-filterall-db-browser"
 
+#define GAP_FILTERALL_LAYERS_ENABLE_PITSTOP_DIALOG  "gap-filterall-enable-pitstop-dialog"
+
 /* ------------------------
  * global gap DEBUG switch
  * ------------------------
@@ -93,10 +97,14 @@ static gint p_pitstop(GimpRunMode run_mode, char *plugin_name, gint text_flag,
 
 static void p_visibilty_restore(gint32 image_id, gint nlayers, int *visible_tab, char *plugin_name);
 static gint32 p_get_indexed_layerid(gint32 image_id, gint *nlayers, gint32 idx, char *plugin_name);
+
+static gint   p_call_pdb_filter_plugin(char *canonical_plugin_name, gint32 image_id, gint32 layer_id, 
GimpRunMode run_mode
+                   , gint32 groupFilterHandlingMode);
+
 static int p_foreach_multilayer(GimpRunMode run_mode, gint32 image_id,
-                         const char *plugin_name, gint32 accelCharacteristic);
+                         const char *plugin_name, gint32 accelCharacteristic, gint32 
groupFilterHandlingMode);
 static int p_foreach_multilayer2(GimpRunMode run_mode, gint32 image_id,
-                         char *canonical_plugin_name, gint32 accelCharacteristic);
+                         char *canonical_plugin_name, gint32 accelCharacteristic, gint32 
groupFilterHandlingMode);
 
 /* ------------------------
  * p_gdisplays_update_full
@@ -118,24 +126,35 @@ p_pitstop(GimpRunMode run_mode, char *plugin_name, gint text_flag,
                       char *step_backup_file, gint len_step_backup_file,
                       gint32 layer_idx)
 {
-  const gchar      *l_env;
   gchar            *l_msg;
   static GapArrButtonArg  l_but_argv[3];
   gint              l_but_argc;
   gint              l_argc;
-  static GapArrArg  l_argv[1];
+  static GapArrArg  l_argv[2];
   int               l_continue;
   char              l_skip_txt[32];
-
-
-
-    gap_arr_arg_init(&l_argv[0], GAP_ARR_WGT_FILESEL);
-    l_argv[0].label_txt = _("Backup to file");
-    l_argv[0].entry_width = 140;        /* pixel */
-    l_argv[0].help_txt  = _("Make backup of the image after each step");
-    l_argv[0].text_buf_len = len_step_backup_file;
-    l_argv[0].text_buf_ret = step_backup_file;
-
+  int               l_ii;
+  int               l_ii_gimprc;
+
+
+  l_ii = 0;
+  l_ii_gimprc = l_ii;
+  gap_arr_arg_init(&l_argv[l_ii], GAP_ARR_WGT_TOGGLE);
+    l_argv[l_ii].label_txt = _("do not show this dialog again");
+    l_argv[l_ii].help_txt  = g_strdup_printf(_("add %s to gimprc configuration to disable this dialog in all 
further sessions")
+                                             ,GAP_FILTERALL_LAYERS_ENABLE_PITSTOP_DIALOG );
+    l_argv[l_ii].int_ret = FALSE;
+    l_argv[l_ii].int_default = FALSE;
+    l_argv[l_ii].has_default = TRUE;
+
+  l_ii = 1;
+  gap_arr_arg_init(&l_argv[l_ii], GAP_ARR_WGT_FILESEL);
+    l_argv[l_ii].label_txt = _("Backup to file");
+    l_argv[l_ii].entry_width = 140;        /* pixel */
+    l_argv[l_ii].help_txt  = _("Make backup of the image after each step");
+    l_argv[l_ii].text_buf_len = len_step_backup_file;
+    l_argv[l_ii].text_buf_ret = step_backup_file;
+  
     l_but_argv[0].but_txt  = _("Continue");
     l_but_argv[0].but_val  = 0;
     l_but_argv[1].but_txt  = GTK_STOCK_CANCEL;
@@ -145,18 +164,15 @@ p_pitstop(GimpRunMode run_mode, char *plugin_name, gint text_flag,
     l_but_argv[2].but_val  = 1;
 
    l_but_argc = 2;
-   l_argc = 0;
+   l_argc = 1;
    /* optional dialog between both calls (to see the effect of 1.call) */
    if(run_mode == GIMP_RUN_INTERACTIVE)
    {
-      l_env = g_getenv("GAP_FILTER_PITSTOP");
-      if(l_env != NULL)
+      if(!gap_base_get_gimprc_gboolean_value(GAP_FILTERALL_LAYERS_ENABLE_PITSTOP_DIALOG, TRUE))
       {
-         if((*l_env == 'N') || (*l_env == 'n'))
-         {
-           return 0;  /* continue without question */
-         }
+         return 0;  /* continue without question */
       }
+
       if(text_flag == 0)
       {
          l_msg = g_strdup_printf (_("2nd call of %s\n(define end-settings)"), plugin_name);
@@ -165,12 +181,17 @@ p_pitstop(GimpRunMode run_mode, char *plugin_name, gint text_flag,
       {
          l_msg = g_strdup_printf (_("Non-Interactive call of %s\n(for all layers in between)"), plugin_name);
          l_but_argc = 3;
-         l_argc = 1;
+         l_argc = 2;
       }
       l_continue = gap_arr_std_dialog (_("Animated Filter Apply"), l_msg,
                                        l_argc,     l_argv,
                                        l_but_argc, l_but_argv, 0);
       g_free (l_msg);
+      
+      if ((l_argv[l_ii_gimprc].int_ret != FALSE) && (l_continue ==0))
+      {
+        gimp_gimprc_set(GAP_FILTERALL_LAYERS_ENABLE_PITSTOP_DIALOG, "no");
+      }
 
       if(l_continue < 0) return -1;
       else               return l_continue;
@@ -193,23 +214,29 @@ p_visibilty_restore(gint32 image_id, gint nlayers, int *visible_tab, char *plugi
   gint       l_nlayers2;
   gint32     l_idx;
 
-      l_layers_list = gimp_image_get_layers(image_id, &l_nlayers2);
-      if(l_nlayers2 == nlayers)
-      {
-        for(l_idx = 0; l_idx < nlayers; l_idx++)
-        {
-          gimp_item_set_visible(l_layers_list[l_idx], visible_tab[l_idx]);
-          if(gap_debug) printf("visibilty restore [%d] %d\n", (int)l_idx, (int)visible_tab[l_idx]);
-        }
-        p_gdisplays_update_full(image_id);
-      }
-      else
+  l_layers_list = gimp_image_get_layers(image_id, &l_nlayers2);
+  if(l_nlayers2 == nlayers)
+  {
+    for(l_idx = 0; l_idx < nlayers; l_idx++)
+    {
+      gimp_item_set_visible(l_layers_list[l_idx], visible_tab[l_idx]);
+      if(gap_debug)
       {
-        printf ("Error: Plugin %s has changed Nr. of layers from %d to %d\ncould not restore Layer 
visibilty.\n",
-                plugin_name, (int)nlayers, (int)l_nlayers2);
+        printf("visibilty restore [%d] %d\n"
+           , (int)l_idx
+           , (int)visible_tab[l_idx]
+           );
       }
+    }
+    p_gdisplays_update_full(image_id);
+  }
+  else
+  {
+    g_message(_("Error: Plugin %s has changed the number of layers from %d to %d\ncould not restore Layer 
visibilty.\n"),
+            plugin_name, (int)nlayers, (int)l_nlayers2);
+  }
 
-      g_free (l_layers_list);
+  g_free (l_layers_list);
 }
 
 /* ------------------------
@@ -242,6 +269,76 @@ p_get_indexed_layerid(gint32 image_id, gint *nlayers, gint32 idx, char *plugin_n
   return (l_layer_id);
 }
 
+/* ---------------------------------------
+ * p_call_pdb_filter_plugin
+ * ---------------------------------------
+ * apply the given filter (canonical_plugin_name) on the specified layer_id
+ * In case the specified layer_id is a group layer
+ * the groupFilterHandlingMode
+ */
+static gint
+p_call_pdb_filter_plugin(char *canonical_plugin_name, gint32 image_id, gint32 layer_id, GimpRunMode run_mode
+   , gint32 groupFilterHandlingMode)
+{
+  gint32 l_resulting_item_id;
+
+  if(gap_debug)
+  {
+    printf("p_call_pdb_filter_plugin: %s  image_id:%d layer_id:%d (%s), run_mode:%d, 
groupFilterHandlingMode:%d\n"
+       , canonical_plugin_name
+       , (int)image_id
+       , (int)layer_id
+       , gimp_item_get_name(layer_id)
+       , (int)run_mode
+       , (int)groupFilterHandlingMode
+       );
+  }
+
+  l_resulting_item_id = layer_id;
+  if (gimp_item_is_group(layer_id))
+  {
+    if(groupFilterHandlingMode == GAP_GROUP_FILTER_HANDLING_SKIP)
+    {
+      if (run_mode == GIMP_RUN_INTERACTIVE)
+      {
+        /* fail because skipping of the interactive calls
+         * is not allowed (those calls are required to setup the last values buffer)
+         */
+        return (-1);
+      }
+      return (0);    /* fake OK to skip processing of this group layer */
+    }
+    
+    if(groupFilterHandlingMode == GAP_GROUP_FILTER_HANDLING_MERGE)
+    {
+      l_resulting_item_id = gap_image_merge_group_layer( image_id
+                                                       , layer_id
+                                                       , GIMP_EXPAND_AS_NECESSARY
+                                                       );
+    }
+  }
+  if (l_resulting_item_id < 0)
+  {
+    return (-1);
+  }
+  
+  if(gap_debug)
+  {
+    printf("p_call_pdb_filter_plugin: %s  image_id:%d l_resulting_item_id:%d (%s), run_mode:%d, 
groupFilterHandlingMode:%d\n"
+       , canonical_plugin_name
+       , (int)image_id
+       , (int)l_resulting_item_id
+       , gimp_item_get_name(l_resulting_item_id)
+       , (int)run_mode
+       , (int)groupFilterHandlingMode
+       );
+  }
+  return (gap_filt_pdb_call_plugin(canonical_plugin_name, image_id, l_resulting_item_id, run_mode));
+
+
+}  /* end p_call_pdb_filter_plugin */
+
+
 /* ----------------------
  * p_foreach_multilayer
  * ----------------------
@@ -251,31 +348,33 @@ p_get_indexed_layerid(gint32 image_id, gint *nlayers, gint32 idx, char *plugin_n
  */
 static int
 p_foreach_multilayer(GimpRunMode run_mode, gint32 image_id,
-                     const char *plugin_name, gint32 accelCharacteristic)
+                     const char *plugin_name, gint32 accelCharacteristic, gint32 groupFilterHandlingMode)
 {
   char *canonical_plugin_name;
   int rc;
-  
+
   canonical_plugin_name = gimp_canonicalize_identifier(plugin_name);
-  rc = p_foreach_multilayer2(run_mode, image_id, canonical_plugin_name, accelCharacteristic);
-  
+  gimp_image_undo_group_start (image_id);
+  rc = p_foreach_multilayer2(run_mode, image_id, canonical_plugin_name, accelCharacteristic, 
groupFilterHandlingMode);
+  gimp_image_undo_group_end (image_id);
+
   g_free(canonical_plugin_name);
 
   return (rc);
-  
+
 }  /* ennd p_foreach_multilayer */
 
 
 /* ----------------------
  * p_foreach_multilayer2
  * ----------------------
- *    apply the given plugin to each layer of the  image.
+ *    apply the given plugin to each toplevel layer of the  image.
  * returns   image_id of the new created multilayer image
  *           (or -1 on error)
  */
 static int
 p_foreach_multilayer2(GimpRunMode run_mode, gint32 image_id,
-                         char *canonical_plugin_name, gint32 accelCharacteristic)
+                         char *canonical_plugin_name, gint32 accelCharacteristic, gint32 
groupFilterHandlingMode)
 {
   static char l_key_from[512];
   static char l_key_to[512];
@@ -287,8 +386,6 @@ p_foreach_multilayer2(GimpRunMode run_mode, gint32 image_id,
   gdouble    l_percentage, l_percentage_step;
   int         l_rc;
   gint        l_plugin_data_len;
-  long        l_child_pid;
-  /* int         l_status; */
   int         *l_visible_tab;
   char         l_step_backup_file[120];
   gint         l_pit_rc;
@@ -331,7 +428,9 @@ p_foreach_multilayer2(GimpRunMode run_mode, gint32 image_id,
       /* allocate a table to store the visibility attributes for each layer */
       l_visible_tab = (gint*) g_malloc((l_nlayers +1) * sizeof (gint));
       if(l_visible_tab == NULL)
+      {
          return -1;
+      }
 
       /* save the visibility of all layers */
       for(l_idx = 0; l_idx < l_nlayers; l_idx++)
@@ -350,54 +449,52 @@ p_foreach_multilayer2(GimpRunMode run_mode, gint32 image_id,
 
       if((l_plugin_iterator != NULL)  && (l_nlayers > 1) && (accelCharacteristic != GAP_ACCEL_CHAR_NONE ))
       {
-        l_child_pid = 0; /* fork(); */
-        if(l_child_pid < 0)
+        /* call plugin Interactive for background layer[n] */
+        if(gap_debug)
         {
-           printf("ERROR: fork failed !\n");
-           return -1;
+          printf("DEBUG start 1.st Interactive call (_FROM values)\n");
         }
 
-        /* if(l_child_pid != 0) */
+        l_idx = l_nlayers -1;
+        l_layer_id = p_get_indexed_layerid(image_id, &l_nlayers, l_idx,  canonical_plugin_name);
+        if(l_layer_id < 0)
+        {
+          l_rc = -1;
+        }
+        else
         {
-          /* parent process: call plugin Interactive for background layer[n] */
-          /* if(gap_debug) printf("forked child process pid=%ld\n", l_child_pid); */
           if(gap_debug)
           {
-            printf("DEBUG start 1.st Interactive call (_FROM values)\n");
-          }
-
-          l_idx = l_nlayers -1;
-          l_layer_id = p_get_indexed_layerid(image_id, &l_nlayers, l_idx,  canonical_plugin_name);
-          if(l_layer_id < 0)
+            printf("DEBUG: applying %s on Layerstack %d id=%d\n", canonical_plugin_name, (int)l_idx, 
(int)l_layer_id);
+                  }
+          l_rc = p_call_pdb_filter_plugin(canonical_plugin_name, image_id, l_layer_id
+                     , GIMP_RUN_INTERACTIVE, groupFilterHandlingMode);
+
+          /* get values, then store with suffix "-ITER-FROM" */
+          l_plugin_data_len = gap_filt_pdb_get_data(canonical_plugin_name);
+          if(l_plugin_data_len > 0)
           {
-            l_rc = -1;
+             g_snprintf(l_key_from, sizeof(l_key_from), "%s%s", canonical_plugin_name, GAP_ITER_FROM_SUFFIX);
+             gap_filt_pdb_set_data(l_key_from, l_plugin_data_len);
           }
           else
           {
-            if(gap_debug) printf("DEBUG: apllying %s on Layerstack %d id=%d\n", canonical_plugin_name, 
(int)l_idx, (int)l_layer_id);
-            l_rc = gap_filt_pdb_call_plugin(canonical_plugin_name, image_id, l_layer_id, 
GIMP_RUN_INTERACTIVE);
-
-            /* get values, then store with suffix "-ITER-FROM" */
-            l_plugin_data_len = gap_filt_pdb_get_data(canonical_plugin_name);
-            if(l_plugin_data_len > 0)
-            {
-               g_snprintf(l_key_from, sizeof(l_key_from), "%s%s", canonical_plugin_name, 
GAP_ITER_FROM_SUFFIX);
-               gap_filt_pdb_set_data(l_key_from, l_plugin_data_len);
-            }
-            else l_rc = -1;
+            l_rc = -1;
+          }
 
-            if(run_mode == GIMP_RUN_INTERACTIVE)
-            {
-              l_percentage += l_percentage_step;
-              gimp_progress_update (l_percentage);
-            }
+          if(run_mode == GIMP_RUN_INTERACTIVE)
+          {
+            l_percentage += l_percentage_step;
+            gimp_progress_update (l_percentage);
           }
         }
-        /* else */
+
         if((l_rc >= 0) && (l_nlayers > 1))
         {
-          /* child process: call plugin Interactive for top layer [0] */
-          if(gap_debug) printf("DEBUG start 2.nd Interactive call (_TO values)\n");
+          if(gap_debug)
+          {
+            printf("DEBUG start 2.nd Interactive call (_TO values)\n");
+          }
 
           /* optional dialog between both calls (to see the effect of 1.call) */
           if(p_pitstop(run_mode, canonical_plugin_name, 0,
@@ -425,7 +522,8 @@ p_foreach_multilayer2(GimpRunMode run_mode, gint32 image_id,
                 p_gdisplays_update_full(image_id);
 
                 if(gap_debug) printf("DEBUG: apllying %s on Layerstack 0  id=%d\n", canonical_plugin_name, 
(int)l_layer_id);
-                l_rc = gap_filt_pdb_call_plugin(canonical_plugin_name, image_id, l_layer_id, 
GIMP_RUN_INTERACTIVE);
+                l_rc = p_call_pdb_filter_plugin(canonical_plugin_name, image_id, l_layer_id
+                           , GIMP_RUN_INTERACTIVE, groupFilterHandlingMode);
 
                 /* get values, then store with suffix "-ITER-TO" */
                 l_plugin_data_len = gap_filt_pdb_get_data(canonical_plugin_name);
@@ -434,7 +532,10 @@ p_foreach_multilayer2(GimpRunMode run_mode, gint32 image_id,
                    g_snprintf(l_key_to, sizeof(l_key_to), "%s%s", canonical_plugin_name, GAP_ITER_TO_SUFFIX);
                    gap_filt_pdb_set_data(l_key_to, l_plugin_data_len);
                 }
-                else l_rc = -1;
+                else
+                {
+                  l_rc = -1;
+                }
 
                 if(run_mode == GIMP_RUN_INTERACTIVE)
                 {
@@ -450,9 +551,6 @@ p_foreach_multilayer2(GimpRunMode run_mode, gint32 image_id,
 
         }
         l_top_layer = 1;
-
-        /* wait until exit of childprocess */
-        /* waitpid(l_child_pid, &l_status, 0); */
       }
       else
       {
@@ -468,7 +566,8 @@ p_foreach_multilayer2(GimpRunMode run_mode, gint32 image_id,
           else
           {
             if(gap_debug) printf("DEBUG: NO Varying, applying %s on Layer id=%d\n", canonical_plugin_name, 
(int)l_layer_id);
-            l_rc = gap_filt_pdb_call_plugin(canonical_plugin_name, image_id, l_layer_id, 
GIMP_RUN_INTERACTIVE);
+            l_rc = p_call_pdb_filter_plugin(canonical_plugin_name, image_id, l_layer_id
+                        , GIMP_RUN_INTERACTIVE, groupFilterHandlingMode);
             l_top_layer = 0;
             if(run_mode == GIMP_RUN_INTERACTIVE)
             {
@@ -514,7 +613,7 @@ p_foreach_multilayer2(GimpRunMode run_mode, gint32 image_id,
                 , canonical_plugin_name
                 , (int)l_idx
                 , (int)l_layer_id
-                , (int)l_nlayers -1 
+                , (int)l_nlayers -1
                 , (int)l_idx
                 );
           }
@@ -523,8 +622,8 @@ p_foreach_multilayer2(GimpRunMode run_mode, gint32 image_id,
           if((l_plugin_iterator != NULL) && (accelCharacteristic != GAP_ACCEL_CHAR_NONE ))
           {
             gdouble accelStep;
-       
-       
+
+
             accelStep = gap_calculate_current_step_with_acceleration((gdouble)l_idx, l_nlayers -1, 
accelCharacteristic);
             /* call plugin-specific iterator (or the common iterator), to modify
              * the plugin's last_values
@@ -540,12 +639,16 @@ p_foreach_multilayer2(GimpRunMode run_mode, gint32 image_id,
             }
           }
 
-          if(l_rc < 0) break;
+          if(l_rc < 0)
+          {
+            break;
+          }
 
           if(l_pit_rc == 0)  /* 0 == continue without further dialogs */
           {
              /* call the plugin itself with runmode RUN_WITH_LAST_VALUES */
-             l_rc = gap_filt_pdb_call_plugin(canonical_plugin_name, image_id, l_layer_id, 
GIMP_RUN_WITH_LAST_VALS);
+             l_rc = p_call_pdb_filter_plugin(canonical_plugin_name, image_id, l_layer_id
+                       , GIMP_RUN_WITH_LAST_VALS, groupFilterHandlingMode);
              /* check if to save each step to backup file */
              if((l_step_backup_file[0] != '\0') && (l_step_backup_file[0] != ' '))
              {
@@ -589,7 +692,9 @@ gap_proc_anim_apply(GimpRunMode run_mode, gint32 image_id, char *plugin_name
   , gint32 accelCharacteristic)
 {
   GapDbBrowserResult  l_browser_result;
+  gint                l_rc;
   l_browser_result.accelCharacteristic = GAP_ACCEL_CHAR_LINEAR;
+  l_browser_result.groupFilterHandlingMode = GAP_GROUP_FILTER_HANDLING_NORMAL;
 
   if(run_mode == GIMP_RUN_INTERACTIVE)
   {
@@ -610,13 +715,13 @@ gap_proc_anim_apply(GimpRunMode run_mode, gint32 image_id, char *plugin_name
     }
 
     strcpy(plugin_name, l_browser_result.selected_proc_name);
-    
+
     /* invert acceleration to deceleration and vice versa
-     * (because processing layer indexes is done from high to low values) 
+     * (because processing layer indexes is done from high to low values)
      */
     accelCharacteristic = (-1 * l_browser_result.accelCharacteristic);
 
-    if(gap_debug) 
+    if(gap_debug)
     {
       printf("DEBUG: gap_db_browser_dialog SELECTED:%s accelCharacteristic:%d\n"
            , plugin_name
@@ -626,9 +731,10 @@ gap_proc_anim_apply(GimpRunMode run_mode, gint32 image_id, char *plugin_name
 
   }
 
-  return(p_foreach_multilayer(run_mode,
+  l_rc = p_foreach_multilayer(run_mode,
                               image_id,
                               plugin_name,
-                              accelCharacteristic ));
-
+                              accelCharacteristic,
+                              l_browser_result.groupFilterHandlingMode);
+  return(l_rc);
 }
diff --git a/gap/gap_filter_iterators.c b/gap/gap_filter_iterators.c
index 882e0c0..1af857e 100644
--- a/gap/gap_filter_iterators.c
+++ b/gap/gap_filter_iterators.c
@@ -98,6 +98,7 @@
 #include "gap_frame_fetcher.h"
 #include "gap_drawable_vref_parasite.h"
 #include "gap_lib.h"
+#include "gap_image.h"
 #include "gap/gap_layer_copy.h"
 
 
@@ -447,6 +448,7 @@ p_delta_drawable_simple(gint32 *val, gint32 val_from, gint32 val_to, gint32 tota
   gint    l_nlayers;
   gint32 *l_layers_list;
   gint32  l_tmp_image_id;
+  gint32  l_parent_id;
   gint    l_idx, l_idx_from, l_idx_to;
 
   if(gap_debug)
@@ -461,25 +463,36 @@ p_delta_drawable_simple(gint32 *val, gint32 val_from, gint32 val_to, gint32 tota
   {
     return;
   }
-  if(gimp_drawable_is_valid(val_from) != TRUE)
+  if(gimp_item_is_valid(val_from) != TRUE)
   {
     return;
   }
-  if(gimp_drawable_is_valid(val_to) != TRUE)
+  if(gimp_item_is_valid(val_to) != TRUE)
   {
     return;
   }
   l_tmp_image_id = gimp_item_get_image(val_from);
+  l_parent_id = gimp_item_get_parent(val_from);
 
-  /* check if from and to values are both valid drawables within the same image */
+  /* check if from and to values are both valid drawables 
+   * within the same image at same level
+   */
   if ((l_tmp_image_id > 0)
-  &&  (l_tmp_image_id = gimp_item_get_image(val_to)))
+  &&  (l_tmp_image_id == gimp_item_get_image(val_to))
+  &&  (l_parent_id == gimp_item_get_parent(val_to)))
   {
      l_idx_from = -1;
      l_idx_to   = -1;
 
      /* check the layerstack index of from and to drawable */
-     l_layers_list = gimp_image_get_layers(l_tmp_image_id, &l_nlayers);
+     if (l_parent_id > 0)
+     {
+       l_layers_list = gimp_item_get_children(l_parent_id, &l_nlayers);
+     }
+     else
+     {
+       l_layers_list = gimp_image_get_layers(l_tmp_image_id, &l_nlayers);
+     }
      for (l_idx = l_nlayers -1; l_idx >= 0; l_idx--)
      {
         if( l_layers_list[l_idx] == val_from ) l_idx_from = l_idx;
@@ -498,6 +511,7 @@ p_delta_drawable_simple(gint32 *val, gint32 val_from, gint32 val_to, gint32 tota
 }  /* end p_delta_drawable_simple */
 
 
+
 /* --------------------------------------------
  * p_capture_image_name_and_assign_pesistent_id
  * --------------------------------------------
@@ -525,6 +539,7 @@ p_capture_image_name_and_assign_pesistent_id(GapFmacContext *fmacContext, gint32
   gint32 stackposition;
   gint32 track;
   char   *filename;
+  char   *parentpositions;
   
   
   if(gap_debug)
@@ -534,7 +549,7 @@ p_capture_image_name_and_assign_pesistent_id(GapFmacContext *fmacContext, gint32
       );
   }
 
-  if(gimp_drawable_is_valid(drawable_id) != TRUE)
+  if(gimp_item_is_valid(drawable_id) != TRUE)
   {
     /* drawable is no longer valid and can not be mapped.
      * This may happen if the layer was removed or the refered image was closed
@@ -546,6 +561,7 @@ p_capture_image_name_and_assign_pesistent_id(GapFmacContext *fmacContext, gint32
   
   persistent_drawable_id = drawable_id;
   filename = NULL;
+  parentpositions = NULL;
   
   dvref = gap_dvref_get_drawable_video_reference_via_parasite(drawable_id);
   if (dvref != NULL)
@@ -570,6 +586,7 @@ p_capture_image_name_and_assign_pesistent_id(GapFmacContext *fmacContext, gint32
     
     image_id = gimp_item_get_image(drawable_id);
     filename = gimp_image_get_filename(image_id);
+    parentpositions = gap_image_get_parentpositions_as_int_stringlist(drawable_id);
     ainfo_type = GAP_AINFO_ANIMIMAGE;
     stackposition = gap_layer_get_stackposition(image_id, drawable_id);
     track = 1;
@@ -616,6 +633,7 @@ p_capture_image_name_and_assign_pesistent_id(GapFmacContext *fmacContext, gint32
     persistent_drawable_id = gap_fmct_add_GapFmacRefEntry(ainfo_type
                                  , frame_nr
                                  , stackposition
+                                 , parentpositions
                                  , track
                                  , drawable_id
                                  , filename
@@ -625,6 +643,10 @@ p_capture_image_name_and_assign_pesistent_id(GapFmacContext *fmacContext, gint32
     g_free(filename);
   }
 
+  if(parentpositions != NULL)
+  {
+    g_free(parentpositions);
+  }
 
   if(gap_debug)
   {
@@ -638,6 +660,8 @@ p_capture_image_name_and_assign_pesistent_id(GapFmacContext *fmacContext, gint32
 }  /* end p_capture_image_name_and_assign_pesistent_id */
 
 
+
+
 /* -------------------------------------
  * p_iteration_by_pesistent_id
  * -------------------------------------
@@ -704,16 +728,26 @@ p_iteration_by_pesistent_id(GapFmacContext *fmacContext
         
         if (fmref_entry_from->ainfo_type == GAP_AINFO_ANIMIMAGE)
         {
-          /* iterate stackposition */
+          /* iterate stackposition (restriction: this is only possible when from and to value are at same 
level) */
           gint32 stackposition;
+          gboolean isSameLevel;
+          
+          isSameLevel = FALSE;
+          if(strcmp(fmref_entry_from->parentpositions, fmref_entry_to->parentpositions) == 0)
+          {
+            isSameLevel = TRUE;
+          }
           
           stackposition = fmref_entry_from->stackposition;
-          p_delta_gint32(&stackposition, fmref_entry_from->stackposition, fmref_entry_to->stackposition
+          if (isSameLevel)
+          {
+            p_delta_gint32(&stackposition, fmref_entry_from->stackposition, fmref_entry_to->stackposition
                         ,total_steps, current_step);
-                        
+          }
           fetched_layer_id = gap_frame_fetch_dup_image(fmacContext->ffetch_user_id
                                     ,fmref_entry_from->filename   /* full filename of the image */
                                     ,stackposition                /* pick layer by stackposition */
+                                    ,fmref_entry_from->parentpositions
                                     ,TRUE                         /* enable caching */
                                     );
         }
@@ -740,6 +774,7 @@ p_iteration_by_pesistent_id(GapFmacContext *fmacContext
             fetched_layer_id = gap_frame_fetch_dup_image(fmacContext->ffetch_user_id
                                     ,fmref_entry_from->filename   /* full filename of the image */
                                     ,-1                           /* 0 pick layer on top of stack, -1 merge 
visible layers */
+                                    ,NULL
                                     ,TRUE                         /* enable caching */
                                     );
           }
@@ -772,6 +807,7 @@ p_iteration_by_pesistent_id(GapFmacContext *fmacContext
 }  /* end p_iteration_by_pesistent_id */
 
 
+
 static void
 p_delta_gintdrawable(gint *val, gint val_from, gint val_to, gint32 total_steps, gdouble current_step)
 {
diff --git a/gap/gap_fire_pattern.c b/gap/gap_fire_pattern.c
index 64718aa..069f8cd 100644
--- a/gap/gap_fire_pattern.c
+++ b/gap/gap_fire_pattern.c
@@ -299,11 +299,11 @@ p_init_default_cuvals(firepattern_val_t *cuvals)
 static void
 p_check_for_valid_cloud_layers(firepattern_val_t *cuvals)
 {
-  if(gimp_drawable_is_valid(cuvals->cloudLayer1) != TRUE)
+  if(gimp_item_is_valid(cuvals->cloudLayer1) != TRUE)
   {
     cuvals->cloudLayer1 = -1;
   }
-  if(gimp_drawable_is_valid(cuvals->fireShapeLayer) != TRUE)
+  if(gimp_item_is_valid(cuvals->fireShapeLayer) != TRUE)
   {
     cuvals->fireShapeLayer = -1;
   }
@@ -785,7 +785,7 @@ p_init_context_and_cloud_and_shape_layers(gint32 drawable_id, firepattern_val_t
   ctxt->ref_image_id = -1;
  
   /* check if cloud layer (the pattern) is already available */
-  if(!gimp_drawable_is_valid(cuvals->cloudLayer1))
+  if(!gimp_item_is_valid(cuvals->cloudLayer1))
   {
     /* create both cloud layers */
     GRand  *gr;
@@ -845,7 +845,7 @@ p_init_context_and_cloud_and_shape_layers(gint32 drawable_id, firepattern_val_t
 
   }
 
-  if(!gimp_drawable_is_valid(cuvals->fireShapeLayer))
+  if(!gimp_item_is_valid(cuvals->fireShapeLayer))
   {
     if((cuvals->createImage != TRUE) || (ctxt->ref_image_id < 0))
     {
@@ -1011,7 +1011,7 @@ p_drawable_get_name(gint32 drawable_id)
 {
   const char *invalidName = "(invalid)";
   
-  if(gimp_drawable_is_valid(drawable_id))
+  if(gimp_item_is_valid(drawable_id))
   {
     return(gimp_item_get_name(drawable_id));
   }
@@ -1434,11 +1434,11 @@ p_init_widget_values(FirePatternDialog *wcd)
   }
 
   countClouds = 0;
-  if(gimp_drawable_is_valid(wcd->existingCloud1Id))
+  if(gimp_item_is_valid(wcd->existingCloud1Id))
   {
     countClouds++;
   }
-  if(gimp_drawable_is_valid(wcd->existingFireShapeLayerId))
+  if(gimp_item_is_valid(wcd->existingFireShapeLayerId))
   {
     countClouds++;
   }
@@ -1621,7 +1621,7 @@ p_pattern_layer_constrain(gint32 image_id, gint32 drawable_id, FirePatternDialog
      return(TRUE);
   }
 
-  if(gimp_drawable_is_valid(drawable_id) != TRUE)
+  if(gimp_item_is_valid(drawable_id) != TRUE)
   {
      return(FALSE);
   }
@@ -1688,12 +1688,12 @@ do_dialog (FirePatternDialog *wcd, firepattern_val_t *cuvals)
   wcd->existingFireShapeLayerId = -1;
 
   wcd->countPotentialCloudLayers = 0;
-  if(gimp_drawable_is_valid(cuvals->cloudLayer1))
+  if(gimp_item_is_valid(cuvals->cloudLayer1))
   {
     wcd->existingCloud1Id = cuvals->cloudLayer1;
     wcd->createNewPatternDefault = FALSE;
   }
-  if(gimp_drawable_is_valid(cuvals->fireShapeLayer))
+  if(gimp_item_is_valid(cuvals->fireShapeLayer))
   {
     wcd->existingFireShapeLayerId = cuvals->fireShapeLayer;
   }
diff --git a/gap/gap_fmac_base.c b/gap/gap_fmac_base.c
index a82c5b8..ccbeb0e 100644
--- a/gap/gap_fmac_base.c
+++ b/gap/gap_fmac_base.c
@@ -804,7 +804,7 @@ p_fmac_execute(GimpRunMode run_mode, gint32 image_id, gint32 drawable_id
          */
         gap_frame_fetch_delete_list_of_duplicated_images(fmacContext->ffetch_user_id);
 
-        if(gimp_drawable_is_valid(l_drawable_id) != TRUE)
+        if(gimp_item_is_valid(l_drawable_id) != TRUE)
         {
           /* the filter ha made the processed drawable_id invalid
            * (probably by merging with another layer)
diff --git a/gap/gap_fmac_context.c b/gap/gap_fmac_context.c
index 9fbe4ca..6993cda 100644
--- a/gap/gap_fmac_context.c
+++ b/gap/gap_fmac_context.c
@@ -2,7 +2,7 @@
  *
  *
  *  This module handles the filtermacro context.
- *  The filtermacro context is used for itration of "persistent drawable ids" 
+ *  The filtermacro context is used for itration of "persistent drawable ids"
  *  for animated (or constant) filter apply.
  *  If gap controlled filterapply is done via a filtermacro
  *  the iteration is done within a filtermacro context.
@@ -11,7 +11,7 @@
  *  In this case the "persitent_drawable_id" is used to open the referenced
  *  image, frame or videoframe at apply time (this may happen in another gimp
  *  session than the recording of the filtermacro was done).
- *  
+ *
  *
  * Copyright (C) 2008 Wolfgang Hofer <hof gimp org>
  *
@@ -77,7 +77,7 @@ gap_fmct_set_derived_lookup_filename(GapFmacContext *fmacContext, const char *fi
  * This procedure registers a new frame fetcher resource user_id if playback (e.g NOT recording_mode)
  * is used. The drawable_iteration will refere to this ffetch_user_id when fetching
  * frames via mapped persistent drawable ids.
- * 
+ *
  * The current implementation can NOT handle parallell processing of multiple filtermacros
  * because there is only ONE context that will be overwritten in case of concurrent calls.
  */
@@ -111,7 +111,7 @@ void
 gap_fmct_disable_GapFmacContext(void)
 {
   gint            sizeFmacContext;
-  
+
   sizeFmacContext = gimp_get_data_size(GAP_FMAC_CONTEXT_KEYWORD);
 
   if(sizeFmacContext == sizeof(GapFmacContext))
@@ -176,7 +176,7 @@ p_parse_string_raw(char **scan_ptr)
 {
   char *ptr;
   char *result_ptr;
-  
+
   result_ptr = NULL;
   ptr = *scan_ptr;
 
@@ -197,8 +197,8 @@ p_parse_string_raw(char **scan_ptr)
     }
     ptr++;  /* skip white space and continue */
   }
-  
-  
+
+
   while(ptr)
   {
     ptr++;
@@ -231,7 +231,7 @@ p_parse_string_raw(char **scan_ptr)
       }
     }
   }
-  
+
   return (result_ptr);
 }  /* end p_parse_string_raw */
 
@@ -296,6 +296,7 @@ p_parse_and_add_GapFmacRefEntry(GapFmacContext *fmacContext, char *line_ptr)
   long track;
   long mtime;
   char *filename;
+  char *parentpositions;
 
   id = -1;
   ainfo_type = -1;
@@ -304,7 +305,8 @@ p_parse_and_add_GapFmacRefEntry(GapFmacContext *fmacContext, char *line_ptr)
   track = -1;
   mtime = -1;
   filename = NULL;
-  
+  parentpositions = NULL;
+
   scan_ptr = line_ptr;
   while (scan_ptr != NULL)
   {
@@ -319,11 +321,11 @@ p_parse_and_add_GapFmacRefEntry(GapFmacContext *fmacContext, char *line_ptr)
       g_free(l_key);
       break;
     }
-    
+
     if (strcmp(l_key, GAP_FMREF_ID) == 0)
     {
       id = atol(l_value);
-    } 
+    }
     else if (strcmp(l_key, GAP_FMREF_FRAME_NR) == 0)
     {
       frame_nr = atol(l_value);
@@ -348,7 +350,7 @@ p_parse_and_add_GapFmacRefEntry(GapFmacContext *fmacContext, char *line_ptr)
     {
       int len;
       char *l_raw_filename;
-      
+
       l_raw_filename = l_value;
       if(gap_debug)
       {
@@ -368,6 +370,10 @@ p_parse_and_add_GapFmacRefEntry(GapFmacContext *fmacContext, char *line_ptr)
       }
       filename = g_strdup(l_raw_filename);
     }
+    else if (strcmp(l_key, GAP_FMREF_PARENTSTACK) == 0)
+    {
+      parentpositions = g_strdup(l_value);
+    }
     else
     {
       printf("WARNING: unkonwn token: %s\n", l_key);
@@ -408,6 +414,7 @@ p_parse_and_add_GapFmacRefEntry(GapFmacContext *fmacContext, char *line_ptr)
   gap_fmct_add_GapFmacRefEntry(ainfo_type
       , frame_nr
       , stackposition
+      , parentpositions
       , track
       , id
       , filename
@@ -419,6 +426,11 @@ p_parse_and_add_GapFmacRefEntry(GapFmacContext *fmacContext, char *line_ptr)
   {
     g_free(filename);
   }
+  if (parentpositions != NULL)
+  {
+    g_free(parentpositions);
+  }
+
 
 }  /* end p_parse_and_add_GapFmacRefEntry */
 
@@ -456,7 +468,7 @@ gap_fmct_load_GapFmacContext(GapFmacContext *fmacContext)
     {
       printf("line:%s:\n", txf_ptr->line);
     }
-    
+
     if (line_nr == 1)
     {
       if (strncmp(txf_ptr->line, GAP_FMREF_FILEHEADER, strlen(GAP_FMREF_FILEHEADER)) != 0)
@@ -482,7 +494,7 @@ gap_fmct_load_GapFmacContext(GapFmacContext *fmacContext)
   {
     gap_val_free_textfile_lines(txf_ptr_root);
   }
-  
+
   if(gap_debug)
   {
     gap_fmct_debug_print_GapFmacContext(fmacContext);
@@ -511,17 +523,17 @@ gap_fmct_save_GapFmacContext(GapFmacContext *fmacContext)
     printf("ERROR: could not open write file:%s\n", fmacContext->persistent_id_lookup_filename);
     return;
   }
- 
+
   fprintf(fp, "%s\n", GAP_FMREF_FILEHEADER);
   fprintf(fp, "# type: %d=IMAGE,%d=ANIMIMAGE,%d=FRAMES,%d=MOVIE\n"
           , GAP_AINFO_IMAGE, GAP_AINFO_ANIMIMAGE, GAP_AINFO_FRAMES, GAP_AINFO_MOVIE);
 
-  /* write all reference entries in the following format: 
+  /* write all reference entries in the following format:
    * id:800000 frameNr:000001 stack:-1 file:"frame_000001.xcf"   mtime:123455678
    */
   for(fmref_entry = fmacContext->fmref_list; fmref_entry != NULL; fmref_entry = fmref_entry->next)
   {
-    fprintf(fp, "%s%06d %s%06d %s%02d %s%d %s%011d  %s%d %s\"%s\"\n"
+    fprintf(fp, "%s%06d %s%06d %s%02d %s%d %s%011d  %s%d %s\"%s\""
            , GAP_FMREF_ID         , fmref_entry->persistent_drawable_id
            , GAP_FMREF_FRAME_NR   , fmref_entry->frame_nr
            , GAP_FMREF_STACK      , fmref_entry->stackposition
@@ -530,8 +542,15 @@ gap_fmct_save_GapFmacContext(GapFmacContext *fmacContext)
            , GAP_FMREF_TYPE       , fmref_entry->ainfo_type
            , GAP_FMREF_FILE       , fmref_entry->filename
            );
+    if (*fmref_entry->parentpositions != '\0')
+    {
+      fprintf(fp, " %s%s"
+           , GAP_FMREF_PARENTSTACK, fmref_entry->parentpositions
+           );
+    }
+    fprintf(fp, "\n");
   }
-  
+
   fclose(fp);
 
 }  /* end gap_fmct_save_GapFmacContext */
@@ -554,11 +573,11 @@ gap_fmct_debug_print_GapFmacContext(GapFmacContext *fmacContext)
       , fmacContext->recording_mode
       , fmacContext->enabled
       , fmacContext->ffetch_user_id
-      ); 
+      );
 
   for(fmref_entry = fmacContext->fmref_list; fmref_entry != NULL; fmref_entry = fmref_entry->next)
   {
-    printf("%s%06d %s%06d %s%02d %s%d %s%011d  %s%d %s\"%s\"\n"
+    printf("%s%06d %s%06d %s%02d %s%d %s%011d  %s%d %s\"%s\" %s%s\n"
            , GAP_FMREF_ID         , fmref_entry->persistent_drawable_id
            , GAP_FMREF_FRAME_NR   , fmref_entry->frame_nr
            , GAP_FMREF_STACK      , fmref_entry->stackposition
@@ -566,6 +585,7 @@ gap_fmct_debug_print_GapFmacContext(GapFmacContext *fmacContext)
            , GAP_FMREF_MTIME      , fmref_entry->mtime
            , GAP_FMREF_TYPE       , fmref_entry->ainfo_type
            , GAP_FMREF_FILE       , fmref_entry->filename
+           , GAP_FMREF_PARENTSTACK , fmref_entry->parentpositions
            );
   }
 
@@ -594,7 +614,7 @@ gap_fmct_get_GapFmacRefEntry_by_persitent_id(GapFmacContext *fmacContext, gint32
     }
   }
   return (NULL);
-  
+
 }  /* end gap_fmct_get_GapFmacRefEntry_by_persitent_id */
 
 /* --------------------------------------------
@@ -605,6 +625,7 @@ gint32
 gap_fmct_add_GapFmacRefEntry(GapLibAinfoType ainfo_type
   , gint32 frame_nr
   , gint32 stackposition
+  , char *parentpositions
   , gint32 track
   , gint32 drawable_id
   , const char *filename
@@ -614,11 +635,12 @@ gap_fmct_add_GapFmacRefEntry(GapLibAinfoType ainfo_type
   GapFmacRefEntry *new_fmref_entry;
   GapFmacRefEntry *fmref_entry;
   gint32           l_max_persistent_drawable_id;
-  
+  char             l_parentpositions[300];
+
   if(filename == NULL)
   {
      return (drawable_id);
-  } 
+  }
   if(!g_file_test(filename, G_FILE_TEST_EXISTS))
   {
     return (drawable_id);
@@ -626,9 +648,17 @@ gap_fmct_add_GapFmacRefEntry(GapLibAinfoType ainfo_type
   if(fmacContext == NULL)
   {
      return (drawable_id);
-  } 
-
+  }
 
+  l_parentpositions[0] = '\0';
+  if (parentpositions != NULL)
+  {
+    g_snprintf(l_parentpositions
+              , sizeof(l_parentpositions)
+              , "%s"
+              , parentpositions
+              );
+  }
   l_max_persistent_drawable_id = GAP_FMCT_MIN_PERSISTENT_DRAWABLE_ID;
 
   /* check if entry already present in the list */
@@ -638,7 +668,8 @@ gap_fmct_add_GapFmacRefEntry(GapLibAinfoType ainfo_type
     && (fmref_entry->frame_nr == frame_nr)
     && (fmref_entry->stackposition == stackposition)
     && (fmref_entry->track == track)
-    && (strcmp(fmref_entry->filename, filename) == 0))
+    && (strcmp(fmref_entry->filename, filename) == 0)
+    && (strcmp(fmref_entry->parentpositions, l_parentpositions) == 0))
     {
       /* the list already contains an equal entry, nothing left to do.. */
       return(fmref_entry->persistent_drawable_id);
@@ -663,8 +694,17 @@ gap_fmct_add_GapFmacRefEntry(GapLibAinfoType ainfo_type
   new_fmref_entry->track = track;
   new_fmref_entry->mtime = gap_file_get_mtime(filename);
   g_snprintf(new_fmref_entry->filename, sizeof(new_fmref_entry->filename), "%s", filename);
+  new_fmref_entry->parentpositions[0] = '\0';
+  if(parentpositions != NULL)
+  {
+    g_snprintf(new_fmref_entry->parentpositions
+              , sizeof(new_fmref_entry->parentpositions)
+              , "%s"
+              , parentpositions
+              );
+  }
+
 
-    
   new_fmref_entry->next = fmacContext->fmref_list;
   fmacContext->fmref_list = new_fmref_entry;
 
diff --git a/gap/gap_fmac_context.h b/gap/gap_fmac_context.h
index 27fe25f..48e57f2 100644
--- a/gap/gap_fmac_context.h
+++ b/gap/gap_fmac_context.h
@@ -2,7 +2,7 @@
  *
  *
  *  This module handles the filtermacro context.
- *  The filtermacro context is used for itration of "persistent drawable ids" 
+ *  The filtermacro context is used for itration of "persistent drawable ids"
  *  for animated (or constant) filter apply.
  *  If gap controlled filterapply is done via a filtermacro
  *  the iteration is done within a filtermacro context.
@@ -11,7 +11,7 @@
  *  In this case the "persitent_drawable_id" is used to open the referenced
  *  image, frame or videoframe at apply time (this may happen in another gimp
  *  session than the recording of the filtermacro was done).
- *  
+ *
  *
  * Copyright (C) 2008 Wolfgang Hofer <hof gimp org>
  *
@@ -38,6 +38,7 @@
 #include "libgimp/gimp.h"
 #include "gap_lib_common_defs.h"
 
+
 typedef struct GapFmacRefEntry {
   GapLibAinfoType ainfo_type;
   gint32      persistent_drawable_id;
@@ -46,6 +47,7 @@ typedef struct GapFmacRefEntry {
   gint32      track;
   gint32      mtime;
   char        filename[1024];
+  char        parentpositions[300];
   struct GapFmacRefEntry *next;
 } GapFmacRefEntry;
 
@@ -69,6 +71,7 @@ typedef struct GapFmacContext {
 #define GAP_FMREF_MTIME      "mtime:"
 #define GAP_FMREF_TYPE       "type:"
 #define GAP_FMREF_FILE       "file:"
+#define GAP_FMREF_PARENTSTACK "parentstack:"
 
 
 #define GAP_FMAC_CONTEXT_KEYWORD   "GAP_FMAC_CONTEXT_KEYWORD"
@@ -87,6 +90,7 @@ void                 gap_fmct_free_GapFmacRefList(GapFmacContext *fmacContext);
 gint32               gap_fmct_add_GapFmacRefEntry(GapLibAinfoType ainfo_type
                                   , gint32 frame_nr
                                   , gint32 stackposition
+                                  , char *parentpositions   /* list of integers as string "1/2/3/" */
                                   , gint32 track
                                   , gint32 drawable_id
                                   , const char *filename
diff --git a/gap/gap_frame_fetcher.c b/gap/gap_frame_fetcher.c
index 8435696..f8670f4 100644
--- a/gap/gap_frame_fetcher.c
+++ b/gap/gap_frame_fetcher.c
@@ -2,18 +2,18 @@
  *
  *
  *  The FrameFetcher provides access to frames both from imagefiles and videofiles.
- *  
+ *
  *  It holds a global image cache of temporary gimp images intended for
  *  read only access in various gimp-gap render processings.
  *  (those cached images are marked with an image parasite)
- *  
- *  There are methods to get the temporary image 
+ *
+ *  There are methods to get the temporary image
  *  or to get a duplicate that has only one layer at imagesize.
  *  (merged or picked via desired stackposition)
  *
  *  For videofiles it holds a cache of open videofile handles.
  *  (note that caching of videoframes is already available in the videohandle)
- *  
+ *
  *  The current implementation of the frame fetcher is NOT multithread save !
  *  (the procedures may drop cached images that are still in use by a concurrent thread
  *  further the cache lists can be messed up if they are modified by concurrent threads
@@ -21,7 +21,7 @@
  *
  *  Currently there is no support to keep track of cached images during the full length
  *  of a gimp session. Therefore unregister of the last user does NOT drop all resources
- *  
+ *
  *  (If there are still registrated users at exit time, the cached images are still
  *  loaded in the gimp session)
  *
@@ -96,13 +96,13 @@
 #define GAP_FFETCH_GVA_FRAMES_TO_KEEP_CACHED 36
 
 #define GAP_FFETCH_MAX_IMG_CACHE_ELEMENTS_GIMPRC_KEY     "gap_ffetch_max_img_cache_elements"
-#define GAP_FFETCH_MAX_GVC_CACHE_ELEMENTS_GIMPRC_KEY     "gap_ffetch_max_gvc_cache_elements" 
+#define GAP_FFETCH_MAX_GVC_CACHE_ELEMENTS_GIMPRC_KEY     "gap_ffetch_max_gvc_cache_elements"
 #define GAP_FFETCH_GVA_FRAMES_TO_KEEP_CACHED_GIMPRC_KEY  "gap_ffetch_gva_frames_to_keep_cached"
 
 
 /* the lists of cached images and duplicates are implemented via GIMP image parasites,
  * where images are simply loaded by GIMP without adding a display and marked with a non persistent parasite.
- * the GAP_IMAGE_CACHE_PARASITE 
+ * the GAP_IMAGE_CACHE_PARASITE
  *     holds the modification timestamp (mtime), gint32 ffetch_user_id
  *     gint32 type (GAP_IMAGE_CACHE_TYPE_ORIGINAL_SIZE or GAP_IMAGE_CACHE_TYPE_PRESCALE_ENABLED)
  *     gint32 orig_width, gint32 orig_height (the unscaled original size of the image)
@@ -237,7 +237,7 @@ p_get_ffetch_max_img_cache_elements()
 {
   static gint32 value = -1;
   static char *gimprc_key = GAP_FFETCH_MAX_IMG_CACHE_ELEMENTS_GIMPRC_KEY;
-  
+
   if(value == -1)
   {
     if(gap_debug)
@@ -271,7 +271,7 @@ p_get_ffetch_max_gvc_cache_elements()
 {
   static gint32 value = -1;
   static char *gimprc_key = GAP_FFETCH_MAX_GVC_CACHE_ELEMENTS_GIMPRC_KEY;
-  
+
   if(value == -1)
   {
     if(gap_debug)
@@ -305,7 +305,7 @@ p_get_ffetch_gva_frames_to_keep_cached()
 {
   static gint32 value = -1;
   static char *gimprc_key = GAP_FFETCH_GVA_FRAMES_TO_KEEP_CACHED_GIMPRC_KEY;
-  
+
   if(value == -1)
   {
     if(gap_debug)
@@ -334,7 +334,7 @@ p_get_ffetch_gva_frames_to_keep_cached()
 /* ----------------------------------------------------
  * p_find_cache_image
  * ----------------------------------------------------
- * find an image with filename and matching cachedImageType 
+ * find an image with filename and matching cachedImageType
  *   GAP_IMAGE_CACHE_TYPE_ORIGINAL_SIZE or
  *   GAP_IMAGE_CACHE_TYPE_PRESCALE_ENABLED
  * in the cache.
@@ -387,23 +387,23 @@ p_find_cache_image(const char* filename, gint32 ffetch_user_id
     {
       GapImageCacheParasitePointers para;
       GapImageCacheParasitePointers *paraPtr;
-      
+
       paraPtr = &para;
       p_init_GapImageCacheParasitePointers(paraPtr, l_parasite->data);
 
-    
+
       cinf->number_of_cached_images++;
       if (cinf->number_of_old_cached_images < MAX_OLD_IMAGE_IDS)
       {
         cinf->old_cached_image_ids[cinf->number_of_old_cached_images] = images[l_idi];
         cinf->number_of_old_cached_images++;
       }
-      
+
       if ((*(paraPtr->type_ptr) == cachedImageType)
       && (strcmp(filename, paraPtr->filename_ptr) == 0))
       {
         gint32 mtimefile;
-        
+
         mtimefile = gap_file_get_mtime(filename);
         if(mtimefile == *(paraPtr->mtime_ptr))
         {
@@ -439,8 +439,8 @@ p_find_cache_image(const char* filename, gint32 ffetch_user_id
   {
     g_free(images);
   }
-  
-  
+
+
   if (l_image_id >= 0)
   {
     if(gap_debug)
@@ -457,7 +457,7 @@ p_find_cache_image(const char* filename, gint32 ffetch_user_id
       ,filename
       );
   }
-  
+
   return (-1);  /* indicates image not found in cache */
 
 }  /* end p_find_cache_image */
@@ -505,7 +505,7 @@ p_load_image_and_add_to_cache(const char* filename, gint32 ffetch_user_id
   {
     *originalWidthPtr = gimp_image_width(l_image_id);
     *originalHeightPtr = gimp_image_height(l_image_id);
-    
+
     if(addToCache == TRUE)
     {
       guchar *parasite_data;
@@ -514,7 +514,7 @@ p_load_image_and_add_to_cache(const char* filename, gint32 ffetch_user_id
       GapImageCacheParasitePointers para;
       GapImageCacheParasitePointers *paraPtr;
       gint    ii;
-      
+
       if(gap_debug)
       {
          printf("(L2) number_of_cached_images:%d first_cached_image_id:%d\n"
@@ -522,7 +522,7 @@ p_load_image_and_add_to_cache(const char* filename, gint32 ffetch_user_id
             , (int)cinf->old_cached_image_ids[0]
             );
       }
-      
+
       ii = 0;
       while ((cinf->number_of_cached_images >= p_get_ffetch_max_img_cache_elements())
       && (cinf->old_cached_image_ids[ii] >= 0))
@@ -548,10 +548,10 @@ p_load_image_and_add_to_cache(const char* filename, gint32 ffetch_user_id
           break;
         }
       }
-    
+
       /* build parasite data including mtime and full filename with terminating 0 byte */
       len_filename0 = strlen(filename) + 1;
-      parasite_size = 5 * sizeof(gint32) + len_filename0;  
+      parasite_size = 5 * sizeof(gint32) + len_filename0;
       parasite_data = g_malloc0(parasite_size);
 
       paraPtr = &para;
@@ -563,25 +563,25 @@ p_load_image_and_add_to_cache(const char* filename, gint32 ffetch_user_id
       *(paraPtr->orig_width_ptr) = gimp_image_width(l_image_id);
       *(paraPtr->orig_height_ptr) = gimp_image_height(l_image_id);
       memcpy(paraPtr->filename_ptr, filename, len_filename0);
-      
+
       /* attach a parasite to mark the image as part of the gap image cache */
       l_parasite = gimp_parasite_new(GAP_IMAGE_CACHE_PARASITE
                                      ,0  /* GIMP_PARASITE_PERSISTENT  0 for non persistent */
                                      ,parasite_size
                                      ,parasite_data
                                      );
-    
+
       if(l_parasite)
       {
         gimp_image_parasite_attach(l_image_id, l_parasite);
         gimp_parasite_free(l_parasite);
       }
       g_free(parasite_data);
-    
+
     }
-  
+
   }
-  
+
 
   g_free(l_filename);
 
@@ -635,9 +635,9 @@ p_load_cache_image(const char* filename, gint32 ffetch_user_id, gboolean addToCa
       , filename
       );
   }
-  
+
   return (retImgageId);
-  
+
 }   /* end p_load_cache_image */
 
 
@@ -653,7 +653,7 @@ p_drop_image_cache(void)
   gint32 *images;
   gint    nimages;
   gint    l_idi;
-  
+
   if(gap_debug)
   {
     printf("p_drop_image_cache START pid:%d\n", (int) gap_base_getpid());
@@ -663,7 +663,7 @@ p_drop_image_cache(void)
   for(l_idi=0; l_idi < nimages; l_idi++)
   {
     GimpParasite  *l_parasite;
-  
+
     l_parasite = gimp_image_parasite_find(images[l_idi], GAP_IMAGE_CACHE_PARASITE);
 
     if(gap_debug)
@@ -763,7 +763,7 @@ p_drop_vidhandle_cache(void)
   {
     printf("p_drop_vidhandle_cache END\n");
   }
-  
+
 
 }  /* end p_drop_vidhandle_cache */
 #endif
@@ -837,7 +837,7 @@ p_ffetch_get_open_gvahand(const char* filename, gint32 seltrack, const char *pre
                              ,1 /* aud_track */
                              );
   }
-  
+
   if(l_gvahand)
   {
     GVA_set_fcache_size(l_gvahand, p_get_ffetch_gva_frames_to_keep_cached());
@@ -914,7 +914,7 @@ gap_frame_fetch_delete_list_of_duplicated_images(gint32 ffetch_user_id)
   for(l_idi=0; l_idi < nimages; l_idi++)
   {
     GimpParasite  *l_parasite;
-  
+
     l_parasite = gimp_image_parasite_find(images[l_idi], GAP_IMAGE_DUP_CACHE_PARASITE);
 
     if(gap_debug)
@@ -929,7 +929,7 @@ gap_frame_fetch_delete_list_of_duplicated_images(gint32 ffetch_user_id)
     if(l_parasite)
     {
       gint32 *ffetch_user_id_ptr;
-      
+
       ffetch_user_id_ptr = (gint32 *) l_parasite->data;
       if((*ffetch_user_id_ptr == ffetch_user_id) || (ffetch_user_id < 0))
       {
@@ -987,7 +987,7 @@ gap_frame_fetch_image_scale(gint32 imageId, gint32 prescaleWidth, gint32 prescal
   {
     char          *l_filename;
     l_filename = gimp_image_get_filename(imageId);
-    
+
     printf("gap_frame_fetch_image_SCALE id:%d (%dx%d) to newSize ==> (%dx%d) %s\n"
       ,(int)imageId
       ,(int)gimp_image_width(imageId)
@@ -1019,7 +1019,7 @@ gap_frame_fetch_image_duplicate(gint32 imageId)
   {
     char          *l_filename;
     l_filename = gimp_image_get_filename(imageId);
-    
+
     printf("gap_frame_fetch_image_DUPLICATE id:%d (%dx%d) %s\n"
       ,(int)imageId
       ,(int)gimp_image_width(imageId)
@@ -1032,7 +1032,7 @@ gap_frame_fetch_image_duplicate(gint32 imageId)
       g_free(l_filename);
     }
   }
-  
+
   dupImageId = gimp_image_duplicate(imageId);
   return (dupImageId);
 }
@@ -1042,7 +1042,7 @@ gap_frame_fetch_image_duplicate(gint32 imageId)
  * p_duplicate_image_for_prescale
  * -------------------------------
  * duplicate the specified image
- * and mark the duplicate as "prescaleEnabled" 
+ * and mark the duplicate as "prescaleEnabled"
  */
 static gint32
 p_duplicate_image_for_prescale(gint32 origsizeImageId)
@@ -1070,7 +1070,7 @@ p_duplicate_image_for_prescale(gint32 origsizeImageId)
     gimp_parasite_free(l_parasite);
   }
   return (retImageId);
-  
+
 }  /* end p_duplicate_image_for_prescale */
 
 
@@ -1122,15 +1122,15 @@ gap_frame_fetch_prescaled_image(gint32 ffetch_user_id
      &&  (*originalWidthPtr > pWidth))
      {
         retImageId = -1;
-     }          
-        
+     }
+
      /* check height for re-upscale attempt */
      if ((prescaleHeight > pHeight)
      &&  (*originalHeightPtr > pHeight))
      {
         retImageId = -1;
      }
-     
+
      if (retImageId >= 0)
      {
        if ((pWidth != prescaleWidth)
@@ -1145,7 +1145,7 @@ gap_frame_fetch_prescaled_image(gint32 ffetch_user_id
        return(retImageId);
      }
 
-  
+
      if(gap_debug)
      {
        printf("gap_frame_fetch_prescaled_image DELETE img: %d from cache %s\n"
@@ -1201,8 +1201,8 @@ gap_frame_fetch_prescaled_image(gint32 ffetch_user_id
       {
         return (origsizeImageId);
       }
-      
-    
+
+
       retImageId = p_duplicate_image_for_prescale(origsizeImageId);
     }
   }
@@ -1221,7 +1221,7 @@ gap_frame_fetch_prescaled_image(gint32 ffetch_user_id
   }
 
   return (retImageId);
-  
+
 
 }  /* end gap_frame_fetch_prescaled_image */
 
@@ -1230,7 +1230,7 @@ gap_frame_fetch_prescaled_image(gint32 ffetch_user_id
 /* ----------------------------
  * gap_frame_fetch_dup_image
  * ----------------------------
- * returns merged or selected layer_id 
+ * returns merged or selected layer_id
  *        (that is the only visible layer in temporary created scratch image)
  *        the caller is resonsible to delete the scratch image when processing is done.
  *         this can be done by calling gap_frame_fetch_delete_list_of_duplicated_images()
@@ -1239,6 +1239,10 @@ gint32
 gap_frame_fetch_dup_image(gint32 ffetch_user_id
     ,const char *filename            /* full filename of the image (already contains framenr) */
     ,gint32      stackpos            /* 0 pick layer on top of stack, -1 merge visible layers */
+    ,const char *parentpositions     /* int list of parent stackpositions as string
+                                      * where NULL refers to image toplevel
+                                      *  example: 2/1/2
+                                      */
     ,gboolean addToCache             /* enable caching */
     )
 {
@@ -1253,7 +1257,7 @@ gap_frame_fetch_dup_image(gint32 ffetch_user_id
   {
     return(-1);
   }
-  
+
   if (stackpos < 0)
   {
     dup_image_id = gap_frame_fetch_image_duplicate(image_id);
@@ -1265,9 +1269,24 @@ gap_frame_fetch_dup_image(gint32 ffetch_user_id
   {
     gint          l_nlayers;
     gint32       *l_layers_list;
-     
+    gboolean      l_has_parents;
 
-    l_layers_list = gimp_image_get_layers(image_id, &l_nlayers);
+    l_has_parents = FALSE;
+    if(parentpositions != NULL)
+    {
+      if (*parentpositions != '\0')
+      {
+        l_has_parents = TRUE;
+      }
+    }
+    if (l_has_parents)
+    {
+      l_layers_list = gap_image_get_layers_at_parentpositions(image_id, &l_nlayers, parentpositions);
+    }
+    else
+    {
+      l_layers_list = gimp_image_get_layers(image_id, &l_nlayers);
+    }
     if(l_layers_list != NULL)
     {
       if (stackpos < l_nlayers)
@@ -1286,10 +1305,10 @@ gap_frame_fetch_dup_image(gint32 ffetch_user_id
 
         l_unit = gimp_image_get_unit(image_id);
         gimp_image_set_unit(dup_image_id, l_unit);
-        
+
         resulting_layer = gap_layer_copy_to_image (dup_image_id, src_layer_id);
       }
-      
+
       g_free (l_layers_list);
     }
   }
@@ -1314,7 +1333,7 @@ gap_frame_fetch_dup_image(gint32 ffetch_user_id
        */
       gap_image_delete_immediate(image_id);
     }
-    
+
   }
 
   return(resulting_layer);
@@ -1342,7 +1361,7 @@ gap_frame_fetch_dup_video(gint32 ffetch_user_id
 #ifdef GAP_ENABLE_VIDEOAPI_SUPPORT
   t_GVA_Handle *gvahand;
   t_GVA_RetCode  l_fcr;
-  
+
   gvahand = p_ffetch_get_open_gvahand(filename, seltrack, preferred_decoder);
   if (gvahand == NULL)
   {
@@ -1365,7 +1384,7 @@ gap_frame_fetch_dup_video(gint32 ffetch_user_id
       if(((gvahand->current_seek_nr + p_get_ffetch_gva_frames_to_keep_cached()) > framenr)
       &&  (gvahand->current_seek_nr < framenr ) )
       {
-        /* near forward seek is performed by dummyreads to fill up the 
+        /* near forward seek is performed by dummyreads to fill up the
          * handles internal framecache
          */
         while(gvahand->current_seek_nr < framenr)
@@ -1393,15 +1412,15 @@ gap_frame_fetch_dup_video(gint32 ffetch_user_id
   /* return the newly created layer from the temporary image in the gvahand stucture.
    */
   l_layer_id = gvahand->layer_id;
-  
+
   p_add_image_to_list_of_duplicated_images(gvahand->image_id, ffetch_user_id);
   gvahand->image_id = -1;
   gvahand->layer_id = -1;
 
-#endif  
+#endif
   return (l_layer_id);
 
-}  /* end gap_frame_fetch_dup_video */    
+}  /* end gap_frame_fetch_dup_video */
 
 
 /* -------------------------------------------------
@@ -1434,14 +1453,14 @@ gap_frame_fetch_register_user(const char *caller_name)
   gint32 max_ffetch_user_id;
   GapFFetchResourceUserElem *usr_ptr;
   GapFFetchResourceUserElem *new_usr_ptr;
-  
+
   max_ffetch_user_id = 0;
   new_usr_ptr = NULL;
-  
+
   for(usr_ptr = global_rsource_users; usr_ptr != NULL; usr_ptr = (GapFFetchResourceUserElem *)usr_ptr->next)
   {
     /* printf("usr_ptr->ffetch_user_id: %d  usr_ptr:%d\n", usr_ptr->ffetch_user_id, usr_ptr); */
-  
+
     if (usr_ptr->ffetch_user_id >= 0)
     {
       max_ffetch_user_id = MAX(max_ffetch_user_id, usr_ptr->ffetch_user_id);
@@ -1451,7 +1470,7 @@ gap_frame_fetch_register_user(const char *caller_name)
       new_usr_ptr = usr_ptr;  /* reuse inactive element */
     }
   }
-  
+
   max_ffetch_user_id++;
   if (new_usr_ptr == NULL)
   {
@@ -1460,7 +1479,7 @@ gap_frame_fetch_register_user(const char *caller_name)
     global_rsource_users = new_usr_ptr;
   }
   new_usr_ptr->ffetch_user_id = max_ffetch_user_id;
-  
+
   if(gap_debug)
   {
     printf("gap_frame_fetch_register_user: REGISTRATED ffetch_user_id:%d  caller_name:%s  new_usr_ptr:%d 
pid:%d\n"
@@ -1518,7 +1537,7 @@ gap_frame_fetch_unregister_user(gint32 ffetch_user_id)
       count_active_users++;
     }
   }
-  
+
   if(count_active_users == 0)
   {
     if(gap_debug)
@@ -1545,7 +1564,7 @@ gboolean
 gap_frame_fetch_is_image_in_cache(gint32 image_id)
 {
   GimpParasite  *l_parasite;
- 
+
   l_parasite = gimp_image_parasite_find(image_id, GAP_IMAGE_CACHE_PARASITE);
 
   if(l_parasite)
@@ -1553,9 +1572,9 @@ gap_frame_fetch_is_image_in_cache(gint32 image_id)
     gimp_parasite_free(l_parasite);
     return(TRUE);  /* isCacheMember */
   }
-  
+
   return (FALSE);
-  
+
 }  /* end gap_frame_fetch_is_image_in_cache */
 
 
@@ -1569,7 +1588,7 @@ void
 gap_frame_fetch_remove_parasite(gint32 image_id)
 {
   GimpParasite  *l_parasite;
- 
+
   l_parasite = gimp_image_parasite_find(image_id, GAP_IMAGE_CACHE_PARASITE);
 
   if(l_parasite)
@@ -1611,9 +1630,9 @@ p_dump_resources_gvahand()
     for(gvc_ptr = gvcache->gvc_list; gvc_ptr != NULL; gvc_ptr = (GapFFetchGvahandCacheElem *)gvc_ptr->next)
     {
       t_GVA_Handle *gvahand;
-      
+
       gvahand = gvc_ptr->gvahand;
-      
+
       count++;
       printf("FrameFetcher GVA_handle: %s   currFrameNr:%d fcache elemSize:%d byteSize:%d\n"
         , gvahand->filename
@@ -1629,7 +1648,7 @@ p_dump_resources_gvahand()
        ,(int)p_get_ffetch_max_gvc_cache_elements()
        ,(int)p_get_ffetch_gva_frames_to_keep_cached
        );
-    
+
   }
   else
   {
@@ -1651,13 +1670,13 @@ p_dump_resources_gvahand()
  * ----------------------------------------------------
  * print memory resources used (in case sysinfo was available on compiletime)
  *
- * NOTE: 
+ * NOTE:
  *   getrusage did not work in 1st test on linux (and is not available on windows)
  *   while  sysinfo worked on my linux development environment, but was not availabe
  *   on Windows MinGW environment.
  *   therefore the configure script cheks for the sysinfo header and
  *   sets the GAP_HAVE_SYSINFO define constant to 1 when available.
- *      
+ *
  */
 static void
 p_dump_process_resource_usage()
@@ -1666,7 +1685,7 @@ p_dump_process_resource_usage()
 
   int rc;
   struct sysinfo info;
-  
+
   rc = sysinfo(&info);
   if(rc == 0)
   {
@@ -1688,7 +1707,7 @@ p_dump_process_resource_usage()
       , (info.mem_unit * info.totalhigh)
       , (info.mem_unit * info.freehigh)
       );
-  
+
   }
   else
   {
@@ -1706,10 +1725,10 @@ p_dump_process_resource_usage()
  * gap_frame_fetch_dump_resources
  * ----------------------------------------------------
  * print current resource usage to stdout
- * this includes information about 
+ * this includes information about
  *  - ALL images currently loaded
  *  - all video filehandles with memory cache sizes
- * 
+ *
  */
 void
 gap_frame_fetch_dump_resources()
@@ -1725,17 +1744,17 @@ gap_frame_fetch_dump_resources()
 
   l_number_of_cached_images = 0;
   images = gimp_image_list(&nimages);
-  
-  
-  
+
+
+
   for(l_idi=0; l_idi < nimages; l_idi++)
   {
     GimpParasite  *l_parasite;
     char          *l_filename;
     char          *l_cacheInfoString;
     gint32         image_id;
-    
-    
+
+
     image_id = images[l_idi];
     l_filename = gimp_image_get_filename(image_id);
     l_parasite = gimp_image_parasite_find(image_id, GAP_IMAGE_CACHE_PARASITE);
@@ -1744,11 +1763,11 @@ gap_frame_fetch_dump_resources()
     {
       GapImageCacheParasitePointers para;
       GapImageCacheParasitePointers *paraPtr;
-      
+
       paraPtr = &para;
       p_init_GapImageCacheParasitePointers(paraPtr, l_parasite->data);
 
-    
+
       l_number_of_cached_images++;
 
       l_cacheInfoString = g_strdup_printf("Cache member: mtime:%d ffetchId:%d %s"
@@ -1756,7 +1775,7 @@ gap_frame_fetch_dump_resources()
                                          ,*(paraPtr->ffetch_id_ptr)
                                          ,paraPtr->filename_ptr
                                          );
-      
+
       gimp_parasite_free(l_parasite);
     }
     else
@@ -1768,11 +1787,11 @@ gap_frame_fetch_dump_resources()
         ffetch_user_id_ptr = (gint32 *) l_parasite->data;
 
         l_number_of_cached_images++;
-  
+
         l_cacheInfoString = g_strdup_printf("Cache member (merged duplicate): ffetchId:%d"
                                          ,*ffetch_user_id_ptr
                                          );
-        
+
         gimp_parasite_free(l_parasite);
       }
       else
@@ -1781,7 +1800,7 @@ gap_frame_fetch_dump_resources()
       }
     }
 
-    
+
     printf(" FrameFetcher ImgId:%d (%d x %d) %s %s\n"
           ,(int)image_id
           ,(int)gimp_image_width(image_id)
@@ -1789,7 +1808,7 @@ gap_frame_fetch_dump_resources()
           ,l_filename
           ,l_cacheInfoString
           );
-    
+
     g_free(l_cacheInfoString);
     if(l_filename != NULL)
     {
@@ -1797,12 +1816,12 @@ gap_frame_fetch_dump_resources()
     }
     l_parasite = NULL;
   }
-  
+
   if(images)
   {
     g_free(images);
   }
-  
+
   printf(" Number of images currently loaded in gimp total: %d gap_ffetch_max_img_cache_elements:%d marked 
as cache member:%d\n"
         ,(int)nimages
         ,(int)p_get_ffetch_max_img_cache_elements()
diff --git a/gap/gap_frame_fetcher.h b/gap/gap_frame_fetcher.h
index ecb99aa..ba9f0a9 100644
--- a/gap/gap_frame_fetcher.h
+++ b/gap/gap_frame_fetcher.h
@@ -2,17 +2,17 @@
  *
  *
  *  The FrameFetcher provides access to frames both from imagefiles and videofiles.
- *  
+ *
  *  It holds a global image cache of temporary gimp images intended for
  *  read only access in various gimp-gap render processings.
- *  
- *  There are methods to get the temporary image 
+ *
+ *  There are methods to get the temporary image
  *  or to get a duplicate that has only one layer at imagesize.
  *  (merged or picked via desired stackposition)
  *
  *  For videofiles it holds a cache of open videofile handles.
  *  (note that caching of videoframes is already available in the videohandle)
- *  
+ *
  *
  * Copyright (C) 2008 Wolfgang Hofer <hof gimp org>
  *
@@ -119,7 +119,7 @@ gap_frame_fetch_prescaled_image(gint32 ffetch_user_id
 /* ----------------------------
  * gap_frame_fetch_dup_image
  * ----------------------------
- * returns merged or selected layer_id 
+ * returns merged or selected layer_id
  *        (that is the only visible layer in temporary created scratch image)
  *        the caller is resonsible to delete the scratch image when processing is done.
  *         this can be done by calling gap_frame_fetch_delete_list_of_duplicated_images()
@@ -128,6 +128,10 @@ gint32
 gap_frame_fetch_dup_image(gint32 ffetch_user_id
     ,const char *filename            /* full filename of the image (already contains framenr) */
     ,gint32      stackpos            /* 0 pick layer on top of stack, -1 merge visible layers */
+    ,const char *parentpositions     /* int list of parent stackpositions as string
+                                      * where NULL refers to image toplevel
+                                      *  example: 2/1/2
+                                      */
     ,gboolean addToCache             /* enable caching */
     );
 
@@ -187,10 +191,10 @@ gap_frame_fetch_remove_parasite(gint32 image_id);
  * gap_frame_fetch_dump_resources
  * ----------------------------------------------------
  * print current resource usage to stdout
- * this includes information about 
+ * this includes information about
  *  - ALL images currently loaded in gimp
  *  - all video filehandles with memory cache sizes
- * 
+ *
  */
 void
 gap_frame_fetch_dump_resources();
diff --git a/gap/gap_image.c b/gap/gap_image.c
index 4100eca..49c9e6c 100644
--- a/gap/gap_image.c
+++ b/gap/gap_image.c
@@ -1114,7 +1114,7 @@ gap_image_reorder_layer(gint32 image_id, gint32 layer_id,
       l_name = g_strdup(new_layername);
     }
   }
-  
+
   if (l_name == NULL)
   {
    l_name = gimp_item_get_name(layer_id);
@@ -1128,3 +1128,268 @@ gap_image_reorder_layer(gint32 image_id, gint32 layer_id,
   return (0); /* OK */
 
 }  /* end gap_image_reorder_layer */
+
+/* ------------------------------------
+ * gap_image_merge_group_layer
+ * ------------------------------------
+ * merge the specified group layer and return the id of the resulting layer.
+ *
+ * The merge strategy
+ *  o) create a temporary image  of same size/type (l_tmp_img_id)
+ *  o) copy the specified grouplayer to the temporary image (l_tmp_img_id)
+ *  o) call gimp_image_merge_visible_layers on the temporary image (l_tmp_img_id, mode)
+ *  o) copy the merged layer back to the original image
+ *      to the same group at the position of the original layergroup
+ *  o) remove the temporary image
+ *  o) remove original layergroup
+ *  o) rename the resuling merged layer.
+ *
+ * returns   0 if all done OK
+ *           (or -1 on error)
+ */
+gint32
+gap_image_merge_group_layer(gint32 image_id,
+              gint32 group_layer_id,
+              gint merge_mode)
+{
+  gint32   l_tmp_img_id;
+  gint32   l_new_layer_id;
+  gint32   l_merged_layer_id;
+  gint32   l_parent_id;
+  gint32   l_position;
+  gint     l_src_offset_x;
+  gint     l_src_offset_y;
+  gboolean l_visible;
+  char    *l_name;
+
+  if (!gimp_item_is_group(group_layer_id))
+  {
+    /* the specified group_layer_id is not a group
+     * -- no merge is done, return its id as result --
+     */
+    return(group_layer_id);
+  }
+  l_visible = gimp_item_get_visible(group_layer_id);
+  l_name = gimp_item_get_name(group_layer_id);
+
+  /* create a temporary image */
+  l_tmp_img_id = gap_image_new_of_samesize(image_id);
+
+  /* copy the grouplayer to the temporary image  */
+  l_new_layer_id = gap_layer_copy_to_dest_image(l_tmp_img_id,
+                                         group_layer_id,
+                                         100.0,   /* full opacity */
+                                         0,       /* NORMAL paintmode */
+                                         &l_src_offset_x,
+                                         &l_src_offset_y
+                                         );
+
+  gimp_image_insert_layer (l_tmp_img_id, l_new_layer_id, 0, 0);
+  gimp_layer_set_offsets(l_new_layer_id, l_src_offset_x, l_src_offset_y);
+  gimp_item_set_visible(l_new_layer_id, TRUE);
+
+
+  /* merge visible layers in the temporary image */
+  l_merged_layer_id = gimp_image_merge_visible_layers (l_tmp_img_id, merge_mode);
+  l_new_layer_id = gap_layer_copy_to_dest_image(image_id,
+                                         l_merged_layer_id,
+                                         gimp_layer_get_opacity(group_layer_id),
+                                         gimp_layer_get_mode(group_layer_id),
+                                         &l_src_offset_x,
+                                         &l_src_offset_y
+                                         );
+  l_position = gimp_image_get_item_position (image_id, group_layer_id);
+  l_parent_id = gimp_item_get_parent(group_layer_id);
+  if (l_parent_id < 0)
+  {
+    l_parent_id = 0;
+  }
+  gimp_image_insert_layer (image_id, l_new_layer_id, l_parent_id, l_position);
+  gimp_layer_set_offsets(l_new_layer_id, l_src_offset_x, l_src_offset_y);
+
+  /* remove the original group layer from the original image */
+  gimp_image_remove_layer(image_id, group_layer_id);
+
+  /* restore the original layer name */
+  if (l_name != NULL)
+  {
+    gimp_item_set_name(l_new_layer_id, l_name);
+    g_free(l_name);
+  }
+  gimp_item_set_visible(l_new_layer_id, l_visible);
+
+  /* remove the temporary image */
+  gap_image_delete_immediate(l_tmp_img_id);
+  return(l_new_layer_id);
+
+}  /* end gap_image_merge_group_layer */
+
+
+/* -----------------------------------------------
+ * gap_image_get_parentpositions_as_int_stringlist
+ * -----------------------------------------------
+ * returns the list of parent stackpositions as list of integer numbers
+ * separated by the "/" delimiter.
+ *  example 2/3/2
+ * return NULL in case the specified drawable is invalid or has no perent item 
+ */
+char *
+gap_image_get_parentpositions_as_int_stringlist(gint32 drawable_id)
+{
+  char *parentpositions;
+  gint32 l_parent_id;
+  gint32 l_image_id;
+  
+  parentpositions = NULL;
+  l_parent_id = gimp_item_get_parent(drawable_id);
+  if (l_parent_id > 0)
+  {
+    gint l_position;
+    
+    l_image_id = gimp_item_get_image(drawable_id);
+    l_position = gimp_image_get_item_position (l_image_id, l_parent_id);
+
+
+    parentpositions = g_strdup_printf("%d", l_position);
+    while(l_parent_id > 0)
+    {
+      l_parent_id = gimp_item_get_parent(l_parent_id);
+      if (l_parent_id > 0)
+      {
+        char *new_parentpositions;
+        
+        l_position = gimp_image_get_item_position (l_image_id, l_parent_id);
+        new_parentpositions = g_strdup_printf("%d/%s"
+                                 , (int)l_position
+                                 , parentpositions
+                                 );
+        g_free(parentpositions);
+        parentpositions = new_parentpositions;
+      }
+    }
+  }
+
+  if(gap_debug)
+  {
+    printf("parentpositions_as_int_stringlist: %s\n"
+       , parentpositions == NULL ? "null" : parentpositions
+       );
+  }
+  return (parentpositions);
+  
+}  /* end gap_image_get_parentpositions_as_int_stringlist */
+
+
+/* -----------------------------------------------
+ * gap_image_get_layers_at_parentpositions
+ * -----------------------------------------------
+ * returns the list layers at toplevel image (when parentpositions == NULL)
+ *    otherwise return the list of layers of the nested group
+ *    where  parentpositions specifies a list of integer stackpositions
+ *    from toplevel to the deepest nested group delimited by "/"
+ *    note that all specified parentpositions MUST refere to group layers.
+ * return NULL in case no matching layerstack was found in the image.
+ */
+gint32 *
+gap_image_get_layers_at_parentpositions(gint32 image_id, gint *nlayers, const char *parentpositions)
+{
+  gint          l_nlayers;
+  gint32       *l_toplevel_layers_list;
+  gint32       *l_layers_list;
+  gboolean      l_has_parents;
+
+  *nlayers = 0;
+  l_toplevel_layers_list = gimp_image_get_layers(image_id, &l_nlayers);
+  if (l_toplevel_layers_list == NULL)
+  {
+    return (NULL);
+  }
+  l_layers_list = l_toplevel_layers_list;
+
+
+  l_has_parents = FALSE;
+  if(parentpositions != NULL)
+  {
+    if (*parentpositions != '\0')
+    {
+      l_has_parents = TRUE;
+    }
+  }
+  if (l_has_parents == TRUE)
+  {
+    gchar     **posValueArray;
+    gint      l_ii;
+    posValueArray = g_strsplit(parentpositions
+                         , "/"
+                         , -1   /* max_tokens  less than 1 splits the string completely. */
+                         );
+    for(l_ii = 0; posValueArray[l_ii] != NULL; l_ii++)
+    {
+      long l_pos;
+      
+      
+      l_pos = atol(posValueArray[l_ii]);
+      if ((l_pos >= 0) && (l_pos < l_nlayers))
+      {
+        gint32 l_layer_id;
+        
+        l_layer_id == l_layers_list[l_pos];
+        if (gimp_item_is_group(l_layer_id))
+        {
+          g_free(l_layers_list);
+          l_layers_list = gimp_item_get_children(l_layer_id, &l_nlayers);
+        }
+        else
+          /* error: position is not a group */
+          if(gap_debug)
+          {
+            printf("gap_image_get_layers_at_parentpositions: position %d is no GROUP"
+                   "(l_nlayers:%d) l_layer_id:%d (%s) parentpositions: %s \n"
+               , (int) l_pos
+               , (int) l_nlayers
+               , (int) l_layer_id
+               , gimp_item_get_name(l_layer_id)
+               , parentpositions
+               );
+          }
+          g_strfreev(posValueArray);
+          g_free(l_layers_list);
+          return (NULL);
+        {
+        }
+      }
+      else
+      {
+        /* error: position is invalid (not an integer within valid stackposition range */
+        if(gap_debug)
+        {
+          printf("gap_image_get_layers_at_parentpositions: position %d not in valid range"
+                 " (l_nlayers:%d) parentpositions: %s \n"
+               , (int) l_pos
+               , (int) l_nlayers
+               , parentpositions
+               );
+        }
+        g_strfreev(posValueArray);
+        g_free(l_layers_list);
+        return (NULL);
+      }
+      
+
+   }
+
+   g_strfreev(posValueArray);
+
+   *nlayers = l_nlayers;
+   return (l_layers_list);
+  
+  }
+  
+  /* has no parents: deliver toplevel layers list */
+
+  *nlayers = l_nlayers;
+  return (l_toplevel_layers_list);
+
+
+} /* end gap_image_get_layers_at_parentpositions */
+
diff --git a/gap/gap_image.h b/gap/gap_image.h
index 40b46ad..4512863 100644
--- a/gap/gap_image.h
+++ b/gap/gap_image.h
@@ -91,5 +91,14 @@ gint32  gap_image_reorder_layer(gint32 image_id, gint32 layer_id,
               gboolean enableGroupCreation,
               char *new_layername);
 
+gint32  gap_image_merge_group_layer(gint32 image_id,
+              gint32 group_layer_id,
+              gint merge_mode);
+
+
+char *   gap_image_get_parentpositions_as_int_stringlist(gint32 drawable_id);
+gint32 * gap_image_get_layers_at_parentpositions(gint32 image_id, gint *nlayers, const char 
*parentpositions);
+
+
 #endif
 
diff --git a/gap/gap_mod_layer.c b/gap/gap_mod_layer.c
index 976fa13..55a645f 100644
--- a/gap/gap_mod_layer.c
+++ b/gap/gap_mod_layer.c
@@ -84,6 +84,7 @@ extern      int gap_debug; /* ==0  ... dont print debug infos */
 
 
 #define GAP_DB_BROWSER_MODFRAMES_HELP_ID  "gap-modframes-db-browser"
+#define GAP_MODIFY_LAYERS_ENABLE_PITSTOP_DIALOG  "gap-modify-enable-pitstop-dialog"
 
 static int  p_merge_selected_toplevel_layers(gint32 image_id,
               gint merge_mode,
@@ -102,16 +103,15 @@ static int  p_merge_selected_group_member_layers(gint32 image_id,
               char *new_layername
               );
 
-/* ============================================================================
+/* ------------------
  * p_pitstop_dialog
+ * ------------------
  *   return -1  on CANCEL
  *           0  on Continue (OK)
- * ============================================================================
  */
 static gint
 p_pitstop_dialog(gint text_flag, char *filter_procname)
 {
-  const gchar      *l_env;
   gchar            *l_msg;
   static GapArrButtonArg  l_but_argv[2];
   gint              l_but_argc;
@@ -121,6 +121,13 @@ p_pitstop_dialog(gint text_flag, char *filter_procname)
 
 
 
+  gap_arr_arg_init(&l_argv[0], GAP_ARR_WGT_TOGGLE);
+  l_argv[0].label_txt = _("do not show this dialog again");
+  l_argv[0].help_txt  = g_strdup_printf(_("add %s to gimprc configuration to disable this dialog in all 
further sessions")
+                                             ,GAP_MODIFY_LAYERS_ENABLE_PITSTOP_DIALOG );
+  l_argv[0].int_ret = FALSE;
+  l_argv[0].int_default = FALSE;
+  l_argv[0].has_default = TRUE;
 
   l_but_argv[0].but_txt  = _("Continue");
   l_but_argv[0].but_val  = 0;
@@ -128,17 +135,15 @@ p_pitstop_dialog(gint text_flag, char *filter_procname)
   l_but_argv[1].but_val  = -1;
 
   l_but_argc = 2;
-  l_argc = 0;
+  l_argc = 1;
 
   /* optional dialog between both calls (to see the effect of 1.call) */
-  l_env = g_getenv("GAP_FILTER_PITSTOP");
-  if(l_env != NULL)
+  if(!gap_base_get_gimprc_gboolean_value(GAP_MODIFY_LAYERS_ENABLE_PITSTOP_DIALOG, TRUE))
   {
-     if((*l_env == 'N') || (*l_env == 'n'))
-     {
-       return 0;  /* continue without question */
-     }
+    return 0;  /* continue without question */
   }
+
+
   if(text_flag == 0)
   {
      l_msg = g_strdup_printf (_("2nd call of %s\n(define end-settings)"), filter_procname);
@@ -151,6 +156,10 @@ p_pitstop_dialog(gint text_flag, char *filter_procname)
                                    l_argc,     l_argv,
                                    l_but_argc, l_but_argv, 0);
   g_free (l_msg);
+  if ((l_argv[0].int_ret != FALSE) && (l_continue ==0))
+  {
+    gimp_gimprc_set(GAP_MODIFY_LAYERS_ENABLE_PITSTOP_DIALOG, "no");
+  }
 
   return (l_continue);
 
@@ -222,6 +231,34 @@ gap_mod_get_1st_selected (GapModLayliElem * layli_ptr, gint nlayers)
   return(-1);
 }       /* end gap_mod_get_1st_selected */
 
+/* ---------------------------------------
+ * p_get_layer_according_to_group_handling
+ * ---------------------------------------
+ */
+static gint32
+p_get_layer_according_to_group_handling(gint32 l_drawable_id, gint32 groupFilterHandlingMode)
+{
+  gint32 l_resulting_item_id;
+
+  l_resulting_item_id = l_drawable_id;
+  if (gimp_item_is_group(l_drawable_id))
+  {
+    if(groupFilterHandlingMode == GAP_GROUP_FILTER_HANDLING_SKIP)
+    {
+      l_resulting_item_id = -1;
+    } else if(groupFilterHandlingMode == GAP_GROUP_FILTER_HANDLING_MERGE)
+    {
+      l_resulting_item_id = gap_image_merge_group_layer( gimp_item_get_image(l_drawable_id)
+                                                       , l_drawable_id
+                                                       , GIMP_EXPAND_AS_NECESSARY
+                                                       );
+    }
+  }
+  return (l_resulting_item_id);
+
+}  /* end p_get_layer_according_to_group_handling */
+
+
 /* -----------------------------
  * gap_mod_alloc_layli_group
  * -----------------------------
@@ -541,7 +578,7 @@ p_apply_selection_action(gint32 image_id, gint32 action_mode
  * ---------------------------------
  * perform merge of selcted toplevel layer(s)
  *
- * This merge strategy 
+ * This merge strategy
  *  o) hides all unselected layers (at top image level)
  *  o) calls the merge visible layers procedure of the GIMP core
  *  o) (optionally) sets a new name for the merged layer
@@ -561,7 +598,6 @@ p_merge_selected_toplevel_layers(gint32 image_id,
               )
 {
   int     l_idx;
-  int     l_rc;
   gint    l_vis_result;
   char    l_name_buff[MAX_LAYERNAME];
   gint32  l_layer_id;
@@ -616,17 +652,17 @@ p_merge_selected_toplevel_layers(gint32 image_id,
   }
 
   return(0);
-     
+
 }  /* end p_merge_selected_toplevel_layers */
 
 
 /* ------------------------------------
  * p_merge_selected_group_member_layers
  * ------------------------------------
- * perform merge of selcted layer(s) that are all members of 
+ * perform merge of selcted layer(s) that are all members of
  * the same layergroup.
  *
- * This merge strategy 
+ * This merge strategy
  *  o) creates a temporary image  of same size/type (l_tmp_img_id)
  *  o) copies all selected layers to the temporary image (l_tmp_img_id)
  *  o) calls gimp_image_merge_visible_layers on the temporary image (l_tmp_img_id, mode)
@@ -648,7 +684,6 @@ p_merge_selected_group_member_layers(gint32 image_id,
               char *new_layername)
 {
   int     l_idx;
-  int     l_rc;
   char    l_name_buff[MAX_LAYERNAME];
   gint32  l_tmp_img_id;
   gint32  l_layer_id;
@@ -660,12 +695,12 @@ p_merge_selected_group_member_layers(gint32 image_id,
   gint    l_src_offset_x;
   gint    l_src_offset_y;
   char   *l_name;
-    
+
 
   /* create a temporary image */
   l_tmp_img_id = gap_image_new_of_samesize(image_id);
   l_name = NULL;
-  
+
   /* copy all selected layers to the temporary image */
   l_last_selected_layer_id = -1;
   for(l_idx = nlayers; l_idx >= 0; l_idx--)
@@ -678,7 +713,7 @@ p_merge_selected_group_member_layers(gint32 image_id,
         l_last_selected_layer_id = l_layer_id;
         l_name = gimp_item_get_name(l_last_selected_layer_id);
       }
-    
+
       /* copy the layer from the temp image to the preview multilayer image */
       l_new_layer_id = gap_layer_copy_to_dest_image(l_tmp_img_id,
                                          l_layer_id,
@@ -687,12 +722,12 @@ p_merge_selected_group_member_layers(gint32 image_id,
                                          &l_src_offset_x,
                                          &l_src_offset_y
                                          );
-      
+
        gimp_image_insert_layer (l_tmp_img_id, l_new_layer_id, 0, 0);
        gimp_layer_set_offsets(l_new_layer_id, l_src_offset_x, l_src_offset_y);
     }
   }
-  
+
   /* merge visible layers in the temporary image */
   l_merged_layer_id = gimp_image_merge_visible_layers (l_tmp_img_id, merge_mode);
   l_new_layer_id = gap_layer_copy_to_dest_image(image_id,
@@ -704,6 +739,10 @@ p_merge_selected_group_member_layers(gint32 image_id,
                                          );
   l_position = gimp_image_get_item_position (image_id, l_last_selected_layer_id);
   l_parent_id = gimp_item_get_parent(l_last_selected_layer_id);
+  if (l_parent_id < 0)
+  {
+    l_parent_id = 0;
+  }
   gimp_image_insert_layer (image_id, l_new_layer_id, l_parent_id, l_position);
   gimp_layer_set_offsets(l_new_layer_id, l_src_offset_x, l_src_offset_y);
 
@@ -729,12 +768,12 @@ p_merge_selected_group_member_layers(gint32 image_id,
   {
     gimp_item_set_name(l_new_layer_id, l_name);
   }
-  
+
   if (l_name != NULL)
   {
     g_free(l_name);
   }
-  
+
 
   /* remove the temporary image */
   gap_image_delete_immediate(l_tmp_img_id);
@@ -771,7 +810,8 @@ p_apply_action2(gint32 image_id,
               gint32 master_image_id,
               gint32 new_position,
               char *new_groupname,
-              char *delimiter
+              char *delimiter,
+              gint32 groupFilterHandlingMode
               )
 {
   int   l_idx;
@@ -788,7 +828,7 @@ p_apply_action2(gint32 image_id,
 
   l_merge_mode = -44; /* none of the flatten modes */
 
- 
+
   if(action_mode == GAP_MOD_ACM_MERGE_EXPAND) l_merge_mode = GAP_RANGE_OPS_FLAM_MERG_EXPAND;
   if(action_mode == GAP_MOD_ACM_MERGE_IMG)    l_merge_mode = GAP_RANGE_OPS_FLAM_MERG_CLIP_IMG;
   if(action_mode == GAP_MOD_ACM_MERGE_BG)     l_merge_mode = GAP_RANGE_OPS_FLAM_MERG_CLIP_BG;
@@ -843,9 +883,9 @@ p_apply_action2(gint32 image_id,
        {
          return(0);  /* there is only one layer selected that is not a group, nothing to merge */
        }
-       
+
      }
-     
+
      l_parent_id = gimp_item_get_parent(l_first_selected_layer_id);
      if (l_parent_id > 0)
      {
@@ -919,10 +959,18 @@ p_apply_action2(gint32 image_id,
           p_lower_layer(image_id, l_layer_id, layli_ptr, nlayers, TRUE);
           break;
         case GAP_MOD_ACM_APPLY_FILTER:
-          l_rc = gap_filt_pdb_call_plugin(filter_procname,
+          {
+            gint32 l_relevant_item_id;
+            l_relevant_item_id = p_get_layer_according_to_group_handling(l_layer_id, 
groupFilterHandlingMode);
+
+            if (l_relevant_item_id >= 0)
+            {
+              l_rc = gap_filt_pdb_call_plugin(filter_procname,
                                image_id,
-                               l_layer_id,
+                               l_relevant_item_id,
                                GIMP_RUN_WITH_LAST_VALS);
+            }
+          }
           if(gap_debug) printf("gap: p_apply_action2 FILTER:%s rc =%d\n",
                                 filter_procname, (int)l_rc);
           break;
@@ -939,7 +987,7 @@ p_apply_action2(gint32 image_id,
           {
             gint32 l_parent_id;
             gint32 l_position;
-            
+
             l_parent_id = gimp_item_get_parent(l_layer_id);
             l_position = gimp_image_get_item_position(image_id, l_layer_id);
             l_new_layer_id = gimp_layer_copy(l_layer_id);
@@ -1316,7 +1364,7 @@ p_apply_action2(gint32 image_id,
   }
 
   return (l_rc);
-}  /* end p_apply_action2 */              
+}  /* end p_apply_action2 */
 
 
 /* ---------------------------------
@@ -1338,13 +1386,14 @@ p_apply_action(gint32 image_id,
               gint32 master_image_id,
               gint32 new_position,
               char *new_groupname,
-              char *delimiter
+              char *delimiter,
+              gint32 groupFilterHandlingMode
               )
 {
   int l_rc;
-  
+
   gimp_image_undo_group_start (image_id);
-  
+
   l_rc = p_apply_action2(image_id,
               action_mode,
               layli_ptr,
@@ -1358,7 +1407,8 @@ p_apply_action(gint32 image_id,
               master_image_id,
               new_position,
               new_groupname,
-              delimiter
+              delimiter,
+              groupFilterHandlingMode
               );
   gimp_image_undo_group_end (image_id);
   return l_rc;
@@ -1381,6 +1431,7 @@ p_do_filter_dialogs(GapAnimInfo *ainfo_ptr,
                     char *filter_procname, int filt_len,
                     gint *plugin_data_len,
                     gint32 *accelCharacteristic,
+                    gint32 *groupFilterHandlingMode,
                     gboolean operate_on_layermask
                     )
 {
@@ -1392,6 +1443,7 @@ p_do_filter_dialogs(GapAnimInfo *ainfo_ptr,
   static char *canonical_proc_name;
 
   l_browser_result.accelCharacteristic = GAP_ACCEL_CHAR_LINEAR;
+  l_browser_result.groupFilterHandlingMode = GAP_GROUP_FILTER_HANDLING_NORMAL;
 
   /* GAP-PDB-Browser Dialog */
   /* ---------------------- */
@@ -1419,6 +1471,7 @@ p_do_filter_dialogs(GapAnimInfo *ainfo_ptr,
    * (because processing runs backwards from total_frames down to 0)
    */
   *accelCharacteristic = (-1 * l_browser_result.accelCharacteristic);
+  *groupFilterHandlingMode = l_browser_result.groupFilterHandlingMode;
 
   /* 1.st INTERACTIV Filtercall dialog */
   /* --------------------------------- */
@@ -1438,7 +1491,14 @@ p_do_filter_dialogs(GapAnimInfo *ainfo_ptr,
      printf("ERROR: No layer selected in 1.st handled frame\n");
      return (-1);
   }
-  l_drawable_id = layli_ptr[l_idx].layer_id;
+  l_drawable_id = p_get_layer_according_to_group_handling(layli_ptr[l_idx].layer_id, 
*groupFilterHandlingMode);
+  if (l_drawable_id < 0)
+  {
+     g_message (_("Modify Layers cancelled: No normal layer selected in 1.st handled frame"));
+     return (-1);
+  }
+
+
   if(operate_on_layermask)
   {
     l_drawable_id = gimp_layer_get_mask(layli_ptr[l_idx].layer_id);
@@ -1483,22 +1543,23 @@ p_do_filter_dialogs(GapAnimInfo *ainfo_ptr,
 }       /* end p_do_filter_dialogs */
 
 
-/* ============================================================================
+/* -------------------------
  * p_do_2nd_filter_dialogs
+ * -------------------------
  *    d) [ 2nd interactive filtercall
  *    e)   2nd pitstop dialog ]
  *
  *   (temporary) open the last frame of the range
- *   get its 1.st selected laye
+ *   get its 1.st selected layer
  *   and do the Interctive Filtercall (to get the end-values)
  *
  * then close everything (without save).
  * (the last frame will be processed later, with all its selected layers)
- * ============================================================================
  */
 static gint
 p_do_2nd_filter_dialogs(char *filter_procname,
                         gint32  accelCharacteristic,
+                        gint32  groupFilterHandlingMode,
                         char *last_frame_filename,
                         gint32 sel_mode, gint32 sel_case,
                         gint32 sel_invert, char *sel_pattern,
@@ -1527,38 +1588,100 @@ p_do_2nd_filter_dialogs(char *filter_procname,
   /* --------------------------------- */
   if(last_frame_filename == NULL)
   {
+    if(gap_debug)
+    {
+      printf("p_do_2nd_filter_dialogs last_frame_filename is NULL\n");
+    }
     return (-1);  /* there is no 2.nd frame for 2.nd filter call */
   }
 
   if(p_pitstop_dialog(0, filter_procname) < 0)
-     goto cleanup;
-
+  {
+    if(gap_debug)
+    {
+      printf("p_do_2nd_filter_dialogs Cancelled via pitstop dialog l_rc:%d\n"
+         , (int)l_rc
+         );
+    }
+    goto cleanup;
+  }
+  
   /* load last frame into temporary image */
   l_last_image_id = gap_lib_load_image(last_frame_filename);
   if (l_last_image_id < 0)
-     goto cleanup;
-
+  {
+    if(gap_debug)
+    {
+      printf("p_do_2nd_filter_dialogs load latst image FAILED l_rc:%d last_frame_filename:%s\n"
+          , (int)l_rc
+          , last_frame_filename
+          );
+    }
+    goto cleanup;
+  }
+ 
   /* get informations (id, visible, selected) about all layers */
   l_layli_ptr = gap_mod_alloc_layli_group(l_last_image_id, &l_sel_cnt, &l_nlayers,
                                sel_mode, sel_case, sel_invert, sel_pattern,
                                sel_groupname, delimiter);
 
   if (l_layli_ptr == NULL)
-     goto cleanup;
-
+  {
+    if(gap_debug)
+    {
+      printf("p_do_2nd_filter_dialogs l_layli_ptr is NULL l_rc:%d, sel_groupname:%s \n"
+         , (int)l_rc
+         , sel_groupname
+         );
+    }
+    g_message(_("No selected layer for group:%s in last handled frame"), sel_groupname);
+    goto cleanup;
+  }
+  
   /* get 1.st selected layer (of last handled frame in range ) */
   l_idx = gap_mod_get_1st_selected(l_layli_ptr, l_nlayers);
   if(l_idx < 0)
   {
+     if(gap_debug)
+     {
+       printf("p_do_2nd_filter_dialogs No layer selected in last handled frame l_rc:%d, sel_groupname:%s 
l_idx:%d\n"
+         , (int)l_rc
+         , sel_groupname
+         , (int)l_idx
+         );
+     }
      g_message (_("Modify Layers cancelled: No layer selected in last handled frame"));
      goto cleanup;
   }
-  l_drawable_id = l_layli_ptr[l_idx].layer_id;
+  l_drawable_id = p_get_layer_according_to_group_handling(l_layli_ptr[l_idx].layer_id, 
groupFilterHandlingMode);
+  if (l_drawable_id < 0)
+  {
+     if(gap_debug)
+     {
+       printf("p_do_2nd_filter_dialogs No layer selected in last handled frame l_rc:%d, sel_groupname:%s 
l_drawable_id:%d layer:%d (%s) is a GROUPLAYER\n"
+         , (int)l_rc
+         , sel_groupname
+         , (int)l_drawable_id
+         , (int)l_layli_ptr[l_idx].layer_id
+         , gimp_item_get_name(l_layli_ptr[l_idx].layer_id)
+         );
+     }
+     g_message (_("Modify Layers cancelled: No normal layer selected in last handled frame"));
+     goto cleanup;
+  }
   if(operate_on_layermask)
   {
     l_drawable_id = gimp_layer_get_mask(l_layli_ptr[l_idx].layer_id);
     if(l_drawable_id < 0)
     {
+      if(gap_debug)
+      {
+        printf("p_do_2nd_filter_dialogs first selected layer in last handled frame has no layermask l_rc:%d, 
l_drawable_id:%d (%s)\n"
+          , (int)l_rc
+          , (int)l_drawable_id
+          , gimp_item_get_name(l_drawable_id)
+          );
+      }
       g_message (_("Modify Layers cancelled: first selected layer \"%s\"\nin last frame has no layermask"),
                     gimp_item_get_name(l_layli_ptr[l_idx].layer_id)
                     );
@@ -1576,15 +1699,16 @@ p_do_2nd_filter_dialogs(char *filter_procname,
   /* get values, then store with suffix "-ITER-TO" */
   l_plugin_data_len = gap_filt_pdb_get_data(filter_procname);
   if(l_plugin_data_len <= 0)
+  {
      goto cleanup;
+  }
+  g_snprintf(l_key_to, sizeof(l_key_to), "%s%s", filter_procname, GAP_ITER_TO_SUFFIX);
+  gap_filt_pdb_set_data(l_key_to, l_plugin_data_len);
 
-   g_snprintf(l_key_to, sizeof(l_key_to), "%s%s", filter_procname, GAP_ITER_TO_SUFFIX);
-   gap_filt_pdb_set_data(l_key_to, l_plugin_data_len);
-
-   /* get FROM values */
-   g_snprintf(l_key_from, sizeof(l_key_from), "%s%s", filter_procname, GAP_ITER_FROM_SUFFIX);
-   l_plugin_data_len = gap_filt_pdb_get_data(l_key_from);
-   gap_filt_pdb_set_data(filter_procname, l_plugin_data_len);
+  /* get FROM values */
+  g_snprintf(l_key_from, sizeof(l_key_from), "%s%s", filter_procname, GAP_ITER_FROM_SUFFIX);
+  l_plugin_data_len = gap_filt_pdb_get_data(l_key_from);
+  gap_filt_pdb_set_data(filter_procname, l_plugin_data_len);
 
   l_rc = p_pitstop_dialog(1, filter_procname);
 
@@ -1656,6 +1780,7 @@ gap_mod_frames_modify(GapAnimInfo *ainfo_ptr,
   gdouble    l_cur_step;
   gint       l_total_steps;
   gint32        accelCharacteristic;
+  gint32        groupFilterHandlingMode;
   char         *l_last_frame_filename;
   gint          l_count;
   gboolean      l_operating_on_current_image;
@@ -1731,12 +1856,18 @@ gap_mod_frames_modify(GapAnimInfo *ainfo_ptr,
     }
 
     /* build the frame name */
-    if(ainfo_ptr->new_filename != NULL) g_free(ainfo_ptr->new_filename);
+    if(ainfo_ptr->new_filename != NULL)
+    {
+      g_free(ainfo_ptr->new_filename);
+    }
     ainfo_ptr->new_filename = gap_lib_alloc_fname(ainfo_ptr->basename,
                                         l_cur_frame_nr,
                                         ainfo_ptr->extension);
     if(ainfo_ptr->new_filename == NULL)
     {
+       printf("gap_mod_frames_modify Failed to allocate filename at l_cur_frame_nr:%d filename is NULL \n"
+             , (int)l_cur_frame_nr
+             );
        goto error;
     }
 
@@ -1760,6 +1891,10 @@ gap_mod_frames_modify(GapAnimInfo *ainfo_ptr,
     }
     if(l_tmp_image_id < 0)
     {
+       printf("gap_mod_frames_modify Failed to load frame l_cur_frame_nr:%d l_tmp_image_id:%d \n"
+             , (int)l_cur_frame_nr
+             , (int)l_tmp_image_id
+             );
        goto error;
     }
 
@@ -1768,16 +1903,23 @@ gap_mod_frames_modify(GapAnimInfo *ainfo_ptr,
                                 sel_mode, sel_case, sel_invert, sel_pattern,
                                 sel_groupname, delimiter);
 
-    if(l_layli_ptr == NULL)
-    {
-       printf("gap: gap_mod_frames_modify: cant alloc layer info list\n");
-       goto error;
-    }
 
     if((l_cur_frame_nr == l_begin)
     && ((action_mode == GAP_MOD_ACM_APPLY_FILTER) || (action_mode == GAP_MOD_ACM_APPLY_FILTER_ON_LAYERMASK)))
     {
       /* ------------- 1.st frame: extra dialogs for APPLY_FILTER ---------- */
+      if(l_layli_ptr == NULL)
+      {
+        if(gap_debug)
+        {
+          printf("gap: gap_mod_frames_modify: l_layli_ptr is NULL (no relevant layer available in this 
frame) l_cur_frame_nr:%d sel_groupname:%s\n"
+            , (int)l_cur_frame_nr
+            , sel_groupname
+            );
+        }
+        g_message(_("No selected layer for group:%s in start frame"), sel_groupname);
+        goto error;
+      }
 
       if(l_sel_cnt < 1)
       {
@@ -1814,14 +1956,23 @@ gap_mod_frames_modify(GapAnimInfo *ainfo_ptr,
        *                          e)   2nd pitstop dialog ]
        */
 
+      gimp_image_undo_group_start (l_tmp_image_id);
       l_rc = p_do_filter_dialogs(ainfo_ptr,
                                  l_tmp_image_id, &l_dpy_id,
                                  l_layli_ptr, l_nlayers,
                                 &l_filter_procname[0], sizeof(l_filter_procname),
                                 &l_plugin_data_len,
                                 &accelCharacteristic,
+                                &groupFilterHandlingMode,
                                  l_operate_on_layermask
                                  );
+      gimp_image_undo_group_end (l_tmp_image_id);
+      if(gap_debug)
+      {
+        printf("gap: gap_mod_frames_modify p_do_filter_dialogs (1) l_rc:%d\n"
+             , (int)l_rc
+             );
+      }                                  
 
       if(l_last_frame_filename != NULL)
       {
@@ -1829,11 +1980,18 @@ gap_mod_frames_modify(GapAnimInfo *ainfo_ptr,
         {
           l_rc = p_do_2nd_filter_dialogs(&l_filter_procname[0],
                                    accelCharacteristic,
+                                   groupFilterHandlingMode,
                                    l_last_frame_filename,
                                    sel_mode, sel_case, sel_invert, sel_pattern,
                                    l_operate_on_layermask,
                                    sel_groupname, delimiter
                                   );
+          if(gap_debug)
+          {
+            printf("gap: gap_mod_frames_modify p_do_2nd_filter_dialogs (2) l_rc:%d\n"
+               , (int)l_rc
+               );
+          }                                  
         }
 
         g_free(l_last_frame_filename);
@@ -1857,15 +2015,36 @@ gap_mod_frames_modify(GapAnimInfo *ainfo_ptr,
       {
         l_plugin_iterator =  gap_filt_pdb_get_iterator_proc(&l_filter_procname[0], &l_count);
       }
-    }
+    }     /* -- END -- 1.st extra dialog stuff -- */
+
 
     if(l_rc != 0)
     {
+      if(gap_debug) 
+      {
+        printf("gap: gap_mod_frames_modify failed. rc=%d l_cur_frame_nr:%d\n"
+            , (int)l_rc
+            , (int)l_cur_frame_nr
+            );
+      }
       goto error;
     }
 
-    /* perform function (defined by action_mode) on selcted layer(s) */
-    l_rc = p_apply_action(l_tmp_image_id,
+    if(l_layli_ptr == NULL)
+    {
+      if(gap_debug)
+      {
+       printf("gap: gap_mod_frames_modify: l_layli_ptr is NULL (no layer relevant layer available in this 
frame) l_cur_frame_nr:%d sel_groupname:%s\n"
+            , (int)l_cur_frame_nr
+            , sel_groupname
+            );
+      }
+      /* continue with next frame */
+    }
+    else
+    {
+      /* perform function (defined by action_mode) on selcted layer(s) */
+      l_rc = p_apply_action(l_tmp_image_id,
                    action_mode,
                    l_layli_ptr,
                    l_nlayers,
@@ -1876,11 +2055,18 @@ gap_mod_frames_modify(GapAnimInfo *ainfo_ptr,
                    ainfo_ptr->image_id,     /* MASTER_image_id */
                    new_position,
                    new_groupname,
-                   delimiter
+                   delimiter,
+                   groupFilterHandlingMode
                    );
+    }
+
+
     if(l_rc != 0)
     {
-      if(gap_debug) printf("gap: gap_mod_frames_modify p_apply-action failed. rc=%d\n", (int)l_rc);
+      if(gap_debug) 
+      {
+        printf("gap: gap_mod_frames_modify p_apply-action failed. rc=%d\n", (int)l_rc);
+      }
       goto error;
     }
 
@@ -1901,7 +2087,10 @@ gap_mod_frames_modify(GapAnimInfo *ainfo_ptr,
       printf("gap: gap_mod_frames_modify save frame %d failed.\n", (int)l_cur_frame_nr);
       goto error;
     }
-    else l_rc = 0;
+    else
+    {
+      l_rc = 0;
+    }
 
     /* iterator call (for filter apply with varying values) */
     if((action_mode == GAP_MOD_ACM_APPLY_FILTER)
@@ -1973,6 +2162,12 @@ gap_mod_frames_modify(GapAnimInfo *ainfo_ptr,
 
     if(l_rc != 0)
     {
+      if(gap_debug) 
+      {
+        printf("gap: gap_mod_frames_modify p_apply-action failed with rc=%d\n"
+            , (int)l_rc
+            );
+      }
       goto error;
     }
 
@@ -2051,12 +2246,18 @@ modify_advance_to_next_frame:
     }
   }
 
-  if(gap_debug) printf("gap_mod_frames_modify End OK\n");
+  if(gap_debug)
+  {
+    printf("gap_mod_frames_modify End OK\n");
+  }
 
   return 0;
 
 error:
-  if(gap_debug) printf("gap: gap_mod_frames_modify exit with Error\n");
+  if(gap_debug)
+  {
+    printf("gap: gap_mod_frames_modify exit with Error\n");
+  }
 
   if((l_tmp_image_id >= 0) && (l_operating_on_current_image == FALSE))
   {
@@ -2067,15 +2268,21 @@ error:
       gimp_display_delete(l_dpy_id);
       l_dpy_id = -1;
   }
-  if(l_layli_ptr != NULL) g_free(l_layli_ptr);
-  if(l_plugin_iterator != NULL)  g_free(l_plugin_iterator);
+  if(l_layli_ptr != NULL)
+  {
+    g_free(l_layli_ptr);
+  }
+  if(l_plugin_iterator != NULL)
+  {
+    g_free(l_plugin_iterator);
+  }
   return -1;
 
 }               /* end gap_mod_frames_modify */
 
-/* ============================================================================
+/* ---------------
  * gap_mod_layer
- * ============================================================================
+ * ---------------
  */
 gint gap_mod_layer(GimpRunMode run_mode, gint32 image_id,
                    gint32 range_from,  gint32 range_to,
@@ -2118,6 +2325,7 @@ gint gap_mod_layer(GimpRunMode run_mode, gint32 image_id,
 
     if (0 == gap_lib_dir_ainfo(ainfo_ptr))
     {
+ 
       if(run_mode == GIMP_RUN_INTERACTIVE)
       {
          /* note: for interactive call the processing is already done
@@ -2156,7 +2364,7 @@ gint gap_mod_layer(GimpRunMode run_mode, gint32 image_id,
       if(l_rc >= 0)
       {
         gboolean run_flag;
-
+        
         run_flag = TRUE;
         /* no need to save the current image before processing
          * because the gap_mod_frames_modify procedure operates directly on the current frame
diff --git a/gap/gap_player_cache.c b/gap/gap_player_cache.c
index 95ac5a5..3fd8b75 100644
--- a/gap/gap_player_cache.c
+++ b/gap/gap_player_cache.c
@@ -104,9 +104,6 @@
 
 extern int gap_debug;  /* 1 == print debug infos , 0 dont print debug infos */
 
-// local debug setting
-//static gint gap_debug = 1;  /* 1 == print debug infos , 0 dont print debug infos */
-
 
 typedef struct GapPlayerCacheElem {
   gchar                            *ckey;
diff --git a/gap/gap_water_pattern.c b/gap/gap_water_pattern.c
index f0809a4..0e3434e 100644
--- a/gap/gap_water_pattern.c
+++ b/gap/gap_water_pattern.c
@@ -224,11 +224,11 @@ p_int_default_cuvals(waterpattern_val_t *cuvals)
 static void
 p_check_for_valid_cloud_layers(waterpattern_val_t *cuvals)
 {
-  if(gimp_drawable_is_valid(cuvals->cloudLayer1) != TRUE)
+  if(gimp_item_is_valid(cuvals->cloudLayer1) != TRUE)
   {
     cuvals->cloudLayer1 = -1;
   }
-  if(gimp_drawable_is_valid(cuvals->cloudLayer2) != TRUE)
+  if(gimp_item_is_valid(cuvals->cloudLayer2) != TRUE)
   {
     cuvals->cloudLayer2 = -1;
   }
@@ -305,7 +305,7 @@ p_init_context_and_cloud_layers(gint32 drawable_id, waterpattern_val_t *cuvals,
 
 
   /* check if both cloud layers are already available */
-  if((!gimp_drawable_is_valid(cuvals->cloudLayer1)) || (!gimp_drawable_is_valid(cuvals->cloudLayer2)))
+  if((!gimp_item_is_valid(cuvals->cloudLayer1)) || (!gimp_item_is_valid(cuvals->cloudLayer2)))
   {
     /* create both cloud layers */
     GRand  *gr;
@@ -792,11 +792,11 @@ p_init_widget_values(WaterPatternDialog *wcd)
   }
 
   countClouds = 0;
-  if(gimp_drawable_is_valid(wcd->existingCloud1Id))
+  if(gimp_item_is_valid(wcd->existingCloud1Id))
   {
     countClouds++;
   }
-  if(gimp_drawable_is_valid(wcd->existingCloud2Id))
+  if(gimp_item_is_valid(wcd->existingCloud2Id))
   {
     countClouds++;
   }
@@ -946,7 +946,7 @@ p_pattern_layer_constrain(gint32 image_id, gint32 drawable_id, WaterPatternDialo
      return(TRUE);
   }
 
-  if(gimp_drawable_is_valid(drawable_id) != TRUE)
+  if(gimp_item_is_valid(drawable_id) != TRUE)
   {
      return(FALSE);
   }
@@ -1012,12 +1012,12 @@ do_dialog (WaterPatternDialog *wcd, waterpattern_val_t *cuvals)
   wcd->existingCloud2Id = -1;
   countClouds = 0;
   wcd->countPotentialCloudLayers = 0;
-  if(gimp_drawable_is_valid(cuvals->cloudLayer1))
+  if(gimp_item_is_valid(cuvals->cloudLayer1))
   {
     countClouds++;
     wcd->existingCloud1Id = cuvals->cloudLayer1;
   }
-  if(gimp_drawable_is_valid(cuvals->cloudLayer2))
+  if(gimp_item_is_valid(cuvals->cloudLayer2))
   {
     countClouds++;
     wcd->existingCloud2Id = cuvals->cloudLayer2;
diff --git a/gap/iter_ALT/mod/plug_in_bump_map_iter_ALT.inc b/gap/iter_ALT/mod/plug_in_bump_map_iter_ALT.inc
index 1cf824a..ece022c 100644
--- a/gap/iter_ALT/mod/plug_in_bump_map_iter_ALT.inc
+++ b/gap/iter_ALT/mod/plug_in_bump_map_iter_ALT.inc
@@ -6,20 +6,23 @@ gint p_plug_in_bump_map_iter_ALT(GimpRunMode run_mode, gint32 total_steps, gdoub
 {
     typedef struct t_plug_in_bump_map_Vals 
     {
-      gint32    bumpmap;
-      gdouble   azimuth;
-      gdouble   elevation;
-      long      depth;
-      long      xofs;
-      long      yofs;
-      long      waterlevel;
-      long      ambient;
-      long      compensate;
-      long      invert;
-      long      type;
-      long      tiled;
+      gint32      bumpmap_id;
+      gdouble     azimuth;
+      gdouble     elevation;
+      gint        depth;
+      gint        xofs;
+      gint        yofs;
+      gint        waterlevel;
+      gint        ambient;
+      gboolean    compensate;
+      gboolean    invert;
+      gint        type;
+      gboolean    tiled;
     } t_plug_in_bump_map_Vals; 
 
+
+
+
     t_plug_in_bump_map_Vals  buf, *buf_from, *buf_to; 
 
     if(len_struct != sizeof(t_plug_in_bump_map_Vals)) 
@@ -36,17 +39,15 @@ gint p_plug_in_bump_map_iter_ALT(GimpRunMode run_mode, gint32 total_steps, gdoub
     buf_to   = (t_plug_in_bump_map_Vals *)&g_plugin_data_to[0]; 
     memcpy(&buf, buf_from, sizeof(buf));
 
-    p_delta_drawable(&buf.bumpmap, buf_from->bumpmap, buf_to->bumpmap, total_steps, current_step);
+    p_delta_drawable(&buf.bumpmap_id, buf_from->bumpmap_id, buf_to->bumpmap_id, total_steps, current_step);
     p_delta_gdouble(&buf.azimuth, buf_from->azimuth, buf_to->azimuth, total_steps, current_step);
     p_delta_gdouble(&buf.elevation, buf_from->elevation, buf_to->elevation, total_steps, current_step);
-    p_delta_long(&buf.depth, buf_from->depth, buf_to->depth, total_steps, current_step);
-    p_delta_long(&buf.xofs, buf_from->xofs, buf_to->xofs, total_steps, current_step);
-    p_delta_long(&buf.yofs, buf_from->yofs, buf_to->yofs, total_steps, current_step);
-    p_delta_long(&buf.waterlevel, buf_from->waterlevel, buf_to->waterlevel, total_steps, current_step);
-    p_delta_long(&buf.ambient, buf_from->ambient, buf_to->ambient, total_steps, current_step);
-    p_delta_long(&buf.compensate, buf_from->compensate, buf_to->compensate, total_steps, current_step);
-    p_delta_long(&buf.invert, buf_from->invert, buf_to->invert, total_steps, current_step);
-    p_delta_long(&buf.type, buf_from->type, buf_to->type, total_steps, current_step);
+    p_delta_gint(&buf.depth, buf_from->depth, buf_to->depth, total_steps, current_step);
+    p_delta_gint(&buf.xofs, buf_from->xofs, buf_to->xofs, total_steps, current_step);
+    p_delta_gint(&buf.yofs, buf_from->yofs, buf_to->yofs, total_steps, current_step);
+    p_delta_gint(&buf.waterlevel, buf_from->waterlevel, buf_to->waterlevel, total_steps, current_step);
+    p_delta_gint(&buf.ambient, buf_from->ambient, buf_to->ambient, total_steps, current_step);
+    p_delta_gint(&buf.type, buf_from->type, buf_to->type, total_steps, current_step);
 
     gimp_set_data("plug-in-bump-map", &buf, sizeof(buf)); 
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]