/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * pikaplugin-cleanup.c * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include #include #include "plug-in-types.h" #include "core/pika.h" #include "core/pikacontainer.h" #include "core/pikadrawable.h" #include "core/pikadrawable-shadow.h" #include "core/pikaimage.h" #include "core/pikaimage-undo.h" #include "core/pikaundostack.h" #include "pikaplugin.h" #include "pikaplugin-cleanup.h" #include "pikapluginmanager.h" #include "pikapluginprocedure.h" #include "pika-log.h" typedef struct _PikaPlugInCleanupImage PikaPlugInCleanupImage; struct _PikaPlugInCleanupImage { PikaImage *image; gint image_id; gint undo_group_count; gint layers_freeze_count; gint channels_freeze_count; gint vectors_freeze_count; }; typedef struct _PikaPlugInCleanupItem PikaPlugInCleanupItem; struct _PikaPlugInCleanupItem { PikaItem *item; gint item_id; gboolean shadow_buffer; }; /* local function prototypes */ static PikaPlugInCleanupImage * pika_plug_in_cleanup_image_new (PikaPlugInProcFrame *proc_frame, PikaImage *image); static void pika_plug_in_cleanup_image_free (PikaPlugInProcFrame *proc_frame, PikaPlugInCleanupImage *cleanup); static gboolean pika_plug_in_cleanup_image_is_clean (PikaPlugInCleanupImage *cleanup); static PikaPlugInCleanupImage * pika_plug_in_cleanup_image_get (PikaPlugInProcFrame *proc_frame, PikaImage *image); static void pika_plug_in_cleanup_image (PikaPlugInProcFrame *proc_frame, PikaPlugInCleanupImage *cleanup); static PikaPlugInCleanupItem * pika_plug_in_cleanup_item_new (PikaPlugInProcFrame *proc_frame, PikaItem *item); static void pika_plug_in_cleanup_item_free (PikaPlugInProcFrame *proc_frame, PikaPlugInCleanupItem *cleanup); static gboolean pika_plug_in_cleanup_item_is_clean (PikaPlugInCleanupItem *cleanup); static PikaPlugInCleanupItem * pika_plug_in_cleanup_item_get (PikaPlugInProcFrame *proc_frame, PikaItem *item); static void pika_plug_in_cleanup_item (PikaPlugInProcFrame *proc_frame, PikaPlugInCleanupItem *cleanup); /* public functions */ gboolean pika_plug_in_cleanup_undo_group_start (PikaPlugIn *plug_in, PikaImage *image) { PikaPlugInProcFrame *proc_frame; PikaPlugInCleanupImage *cleanup; g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE); g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE); proc_frame = pika_plug_in_get_proc_frame (plug_in); cleanup = pika_plug_in_cleanup_image_get (proc_frame, image); if (! cleanup) cleanup = pika_plug_in_cleanup_image_new (proc_frame, image); cleanup->undo_group_count++; return TRUE; } gboolean pika_plug_in_cleanup_undo_group_end (PikaPlugIn *plug_in, PikaImage *image) { PikaPlugInProcFrame *proc_frame; PikaPlugInCleanupImage *cleanup; g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE); g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE); proc_frame = pika_plug_in_get_proc_frame (plug_in); cleanup = pika_plug_in_cleanup_image_get (proc_frame, image); if (! cleanup) return FALSE; if (cleanup->undo_group_count > 0) { cleanup->undo_group_count--; if (pika_plug_in_cleanup_image_is_clean (cleanup)) pika_plug_in_cleanup_image_free (proc_frame, cleanup); return TRUE; } return FALSE; } gboolean pika_plug_in_cleanup_layers_freeze (PikaPlugIn *plug_in, PikaImage *image) { PikaPlugInProcFrame *proc_frame; PikaPlugInCleanupImage *cleanup; g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE); g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE); proc_frame = pika_plug_in_get_proc_frame (plug_in); cleanup = pika_plug_in_cleanup_image_get (proc_frame, image); if (! cleanup) cleanup = pika_plug_in_cleanup_image_new (proc_frame, image); cleanup->layers_freeze_count++; return TRUE; } gboolean pika_plug_in_cleanup_layers_thaw (PikaPlugIn *plug_in, PikaImage *image) { PikaPlugInProcFrame *proc_frame; PikaPlugInCleanupImage *cleanup; g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE); g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE); proc_frame = pika_plug_in_get_proc_frame (plug_in); cleanup = pika_plug_in_cleanup_image_get (proc_frame, image); if (! cleanup) return FALSE; if (cleanup->layers_freeze_count > 0) { cleanup->layers_freeze_count--; if (pika_plug_in_cleanup_image_is_clean (cleanup)) pika_plug_in_cleanup_image_free (proc_frame, cleanup); return TRUE; } return FALSE; } gboolean pika_plug_in_cleanup_channels_freeze (PikaPlugIn *plug_in, PikaImage *image) { PikaPlugInProcFrame *proc_frame; PikaPlugInCleanupImage *cleanup; g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE); g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE); proc_frame = pika_plug_in_get_proc_frame (plug_in); cleanup = pika_plug_in_cleanup_image_get (proc_frame, image); if (! cleanup) cleanup = pika_plug_in_cleanup_image_new (proc_frame, image); cleanup->channels_freeze_count++; return TRUE; } gboolean pika_plug_in_cleanup_channels_thaw (PikaPlugIn *plug_in, PikaImage *image) { PikaPlugInProcFrame *proc_frame; PikaPlugInCleanupImage *cleanup; g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE); g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE); proc_frame = pika_plug_in_get_proc_frame (plug_in); cleanup = pika_plug_in_cleanup_image_get (proc_frame, image); if (! cleanup) return FALSE; if (cleanup->channels_freeze_count > 0) { cleanup->channels_freeze_count--; if (pika_plug_in_cleanup_image_is_clean (cleanup)) pika_plug_in_cleanup_image_free (proc_frame, cleanup); return TRUE; } return FALSE; } gboolean pika_plug_in_cleanup_vectors_freeze (PikaPlugIn *plug_in, PikaImage *image) { PikaPlugInProcFrame *proc_frame; PikaPlugInCleanupImage *cleanup; g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE); g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE); proc_frame = pika_plug_in_get_proc_frame (plug_in); cleanup = pika_plug_in_cleanup_image_get (proc_frame, image); if (! cleanup) cleanup = pika_plug_in_cleanup_image_new (proc_frame, image); cleanup->vectors_freeze_count++; return TRUE; } gboolean pika_plug_in_cleanup_vectors_thaw (PikaPlugIn *plug_in, PikaImage *image) { PikaPlugInProcFrame *proc_frame; PikaPlugInCleanupImage *cleanup; g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE); g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE); proc_frame = pika_plug_in_get_proc_frame (plug_in); cleanup = pika_plug_in_cleanup_image_get (proc_frame, image); if (! cleanup) return FALSE; if (cleanup->vectors_freeze_count > 0) { cleanup->vectors_freeze_count--; if (pika_plug_in_cleanup_image_is_clean (cleanup)) pika_plug_in_cleanup_image_free (proc_frame, cleanup); return TRUE; } return FALSE; } gboolean pika_plug_in_cleanup_add_shadow (PikaPlugIn *plug_in, PikaDrawable *drawable) { PikaPlugInProcFrame *proc_frame; PikaPlugInCleanupItem *cleanup; g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE); g_return_val_if_fail (PIKA_IS_DRAWABLE (drawable), FALSE); proc_frame = pika_plug_in_get_proc_frame (plug_in); cleanup = pika_plug_in_cleanup_item_get (proc_frame, PIKA_ITEM (drawable)); if (! cleanup) cleanup = pika_plug_in_cleanup_item_new (proc_frame, PIKA_ITEM (drawable)); cleanup->shadow_buffer = TRUE; return TRUE; } gboolean pika_plug_in_cleanup_remove_shadow (PikaPlugIn *plug_in, PikaDrawable *drawable) { PikaPlugInProcFrame *proc_frame; PikaPlugInCleanupItem *cleanup; g_return_val_if_fail (PIKA_IS_PLUG_IN (plug_in), FALSE); g_return_val_if_fail (PIKA_IS_DRAWABLE (drawable), FALSE); proc_frame = pika_plug_in_get_proc_frame (plug_in); cleanup = pika_plug_in_cleanup_item_get (proc_frame, PIKA_ITEM (drawable)); if (! cleanup) return FALSE; if (cleanup->shadow_buffer) { cleanup->shadow_buffer = FALSE; if (pika_plug_in_cleanup_item_is_clean (cleanup)) pika_plug_in_cleanup_item_free (proc_frame, cleanup); return TRUE; } return FALSE; } void pika_plug_in_cleanup (PikaPlugIn *plug_in, PikaPlugInProcFrame *proc_frame) { g_return_if_fail (PIKA_IS_PLUG_IN (plug_in)); g_return_if_fail (proc_frame != NULL); while (proc_frame->image_cleanups) { PikaPlugInCleanupImage *cleanup = proc_frame->image_cleanups->data; if (pika_image_get_by_id (plug_in->manager->pika, cleanup->image_id) == cleanup->image) { pika_plug_in_cleanup_image (proc_frame, cleanup); } pika_plug_in_cleanup_image_free (proc_frame, cleanup); } while (proc_frame->item_cleanups) { PikaPlugInCleanupItem *cleanup = proc_frame->item_cleanups->data; if (pika_item_get_by_id (plug_in->manager->pika, cleanup->item_id) == cleanup->item) { pika_plug_in_cleanup_item (proc_frame, cleanup); } pika_plug_in_cleanup_item_free (proc_frame, cleanup); } } /* private functions */ static PikaPlugInCleanupImage * pika_plug_in_cleanup_image_new (PikaPlugInProcFrame *proc_frame, PikaImage *image) { PikaPlugInCleanupImage *cleanup = g_slice_new0 (PikaPlugInCleanupImage); cleanup->image = image; cleanup->image_id = pika_image_get_id (image); proc_frame->image_cleanups = g_list_prepend (proc_frame->image_cleanups, cleanup); return cleanup; } static void pika_plug_in_cleanup_image_free (PikaPlugInProcFrame *proc_frame, PikaPlugInCleanupImage *cleanup) { proc_frame->image_cleanups = g_list_remove (proc_frame->image_cleanups, cleanup); g_slice_free (PikaPlugInCleanupImage, cleanup); } static gboolean pika_plug_in_cleanup_image_is_clean (PikaPlugInCleanupImage *cleanup) { if (cleanup->undo_group_count > 0) return FALSE; if (cleanup->layers_freeze_count > 0) return FALSE; if (cleanup->channels_freeze_count > 0) return FALSE; if (cleanup->vectors_freeze_count > 0) return FALSE; return TRUE; } static PikaPlugInCleanupImage * pika_plug_in_cleanup_image_get (PikaPlugInProcFrame *proc_frame, PikaImage *image) { GList *list; for (list = proc_frame->image_cleanups; list; list = g_list_next (list)) { PikaPlugInCleanupImage *cleanup = list->data; if (cleanup->image == image) return cleanup; } return NULL; } static void pika_plug_in_cleanup_image (PikaPlugInProcFrame *proc_frame, PikaPlugInCleanupImage *cleanup) { PikaImage *image = cleanup->image; PikaContainer *container; if (cleanup->undo_group_count > 0) { g_message ("Plug-in '%s' left image undo in inconsistent state, " "closing open undo groups.", pika_procedure_get_label (proc_frame->procedure)); while (cleanup->undo_group_count--) if (! pika_image_undo_group_end (image)) break; } container = pika_image_get_layers (image); if (cleanup->layers_freeze_count > 0) { g_message ("Plug-in '%s' left image's layers frozen, " "thawing layers.", pika_procedure_get_label (proc_frame->procedure)); while (cleanup->layers_freeze_count-- > 0 && pika_container_frozen (container)) { pika_container_thaw (container); } } container = pika_image_get_channels (image); if (cleanup->channels_freeze_count > 0) { g_message ("Plug-in '%s' left image's channels frozen, " "thawing channels.", pika_procedure_get_label (proc_frame->procedure)); while (cleanup->channels_freeze_count-- > 0 && pika_container_frozen (container)) { pika_container_thaw (container); } } container = pika_image_get_vectors (image); if (cleanup->vectors_freeze_count > 0) { g_message ("Plug-in '%s' left image's vectors frozen, " "thawing vectors.", pika_procedure_get_label (proc_frame->procedure)); while (cleanup->vectors_freeze_count > 0 && pika_container_frozen (container)) { pika_container_thaw (container); } } } static PikaPlugInCleanupItem * pika_plug_in_cleanup_item_new (PikaPlugInProcFrame *proc_frame, PikaItem *item) { PikaPlugInCleanupItem *cleanup = g_slice_new0 (PikaPlugInCleanupItem); cleanup->item = item; cleanup->item_id = pika_item_get_id (item); proc_frame->item_cleanups = g_list_prepend (proc_frame->item_cleanups, cleanup); return cleanup; } static void pika_plug_in_cleanup_item_free (PikaPlugInProcFrame *proc_frame, PikaPlugInCleanupItem *cleanup) { proc_frame->item_cleanups = g_list_remove (proc_frame->item_cleanups, cleanup); g_slice_free (PikaPlugInCleanupItem, cleanup); } static gboolean pika_plug_in_cleanup_item_is_clean (PikaPlugInCleanupItem *cleanup) { if (cleanup->shadow_buffer) return FALSE; return TRUE; } static PikaPlugInCleanupItem * pika_plug_in_cleanup_item_get (PikaPlugInProcFrame *proc_frame, PikaItem *item) { GList *list; for (list = proc_frame->item_cleanups; list; list = g_list_next (list)) { PikaPlugInCleanupItem *cleanup = list->data; if (cleanup->item == item) return cleanup; } return NULL; } static void pika_plug_in_cleanup_item (PikaPlugInProcFrame *proc_frame, PikaPlugInCleanupItem *cleanup) { PikaItem *item = cleanup->item; if (cleanup->shadow_buffer) { PIKA_LOG (SHADOW_TILES, "Freeing shadow buffer of drawable '%s' on behalf of '%s'.", pika_object_get_name (item), pika_procedure_get_label (proc_frame->procedure)); pika_drawable_free_shadow_buffer (PIKA_DRAWABLE (item)); cleanup->shadow_buffer = FALSE; } }