/* LIBPIKA - The PIKA Library * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball * * pikacolordisplaystack.c * Copyright (C) 2003 Michael Natterer * * This library is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . */ #include "config.h" #include #include #include "libpikacolor/pikacolor.h" #include "pikawidgetstypes.h" #include "pikacolordisplay.h" #include "pikacolordisplaystack.h" #include "pikawidgetsmarshal.h" /** * SECTION: pikacolordisplaystack * @title: PikaColorDisplayStack * @short_description: A stack of color correction modules. * @see_also: #PikaColorDisplay * * A stack of color correction modules. **/ enum { CHANGED, ADDED, REMOVED, REORDERED, LAST_SIGNAL }; struct _PikaColorDisplayStackPrivate { GList *filters; }; #define GET_PRIVATE(obj) (((PikaColorDisplayStack *) (obj))->priv) static void pika_color_display_stack_dispose (GObject *object); static void pika_color_display_stack_display_changed (PikaColorDisplay *display, PikaColorDisplayStack *stack); static void pika_color_display_stack_display_enabled (PikaColorDisplay *display, GParamSpec *pspec, PikaColorDisplayStack *stack); static void pika_color_display_stack_disconnect (PikaColorDisplayStack *stack, PikaColorDisplay *display); G_DEFINE_TYPE_WITH_PRIVATE (PikaColorDisplayStack, pika_color_display_stack, G_TYPE_OBJECT) #define parent_class pika_color_display_stack_parent_class static guint stack_signals[LAST_SIGNAL] = { 0 }; static void pika_color_display_stack_class_init (PikaColorDisplayStackClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); stack_signals[CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (PikaColorDisplayStackClass, changed), NULL, NULL, NULL, G_TYPE_NONE, 0); stack_signals[ADDED] = g_signal_new ("added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (PikaColorDisplayStackClass, added), NULL, NULL, _pika_widgets_marshal_VOID__OBJECT_INT, G_TYPE_NONE, 2, PIKA_TYPE_COLOR_DISPLAY, G_TYPE_INT); stack_signals[REMOVED] = g_signal_new ("removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (PikaColorDisplayStackClass, removed), NULL, NULL, NULL, G_TYPE_NONE, 1, PIKA_TYPE_COLOR_DISPLAY); stack_signals[REORDERED] = g_signal_new ("reordered", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (PikaColorDisplayStackClass, reordered), NULL, NULL, _pika_widgets_marshal_VOID__OBJECT_INT, G_TYPE_NONE, 2, PIKA_TYPE_COLOR_DISPLAY, G_TYPE_INT); object_class->dispose = pika_color_display_stack_dispose; klass->changed = NULL; klass->added = NULL; klass->removed = NULL; klass->reordered = NULL; } static void pika_color_display_stack_init (PikaColorDisplayStack *stack) { stack->priv = pika_color_display_stack_get_instance_private (stack); } static void pika_color_display_stack_dispose (GObject *object) { PikaColorDisplayStack *stack = PIKA_COLOR_DISPLAY_STACK (object); PikaColorDisplayStackPrivate *private = GET_PRIVATE (object); if (private->filters) { GList *list; for (list = private->filters; list; list = g_list_next (list)) { PikaColorDisplay *display = list->data; pika_color_display_stack_disconnect (stack, display); g_object_unref (display); } g_list_free (private->filters); private->filters = NULL; } G_OBJECT_CLASS (parent_class)->dispose (object); } /* public functions */ /** * pika_color_display_stack_new: * * Creates a new stack of color correction modules. * * Returns: (transfer full): a newly allocated #PikaColorDisplayStack. * * Since: 2.0 **/ PikaColorDisplayStack * pika_color_display_stack_new (void) { return g_object_new (PIKA_TYPE_COLOR_DISPLAY_STACK, NULL); } /** * pika_color_display_stack_clone: * @stack: a #PikaColorDisplayStack * * Creates a copy of @stack with all its display color modules also * duplicated. * * Returns: (transfer full): a duplicate of @stack. * * Since: 2.0 **/ PikaColorDisplayStack * pika_color_display_stack_clone (PikaColorDisplayStack *stack) { PikaColorDisplayStackPrivate *private; PikaColorDisplayStack *clone; GList *list; g_return_val_if_fail (PIKA_IS_COLOR_DISPLAY_STACK (stack), NULL); private = GET_PRIVATE (stack); clone = g_object_new (PIKA_TYPE_COLOR_DISPLAY_STACK, NULL); for (list = private->filters; list; list = g_list_next (list)) { PikaColorDisplay *display; display = pika_color_display_clone (list->data); pika_color_display_stack_add (clone, display); g_object_unref (display); } return clone; } /** * pika_color_display_stack_changed: * @stack: a #PikaColorDisplayStack * * Emit the "changed" signal of @stack. * * Since: 2.0 **/ void pika_color_display_stack_changed (PikaColorDisplayStack *stack) { g_return_if_fail (PIKA_IS_COLOR_DISPLAY_STACK (stack)); g_signal_emit (stack, stack_signals[CHANGED], 0); } /** * pika_color_display_stack_get_filters: * @stack: a #PikaColorDisplayStack * * Gets the list of added color modules. * * Returns: (transfer none) (element-type PikaColorDisplay): the list of @stack's display color modules. * * Since: 3.0 **/ GList * pika_color_display_stack_get_filters (PikaColorDisplayStack *stack) { g_return_val_if_fail (PIKA_IS_COLOR_DISPLAY_STACK (stack), NULL); return GET_PRIVATE (stack)->filters; } /** * pika_color_display_stack_add: * @stack: a #PikaColorDisplayStack * @display: (transfer none): a #PikaColorDisplay * * Add the color module @display to @stack. * * Since: 2.0 **/ void pika_color_display_stack_add (PikaColorDisplayStack *stack, PikaColorDisplay *display) { PikaColorDisplayStackPrivate *private; g_return_if_fail (PIKA_IS_COLOR_DISPLAY_STACK (stack)); g_return_if_fail (PIKA_IS_COLOR_DISPLAY (display)); private = GET_PRIVATE (stack); g_return_if_fail (g_list_find (private->filters, display) == NULL); private->filters = g_list_append (private->filters, g_object_ref (display)); g_signal_connect (display, "changed", G_CALLBACK (pika_color_display_stack_display_changed), G_OBJECT (stack)); g_signal_connect (display, "notify::enabled", G_CALLBACK (pika_color_display_stack_display_enabled), G_OBJECT (stack)); g_signal_emit (stack, stack_signals[ADDED], 0, display, g_list_length (private->filters) - 1); pika_color_display_stack_changed (stack); } /** * pika_color_display_stack_remove: * @stack: a #PikaColorDisplayStack * @display: (transfer none): a #PikaColorDisplay * * Remove the color module @display from @stack. * * Since: 2.0 **/ void pika_color_display_stack_remove (PikaColorDisplayStack *stack, PikaColorDisplay *display) { PikaColorDisplayStackPrivate *private; g_return_if_fail (PIKA_IS_COLOR_DISPLAY_STACK (stack)); g_return_if_fail (PIKA_IS_COLOR_DISPLAY (display)); private = GET_PRIVATE (stack); g_return_if_fail (g_list_find (private->filters, display) != NULL); pika_color_display_stack_disconnect (stack, display); private->filters = g_list_remove (private->filters, display); g_signal_emit (stack, stack_signals[REMOVED], 0, display); pika_color_display_stack_changed (stack); g_object_unref (display); } /** * pika_color_display_stack_reorder_up: * @stack: a #PikaColorDisplayStack * @display: a #PikaColorDisplay * * Move the color module @display up in the filter list of @stack. * * Since: 2.0 **/ void pika_color_display_stack_reorder_up (PikaColorDisplayStack *stack, PikaColorDisplay *display) { PikaColorDisplayStackPrivate *private; GList *list; g_return_if_fail (PIKA_IS_COLOR_DISPLAY_STACK (stack)); g_return_if_fail (PIKA_IS_COLOR_DISPLAY (display)); private = GET_PRIVATE (stack); list = g_list_find (private->filters, display); g_return_if_fail (list != NULL); if (list->prev) { list->data = list->prev->data; list->prev->data = display; g_signal_emit (stack, stack_signals[REORDERED], 0, display, g_list_position (private->filters, list->prev)); pika_color_display_stack_changed (stack); } } /** * pika_color_display_stack_reorder_down: * @stack: a #PikaColorDisplayStack * @display: a #PikaColorDisplay * * Move the color module @display down in the filter list of @stack. * * Since: 2.0 **/ void pika_color_display_stack_reorder_down (PikaColorDisplayStack *stack, PikaColorDisplay *display) { PikaColorDisplayStackPrivate *private; GList *list; g_return_if_fail (PIKA_IS_COLOR_DISPLAY_STACK (stack)); g_return_if_fail (PIKA_IS_COLOR_DISPLAY (display)); private = GET_PRIVATE (stack); list = g_list_find (private->filters, display); g_return_if_fail (list != NULL); if (list->next) { list->data = list->next->data; list->next->data = display; g_signal_emit (stack, stack_signals[REORDERED], 0, display, g_list_position (private->filters, list->next)); pika_color_display_stack_changed (stack); } } /** * pika_color_display_stack_convert_buffer: * @stack: a #PikaColorDisplayStack * @buffer: a #GeglBuffer * @area: area of @buffer to convert * * Runs all the stack's filters on all pixels in @area of @buffer. * * Since: 2.10 **/ void pika_color_display_stack_convert_buffer (PikaColorDisplayStack *stack, GeglBuffer *buffer, GeglRectangle *area) { PikaColorDisplayStackPrivate *private; GList *list; g_return_if_fail (PIKA_IS_COLOR_DISPLAY_STACK (stack)); g_return_if_fail (GEGL_IS_BUFFER (buffer)); private = GET_PRIVATE (stack); for (list = private->filters; list; list = g_list_next (list)) { PikaColorDisplay *display = list->data; pika_color_display_convert_buffer (display, buffer, area); } } /* private functions */ static void pika_color_display_stack_display_changed (PikaColorDisplay *display, PikaColorDisplayStack *stack) { if (pika_color_display_get_enabled (display)) pika_color_display_stack_changed (stack); } static void pika_color_display_stack_display_enabled (PikaColorDisplay *display, GParamSpec *pspec, PikaColorDisplayStack *stack) { pika_color_display_stack_changed (stack); } static void pika_color_display_stack_disconnect (PikaColorDisplayStack *stack, PikaColorDisplay *display) { g_signal_handlers_disconnect_by_func (display, pika_color_display_stack_display_changed, stack); g_signal_handlers_disconnect_by_func (display, pika_color_display_stack_display_enabled, stack); }