Initial checkin of Pika from heckimp
This commit is contained in:
1515
app/core/core-enums.c
Normal file
1515
app/core/core-enums.c
Normal file
File diff suppressed because it is too large
Load Diff
789
app/core/core-enums.h
Normal file
789
app/core/core-enums.h
Normal file
@ -0,0 +1,789 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __CORE_ENUMS_H__
|
||||
#define __CORE_ENUMS_H__
|
||||
|
||||
|
||||
#if 0
|
||||
This file is parsed by two scripts, enumgen.pl in pdb,
|
||||
and pika-mkenums. All enums that are not marked with
|
||||
/*< pdb-skip >*/ are exported to libpika and the PDB. Enums that are
|
||||
not marked with /*< skip >*/ are registered with the GType system.
|
||||
If you want the enum to be skipped by both scripts, you have to use
|
||||
/*< pdb-skip, skip >*/.
|
||||
|
||||
The same syntax applies to enum values.
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* these enums are registered with the type system
|
||||
*/
|
||||
|
||||
|
||||
#define PIKA_TYPE_ALIGN_REFERENCE_TYPE (pika_align_reference_type_get_type ())
|
||||
|
||||
GType pika_align_reference_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_ALIGN_REFERENCE_IMAGE, /*< desc="Image" >*/
|
||||
PIKA_ALIGN_REFERENCE_SELECTION, /*< desc="Selection" >*/
|
||||
PIKA_ALIGN_REFERENCE_PICK, /*< desc="Picked reference object" >*/
|
||||
} PikaAlignReferenceType;
|
||||
|
||||
|
||||
#define PIKA_TYPE_ALIGNMENT_TYPE (pika_alignment_type_get_type ())
|
||||
|
||||
GType pika_alignment_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_ALIGN_LEFT, /*< desc="Align to the left" >*/
|
||||
PIKA_ALIGN_HCENTER, /*< desc="Center horizontally" >*/
|
||||
PIKA_ALIGN_RIGHT, /*< desc="Align to the right" >*/
|
||||
PIKA_ALIGN_TOP, /*< desc="Align to the top" >*/
|
||||
PIKA_ALIGN_VCENTER, /*< desc="Center vertically" >*/
|
||||
PIKA_ALIGN_BOTTOM, /*< desc="Align to the bottom" >*/
|
||||
PIKA_ARRANGE_HFILL, /*< desc="Distribute anchor points horizontally evenly" >*/
|
||||
PIKA_ARRANGE_VFILL, /*< desc="Distribute anchor points vertically evenly" >*/
|
||||
PIKA_DISTRIBUTE_EVEN_HORIZONTAL_GAP, /*< desc="Distribute horizontally with even horizontal gaps" >*/
|
||||
PIKA_DISTRIBUTE_EVEN_VERTICAL_GAP, /*< desc="Distribute vertically with even vertical gaps" >*/
|
||||
} PikaAlignmentType;
|
||||
|
||||
|
||||
/**
|
||||
* PikaBucketFillMode:
|
||||
* @PIKA_BUCKET_FILL_FG: FG color fill
|
||||
* @PIKA_BUCKET_FILL_BG: BG color fill
|
||||
* @PIKA_BUCKET_FILL_PATTERN: Pattern fill
|
||||
*
|
||||
* Bucket fill modes.
|
||||
*/
|
||||
#define PIKA_TYPE_BUCKET_FILL_MODE (pika_bucket_fill_mode_get_type ())
|
||||
|
||||
GType pika_bucket_fill_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_BUCKET_FILL_FG, /*< desc="FG color fill" >*/
|
||||
PIKA_BUCKET_FILL_BG, /*< desc="BG color fill" >*/
|
||||
PIKA_BUCKET_FILL_PATTERN /*< desc="Pattern fill" >*/
|
||||
} PikaBucketFillMode;
|
||||
|
||||
|
||||
#define PIKA_TYPE_CHANNEL_BORDER_STYLE (pika_channel_border_style_get_type ())
|
||||
|
||||
GType pika_channel_border_style_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_CHANNEL_BORDER_STYLE_HARD, /*< desc="Hard" >*/
|
||||
PIKA_CHANNEL_BORDER_STYLE_SMOOTH, /*< desc="Smooth" >*/
|
||||
PIKA_CHANNEL_BORDER_STYLE_FEATHERED /*< desc="Feathered" >*/
|
||||
} PikaChannelBorderStyle;
|
||||
|
||||
|
||||
/* Note: when appending values here, don't forget to update
|
||||
* PikaColorFrame and other places use this enum to create combo
|
||||
* boxes.
|
||||
*/
|
||||
#define PIKA_TYPE_COLOR_PICK_MODE (pika_color_pick_mode_get_type ())
|
||||
|
||||
GType pika_color_pick_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_COLOR_PICK_MODE_PIXEL, /*< desc="Pixel" >*/
|
||||
PIKA_COLOR_PICK_MODE_RGB_PERCENT, /*< desc="RGB (%)" >*/
|
||||
PIKA_COLOR_PICK_MODE_RGB_U8, /*< desc="RGB (0..255)" >*/
|
||||
PIKA_COLOR_PICK_MODE_GRAYSCALE, /*< desc="Grayscale (%)">*/
|
||||
PIKA_COLOR_PICK_MODE_HSV, /*< desc="HSV" >*/
|
||||
PIKA_COLOR_PICK_MODE_LCH, /*< desc="CIE LCh" >*/
|
||||
PIKA_COLOR_PICK_MODE_LAB, /*< desc="CIE LAB" >*/
|
||||
PIKA_COLOR_PICK_MODE_CMYK, /*< desc="CMYK" >*/
|
||||
PIKA_COLOR_PICK_MODE_XYY, /*< desc="CIE xyY" >*/
|
||||
PIKA_COLOR_PICK_MODE_YUV, /*< desc="CIE Yu'v'" >*/
|
||||
|
||||
PIKA_COLOR_PICK_MODE_LAST = PIKA_COLOR_PICK_MODE_YUV /*< skip >*/
|
||||
} PikaColorPickMode;
|
||||
|
||||
|
||||
#define PIKA_TYPE_COLOR_PROFILE_POLICY (pika_color_profile_policy_get_type ())
|
||||
|
||||
GType pika_color_profile_policy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_COLOR_PROFILE_POLICY_ASK, /*< desc="Ask what to do" >*/
|
||||
PIKA_COLOR_PROFILE_POLICY_KEEP, /*< desc="Keep embedded profile" >*/
|
||||
PIKA_COLOR_PROFILE_POLICY_CONVERT_BUILTIN, /*< desc="Convert to built-in sRGB or grayscale profile" >*/
|
||||
PIKA_COLOR_PROFILE_POLICY_CONVERT_PREFERRED, /*< desc="Convert to preferred RGB or grayscale profile (defaulting to built-in)" >*/
|
||||
} PikaColorProfilePolicy;
|
||||
|
||||
|
||||
#define PIKA_TYPE_COMPONENT_MASK (pika_component_mask_get_type ())
|
||||
|
||||
GType pika_component_mask_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_COMPONENT_MASK_RED = 1 << 0,
|
||||
PIKA_COMPONENT_MASK_GREEN = 1 << 1,
|
||||
PIKA_COMPONENT_MASK_BLUE = 1 << 2,
|
||||
PIKA_COMPONENT_MASK_ALPHA = 1 << 3,
|
||||
|
||||
PIKA_COMPONENT_MASK_ALL = (PIKA_COMPONENT_MASK_RED |
|
||||
PIKA_COMPONENT_MASK_GREEN |
|
||||
PIKA_COMPONENT_MASK_BLUE |
|
||||
PIKA_COMPONENT_MASK_ALPHA)
|
||||
} PikaComponentMask;
|
||||
|
||||
|
||||
#define PIKA_TYPE_CONTAINER_POLICY (pika_container_policy_get_type ())
|
||||
|
||||
GType pika_container_policy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_CONTAINER_POLICY_STRONG,
|
||||
PIKA_CONTAINER_POLICY_WEAK
|
||||
} PikaContainerPolicy;
|
||||
|
||||
|
||||
#define PIKA_TYPE_CONVERT_DITHER_TYPE (pika_convert_dither_type_get_type ())
|
||||
|
||||
GType pika_convert_dither_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_CONVERT_DITHER_NONE, /*< desc="None" >*/
|
||||
PIKA_CONVERT_DITHER_FS, /*< desc="Floyd-Steinberg (normal)" >*/
|
||||
PIKA_CONVERT_DITHER_FS_LOWBLEED, /*< desc="Floyd-Steinberg (reduced color bleeding)" >*/
|
||||
PIKA_CONVERT_DITHER_FIXED, /*< desc="Positioned" >*/
|
||||
PIKA_CONVERT_DITHER_NODESTRUCT /*< pdb-skip, skip >*/
|
||||
} PikaConvertDitherType;
|
||||
|
||||
|
||||
#define PIKA_TYPE_CONVOLUTION_TYPE (pika_convolution_type_get_type ())
|
||||
|
||||
GType pika_convolution_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_NORMAL_CONVOL, /* Negative numbers truncated */
|
||||
PIKA_ABSOLUTE_CONVOL, /* Absolute value */
|
||||
PIKA_NEGATIVE_CONVOL /* add 127 to values */
|
||||
} PikaConvolutionType;
|
||||
|
||||
|
||||
#define PIKA_TYPE_CURVE_POINT_TYPE (pika_curve_point_type_get_type ())
|
||||
|
||||
GType pika_curve_point_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_CURVE_POINT_SMOOTH, /*< desc="Smooth" >*/
|
||||
PIKA_CURVE_POINT_CORNER /*< desc="Corner" >*/
|
||||
} PikaCurvePointType;
|
||||
|
||||
|
||||
#define PIKA_TYPE_CURVE_TYPE (pika_curve_type_get_type ())
|
||||
|
||||
GType pika_curve_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_CURVE_SMOOTH, /*< desc="Smooth" >*/
|
||||
PIKA_CURVE_FREE /*< desc="Freehand" >*/
|
||||
} PikaCurveType;
|
||||
|
||||
|
||||
#define PIKA_TYPE_DASH_PRESET (pika_dash_preset_get_type ())
|
||||
|
||||
GType pika_dash_preset_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_DASH_CUSTOM, /*< desc="Custom" >*/
|
||||
PIKA_DASH_LINE, /*< desc="Line" >*/
|
||||
PIKA_DASH_LONG_DASH, /*< desc="Long dashes" >*/
|
||||
PIKA_DASH_MEDIUM_DASH, /*< desc="Medium dashes" >*/
|
||||
PIKA_DASH_SHORT_DASH, /*< desc="Short dashes" >*/
|
||||
PIKA_DASH_SPARSE_DOTS, /*< desc="Sparse dots" >*/
|
||||
PIKA_DASH_NORMAL_DOTS, /*< desc="Normal dots" >*/
|
||||
PIKA_DASH_DENSE_DOTS, /*< desc="Dense dots" >*/
|
||||
PIKA_DASH_STIPPLES, /*< desc="Stipples" >*/
|
||||
PIKA_DASH_DASH_DOT, /*< desc="Dash, dot" >*/
|
||||
PIKA_DASH_DASH_DOT_DOT /*< desc="Dash, dot, dot" >*/
|
||||
} PikaDashPreset;
|
||||
|
||||
|
||||
#define PIKA_TYPE_DEBUG_POLICY (pika_debug_policy_get_type ())
|
||||
|
||||
GType pika_debug_policy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_DEBUG_POLICY_WARNING, /*< desc="Debug warnings, critical errors and crashes" >*/
|
||||
PIKA_DEBUG_POLICY_CRITICAL, /*< desc="Debug critical errors and crashes" >*/
|
||||
PIKA_DEBUG_POLICY_FATAL, /*< desc="Debug crashes only" >*/
|
||||
PIKA_DEBUG_POLICY_NEVER /*< desc="Never debug PIKA" >*/
|
||||
} PikaDebugPolicy;
|
||||
|
||||
|
||||
#define PIKA_TYPE_DIRTY_MASK (pika_dirty_mask_get_type ())
|
||||
|
||||
GType pika_dirty_mask_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_DIRTY_NONE = 0,
|
||||
|
||||
PIKA_DIRTY_IMAGE = 1 << 0,
|
||||
PIKA_DIRTY_IMAGE_SIZE = 1 << 1,
|
||||
PIKA_DIRTY_IMAGE_META = 1 << 2,
|
||||
PIKA_DIRTY_IMAGE_STRUCTURE = 1 << 3,
|
||||
PIKA_DIRTY_ITEM = 1 << 4,
|
||||
PIKA_DIRTY_ITEM_META = 1 << 5,
|
||||
PIKA_DIRTY_DRAWABLE = 1 << 6,
|
||||
PIKA_DIRTY_VECTORS = 1 << 7,
|
||||
PIKA_DIRTY_SELECTION = 1 << 8,
|
||||
PIKA_DIRTY_ACTIVE_DRAWABLE = 1 << 9,
|
||||
|
||||
PIKA_DIRTY_ALL = 0xffff
|
||||
} PikaDirtyMask;
|
||||
|
||||
|
||||
#define PIKA_TYPE_DYNAMICS_OUTPUT_TYPE (pika_dynamics_output_type_get_type ())
|
||||
|
||||
GType pika_dynamics_output_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_DYNAMICS_OUTPUT_OPACITY, /*< desc="Opacity" >*/
|
||||
PIKA_DYNAMICS_OUTPUT_SIZE, /*< desc="Size" >*/
|
||||
PIKA_DYNAMICS_OUTPUT_ANGLE, /*< desc="Angle" >*/
|
||||
PIKA_DYNAMICS_OUTPUT_COLOR, /*< desc="Color" >*/
|
||||
PIKA_DYNAMICS_OUTPUT_HARDNESS, /*< desc="Hardness" >*/
|
||||
PIKA_DYNAMICS_OUTPUT_FORCE, /*< desc="Force" >*/
|
||||
PIKA_DYNAMICS_OUTPUT_ASPECT_RATIO, /*< desc="Aspect ratio" >*/
|
||||
PIKA_DYNAMICS_OUTPUT_SPACING, /*< desc="Spacing" >*/
|
||||
PIKA_DYNAMICS_OUTPUT_RATE, /*< desc="Rate" >*/
|
||||
PIKA_DYNAMICS_OUTPUT_FLOW, /*< desc="Flow" >*/
|
||||
PIKA_DYNAMICS_OUTPUT_JITTER, /*< desc="Jitter" >*/
|
||||
} PikaDynamicsOutputType;
|
||||
|
||||
|
||||
#define PIKA_TYPE_CUSTOM_STYLE (pika_custom_style_get_type ())
|
||||
|
||||
GType pika_custom_style_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_CUSTOM_STYLE_SOLID_COLOR, /*< desc="Solid color" >*/
|
||||
PIKA_CUSTOM_STYLE_PATTERN /*< desc="Pattern" >*/
|
||||
} PikaCustomStyle;
|
||||
|
||||
#define PIKA_TYPE_FILL_STYLE (pika_fill_style_get_type ())
|
||||
|
||||
GType pika_fill_style_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_FILL_STYLE_FG_COLOR, /*< desc="Foreground color" >*/
|
||||
PIKA_FILL_STYLE_BG_COLOR, /*< desc="Background color" >*/
|
||||
PIKA_FILL_STYLE_PATTERN /*< desc="Pattern" >*/
|
||||
} PikaFillStyle;
|
||||
|
||||
|
||||
#define PIKA_TYPE_FILTER_REGION (pika_filter_region_get_type ())
|
||||
|
||||
GType pika_filter_region_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_FILTER_REGION_SELECTION, /*< desc="Use the selection as input" >*/
|
||||
PIKA_FILTER_REGION_DRAWABLE /*< desc="Use the entire layer as input" >*/
|
||||
} PikaFilterRegion;
|
||||
|
||||
|
||||
#define PIKA_TYPE_GRADIENT_COLOR (pika_gradient_color_get_type ())
|
||||
|
||||
GType pika_gradient_color_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_GRADIENT_COLOR_FIXED, /*< desc="Fixed" >*/
|
||||
PIKA_GRADIENT_COLOR_FOREGROUND, /*< desc="Foreground color", abbrev="FG" >*/
|
||||
PIKA_GRADIENT_COLOR_FOREGROUND_TRANSPARENT, /*< desc="Foreground color (transparent)", abbrev="FG (t)" >*/
|
||||
PIKA_GRADIENT_COLOR_BACKGROUND, /*< desc="Background color", abbrev="BG" >*/
|
||||
PIKA_GRADIENT_COLOR_BACKGROUND_TRANSPARENT /*< desc="Background color (transparent)", abbrev="BG (t)" >*/
|
||||
} PikaGradientColor;
|
||||
|
||||
|
||||
#define PIKA_TYPE_GRAVITY_TYPE (pika_gravity_type_get_type ())
|
||||
|
||||
GType pika_gravity_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_GRAVITY_NONE,
|
||||
PIKA_GRAVITY_NORTH_WEST,
|
||||
PIKA_GRAVITY_NORTH,
|
||||
PIKA_GRAVITY_NORTH_EAST,
|
||||
PIKA_GRAVITY_WEST,
|
||||
PIKA_GRAVITY_CENTER,
|
||||
PIKA_GRAVITY_EAST,
|
||||
PIKA_GRAVITY_SOUTH_WEST,
|
||||
PIKA_GRAVITY_SOUTH,
|
||||
PIKA_GRAVITY_SOUTH_EAST
|
||||
} PikaGravityType;
|
||||
|
||||
|
||||
#define PIKA_TYPE_GUIDE_STYLE (pika_guide_style_get_type ())
|
||||
|
||||
GType pika_guide_style_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_GUIDE_STYLE_NONE,
|
||||
PIKA_GUIDE_STYLE_NORMAL,
|
||||
PIKA_GUIDE_STYLE_MIRROR,
|
||||
PIKA_GUIDE_STYLE_MANDALA,
|
||||
PIKA_GUIDE_STYLE_SPLIT_VIEW
|
||||
} PikaGuideStyle;
|
||||
|
||||
|
||||
#define PIKA_TYPE_HISTOGRAM_CHANNEL (pika_histogram_channel_get_type ())
|
||||
|
||||
GType pika_histogram_channel_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_HISTOGRAM_VALUE = 0, /*< desc="Value" >*/
|
||||
PIKA_HISTOGRAM_RED = 1, /*< desc="Red" >*/
|
||||
PIKA_HISTOGRAM_GREEN = 2, /*< desc="Green" >*/
|
||||
PIKA_HISTOGRAM_BLUE = 3, /*< desc="Blue" >*/
|
||||
PIKA_HISTOGRAM_ALPHA = 4, /*< desc="Alpha" >*/
|
||||
PIKA_HISTOGRAM_LUMINANCE = 5, /*< desc="Luminance" >*/
|
||||
PIKA_HISTOGRAM_RGB = 6 /*< desc="RGB", pdb-skip >*/
|
||||
} PikaHistogramChannel;
|
||||
|
||||
|
||||
#define PIKA_TYPE_ITEM_SET (pika_item_set_get_type ())
|
||||
|
||||
GType pika_item_set_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_ITEM_SET_NONE, /*< desc="None" >*/
|
||||
PIKA_ITEM_SET_ALL, /*< desc="All layers" >*/
|
||||
PIKA_ITEM_SET_IMAGE_SIZED, /*< desc="Image-sized layers" >*/
|
||||
PIKA_ITEM_SET_VISIBLE, /*< desc="All visible layers" >*/
|
||||
} PikaItemSet;
|
||||
|
||||
|
||||
#define PIKA_TYPE_MATTING_ENGINE (pika_matting_engine_get_type ())
|
||||
|
||||
GType pika_matting_engine_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_MATTING_ENGINE_GLOBAL, /*< desc="Matting Global" >*/
|
||||
PIKA_MATTING_ENGINE_LEVIN, /*< desc="Matting Levin" >*/
|
||||
} PikaMattingEngine;
|
||||
|
||||
|
||||
#define PIKA_TYPE_MESSAGE_SEVERITY (pika_message_severity_get_type ())
|
||||
|
||||
GType pika_message_severity_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_MESSAGE_INFO, /*< desc="Message" >*/
|
||||
PIKA_MESSAGE_WARNING, /*< desc="Warning" >*/
|
||||
PIKA_MESSAGE_ERROR, /*< desc="Error" >*/
|
||||
PIKA_MESSAGE_BUG_WARNING, /*< desc="WARNING" >*/
|
||||
PIKA_MESSAGE_BUG_CRITICAL /*< desc="CRITICAL" >*/
|
||||
} PikaMessageSeverity;
|
||||
|
||||
|
||||
#define PIKA_TYPE_METADATA_ROTATION_POLICY (pika_metadata_rotation_policy_get_type ())
|
||||
|
||||
GType pika_metadata_rotation_policy_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_METADATA_ROTATION_POLICY_ASK, /*< desc="Ask what to do" >*/
|
||||
PIKA_METADATA_ROTATION_POLICY_KEEP, /*< desc="Discard metadata without rotating" >*/
|
||||
PIKA_METADATA_ROTATION_POLICY_ROTATE /*< desc="Rotate the image then discard metadata" >*/
|
||||
} PikaMetadataRotationPolicy;
|
||||
|
||||
|
||||
#define PIKA_TYPE_PASTE_TYPE (pika_paste_type_get_type ())
|
||||
|
||||
GType pika_paste_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_PASTE_TYPE_FLOATING,
|
||||
PIKA_PASTE_TYPE_FLOATING_IN_PLACE,
|
||||
PIKA_PASTE_TYPE_FLOATING_INTO,
|
||||
PIKA_PASTE_TYPE_FLOATING_INTO_IN_PLACE,
|
||||
PIKA_PASTE_TYPE_NEW_LAYER,
|
||||
PIKA_PASTE_TYPE_NEW_LAYER_IN_PLACE,
|
||||
PIKA_PASTE_TYPE_NEW_LAYER_OR_FLOATING,
|
||||
PIKA_PASTE_TYPE_NEW_LAYER_OR_FLOATING_IN_PLACE,
|
||||
PIKA_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING,
|
||||
PIKA_PASTE_TYPE_NEW_MERGED_LAYER_OR_FLOATING_IN_PLACE,
|
||||
} PikaPasteType;
|
||||
|
||||
|
||||
#define PIKA_TYPE_WIN32_POINTER_INPUT_API (pika_win32_pointer_input_api_get_type ())
|
||||
|
||||
GType pika_win32_pointer_input_api_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_WIN32_POINTER_INPUT_API_WINTAB, /*< desc="Wintab" >*/
|
||||
PIKA_WIN32_POINTER_INPUT_API_WINDOWS_INK /*< desc="Windows Ink" >*/
|
||||
} PikaWin32PointerInputAPI;
|
||||
|
||||
|
||||
#define PIKA_TYPE_THUMBNAIL_SIZE (pika_thumbnail_size_get_type ())
|
||||
|
||||
GType pika_thumbnail_size_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_THUMBNAIL_SIZE_NONE = 0, /*< desc="No thumbnails" >*/
|
||||
PIKA_THUMBNAIL_SIZE_NORMAL = 128, /*< desc="Normal (128x128)" >*/
|
||||
PIKA_THUMBNAIL_SIZE_LARGE = 256 /*< desc="Large (256x256)" >*/
|
||||
} PikaThumbnailSize;
|
||||
|
||||
|
||||
#define PIKA_TYPE_TRC_TYPE (pika_trc_type_get_type ())
|
||||
|
||||
GType pika_trc_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_TRC_LINEAR, /*< desc="Linear" >*/
|
||||
PIKA_TRC_NON_LINEAR, /*< desc="Non-Linear" >*/
|
||||
PIKA_TRC_PERCEPTUAL /*< desc="Perceptual" >*/
|
||||
} PikaTRCType;
|
||||
|
||||
|
||||
#define PIKA_TYPE_UNDO_EVENT (pika_undo_event_get_type ())
|
||||
|
||||
GType pika_undo_event_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_UNDO_EVENT_UNDO_PUSHED, /* a new undo has been added to the undo stack */
|
||||
PIKA_UNDO_EVENT_UNDO_EXPIRED, /* an undo has been freed from the undo stack */
|
||||
PIKA_UNDO_EVENT_REDO_EXPIRED, /* a redo has been freed from the redo stack */
|
||||
PIKA_UNDO_EVENT_UNDO, /* an undo has been executed */
|
||||
PIKA_UNDO_EVENT_REDO, /* a redo has been executed */
|
||||
PIKA_UNDO_EVENT_UNDO_FREE, /* all undo and redo info has been cleared */
|
||||
PIKA_UNDO_EVENT_UNDO_FREEZE, /* undo has been frozen */
|
||||
PIKA_UNDO_EVENT_UNDO_THAW /* undo has been thawn */
|
||||
} PikaUndoEvent;
|
||||
|
||||
|
||||
#define PIKA_TYPE_UNDO_MODE (pika_undo_mode_get_type ())
|
||||
|
||||
GType pika_undo_mode_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_UNDO_MODE_UNDO,
|
||||
PIKA_UNDO_MODE_REDO
|
||||
} PikaUndoMode;
|
||||
|
||||
|
||||
#define PIKA_TYPE_UNDO_TYPE (pika_undo_type_get_type ())
|
||||
|
||||
GType pika_undo_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
/* Type NO_UNDO_GROUP (0) is special - in the pikaimage structure it
|
||||
* means there is no undo group currently being added to.
|
||||
*/
|
||||
PIKA_UNDO_GROUP_NONE = 0, /*< desc="<<invalid>>" >*/
|
||||
|
||||
PIKA_UNDO_GROUP_FIRST = PIKA_UNDO_GROUP_NONE, /*< skip >*/
|
||||
|
||||
PIKA_UNDO_GROUP_IMAGE_SCALE, /*< desc="Scale image" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_RESIZE, /*< desc="Resize image" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_FLIP, /*< desc="Flip image" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_ROTATE, /*< desc="Rotate image" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_TRANSFORM, /*< desc="Transform image" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_CROP, /*< desc="Crop image" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_CONVERT, /*< desc="Convert image" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_ITEM_REMOVE, /*< desc="Remove item" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_ITEM_REORDER, /*< desc="Reorder item" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_LAYERS_MERGE, /*< desc="Merge layers" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE, /*< desc="Merge paths" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_QUICK_MASK, /*< desc="Quick Mask" >*/
|
||||
PIKA_UNDO_GROUP_IMAGE_GRID, /*< desc="Grid" >*/
|
||||
PIKA_UNDO_GROUP_GUIDE, /*< desc="Guide" >*/
|
||||
PIKA_UNDO_GROUP_SAMPLE_POINT, /*< desc="Sample Point" >*/
|
||||
PIKA_UNDO_GROUP_DRAWABLE, /*< desc="Layer/Channel" >*/
|
||||
PIKA_UNDO_GROUP_DRAWABLE_MOD, /*< desc="Layer/Channel modification" >*/
|
||||
PIKA_UNDO_GROUP_MASK, /*< desc="Selection mask" >*/
|
||||
PIKA_UNDO_GROUP_ITEM_VISIBILITY, /*< desc="Item visibility" >*/
|
||||
PIKA_UNDO_GROUP_ITEM_LOCK_CONTENTS, /*< desc="Lock/Unlock contents" >*/
|
||||
PIKA_UNDO_GROUP_ITEM_LOCK_POSITION, /*< desc="Lock/Unlock position" >*/
|
||||
PIKA_UNDO_GROUP_ITEM_LOCK_VISIBILITY, /*< desc="Lock/Unlock visibility" >*/
|
||||
PIKA_UNDO_GROUP_ITEM_PROPERTIES, /*< desc="Item properties" >*/
|
||||
PIKA_UNDO_GROUP_ITEM_DISPLACE, /*< desc="Move item" >*/
|
||||
PIKA_UNDO_GROUP_ITEM_SCALE, /*< desc="Scale item" >*/
|
||||
PIKA_UNDO_GROUP_ITEM_RESIZE, /*< desc="Resize item" >*/
|
||||
PIKA_UNDO_GROUP_LAYER_ADD, /*< desc="Add layer" >*/
|
||||
PIKA_UNDO_GROUP_LAYER_ADD_ALPHA, /*< desc="Add alpha channel" >*/
|
||||
PIKA_UNDO_GROUP_LAYER_ADD_MASK, /*< desc="Add layer mask" >*/
|
||||
PIKA_UNDO_GROUP_LAYER_APPLY_MASK, /*< desc="Apply layer mask" >*/
|
||||
PIKA_UNDO_GROUP_LAYER_REMOVE_ALPHA, /*< desc="Remove alpha channel" >*/
|
||||
PIKA_UNDO_GROUP_LAYER_LOCK_ALPHA, /*< desc="Lock/Unlock alpha channels" >*/
|
||||
PIKA_UNDO_GROUP_LAYER_OPACITY, /*< desc="Set layers opacity" >*/
|
||||
PIKA_UNDO_GROUP_LAYER_MODE, /*< desc="Set layers mode" >*/
|
||||
PIKA_UNDO_GROUP_CHANNEL_ADD, /*< desc="Add channels" >*/
|
||||
PIKA_UNDO_GROUP_FS_TO_LAYER, /*< desc="Floating selection to layer" >*/
|
||||
PIKA_UNDO_GROUP_FS_FLOAT, /*< desc="Float selection" >*/
|
||||
PIKA_UNDO_GROUP_FS_ANCHOR, /*< desc="Anchor floating selection" >*/
|
||||
PIKA_UNDO_GROUP_EDIT_PASTE, /*< desc="Paste" >*/
|
||||
PIKA_UNDO_GROUP_EDIT_CUT, /*< desc="Cut" >*/
|
||||
PIKA_UNDO_GROUP_TEXT, /*< desc="Text" >*/
|
||||
PIKA_UNDO_GROUP_TRANSFORM, /*< desc="Transform" >*/
|
||||
PIKA_UNDO_GROUP_PAINT, /*< desc="Paint" >*/
|
||||
PIKA_UNDO_GROUP_PARASITE_ATTACH, /*< desc="Attach parasite" >*/
|
||||
PIKA_UNDO_GROUP_PARASITE_REMOVE, /*< desc="Remove parasite" >*/
|
||||
PIKA_UNDO_GROUP_VECTORS_IMPORT, /*< desc="Import paths" >*/
|
||||
PIKA_UNDO_GROUP_MISC, /*< desc="Plug-In" >*/
|
||||
|
||||
PIKA_UNDO_GROUP_LAST = PIKA_UNDO_GROUP_MISC, /*< skip >*/
|
||||
|
||||
/* Undo types which actually do something */
|
||||
|
||||
PIKA_UNDO_IMAGE_TYPE, /*< desc="Image type" >*/
|
||||
PIKA_UNDO_IMAGE_PRECISION, /*< desc="Image precision" >*/
|
||||
PIKA_UNDO_IMAGE_SIZE, /*< desc="Image size" >*/
|
||||
PIKA_UNDO_IMAGE_RESOLUTION, /*< desc="Image resolution change" >*/
|
||||
PIKA_UNDO_IMAGE_GRID, /*< desc="Grid" >*/
|
||||
PIKA_UNDO_IMAGE_METADATA, /*< desc="Change metadata" >*/
|
||||
PIKA_UNDO_IMAGE_COLORMAP, /*< desc="Change indexed palette" >*/
|
||||
PIKA_UNDO_IMAGE_HIDDEN_PROFILE, /*< desc="Hide/Unhide color profile" >*/
|
||||
PIKA_UNDO_GUIDE, /*< desc="Guide" >*/
|
||||
PIKA_UNDO_SAMPLE_POINT, /*< desc="Sample Point" >*/
|
||||
PIKA_UNDO_DRAWABLE, /*< desc="Layer/Channel" >*/
|
||||
PIKA_UNDO_DRAWABLE_MOD, /*< desc="Layer/Channel modification" >*/
|
||||
PIKA_UNDO_DRAWABLE_FORMAT, /*< desc="Layer/Channel format" >*/
|
||||
PIKA_UNDO_MASK, /*< desc="Selection mask" >*/
|
||||
PIKA_UNDO_ITEM_REORDER, /*< desc="Reorder item" >*/
|
||||
PIKA_UNDO_ITEM_RENAME, /*< desc="Rename item" >*/
|
||||
PIKA_UNDO_ITEM_DISPLACE, /*< desc="Move item" >*/
|
||||
PIKA_UNDO_ITEM_VISIBILITY, /*< desc="Item visibility" >*/
|
||||
PIKA_UNDO_ITEM_COLOR_TAG, /*< desc="Item color tag" >*/
|
||||
PIKA_UNDO_ITEM_LOCK_CONTENT, /*< desc="Lock/Unlock content" >*/
|
||||
PIKA_UNDO_ITEM_LOCK_POSITION, /*< desc="Lock/Unlock position" >*/
|
||||
PIKA_UNDO_ITEM_LOCK_VISIBILITY, /*< desc="Lock/Unlock visibility" >*/
|
||||
PIKA_UNDO_LAYER_ADD, /*< desc="New layer" >*/
|
||||
PIKA_UNDO_LAYER_REMOVE, /*< desc="Delete layer" >*/
|
||||
PIKA_UNDO_LAYER_MODE, /*< desc="Set layer mode" >*/
|
||||
PIKA_UNDO_LAYER_OPACITY, /*< desc="Set layer opacity" >*/
|
||||
PIKA_UNDO_LAYER_LOCK_ALPHA, /*< desc="Lock/Unlock alpha channel" >*/
|
||||
PIKA_UNDO_GROUP_LAYER_SUSPEND_RESIZE, /*< desc="Suspend group layer resize" >*/
|
||||
PIKA_UNDO_GROUP_LAYER_RESUME_RESIZE, /*< desc="Resume group layer resize" >*/
|
||||
PIKA_UNDO_GROUP_LAYER_SUSPEND_MASK, /*< desc="Suspend group layer mask" >*/
|
||||
PIKA_UNDO_GROUP_LAYER_RESUME_MASK, /*< desc="Resume group layer mask" >*/
|
||||
PIKA_UNDO_GROUP_LAYER_START_TRANSFORM, /*< desc="Start transforming group layer" >*/
|
||||
PIKA_UNDO_GROUP_LAYER_END_TRANSFORM, /*< desc="End transforming group layer" >*/
|
||||
PIKA_UNDO_GROUP_LAYER_CONVERT, /*< desc="Convert group layer" >*/
|
||||
PIKA_UNDO_TEXT_LAYER, /*< desc="Text layer" >*/
|
||||
PIKA_UNDO_TEXT_LAYER_MODIFIED, /*< desc="Text layer modification" >*/
|
||||
PIKA_UNDO_TEXT_LAYER_CONVERT, /*< desc="Convert text layer" >*/
|
||||
PIKA_UNDO_LAYER_MASK_ADD, /*< desc="Add layer mask" >*/
|
||||
PIKA_UNDO_LAYER_MASK_REMOVE, /*< desc="Delete layer mask" >*/
|
||||
PIKA_UNDO_LAYER_MASK_APPLY, /*< desc="Apply layer mask" >*/
|
||||
PIKA_UNDO_LAYER_MASK_SHOW, /*< desc="Show layer mask" >*/
|
||||
PIKA_UNDO_CHANNEL_ADD, /*< desc="New channel" >*/
|
||||
PIKA_UNDO_CHANNEL_REMOVE, /*< desc="Delete channel" >*/
|
||||
PIKA_UNDO_CHANNEL_COLOR, /*< desc="Channel color" >*/
|
||||
PIKA_UNDO_VECTORS_ADD, /*< desc="New path" >*/
|
||||
PIKA_UNDO_VECTORS_REMOVE, /*< desc="Delete path" >*/
|
||||
PIKA_UNDO_VECTORS_MOD, /*< desc="Path modification" >*/
|
||||
PIKA_UNDO_FS_TO_LAYER, /*< desc="Floating selection to layer" >*/
|
||||
PIKA_UNDO_TRANSFORM_GRID, /*< desc="Transform grid" >*/
|
||||
PIKA_UNDO_PAINT, /*< desc="Paint" >*/
|
||||
PIKA_UNDO_INK, /*< desc="Ink" >*/
|
||||
PIKA_UNDO_FOREGROUND_SELECT, /*< desc="Select foreground" >*/
|
||||
PIKA_UNDO_PARASITE_ATTACH, /*< desc="Attach parasite" >*/
|
||||
PIKA_UNDO_PARASITE_REMOVE, /*< desc="Remove parasite" >*/
|
||||
|
||||
PIKA_UNDO_CANT /*< desc="Not undoable" >*/
|
||||
} PikaUndoType;
|
||||
|
||||
|
||||
#define PIKA_TYPE_VIEW_SIZE (pika_view_size_get_type ())
|
||||
|
||||
GType pika_view_size_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_VIEW_SIZE_TINY = 12, /*< desc="Tiny" >*/
|
||||
PIKA_VIEW_SIZE_EXTRA_SMALL = 16, /*< desc="Very small" >*/
|
||||
PIKA_VIEW_SIZE_SMALL = 24, /*< desc="Small" >*/
|
||||
PIKA_VIEW_SIZE_MEDIUM = 32, /*< desc="Medium" >*/
|
||||
PIKA_VIEW_SIZE_LARGE = 48, /*< desc="Large" >*/
|
||||
PIKA_VIEW_SIZE_EXTRA_LARGE = 64, /*< desc="Very large" >*/
|
||||
PIKA_VIEW_SIZE_HUGE = 96, /*< desc="Huge" >*/
|
||||
PIKA_VIEW_SIZE_ENORMOUS = 128, /*< desc="Enormous" >*/
|
||||
PIKA_VIEW_SIZE_GIGANTIC = 192 /*< desc="Gigantic" >*/
|
||||
} PikaViewSize;
|
||||
|
||||
|
||||
#define PIKA_TYPE_VIEW_TYPE (pika_view_type_get_type ())
|
||||
|
||||
GType pika_view_type_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_VIEW_TYPE_LIST, /*< desc="View as list" >*/
|
||||
PIKA_VIEW_TYPE_GRID /*< desc="View as grid" >*/
|
||||
} PikaViewType;
|
||||
|
||||
|
||||
#define PIKA_TYPE_SELECT_METHOD (pika_select_method_get_type ())
|
||||
|
||||
GType pika_select_method_get_type (void) G_GNUC_CONST;
|
||||
|
||||
typedef enum /*< pdb-skip >*/
|
||||
{
|
||||
PIKA_SELECT_PLAIN_TEXT, /*< desc="Selection by basic text search" >*/
|
||||
PIKA_SELECT_REGEX_PATTERN, /*< desc="Selection by regular expression search" >*/
|
||||
PIKA_SELECT_GLOB_PATTERN, /*< desc="Selection by glob pattern search" >*/
|
||||
} PikaSelectMethod;
|
||||
|
||||
/*
|
||||
* non-registered enums; register them if needed
|
||||
*/
|
||||
|
||||
|
||||
typedef enum /*< pdb-skip, skip >*/
|
||||
{
|
||||
PIKA_CONTEXT_PROP_FIRST = 2,
|
||||
|
||||
PIKA_CONTEXT_PROP_IMAGE = PIKA_CONTEXT_PROP_FIRST,
|
||||
PIKA_CONTEXT_PROP_DISPLAY = 3,
|
||||
PIKA_CONTEXT_PROP_TOOL = 4,
|
||||
PIKA_CONTEXT_PROP_PAINT_INFO = 5,
|
||||
PIKA_CONTEXT_PROP_FOREGROUND = 6,
|
||||
PIKA_CONTEXT_PROP_BACKGROUND = 7,
|
||||
PIKA_CONTEXT_PROP_OPACITY = 8,
|
||||
PIKA_CONTEXT_PROP_PAINT_MODE = 9,
|
||||
PIKA_CONTEXT_PROP_BRUSH = 10,
|
||||
PIKA_CONTEXT_PROP_DYNAMICS = 11,
|
||||
PIKA_CONTEXT_PROP_MYBRUSH = 12,
|
||||
PIKA_CONTEXT_PROP_PATTERN = 13,
|
||||
PIKA_CONTEXT_PROP_GRADIENT = 14,
|
||||
PIKA_CONTEXT_PROP_PALETTE = 15,
|
||||
PIKA_CONTEXT_PROP_FONT = 16,
|
||||
PIKA_CONTEXT_PROP_TOOL_PRESET = 17,
|
||||
PIKA_CONTEXT_PROP_BUFFER = 18,
|
||||
PIKA_CONTEXT_PROP_IMAGEFILE = 19,
|
||||
PIKA_CONTEXT_PROP_TEMPLATE = 20,
|
||||
|
||||
PIKA_CONTEXT_PROP_LAST = PIKA_CONTEXT_PROP_TEMPLATE
|
||||
} PikaContextPropType;
|
||||
|
||||
|
||||
typedef enum /*< pdb-skip, skip >*/
|
||||
{
|
||||
PIKA_CONTEXT_PROP_MASK_IMAGE = 1 << 2,
|
||||
PIKA_CONTEXT_PROP_MASK_DISPLAY = 1 << 3,
|
||||
PIKA_CONTEXT_PROP_MASK_TOOL = 1 << 4,
|
||||
PIKA_CONTEXT_PROP_MASK_PAINT_INFO = 1 << 5,
|
||||
PIKA_CONTEXT_PROP_MASK_FOREGROUND = 1 << 6,
|
||||
PIKA_CONTEXT_PROP_MASK_BACKGROUND = 1 << 7,
|
||||
PIKA_CONTEXT_PROP_MASK_OPACITY = 1 << 8,
|
||||
PIKA_CONTEXT_PROP_MASK_PAINT_MODE = 1 << 9,
|
||||
PIKA_CONTEXT_PROP_MASK_BRUSH = 1 << 10,
|
||||
PIKA_CONTEXT_PROP_MASK_DYNAMICS = 1 << 11,
|
||||
PIKA_CONTEXT_PROP_MASK_MYBRUSH = 1 << 12,
|
||||
PIKA_CONTEXT_PROP_MASK_PATTERN = 1 << 13,
|
||||
PIKA_CONTEXT_PROP_MASK_GRADIENT = 1 << 14,
|
||||
PIKA_CONTEXT_PROP_MASK_PALETTE = 1 << 15,
|
||||
PIKA_CONTEXT_PROP_MASK_FONT = 1 << 16,
|
||||
PIKA_CONTEXT_PROP_MASK_TOOL_PRESET = 1 << 17,
|
||||
PIKA_CONTEXT_PROP_MASK_BUFFER = 1 << 18,
|
||||
PIKA_CONTEXT_PROP_MASK_IMAGEFILE = 1 << 19,
|
||||
PIKA_CONTEXT_PROP_MASK_TEMPLATE = 1 << 20,
|
||||
|
||||
/* aliases */
|
||||
PIKA_CONTEXT_PROP_MASK_PAINT = (PIKA_CONTEXT_PROP_MASK_FOREGROUND |
|
||||
PIKA_CONTEXT_PROP_MASK_BACKGROUND |
|
||||
PIKA_CONTEXT_PROP_MASK_OPACITY |
|
||||
PIKA_CONTEXT_PROP_MASK_PAINT_MODE |
|
||||
PIKA_CONTEXT_PROP_MASK_BRUSH |
|
||||
PIKA_CONTEXT_PROP_MASK_DYNAMICS |
|
||||
PIKA_CONTEXT_PROP_MASK_PATTERN |
|
||||
PIKA_CONTEXT_PROP_MASK_GRADIENT),
|
||||
|
||||
PIKA_CONTEXT_PROP_MASK_ALL = (PIKA_CONTEXT_PROP_MASK_IMAGE |
|
||||
PIKA_CONTEXT_PROP_MASK_DISPLAY |
|
||||
PIKA_CONTEXT_PROP_MASK_TOOL |
|
||||
PIKA_CONTEXT_PROP_MASK_PAINT_INFO |
|
||||
PIKA_CONTEXT_PROP_MASK_MYBRUSH |
|
||||
PIKA_CONTEXT_PROP_MASK_PALETTE |
|
||||
PIKA_CONTEXT_PROP_MASK_FONT |
|
||||
PIKA_CONTEXT_PROP_MASK_TOOL_PRESET |
|
||||
PIKA_CONTEXT_PROP_MASK_BUFFER |
|
||||
PIKA_CONTEXT_PROP_MASK_IMAGEFILE |
|
||||
PIKA_CONTEXT_PROP_MASK_TEMPLATE |
|
||||
PIKA_CONTEXT_PROP_MASK_PAINT)
|
||||
} PikaContextPropMask;
|
||||
|
||||
|
||||
typedef enum /*< pdb-skip, skip >*/
|
||||
{
|
||||
PIKA_IMAGE_SCALE_OK,
|
||||
PIKA_IMAGE_SCALE_TOO_SMALL,
|
||||
PIKA_IMAGE_SCALE_TOO_BIG
|
||||
} PikaImageScaleCheckType;
|
||||
|
||||
|
||||
typedef enum /*< pdb-skip, skip >*/
|
||||
{
|
||||
PIKA_ITEM_TYPE_LAYERS = 1 << 0,
|
||||
PIKA_ITEM_TYPE_CHANNELS = 1 << 1,
|
||||
PIKA_ITEM_TYPE_VECTORS = 1 << 2,
|
||||
|
||||
PIKA_ITEM_TYPE_ALL = (PIKA_ITEM_TYPE_LAYERS |
|
||||
PIKA_ITEM_TYPE_CHANNELS |
|
||||
PIKA_ITEM_TYPE_VECTORS)
|
||||
} PikaItemTypeMask;
|
||||
|
||||
|
||||
#endif /* __CORE_ENUMS_H__ */
|
||||
327
app/core/core-types.h
Normal file
327
app/core/core-types.h
Normal file
@ -0,0 +1,327 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __CORE_TYPES_H__
|
||||
#define __CORE_TYPES_H__
|
||||
|
||||
|
||||
#include "libpikabase/pikabasetypes.h"
|
||||
#include "libpikamath/pikamathtypes.h"
|
||||
#include "libpikacolor/pikacolortypes.h"
|
||||
#include "libpikamodule/pikamoduletypes.h"
|
||||
#include "libpikathumb/pikathumb-types.h"
|
||||
|
||||
#include "config/config-types.h"
|
||||
|
||||
#include "core/core-enums.h"
|
||||
|
||||
|
||||
/* former base/ defines */
|
||||
|
||||
#define MAX_CHANNELS 4
|
||||
|
||||
#define RED 0
|
||||
#define GREEN 1
|
||||
#define BLUE 2
|
||||
#define ALPHA 3
|
||||
|
||||
#define GRAY 0
|
||||
#define ALPHA_G 1
|
||||
|
||||
#define INDEXED 0
|
||||
#define ALPHA_I 1
|
||||
|
||||
|
||||
/* defines */
|
||||
|
||||
#define PIKA_COORDS_MIN_PRESSURE 0.0
|
||||
#define PIKA_COORDS_MAX_PRESSURE 1.0
|
||||
#define PIKA_COORDS_DEFAULT_PRESSURE 1.0
|
||||
|
||||
#define PIKA_COORDS_MIN_TILT -1.0
|
||||
#define PIKA_COORDS_MAX_TILT 1.0
|
||||
#define PIKA_COORDS_DEFAULT_TILT 0.0
|
||||
|
||||
#define PIKA_COORDS_MIN_WHEEL 0.0
|
||||
#define PIKA_COORDS_MAX_WHEEL 1.0
|
||||
#define PIKA_COORDS_DEFAULT_WHEEL 0.5
|
||||
|
||||
#define PIKA_COORDS_DEFAULT_DISTANCE 0.0
|
||||
#define PIKA_COORDS_DEFAULT_ROTATION 0.0
|
||||
#define PIKA_COORDS_DEFAULT_SLIDER 0.0
|
||||
|
||||
#define PIKA_COORDS_DEFAULT_VELOCITY 0.0
|
||||
|
||||
#define PIKA_COORDS_DEFAULT_DIRECTION 0.0
|
||||
|
||||
#define PIKA_COORDS_DEFAULT_XSCALE 1.0
|
||||
#define PIKA_COORDS_DEFAULT_YSCALE 1.0
|
||||
|
||||
#define PIKA_COORDS_DEFAULT_VALUES { 0.0, 0.0, \
|
||||
PIKA_COORDS_DEFAULT_PRESSURE, \
|
||||
PIKA_COORDS_DEFAULT_TILT, \
|
||||
PIKA_COORDS_DEFAULT_TILT, \
|
||||
PIKA_COORDS_DEFAULT_WHEEL, \
|
||||
PIKA_COORDS_DEFAULT_DISTANCE, \
|
||||
PIKA_COORDS_DEFAULT_ROTATION, \
|
||||
PIKA_COORDS_DEFAULT_SLIDER, \
|
||||
PIKA_COORDS_DEFAULT_VELOCITY, \
|
||||
PIKA_COORDS_DEFAULT_DIRECTION,\
|
||||
PIKA_COORDS_DEFAULT_XSCALE, \
|
||||
PIKA_COORDS_DEFAULT_YSCALE }
|
||||
|
||||
|
||||
/* base classes */
|
||||
|
||||
typedef struct _PikaObject PikaObject;
|
||||
typedef struct _PikaViewable PikaViewable;
|
||||
typedef struct _PikaFilter PikaFilter;
|
||||
typedef struct _PikaItem PikaItem;
|
||||
typedef struct _PikaAuxItem PikaAuxItem;
|
||||
|
||||
typedef struct _Pika Pika;
|
||||
typedef struct _PikaImage PikaImage;
|
||||
|
||||
typedef struct _PikaDisplay PikaDisplay;
|
||||
|
||||
|
||||
/* containers */
|
||||
|
||||
typedef struct _PikaContainer PikaContainer;
|
||||
typedef struct _PikaList PikaList;
|
||||
typedef struct _PikaDocumentList PikaDocumentList;
|
||||
typedef struct _PikaDrawableStack PikaDrawableStack;
|
||||
typedef struct _PikaFilteredContainer PikaFilteredContainer;
|
||||
typedef struct _PikaFilterStack PikaFilterStack;
|
||||
typedef struct _PikaItemList PikaItemList;
|
||||
typedef struct _PikaItemStack PikaItemStack;
|
||||
typedef struct _PikaLayerStack PikaLayerStack;
|
||||
typedef struct _PikaTaggedContainer PikaTaggedContainer;
|
||||
typedef struct _PikaTreeProxy PikaTreeProxy;
|
||||
|
||||
|
||||
/* not really a container */
|
||||
|
||||
typedef struct _PikaItemTree PikaItemTree;
|
||||
|
||||
|
||||
/* context objects */
|
||||
|
||||
typedef struct _PikaContext PikaContext;
|
||||
typedef struct _PikaFillOptions PikaFillOptions;
|
||||
typedef struct _PikaStrokeOptions PikaStrokeOptions;
|
||||
typedef struct _PikaToolOptions PikaToolOptions;
|
||||
|
||||
|
||||
/* info objects */
|
||||
|
||||
typedef struct _PikaPaintInfo PikaPaintInfo;
|
||||
typedef struct _PikaToolGroup PikaToolGroup;
|
||||
typedef struct _PikaToolInfo PikaToolInfo;
|
||||
typedef struct _PikaToolItem PikaToolItem;
|
||||
|
||||
|
||||
/* data objects */
|
||||
|
||||
typedef struct _PikaDataFactory PikaDataFactory;
|
||||
typedef struct _PikaDataLoaderFactory PikaDataLoaderFactory;
|
||||
typedef struct _PikaResource PikaResource;
|
||||
typedef struct _PikaData PikaData;
|
||||
typedef struct _PikaBrush PikaBrush;
|
||||
typedef struct _PikaBrushCache PikaBrushCache;
|
||||
typedef struct _PikaBrushClipboard PikaBrushClipboard;
|
||||
typedef struct _PikaBrushGenerated PikaBrushGenerated;
|
||||
typedef struct _PikaBrushPipe PikaBrushPipe;
|
||||
typedef struct _PikaCurve PikaCurve;
|
||||
typedef struct _PikaDynamics PikaDynamics;
|
||||
typedef struct _PikaDynamicsOutput PikaDynamicsOutput;
|
||||
typedef struct _PikaGradient PikaGradient;
|
||||
typedef struct _PikaMybrush PikaMybrush;
|
||||
typedef struct _PikaPalette PikaPalette;
|
||||
typedef struct _PikaPaletteMru PikaPaletteMru;
|
||||
typedef struct _PikaPattern PikaPattern;
|
||||
typedef struct _PikaPatternClipboard PikaPatternClipboard;
|
||||
typedef struct _PikaToolPreset PikaToolPreset;
|
||||
typedef struct _PikaTagCache PikaTagCache;
|
||||
|
||||
|
||||
/* drawable objects */
|
||||
|
||||
typedef struct _PikaDrawable PikaDrawable;
|
||||
typedef struct _PikaChannel PikaChannel;
|
||||
typedef struct _PikaLayerMask PikaLayerMask;
|
||||
typedef struct _PikaSelection PikaSelection;
|
||||
typedef struct _PikaLayer PikaLayer;
|
||||
typedef struct _PikaGroupLayer PikaGroupLayer;
|
||||
|
||||
|
||||
/* auxiliary image items */
|
||||
|
||||
typedef struct _PikaGuide PikaGuide;
|
||||
typedef struct _PikaSamplePoint PikaSamplePoint;
|
||||
|
||||
|
||||
/* undo objects */
|
||||
|
||||
typedef struct _PikaUndo PikaUndo;
|
||||
typedef struct _PikaUndoStack PikaUndoStack;
|
||||
typedef struct _PikaUndoAccumulator PikaUndoAccumulator;
|
||||
|
||||
|
||||
/* Symmetry transformations */
|
||||
|
||||
typedef struct _PikaSymmetry PikaSymmetry;
|
||||
typedef struct _PikaMirror PikaMirror;
|
||||
typedef struct _PikaTiling PikaTiling;
|
||||
typedef struct _PikaMandala PikaMandala;
|
||||
|
||||
|
||||
/* misc objects */
|
||||
|
||||
typedef struct _PikaAsync PikaAsync;
|
||||
typedef struct _PikaAsyncSet PikaAsyncSet;
|
||||
typedef struct _PikaBuffer PikaBuffer;
|
||||
typedef struct _PikaDrawableFilter PikaDrawableFilter;
|
||||
typedef struct _PikaEnvironTable PikaEnvironTable;
|
||||
typedef struct _PikaExtension PikaExtension;
|
||||
typedef struct _PikaExtensionManager PikaExtensionManager;
|
||||
typedef struct _PikaHistogram PikaHistogram;
|
||||
typedef struct _PikaIdTable PikaIdTable;
|
||||
typedef struct _PikaImagefile PikaImagefile;
|
||||
typedef struct _PikaImageProxy PikaImageProxy;
|
||||
typedef struct _PikaInterpreterDB PikaInterpreterDB;
|
||||
typedef struct _PikaLineArt PikaLineArt;
|
||||
typedef struct _PikaObjectQueue PikaObjectQueue;
|
||||
typedef struct _PikaParasiteList PikaParasiteList;
|
||||
typedef struct _PikaPdbProgress PikaPdbProgress;
|
||||
typedef struct _PikaProjection PikaProjection;
|
||||
typedef struct _PikaSettings PikaSettings;
|
||||
typedef struct _PikaSubProgress PikaSubProgress;
|
||||
typedef struct _PikaTag PikaTag;
|
||||
typedef struct _PikaTreeHandler PikaTreeHandler;
|
||||
typedef struct _PikaTriviallyCancelableWaitable PikaTriviallyCancelableWaitable;
|
||||
typedef struct _PikaUncancelableWaitable PikaUncancelableWaitable;
|
||||
|
||||
|
||||
/* interfaces */
|
||||
|
||||
typedef struct _PikaCancelable PikaCancelable; /* dummy typedef */
|
||||
typedef struct _PikaPickable PikaPickable; /* dummy typedef */
|
||||
typedef struct _PikaProgress PikaProgress; /* dummy typedef */
|
||||
typedef struct _PikaProjectable PikaProjectable; /* dummy typedef */
|
||||
typedef struct _PikaTagged PikaTagged; /* dummy typedef */
|
||||
typedef struct _PikaWaitable PikaWaitable; /* dummy typedef */
|
||||
|
||||
|
||||
/* non-object types */
|
||||
|
||||
typedef struct _PikaBacktrace PikaBacktrace;
|
||||
typedef struct _PikaBoundSeg PikaBoundSeg;
|
||||
typedef struct _PikaChunkIterator PikaChunkIterator;
|
||||
typedef struct _PikaCoords PikaCoords;
|
||||
typedef struct _PikaGradientSegment PikaGradientSegment;
|
||||
typedef struct _PikaPaletteEntry PikaPaletteEntry;
|
||||
typedef struct _PikaScanConvert PikaScanConvert;
|
||||
typedef struct _PikaTempBuf PikaTempBuf;
|
||||
typedef guint32 PikaTattoo;
|
||||
|
||||
/* The following hack is made so that we can reuse the definition
|
||||
* the cairo definition of cairo_path_t without having to translate
|
||||
* between our own version of a bezier description and cairos version.
|
||||
*
|
||||
* to avoid having to include <cairo.h> in each and every file
|
||||
* including this file we only use the "real" definition when cairo.h
|
||||
* already has been included and use something else.
|
||||
*
|
||||
* Note that if you really want to work with PikaBezierDesc (except just
|
||||
* passing pointers to it around) you also need to include <cairo.h>.
|
||||
*/
|
||||
#ifdef CAIRO_VERSION
|
||||
typedef cairo_path_t PikaBezierDesc;
|
||||
#else
|
||||
typedef void * PikaBezierDesc;
|
||||
#endif
|
||||
|
||||
|
||||
/* functions */
|
||||
|
||||
typedef void (* PikaInitStatusFunc) (const gchar *text1,
|
||||
const gchar *text2,
|
||||
gdouble percentage);
|
||||
|
||||
typedef gboolean (* PikaObjectFilterFunc) (PikaObject *object,
|
||||
gpointer user_data);
|
||||
|
||||
typedef gint64 (* PikaMemsizeFunc) (gpointer instance,
|
||||
gint64 *gui_size);
|
||||
|
||||
typedef void (* PikaRunAsyncFunc) (PikaAsync *async,
|
||||
gpointer user_data);
|
||||
|
||||
|
||||
/* structs */
|
||||
|
||||
struct _PikaCoords
|
||||
{
|
||||
/* axes as reported by the device */
|
||||
gdouble x;
|
||||
gdouble y;
|
||||
gdouble pressure;
|
||||
gdouble xtilt;
|
||||
gdouble ytilt;
|
||||
gdouble wheel;
|
||||
gdouble distance;
|
||||
gdouble rotation;
|
||||
gdouble slider;
|
||||
|
||||
/* synthetic axes */
|
||||
gdouble velocity;
|
||||
gdouble direction;
|
||||
|
||||
/* view transform */
|
||||
gdouble xscale; /* the view scale */
|
||||
gdouble yscale;
|
||||
gdouble angle; /* the view rotation angle */
|
||||
gboolean reflect; /* whether the view is reflected */
|
||||
};
|
||||
|
||||
/* temp hack as replacement for GdkSegment */
|
||||
|
||||
typedef struct _PikaSegment PikaSegment;
|
||||
|
||||
struct _PikaSegment
|
||||
{
|
||||
gint x1;
|
||||
gint y1;
|
||||
gint x2;
|
||||
gint y2;
|
||||
};
|
||||
|
||||
|
||||
#include "gegl/pika-gegl-types.h"
|
||||
#include "paint/paint-types.h"
|
||||
#include "text/text-types.h"
|
||||
#include "vectors/vectors-types.h"
|
||||
#include "pdb/pdb-types.h"
|
||||
#include "plug-in/plug-in-types.h"
|
||||
|
||||
|
||||
#endif /* __CORE_TYPES_H__ */
|
||||
280
app/core/meson.build
Normal file
280
app/core/meson.build
Normal file
@ -0,0 +1,280 @@
|
||||
stamp_core_enums = custom_target('stamp-core-enums.h',
|
||||
input : [
|
||||
files(
|
||||
'core-enums.h'
|
||||
),
|
||||
],
|
||||
output: [ 'stamp-core-enums.h', ],
|
||||
command: [
|
||||
mkenums_wrap, perl,
|
||||
meson.project_source_root(), meson.current_source_dir(),
|
||||
meson.current_build_dir(),
|
||||
'core-',
|
||||
'#include <gio/gio.h>\n' +
|
||||
'#include "libpikabase/pikabase.h"\n',
|
||||
'#include "pika-intl.h"'
|
||||
],
|
||||
build_by_default: true
|
||||
)
|
||||
|
||||
appcoremarshal = gnome.genmarshal('pikamarshal',
|
||||
prefix: 'pika_marshal',
|
||||
sources: 'pikamarshal.list',
|
||||
install_header: false,
|
||||
)
|
||||
|
||||
libappcore_sources = [
|
||||
'pika-atomic.c',
|
||||
'pika-batch.c',
|
||||
'pika-cairo.c',
|
||||
'pika-contexts.c',
|
||||
'pika-data-factories.c',
|
||||
'pika-edit.c',
|
||||
'pika-filter-history.c',
|
||||
'pika-gradients.c',
|
||||
'pika-gui.c',
|
||||
'pika-internal-data.c',
|
||||
'pika-memsize.c',
|
||||
'pika-modules.c',
|
||||
'pika-palettes.c',
|
||||
'pika-parallel.cc',
|
||||
'pika-parasites.c',
|
||||
'pika-spawn.c',
|
||||
'pika-tags.c',
|
||||
'pika-templates.c',
|
||||
'pika-transform-resize.c',
|
||||
'pika-transform-3d-utils.c',
|
||||
'pika-transform-utils.c',
|
||||
'pika-units.c',
|
||||
'pika-user-install.c',
|
||||
'pika-utils.c',
|
||||
'pika.c',
|
||||
'pikaasync.c',
|
||||
'pikaasyncset.c',
|
||||
'pikaauxitem.c',
|
||||
'pikaauxitemundo.c',
|
||||
'pikabacktrace-linux.c',
|
||||
'pikabacktrace-none.c',
|
||||
'pikabacktrace-windows.c',
|
||||
'pikabezierdesc.c',
|
||||
'pikaboundary.c',
|
||||
'pikabrush-boundary.c',
|
||||
'pikabrush-load.c',
|
||||
'pikabrush-mipmap.cc',
|
||||
'pikabrush-save.c',
|
||||
'pikabrush-transform.cc',
|
||||
'pikabrush.c',
|
||||
'pikabrushcache.c',
|
||||
'pikabrushclipboard.c',
|
||||
'pikabrushgenerated-load.c',
|
||||
'pikabrushgenerated-save.c',
|
||||
'pikabrushgenerated.c',
|
||||
'pikabrushpipe-load.c',
|
||||
'pikabrushpipe-save.c',
|
||||
'pikabrushpipe.c',
|
||||
'pikabuffer.c',
|
||||
'pikacancelable.c',
|
||||
'pikachannel-combine.c',
|
||||
'pikachannel-select.c',
|
||||
'pikachannel.c',
|
||||
'pikachannelpropundo.c',
|
||||
'pikachannelundo.c',
|
||||
'pikachunkiterator.c',
|
||||
'pikacontainer-filter.c',
|
||||
'pikacontainer.c',
|
||||
'pikacontext.c',
|
||||
'pikacoords-interpolate.c',
|
||||
'pikacoords.c',
|
||||
'pikacurve-load.c',
|
||||
'pikacurve-map.c',
|
||||
'pikacurve-save.c',
|
||||
'pikacurve.c',
|
||||
'pikadashpattern.c',
|
||||
'pikadata.c',
|
||||
'pikadatafactory.c',
|
||||
'pikadataloaderfactory.c',
|
||||
'pikadisplay.c',
|
||||
'pikadocumentlist.c',
|
||||
'pikadrawable-bucket-fill.c',
|
||||
'pikadrawable-combine.c',
|
||||
'pikadrawable-edit.c',
|
||||
'pikadrawable-equalize.c',
|
||||
'pikadrawable-fill.c',
|
||||
'pikadrawable-filters.c',
|
||||
'pikadrawable-floating-selection.c',
|
||||
'pikadrawable-foreground-extract.c',
|
||||
'pikadrawable-gradient.c',
|
||||
'pikadrawable-histogram.c',
|
||||
'pikadrawable-levels.c',
|
||||
'pikadrawable-offset.c',
|
||||
'pikadrawable-operation.c',
|
||||
'pikadrawable-preview.c',
|
||||
'pikadrawable-shadow.c',
|
||||
'pikadrawable-stroke.c',
|
||||
'pikadrawable-transform.c',
|
||||
'pikadrawable.c',
|
||||
'pikadrawablefilter.c',
|
||||
'pikadrawablemodundo.c',
|
||||
'pikadrawablepropundo.c',
|
||||
'pikadrawablestack.c',
|
||||
'pikadrawableundo.c',
|
||||
'pikadynamics-load.c',
|
||||
'pikadynamics-save.c',
|
||||
'pikadynamics.c',
|
||||
'pikadynamicsoutput.c',
|
||||
'pikaerror.c',
|
||||
'pikaextension-error.c',
|
||||
'pikaextension.c',
|
||||
'pikaextensionmanager.c',
|
||||
'pikafilloptions.c',
|
||||
'pikafilter.c',
|
||||
'pikafilteredcontainer.c',
|
||||
'pikafilterstack.c',
|
||||
'pikafloatingselectionundo.c',
|
||||
'pikagradient-load.c',
|
||||
'pikagradient-save.c',
|
||||
'pikagradient.c',
|
||||
'pikagrid.c',
|
||||
'pikagrouplayer.c',
|
||||
'pikagrouplayerundo.c',
|
||||
'pikaguide.c',
|
||||
'pikaguideundo.c',
|
||||
'pikahistogram.c',
|
||||
'pikaidtable.c',
|
||||
'pikaimage-arrange.c',
|
||||
'pikaimage-color-profile.c',
|
||||
'pikaimage-colormap.c',
|
||||
'pikaimage-convert-indexed.c',
|
||||
'pikaimage-convert-precision.c',
|
||||
'pikaimage-convert-type.c',
|
||||
'pikaimage-crop.c',
|
||||
'pikaimage-duplicate.c',
|
||||
'pikaimage-flip.c',
|
||||
'pikaimage-grid.c',
|
||||
'pikaimage-guides.c',
|
||||
'pikaimage-item-list.c',
|
||||
'pikaimage-merge.c',
|
||||
'pikaimage-metadata.c',
|
||||
'pikaimage-new.c',
|
||||
'pikaimage-pick-color.c',
|
||||
'pikaimage-pick-item.c',
|
||||
'pikaimage-preview.c',
|
||||
'pikaimage-quick-mask.c',
|
||||
'pikaimage-resize.c',
|
||||
'pikaimage-rotate.c',
|
||||
'pikaimage-sample-points.c',
|
||||
'pikaimage-scale.c',
|
||||
'pikaimage-snap.c',
|
||||
'pikaimage-symmetry.c',
|
||||
'pikaimage-transform.c',
|
||||
'pikaimage-undo-push.c',
|
||||
'pikaimage-undo.c',
|
||||
'pikaimage.c',
|
||||
'pikaimagefile.c',
|
||||
'pikaimageproxy.c',
|
||||
'pikaimageundo.c',
|
||||
'pikaitem-exclusive.c',
|
||||
'pikaitem-preview.c',
|
||||
'pikaitem.c',
|
||||
'pikaitemlist.c',
|
||||
'pikaitempropundo.c',
|
||||
'pikaitemstack.c',
|
||||
'pikaitemtree.c',
|
||||
'pikaitemundo.c',
|
||||
'pikalayer-floating-selection.c',
|
||||
'pikalayer-new.c',
|
||||
'pikalayer.c',
|
||||
'pikalayermask.c',
|
||||
'pikalayermaskpropundo.c',
|
||||
'pikalayermaskundo.c',
|
||||
'pikalayerpropundo.c',
|
||||
'pikalayerstack.c',
|
||||
'pikalayerundo.c',
|
||||
'pikalineart.c',
|
||||
'pikalist.c',
|
||||
'pikamaskundo.c',
|
||||
'pikamybrush-load.c',
|
||||
'pikamybrush.c',
|
||||
'pikaobject.c',
|
||||
'pikaobjectqueue.c',
|
||||
'pikapaintinfo.c',
|
||||
'pikapalette-import.c',
|
||||
'pikapalette-load.c',
|
||||
'pikapalette-save.c',
|
||||
'pikapalette.c',
|
||||
'pikapalettemru.c',
|
||||
'pikaparamspecs-desc.c',
|
||||
'pikaparamspecs.c',
|
||||
'pikaparasitelist.c',
|
||||
'pikapattern-load.c',
|
||||
'pikapattern-save.c',
|
||||
'pikapattern.c',
|
||||
'pikapatternclipboard.c',
|
||||
'pikapdbprogress.c',
|
||||
'pikapickable-auto-shrink.c',
|
||||
'pikapickable-contiguous-region.cc',
|
||||
'pikapickable.c',
|
||||
'pikaprogress.c',
|
||||
'pikaprojectable.c',
|
||||
'pikaprojection.c',
|
||||
'pikaresource.c',
|
||||
'pikasamplepoint.c',
|
||||
'pikasamplepointundo.c',
|
||||
'pikascanconvert.c',
|
||||
'pikaselection.c',
|
||||
'pikasettings.c',
|
||||
'pikastrokeoptions.c',
|
||||
'pikasubprogress.c',
|
||||
'pikasymmetry-mandala.c',
|
||||
'pikasymmetry-mirror.c',
|
||||
'pikasymmetry-tiling.c',
|
||||
'pikasymmetry.c',
|
||||
'pikatag.c',
|
||||
'pikatagcache.c',
|
||||
'pikatagged.c',
|
||||
'pikataggedcontainer.c',
|
||||
'pikatempbuf.c',
|
||||
'pikatemplate.c',
|
||||
'pikatilehandlerprojectable.c',
|
||||
'pikatoolgroup.c',
|
||||
'pikatoolinfo.c',
|
||||
'pikatoolitem.c',
|
||||
'pikatooloptions.c',
|
||||
'pikatoolpreset-load.c',
|
||||
'pikatoolpreset-save.c',
|
||||
'pikatoolpreset.c',
|
||||
'pikatreehandler.c',
|
||||
'pikatreeproxy.c',
|
||||
'pikatriviallycancelablewaitable.c',
|
||||
'pikauncancelablewaitable.c',
|
||||
'pikaundo.c',
|
||||
'pikaundostack.c',
|
||||
'pikaunit.c',
|
||||
'pikaviewable.c',
|
||||
'pikawaitable.c',
|
||||
|
||||
'core-enums.c',
|
||||
stamp_core_enums,
|
||||
|
||||
appcoremarshal,
|
||||
cursors_sources,
|
||||
pickers_sources,
|
||||
icons_core_sources,
|
||||
]
|
||||
|
||||
libappcore = static_library('appcore',
|
||||
libappcore_sources,
|
||||
include_directories: [ rootInclude, rootAppInclude, ],
|
||||
c_args: '-DG_LOG_DOMAIN="Pika-Core"',
|
||||
dependencies: [
|
||||
cairo,
|
||||
gegl,
|
||||
gdk_pixbuf,
|
||||
libmypaint,
|
||||
gexiv2,
|
||||
appstream_glib,
|
||||
math,
|
||||
dl,
|
||||
libunwind,
|
||||
],
|
||||
)
|
||||
99
app/core/pika-atomic.c
Normal file
99
app/core/pika-atomic.c
Normal file
@ -0,0 +1,99 @@
|
||||
/* 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
|
||||
*
|
||||
* pika-atomic.c
|
||||
* Copyright (C) 2018 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika-atomic.h"
|
||||
|
||||
|
||||
/* GSList */
|
||||
|
||||
|
||||
static GSList pika_atomic_slist_sentinel;
|
||||
|
||||
|
||||
void
|
||||
pika_atomic_slist_push_head (GSList **list,
|
||||
gpointer data)
|
||||
{
|
||||
GSList *old_head;
|
||||
GSList *new_head;
|
||||
|
||||
g_return_if_fail (list != NULL);
|
||||
|
||||
new_head = g_slist_alloc ();
|
||||
|
||||
new_head->data = data;
|
||||
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
old_head = g_atomic_pointer_get (list);
|
||||
}
|
||||
while (old_head == &pika_atomic_slist_sentinel);
|
||||
|
||||
new_head->next = old_head;
|
||||
}
|
||||
while (! g_atomic_pointer_compare_and_exchange (list, old_head, new_head));
|
||||
}
|
||||
|
||||
gpointer
|
||||
pika_atomic_slist_pop_head (GSList **list)
|
||||
{
|
||||
GSList *old_head;
|
||||
GSList *new_head;
|
||||
gpointer data;
|
||||
|
||||
g_return_val_if_fail (list != NULL, NULL);
|
||||
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
old_head = g_atomic_pointer_get (list);
|
||||
}
|
||||
while (old_head == &pika_atomic_slist_sentinel);
|
||||
|
||||
if (! old_head)
|
||||
return NULL;
|
||||
}
|
||||
while (! g_atomic_pointer_compare_and_exchange (list,
|
||||
old_head,
|
||||
&pika_atomic_slist_sentinel));
|
||||
|
||||
new_head = old_head->next;
|
||||
data = old_head->data;
|
||||
|
||||
g_atomic_pointer_set (list, new_head);
|
||||
|
||||
g_slist_free1 (old_head);
|
||||
|
||||
return data;
|
||||
}
|
||||
36
app/core/pika-atomic.h
Normal file
36
app/core/pika-atomic.h
Normal file
@ -0,0 +1,36 @@
|
||||
/* 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
|
||||
*
|
||||
* pika-atomic.h
|
||||
* Copyright (C) 2018 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_ATOMIC_H__
|
||||
#define __PIKA_ATOMIC_H__
|
||||
|
||||
|
||||
/* GSList */
|
||||
|
||||
void pika_atomic_slist_push_head (GSList **list,
|
||||
gpointer data);
|
||||
gpointer pika_atomic_slist_pop_head (GSList **list);
|
||||
|
||||
|
||||
#endif /* __PIKA_ATOMIC_H__ */
|
||||
311
app/core/pika-batch.c
Normal file
311
app/core/pika-batch.c
Normal file
@ -0,0 +1,311 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pika-batch.h"
|
||||
#include "pikaparamspecs.h"
|
||||
|
||||
#include "pdb/pikapdb.h"
|
||||
#include "pdb/pikaprocedure.h"
|
||||
|
||||
#include "plug-in/pikapluginmanager.h"
|
||||
#include "plug-in/pikapluginprocedure.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
static void pika_batch_exit_after_callback (Pika *pika) G_GNUC_NORETURN;
|
||||
|
||||
static gint pika_batch_run_cmd (Pika *pika,
|
||||
const gchar *proc_name,
|
||||
PikaProcedure *procedure,
|
||||
PikaRunMode run_mode,
|
||||
const gchar *cmd);
|
||||
|
||||
|
||||
gint
|
||||
pika_batch_run (Pika *pika,
|
||||
const gchar *batch_interpreter,
|
||||
const gchar **batch_commands)
|
||||
{
|
||||
PikaProcedure *eval_proc;
|
||||
GSList *batch_procedures;
|
||||
GSList *iter;
|
||||
gulong exit_id;
|
||||
gint retval = EXIT_SUCCESS;
|
||||
|
||||
if (! batch_commands || ! batch_commands[0])
|
||||
return retval;
|
||||
|
||||
batch_procedures = pika_plug_in_manager_get_batch_procedures (pika->plug_in_manager);
|
||||
if (g_slist_length (batch_procedures) == 0)
|
||||
{
|
||||
g_message (_("No batch interpreters are available. "
|
||||
"Batch mode disabled."));
|
||||
retval = 69; /* EX_UNAVAILABLE - service unavailable (sysexits.h) */
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (! batch_interpreter)
|
||||
{
|
||||
batch_interpreter = g_getenv ("PIKA_BATCH_INTERPRETER");
|
||||
|
||||
if (! batch_interpreter)
|
||||
{
|
||||
if (g_slist_length (batch_procedures) == 1)
|
||||
{
|
||||
batch_interpreter = pika_object_get_name (batch_procedures->data);;
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_printerr (_("No batch interpreter specified, using "
|
||||
"'%s'.\n"), batch_interpreter);
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = 64; /* EX_USAGE - command line usage error */
|
||||
g_print ("%s\n\n%s\n",
|
||||
_("No batch interpreter specified."),
|
||||
_("Available interpreters are:"));
|
||||
|
||||
for (iter = batch_procedures; iter; iter = iter->next)
|
||||
{
|
||||
PikaPlugInProcedure *proc = iter->data;
|
||||
gchar *locale_name;
|
||||
|
||||
locale_name = g_locale_from_utf8 (proc->batch_interpreter_name,
|
||||
-1, NULL, NULL, NULL);
|
||||
|
||||
g_print ("- %s (%s)\n",
|
||||
pika_object_get_name (iter->data),
|
||||
locale_name ? locale_name : proc->batch_interpreter_name);
|
||||
|
||||
g_free (locale_name);
|
||||
}
|
||||
|
||||
g_print ("\n%s\n",
|
||||
_("Specify one of these interpreters as --batch-interpreter option."));
|
||||
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (iter = batch_procedures; iter; iter = iter->next)
|
||||
{
|
||||
if (g_strcmp0 (pika_object_get_name (iter->data),
|
||||
batch_interpreter) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (iter == NULL)
|
||||
{
|
||||
retval = 69; /* EX_UNAVAILABLE - service unavailable (sysexits.h) */
|
||||
g_print (_("The procedure '%s' is not a valid batch interpreter."),
|
||||
batch_interpreter);
|
||||
g_print ("\n%s\n\n%s\n",
|
||||
_("Batch mode disabled."),
|
||||
_("Available interpreters are:"));
|
||||
|
||||
for (iter = batch_procedures; iter; iter = iter->next)
|
||||
{
|
||||
PikaPlugInProcedure *proc = iter->data;
|
||||
gchar *locale_name;
|
||||
|
||||
locale_name = g_locale_from_utf8 (proc->batch_interpreter_name,
|
||||
-1, NULL, NULL, NULL);
|
||||
|
||||
g_print ("- %s (%s)\n",
|
||||
pika_object_get_name (iter->data),
|
||||
locale_name ? locale_name : proc->batch_interpreter_name);
|
||||
|
||||
g_free (locale_name);
|
||||
}
|
||||
|
||||
g_print ("\n%s\n",
|
||||
_("Specify one of these interpreters as --batch-interpreter option."));
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
exit_id = g_signal_connect_after (pika, "exit",
|
||||
G_CALLBACK (pika_batch_exit_after_callback),
|
||||
NULL);
|
||||
|
||||
eval_proc = pika_pdb_lookup_procedure (pika->pdb, batch_interpreter);
|
||||
if (eval_proc)
|
||||
{
|
||||
gint i;
|
||||
|
||||
retval = EXIT_SUCCESS;
|
||||
for (i = 0; batch_commands[i]; i++)
|
||||
{
|
||||
retval = pika_batch_run_cmd (pika, batch_interpreter, eval_proc,
|
||||
PIKA_RUN_NONINTERACTIVE, batch_commands[i]);
|
||||
|
||||
/* In case of several commands, stop and return last
|
||||
* failed command.
|
||||
*/
|
||||
if (retval != EXIT_SUCCESS)
|
||||
{
|
||||
g_printerr ("Stopping at failing batch command [%d]: %s\n",
|
||||
i, batch_commands[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = 69; /* EX_UNAVAILABLE - service unavailable (sysexits.h) */
|
||||
g_message (_("The batch interpreter '%s' is not available. "
|
||||
"Batch mode disabled."), batch_interpreter);
|
||||
}
|
||||
|
||||
g_signal_handler_disconnect (pika, exit_id);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The purpose of this handler is to exit PIKA cleanly when the batch
|
||||
* procedure calls the pika-exit procedure. Without this callback, the
|
||||
* message "batch command experienced an execution error" would appear
|
||||
* and pika would hang forever.
|
||||
*/
|
||||
static void
|
||||
pika_batch_exit_after_callback (Pika *pika)
|
||||
{
|
||||
if (pika->be_verbose)
|
||||
g_print ("EXIT: %s\n", G_STRFUNC);
|
||||
|
||||
gegl_exit ();
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
PIKA_IS_PARAM_SPEC_RUN_MODE (GParamSpec *pspec)
|
||||
{
|
||||
return (G_IS_PARAM_SPEC_ENUM (pspec) &&
|
||||
pspec->value_type == PIKA_TYPE_RUN_MODE);
|
||||
}
|
||||
|
||||
static gint
|
||||
pika_batch_run_cmd (Pika *pika,
|
||||
const gchar *proc_name,
|
||||
PikaProcedure *procedure,
|
||||
PikaRunMode run_mode,
|
||||
const gchar *cmd)
|
||||
{
|
||||
PikaValueArray *args;
|
||||
PikaValueArray *return_vals;
|
||||
GError *error = NULL;
|
||||
gint i = 0;
|
||||
gint retval = EXIT_SUCCESS;
|
||||
|
||||
args = pika_procedure_get_arguments (procedure);
|
||||
|
||||
if (procedure->num_args > i &&
|
||||
PIKA_IS_PARAM_SPEC_RUN_MODE (procedure->args[i]))
|
||||
{
|
||||
g_value_set_enum (pika_value_array_index (args, i++), run_mode);
|
||||
}
|
||||
|
||||
if (procedure->num_args > i &&
|
||||
G_IS_PARAM_SPEC_STRING (procedure->args[i]))
|
||||
{
|
||||
g_value_set_static_string (pika_value_array_index (args, i++), cmd);
|
||||
}
|
||||
|
||||
return_vals =
|
||||
pika_pdb_execute_procedure_by_name_args (pika->pdb,
|
||||
pika_get_user_context (pika),
|
||||
NULL, &error,
|
||||
proc_name, args);
|
||||
|
||||
switch (g_value_get_enum (pika_value_array_index (return_vals, 0)))
|
||||
{
|
||||
case PIKA_PDB_EXECUTION_ERROR:
|
||||
/* Using Linux's standard exit code as found in /usr/include/sysexits.h
|
||||
* Since other platforms may not have the header, I simply
|
||||
* hardcode the few cases.
|
||||
*/
|
||||
retval = 70; /* EX_SOFTWARE - internal software error */
|
||||
if (error)
|
||||
{
|
||||
g_printerr ("batch command experienced an execution error:\n"
|
||||
"%s\n", error->message);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_printerr ("batch command experienced an execution error\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_PDB_CALLING_ERROR:
|
||||
retval = 64; /* EX_USAGE - command line usage error */
|
||||
if (error)
|
||||
{
|
||||
g_printerr ("batch command experienced a calling error:\n"
|
||||
"%s\n", error->message);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_printerr ("batch command experienced a calling error\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case PIKA_PDB_SUCCESS:
|
||||
retval = EXIT_SUCCESS;
|
||||
g_printerr ("batch command executed successfully\n");
|
||||
break;
|
||||
|
||||
case PIKA_PDB_CANCEL:
|
||||
/* Not in sysexits.h, but usually used for 'Script terminated by
|
||||
* Control-C'. See: https://tldp.org/LDP/abs/html/exitcodes.html
|
||||
*/
|
||||
retval = 130;
|
||||
break;
|
||||
|
||||
case PIKA_PDB_PASS_THROUGH:
|
||||
retval = EXIT_FAILURE; /* Catchall. */
|
||||
break;
|
||||
}
|
||||
|
||||
pika_value_array_unref (return_vals);
|
||||
pika_value_array_unref (args);
|
||||
|
||||
if (error)
|
||||
g_error_free (error);
|
||||
|
||||
return retval;
|
||||
}
|
||||
31
app/core/pika-batch.h
Normal file
31
app/core/pika-batch.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BATCH_H__
|
||||
#define __PIKA_BATCH_H__
|
||||
|
||||
|
||||
gint pika_batch_run (Pika *pika,
|
||||
const gchar *batch_interpreter,
|
||||
const gchar **batch_commands);
|
||||
|
||||
|
||||
#endif /* __PIKA_BATCH_H__ */
|
||||
221
app/core/pika-cairo.c
Normal file
221
app/core/pika-cairo.c
Normal file
@ -0,0 +1,221 @@
|
||||
/* 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
|
||||
*
|
||||
* pika-cairo.c
|
||||
* Copyright (C) 2010-2012 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* Some code here is based on code from librsvg that was originally
|
||||
* written by Raph Levien <raph@artofcode.com> for Gill.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo.h>
|
||||
#include <gegl.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikamath/pikamath.h"
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika-cairo.h"
|
||||
|
||||
|
||||
#define REV (2.0 * G_PI)
|
||||
|
||||
|
||||
static cairo_user_data_key_t surface_data_key = { 0, };
|
||||
|
||||
|
||||
cairo_pattern_t *
|
||||
pika_cairo_pattern_create_stipple (const PikaRGB *fg,
|
||||
const PikaRGB *bg,
|
||||
gint index,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
cairo_pattern_t *pattern;
|
||||
guchar *data;
|
||||
guchar *d;
|
||||
guchar fg_r, fg_g, fg_b, fg_a;
|
||||
guchar bg_r, bg_g, bg_b, bg_a;
|
||||
gint x, y;
|
||||
|
||||
g_return_val_if_fail (fg != NULL, NULL);
|
||||
g_return_val_if_fail (bg != NULL, NULL);
|
||||
|
||||
data = g_malloc (8 * 8 * 4);
|
||||
|
||||
pika_rgba_get_uchar (fg, &fg_r, &fg_g, &fg_b, &fg_a);
|
||||
pika_rgba_get_uchar (bg, &bg_r, &bg_g, &bg_b, &bg_a);
|
||||
|
||||
d = data;
|
||||
|
||||
for (y = 0; y < 8; y++)
|
||||
{
|
||||
for (x = 0; x < 8; x++)
|
||||
{
|
||||
if ((x + y + index) % 8 >= 4)
|
||||
PIKA_CAIRO_ARGB32_SET_PIXEL (d, fg_r, fg_g, fg_b, fg_a);
|
||||
else
|
||||
PIKA_CAIRO_ARGB32_SET_PIXEL (d, bg_r, bg_g, bg_b, bg_a);
|
||||
|
||||
d += 4;
|
||||
}
|
||||
}
|
||||
|
||||
surface = cairo_image_surface_create_for_data (data,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
8, 8, 8 * 4);
|
||||
cairo_surface_set_user_data (surface, &surface_data_key,
|
||||
data, (cairo_destroy_func_t) g_free);
|
||||
|
||||
pattern = cairo_pattern_create_for_surface (surface);
|
||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
if (offset_x != 0.0 || offset_y != 0.0)
|
||||
{
|
||||
cairo_matrix_t matrix;
|
||||
|
||||
cairo_matrix_init_translate (&matrix,
|
||||
fmod (offset_x, 8),
|
||||
fmod (offset_y, 8));
|
||||
cairo_pattern_set_matrix (pattern, &matrix);
|
||||
}
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
void
|
||||
pika_cairo_arc (cairo_t *cr,
|
||||
gdouble center_x,
|
||||
gdouble center_y,
|
||||
gdouble radius,
|
||||
gdouble start_angle,
|
||||
gdouble slice_angle)
|
||||
{
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
if (slice_angle >= 0)
|
||||
{
|
||||
cairo_arc_negative (cr, center_x, center_y, radius,
|
||||
- start_angle,
|
||||
- start_angle - slice_angle);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_arc (cr, center_x, center_y, radius,
|
||||
- start_angle,
|
||||
- start_angle - slice_angle);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_cairo_rounded_rectangle (cairo_t *cr,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
gdouble corner_radius)
|
||||
{
|
||||
g_return_if_fail (cr != NULL);
|
||||
|
||||
if (width < 0.0)
|
||||
{
|
||||
x += width;
|
||||
width = -width;
|
||||
}
|
||||
|
||||
if (height < 0.0)
|
||||
{
|
||||
y += height;
|
||||
height = -height;
|
||||
}
|
||||
|
||||
corner_radius = CLAMP (corner_radius, 0.0, MIN (width, height) / 2.0);
|
||||
|
||||
if (corner_radius == 0.0)
|
||||
{
|
||||
cairo_rectangle (cr, x, y, width, height);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
cairo_new_sub_path (cr);
|
||||
|
||||
cairo_arc (cr,
|
||||
x + corner_radius, y + corner_radius,
|
||||
corner_radius,
|
||||
0.50 * REV, 0.75 * REV);
|
||||
cairo_line_to (cr,
|
||||
x + width - corner_radius, y);
|
||||
|
||||
cairo_arc (cr,
|
||||
x + width - corner_radius, y + corner_radius,
|
||||
corner_radius,
|
||||
0.75 * REV, 1.00 * REV);
|
||||
cairo_line_to (cr,
|
||||
x + width, y + height - corner_radius);
|
||||
|
||||
cairo_arc (cr,
|
||||
x + width - corner_radius, y + height - corner_radius,
|
||||
corner_radius,
|
||||
0.00 * REV, 0.25 * REV);
|
||||
cairo_line_to (cr,
|
||||
x + corner_radius, y + height);
|
||||
|
||||
cairo_arc (cr,
|
||||
x + corner_radius, y + height - corner_radius,
|
||||
corner_radius,
|
||||
0.25 * REV, 0.50 * REV);
|
||||
cairo_line_to (cr,
|
||||
x, y + corner_radius);
|
||||
|
||||
cairo_close_path (cr);
|
||||
}
|
||||
|
||||
void
|
||||
pika_cairo_segments (cairo_t *cr,
|
||||
PikaSegment *segs,
|
||||
gint n_segs)
|
||||
{
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (cr != NULL);
|
||||
g_return_if_fail (segs != NULL && n_segs > 0);
|
||||
|
||||
for (i = 0; i < n_segs; i++)
|
||||
{
|
||||
if (segs[i].x1 == segs[i].x2)
|
||||
{
|
||||
cairo_move_to (cr, segs[i].x1 + 0.5, segs[i].y1 + 0.5);
|
||||
cairo_line_to (cr, segs[i].x2 + 0.5, segs[i].y2 - 0.5);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_move_to (cr, segs[i].x1 + 0.5, segs[i].y1 + 0.5);
|
||||
cairo_line_to (cr, segs[i].x2 - 0.5, segs[i].y2 + 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
55
app/core/pika-cairo.h
Normal file
55
app/core/pika-cairo.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* 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
|
||||
*
|
||||
* pika-cairo.h
|
||||
* Copyright (C) 2010-2012 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* Some code here is based on code from librsvg that was originally
|
||||
* written by Raph Levien <raph@artofcode.com> for Gill.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __APP_PIKA_CAIRO_H__
|
||||
#define __APP_PIKA_CAIRO_H__
|
||||
|
||||
|
||||
cairo_pattern_t * pika_cairo_pattern_create_stipple (const PikaRGB *fg,
|
||||
const PikaRGB *bg,
|
||||
gint index,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y);
|
||||
|
||||
void pika_cairo_arc (cairo_t *cr,
|
||||
gdouble center_x,
|
||||
gdouble center_y,
|
||||
gdouble radius,
|
||||
gdouble start_angle,
|
||||
gdouble slice_angle);
|
||||
void pika_cairo_rounded_rectangle (cairo_t *cr,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble width,
|
||||
gdouble height,
|
||||
gdouble corner_radius);
|
||||
void pika_cairo_segments (cairo_t *cr,
|
||||
PikaSegment *segs,
|
||||
gint n_segs);
|
||||
|
||||
|
||||
#endif /* __APP_PIKA_CAIRO_H__ */
|
||||
165
app/core/pika-contexts.c
Normal file
165
app/core/pika-contexts.c
Normal file
@ -0,0 +1,165 @@
|
||||
/* 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-1999 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pika-contexts.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pikaerror.h"
|
||||
#include "pika-contexts.h"
|
||||
#include "pikacontext.h"
|
||||
|
||||
#include "config/pikaconfig-file.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
void
|
||||
pika_contexts_init (Pika *pika)
|
||||
{
|
||||
PikaContext *context;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
/* the default context contains the user's saved preferences
|
||||
*
|
||||
* TODO: load from disk
|
||||
*/
|
||||
context = pika_context_new (pika, "Default", NULL);
|
||||
pika_set_default_context (pika, context);
|
||||
g_object_unref (context);
|
||||
|
||||
/* the initial user_context is a straight copy of the default context
|
||||
*/
|
||||
context = pika_context_new (pika, "User", context);
|
||||
pika_set_user_context (pika, context);
|
||||
g_object_unref (context);
|
||||
}
|
||||
|
||||
void
|
||||
pika_contexts_exit (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
pika_set_user_context (pika, NULL);
|
||||
pika_set_default_context (pika, NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_contexts_load (Pika *pika,
|
||||
GError **error)
|
||||
{
|
||||
GFile *file;
|
||||
GError *my_error = NULL;
|
||||
gboolean success;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
file = pika_directory_file ("contextrc", NULL);
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Parsing '%s'\n", pika_file_get_utf8_name (file));
|
||||
|
||||
success = pika_config_deserialize_file (PIKA_CONFIG (pika_get_user_context (pika)),
|
||||
file,
|
||||
NULL, &my_error);
|
||||
|
||||
g_object_unref (file);
|
||||
|
||||
if (! success)
|
||||
{
|
||||
if (my_error->code == PIKA_CONFIG_ERROR_OPEN_ENOENT)
|
||||
{
|
||||
g_clear_error (&my_error);
|
||||
success = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_propagate_error (error, my_error);
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_contexts_save (Pika *pika,
|
||||
GError **error)
|
||||
{
|
||||
GFile *file;
|
||||
gboolean success;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
file = pika_directory_file ("contextrc", NULL);
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Writing '%s'\n", pika_file_get_utf8_name (file));
|
||||
|
||||
success = pika_config_serialize_to_file (PIKA_CONFIG (pika_get_user_context (pika)),
|
||||
file,
|
||||
"PIKA user context",
|
||||
"end of user context",
|
||||
NULL, error);
|
||||
|
||||
g_object_unref (file);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_contexts_clear (Pika *pika,
|
||||
GError **error)
|
||||
{
|
||||
GFile *file;
|
||||
GError *my_error = NULL;
|
||||
gboolean success = TRUE;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
|
||||
file = pika_directory_file ("contextrc", NULL);
|
||||
|
||||
if (! g_file_delete (file, NULL, &my_error) &&
|
||||
my_error->code != G_IO_ERROR_NOT_FOUND)
|
||||
{
|
||||
success = FALSE;
|
||||
|
||||
g_set_error (error, PIKA_ERROR, PIKA_FAILED,
|
||||
_("Deleting \"%s\" failed: %s"),
|
||||
pika_file_get_utf8_name (file), my_error->message);
|
||||
}
|
||||
|
||||
g_clear_error (&my_error);
|
||||
g_object_unref (file);
|
||||
|
||||
return success;
|
||||
}
|
||||
40
app/core/pika-contexts.h
Normal file
40
app/core/pika-contexts.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* 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
|
||||
*
|
||||
* pika-contexts.h
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_CONTEXTS_H__
|
||||
#define __PIKA_CONTEXTS_H__
|
||||
|
||||
|
||||
void pika_contexts_init (Pika *pika);
|
||||
void pika_contexts_exit (Pika *pika);
|
||||
|
||||
gboolean pika_contexts_load (Pika *pika,
|
||||
GError **error);
|
||||
gboolean pika_contexts_save (Pika *pika,
|
||||
GError **error);
|
||||
|
||||
gboolean pika_contexts_clear (Pika *pika,
|
||||
GError **error);
|
||||
|
||||
|
||||
#endif /* __PIKA_CONTEXTS_H__ */
|
||||
444
app/core/pika-data-factories.c
Normal file
444
app/core/pika-data-factories.c
Normal file
@ -0,0 +1,444 @@
|
||||
/* 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-2002 Spencer Kimball, Peter Mattis, and others
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "config/pikarc.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pika-data-factories.h"
|
||||
#include "pika-gradients.h"
|
||||
#include "pika-memsize.h"
|
||||
#include "pika-palettes.h"
|
||||
#include "pikacontainer.h"
|
||||
#include "pikabrush-load.h"
|
||||
#include "pikabrush.h"
|
||||
#include "pikabrushclipboard.h"
|
||||
#include "pikabrushgenerated-load.h"
|
||||
#include "pikabrushpipe-load.h"
|
||||
#include "pikadataloaderfactory.h"
|
||||
#include "pikadynamics.h"
|
||||
#include "pikadynamics-load.h"
|
||||
#include "pikagradient-load.h"
|
||||
#include "pikagradient.h"
|
||||
#include "pikamybrush-load.h"
|
||||
#include "pikamybrush.h"
|
||||
#include "pikapalette-load.h"
|
||||
#include "pikapalette.h"
|
||||
#include "pikapattern-load.h"
|
||||
#include "pikapattern.h"
|
||||
#include "pikapatternclipboard.h"
|
||||
#include "pikatagcache.h"
|
||||
#include "pikatoolpreset.h"
|
||||
#include "pikatoolpreset-load.h"
|
||||
|
||||
#include "text/pikafontfactory.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
void
|
||||
pika_data_factories_init (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
pika->brush_factory =
|
||||
pika_data_loader_factory_new (pika,
|
||||
PIKA_TYPE_BRUSH,
|
||||
"brush-path",
|
||||
"brush-path-writable",
|
||||
"brush-paths",
|
||||
pika_brush_new,
|
||||
pika_brush_get_standard);
|
||||
pika_object_set_static_name (PIKA_OBJECT (pika->brush_factory),
|
||||
"brush factory");
|
||||
pika_data_loader_factory_add_loader (pika->brush_factory,
|
||||
"PIKA Brush",
|
||||
pika_brush_load,
|
||||
PIKA_BRUSH_FILE_EXTENSION,
|
||||
TRUE);
|
||||
pika_data_loader_factory_add_loader (pika->brush_factory,
|
||||
"PIKA Brush Pixmap",
|
||||
pika_brush_load,
|
||||
PIKA_BRUSH_PIXMAP_FILE_EXTENSION,
|
||||
FALSE);
|
||||
pika_data_loader_factory_add_loader (pika->brush_factory,
|
||||
"Photoshop ABR Brush",
|
||||
pika_brush_load_abr,
|
||||
PIKA_BRUSH_PS_FILE_EXTENSION,
|
||||
FALSE);
|
||||
pika_data_loader_factory_add_loader (pika->brush_factory,
|
||||
"Paint Shop Pro JBR Brush",
|
||||
pika_brush_load_abr,
|
||||
PIKA_BRUSH_PSP_FILE_EXTENSION,
|
||||
FALSE);
|
||||
pika_data_loader_factory_add_loader (pika->brush_factory,
|
||||
"PIKA Generated Brush",
|
||||
pika_brush_generated_load,
|
||||
PIKA_BRUSH_GENERATED_FILE_EXTENSION,
|
||||
TRUE);
|
||||
pika_data_loader_factory_add_loader (pika->brush_factory,
|
||||
"PIKA Brush Pipe",
|
||||
pika_brush_pipe_load,
|
||||
PIKA_BRUSH_PIPE_FILE_EXTENSION,
|
||||
TRUE);
|
||||
|
||||
pika->dynamics_factory =
|
||||
pika_data_loader_factory_new (pika,
|
||||
PIKA_TYPE_DYNAMICS,
|
||||
"dynamics-path",
|
||||
"dynamics-path-writable",
|
||||
"dynamics-paths",
|
||||
pika_dynamics_new,
|
||||
pika_dynamics_get_standard);
|
||||
pika_object_set_static_name (PIKA_OBJECT (pika->dynamics_factory),
|
||||
"dynamics factory");
|
||||
pika_data_loader_factory_add_loader (pika->dynamics_factory,
|
||||
"PIKA Paint Dynamics",
|
||||
pika_dynamics_load,
|
||||
PIKA_DYNAMICS_FILE_EXTENSION,
|
||||
TRUE);
|
||||
|
||||
pika->mybrush_factory =
|
||||
pika_data_loader_factory_new (pika,
|
||||
PIKA_TYPE_MYBRUSH,
|
||||
"mypaint-brush-path",
|
||||
"mypaint-brush-path-writable",
|
||||
"mypaint-brush-paths",
|
||||
NULL,
|
||||
NULL);
|
||||
pika_object_set_static_name (PIKA_OBJECT (pika->mybrush_factory),
|
||||
"mypaint brush factory");
|
||||
pika_data_loader_factory_add_loader (pika->mybrush_factory,
|
||||
"MyPaint Brush",
|
||||
pika_mybrush_load,
|
||||
PIKA_MYBRUSH_FILE_EXTENSION,
|
||||
FALSE);
|
||||
|
||||
pika->pattern_factory =
|
||||
pika_data_loader_factory_new (pika,
|
||||
PIKA_TYPE_PATTERN,
|
||||
"pattern-path",
|
||||
"pattern-path-writable",
|
||||
"pattern-paths",
|
||||
NULL,
|
||||
pika_pattern_get_standard);
|
||||
pika_object_set_static_name (PIKA_OBJECT (pika->pattern_factory),
|
||||
"pattern factory");
|
||||
pika_data_loader_factory_add_loader (pika->pattern_factory,
|
||||
"PIKA Pattern",
|
||||
pika_pattern_load,
|
||||
PIKA_PATTERN_FILE_EXTENSION,
|
||||
TRUE);
|
||||
pika_data_loader_factory_add_fallback (pika->pattern_factory,
|
||||
"Pattern from GdkPixbuf",
|
||||
pika_pattern_load_pixbuf);
|
||||
|
||||
pika->gradient_factory =
|
||||
pika_data_loader_factory_new (pika,
|
||||
PIKA_TYPE_GRADIENT,
|
||||
"gradient-path",
|
||||
"gradient-path-writable",
|
||||
"gradient-paths",
|
||||
pika_gradient_new,
|
||||
pika_gradient_get_standard);
|
||||
pika_object_set_static_name (PIKA_OBJECT (pika->gradient_factory),
|
||||
"gradient factory");
|
||||
pika_data_loader_factory_add_loader (pika->gradient_factory,
|
||||
"PIKA Gradient",
|
||||
pika_gradient_load,
|
||||
PIKA_GRADIENT_FILE_EXTENSION,
|
||||
TRUE);
|
||||
pika_data_loader_factory_add_loader (pika->gradient_factory,
|
||||
"SVG Gradient",
|
||||
pika_gradient_load_svg,
|
||||
PIKA_GRADIENT_SVG_FILE_EXTENSION,
|
||||
FALSE);
|
||||
|
||||
pika->palette_factory =
|
||||
pika_data_loader_factory_new (pika,
|
||||
PIKA_TYPE_PALETTE,
|
||||
"palette-path",
|
||||
"palette-path-writable",
|
||||
"palette-paths",
|
||||
pika_palette_new,
|
||||
pika_palette_get_standard);
|
||||
pika_object_set_static_name (PIKA_OBJECT (pika->palette_factory),
|
||||
"palette factory");
|
||||
pika_data_loader_factory_add_loader (pika->palette_factory,
|
||||
"PIKA Palette",
|
||||
pika_palette_load,
|
||||
PIKA_PALETTE_FILE_EXTENSION,
|
||||
TRUE);
|
||||
|
||||
pika->font_factory =
|
||||
pika_font_factory_new (pika,
|
||||
"font-path");
|
||||
pika_object_set_static_name (PIKA_OBJECT (pika->font_factory),
|
||||
"font factory");
|
||||
|
||||
pika->tool_preset_factory =
|
||||
pika_data_loader_factory_new (pika,
|
||||
PIKA_TYPE_TOOL_PRESET,
|
||||
"tool-preset-path",
|
||||
"tool-preset-path-writable",
|
||||
"tool-preset-paths",
|
||||
pika_tool_preset_new,
|
||||
NULL);
|
||||
pika_object_set_static_name (PIKA_OBJECT (pika->tool_preset_factory),
|
||||
"tool preset factory");
|
||||
pika_data_loader_factory_add_loader (pika->tool_preset_factory,
|
||||
"PIKA Tool Preset",
|
||||
pika_tool_preset_load,
|
||||
PIKA_TOOL_PRESET_FILE_EXTENSION,
|
||||
TRUE);
|
||||
|
||||
pika->tag_cache = pika_tag_cache_new ();
|
||||
}
|
||||
|
||||
void
|
||||
pika_data_factories_add_builtin (Pika *pika)
|
||||
{
|
||||
PikaData *data;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
/* add the builtin FG -> BG etc. gradients */
|
||||
pika_gradients_init (pika);
|
||||
|
||||
/* add the color history palette */
|
||||
pika_palettes_init (pika);
|
||||
|
||||
/* add the clipboard brushes */
|
||||
data = pika_brush_clipboard_new (pika, FALSE);
|
||||
pika_data_make_internal (data, "pika-brush-clipboard-image");
|
||||
pika_container_add (pika_data_factory_get_container (pika->brush_factory),
|
||||
PIKA_OBJECT (data));
|
||||
g_object_unref (data);
|
||||
|
||||
data = pika_brush_clipboard_new (pika, TRUE);
|
||||
pika_data_make_internal (data, "pika-brush-clipboard-mask");
|
||||
pika_container_add (pika_data_factory_get_container (pika->brush_factory),
|
||||
PIKA_OBJECT (data));
|
||||
g_object_unref (data);
|
||||
|
||||
/* add the clipboard pattern */
|
||||
data = pika_pattern_clipboard_new (pika);
|
||||
pika_data_make_internal (data, "pika-pattern-clipboard-image");
|
||||
pika_container_add (pika_data_factory_get_container (pika->pattern_factory),
|
||||
PIKA_OBJECT (data));
|
||||
g_object_unref (data);
|
||||
}
|
||||
|
||||
void
|
||||
pika_data_factories_clear (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
if (pika->brush_factory)
|
||||
pika_data_factory_data_free (pika->brush_factory);
|
||||
|
||||
if (pika->dynamics_factory)
|
||||
pika_data_factory_data_free (pika->dynamics_factory);
|
||||
|
||||
if (pika->mybrush_factory)
|
||||
pika_data_factory_data_free (pika->mybrush_factory);
|
||||
|
||||
if (pika->pattern_factory)
|
||||
pika_data_factory_data_free (pika->pattern_factory);
|
||||
|
||||
if (pika->gradient_factory)
|
||||
pika_data_factory_data_free (pika->gradient_factory);
|
||||
|
||||
if (pika->palette_factory)
|
||||
pika_data_factory_data_free (pika->palette_factory);
|
||||
|
||||
if (pika->font_factory)
|
||||
pika_data_factory_data_free (pika->font_factory);
|
||||
|
||||
if (pika->tool_preset_factory)
|
||||
pika_data_factory_data_free (pika->tool_preset_factory);
|
||||
}
|
||||
|
||||
void
|
||||
pika_data_factories_exit (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
g_clear_object (&pika->brush_factory);
|
||||
g_clear_object (&pika->dynamics_factory);
|
||||
g_clear_object (&pika->mybrush_factory);
|
||||
g_clear_object (&pika->pattern_factory);
|
||||
g_clear_object (&pika->gradient_factory);
|
||||
g_clear_object (&pika->palette_factory);
|
||||
g_clear_object (&pika->font_factory);
|
||||
g_clear_object (&pika->tool_preset_factory);
|
||||
g_clear_object (&pika->tag_cache);
|
||||
}
|
||||
|
||||
gint64
|
||||
pika_data_factories_get_memsize (Pika *pika,
|
||||
gint64 *gui_size)
|
||||
{
|
||||
gint64 memsize = 0;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), 0);
|
||||
|
||||
memsize += pika_object_get_memsize (PIKA_OBJECT (pika->named_buffers),
|
||||
gui_size);
|
||||
memsize += pika_object_get_memsize (PIKA_OBJECT (pika->brush_factory),
|
||||
gui_size);
|
||||
memsize += pika_object_get_memsize (PIKA_OBJECT (pika->dynamics_factory),
|
||||
gui_size);
|
||||
memsize += pika_object_get_memsize (PIKA_OBJECT (pika->mybrush_factory),
|
||||
gui_size);
|
||||
memsize += pika_object_get_memsize (PIKA_OBJECT (pika->pattern_factory),
|
||||
gui_size);
|
||||
memsize += pika_object_get_memsize (PIKA_OBJECT (pika->gradient_factory),
|
||||
gui_size);
|
||||
memsize += pika_object_get_memsize (PIKA_OBJECT (pika->palette_factory),
|
||||
gui_size);
|
||||
memsize += pika_object_get_memsize (PIKA_OBJECT (pika->font_factory),
|
||||
gui_size);
|
||||
memsize += pika_object_get_memsize (PIKA_OBJECT (pika->tool_preset_factory),
|
||||
gui_size);
|
||||
|
||||
memsize += pika_object_get_memsize (PIKA_OBJECT (pika->tag_cache),
|
||||
gui_size);
|
||||
|
||||
return memsize;
|
||||
}
|
||||
|
||||
void
|
||||
pika_data_factories_data_clean (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
pika_data_factory_data_clean (pika->brush_factory);
|
||||
pika_data_factory_data_clean (pika->dynamics_factory);
|
||||
pika_data_factory_data_clean (pika->mybrush_factory);
|
||||
pika_data_factory_data_clean (pika->pattern_factory);
|
||||
pika_data_factory_data_clean (pika->gradient_factory);
|
||||
pika_data_factory_data_clean (pika->palette_factory);
|
||||
pika_data_factory_data_clean (pika->font_factory);
|
||||
pika_data_factory_data_clean (pika->tool_preset_factory);
|
||||
}
|
||||
|
||||
void
|
||||
pika_data_factories_load (Pika *pika,
|
||||
PikaInitStatusFunc status_callback)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
/* initialize the list of pika brushes */
|
||||
status_callback (NULL, _("Brushes"), 0.1);
|
||||
pika_data_factory_data_init (pika->brush_factory, pika->user_context,
|
||||
pika->no_data);
|
||||
|
||||
/* initialize the list of pika dynamics */
|
||||
status_callback (NULL, _("Dynamics"), 0.15);
|
||||
pika_data_factory_data_init (pika->dynamics_factory, pika->user_context,
|
||||
pika->no_data);
|
||||
|
||||
/* initialize the list of mypaint brushes */
|
||||
status_callback (NULL, _("MyPaint Brushes"), 0.2);
|
||||
pika_data_factory_data_init (pika->mybrush_factory, pika->user_context,
|
||||
pika->no_data);
|
||||
|
||||
/* initialize the list of pika patterns */
|
||||
status_callback (NULL, _("Patterns"), 0.3);
|
||||
pika_data_factory_data_init (pika->pattern_factory, pika->user_context,
|
||||
pika->no_data);
|
||||
|
||||
/* initialize the list of pika palettes */
|
||||
status_callback (NULL, _("Palettes"), 0.4);
|
||||
pika_data_factory_data_init (pika->palette_factory, pika->user_context,
|
||||
pika->no_data);
|
||||
|
||||
/* initialize the list of pika gradients */
|
||||
status_callback (NULL, _("Gradients"), 0.5);
|
||||
pika_data_factory_data_init (pika->gradient_factory, pika->user_context,
|
||||
pika->no_data);
|
||||
|
||||
/* initialize the color history */
|
||||
status_callback (NULL, _("Color History"), 0.55);
|
||||
pika_palettes_load (pika);
|
||||
|
||||
/* initialize the list of pika fonts */
|
||||
status_callback (NULL, _("Fonts"), 0.6);
|
||||
pika_data_factory_data_init (pika->font_factory, pika->user_context,
|
||||
pika->no_fonts);
|
||||
|
||||
/* initialize the list of pika tool presets if we have a GUI */
|
||||
if (! pika->no_interface)
|
||||
{
|
||||
status_callback (NULL, _("Tool Presets"), 0.7);
|
||||
pika_data_factory_data_init (pika->tool_preset_factory, pika->user_context,
|
||||
pika->no_data);
|
||||
}
|
||||
|
||||
/* update tag cache */
|
||||
status_callback (NULL, _("Updating tag cache"), 0.75);
|
||||
pika_tag_cache_load (pika->tag_cache);
|
||||
pika_tag_cache_add_container (pika->tag_cache,
|
||||
pika_data_factory_get_container (pika->brush_factory));
|
||||
pika_tag_cache_add_container (pika->tag_cache,
|
||||
pika_data_factory_get_container (pika->dynamics_factory));
|
||||
pika_tag_cache_add_container (pika->tag_cache,
|
||||
pika_data_factory_get_container (pika->mybrush_factory));
|
||||
pika_tag_cache_add_container (pika->tag_cache,
|
||||
pika_data_factory_get_container (pika->pattern_factory));
|
||||
pika_tag_cache_add_container (pika->tag_cache,
|
||||
pika_data_factory_get_container (pika->gradient_factory));
|
||||
pika_tag_cache_add_container (pika->tag_cache,
|
||||
pika_data_factory_get_container (pika->palette_factory));
|
||||
pika_tag_cache_add_container (pika->tag_cache,
|
||||
pika_data_factory_get_container (pika->font_factory));
|
||||
pika_tag_cache_add_container (pika->tag_cache,
|
||||
pika_data_factory_get_container (pika->tool_preset_factory));
|
||||
}
|
||||
|
||||
void
|
||||
pika_data_factories_save (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
pika_tag_cache_save (pika->tag_cache);
|
||||
|
||||
pika_data_factory_data_save (pika->brush_factory);
|
||||
pika_data_factory_data_save (pika->dynamics_factory);
|
||||
pika_data_factory_data_save (pika->mybrush_factory);
|
||||
pika_data_factory_data_save (pika->pattern_factory);
|
||||
pika_data_factory_data_save (pika->gradient_factory);
|
||||
pika_data_factory_data_save (pika->palette_factory);
|
||||
pika_data_factory_data_save (pika->font_factory);
|
||||
pika_data_factory_data_save (pika->tool_preset_factory);
|
||||
|
||||
pika_palettes_save (pika);
|
||||
}
|
||||
40
app/core/pika-data-factories.h
Normal file
40
app/core/pika-data-factories.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* 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-2002 Spencer Kimball, Peter Mattis, and others
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_DATA_FACTORIES_H__
|
||||
#define __PIKA_DATA_FACTORIES_H__
|
||||
|
||||
|
||||
void pika_data_factories_init (Pika *pika);
|
||||
void pika_data_factories_add_builtin (Pika *pika);
|
||||
void pika_data_factories_clear (Pika *pika);
|
||||
void pika_data_factories_exit (Pika *pika);
|
||||
|
||||
gint64 pika_data_factories_get_memsize (Pika *pika,
|
||||
gint64 *gui_size);
|
||||
void pika_data_factories_data_clean (Pika *pika);
|
||||
|
||||
void pika_data_factories_load (Pika *pika,
|
||||
PikaInitStatusFunc status_callback);
|
||||
void pika_data_factories_save (Pika *pika);
|
||||
|
||||
|
||||
#endif /* __PIKA_DATA_FACTORIES_H__ */
|
||||
1209
app/core/pika-edit.c
Normal file
1209
app/core/pika-edit.c
Normal file
File diff suppressed because it is too large
Load Diff
68
app/core/pika-edit.h
Normal file
68
app/core/pika-edit.h
Normal file
@ -0,0 +1,68 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_EDIT_H__
|
||||
#define __PIKA_EDIT_H__
|
||||
|
||||
|
||||
PikaObject * pika_edit_cut (PikaImage *image,
|
||||
GList *drawables,
|
||||
PikaContext *context,
|
||||
GError **error);
|
||||
PikaObject * pika_edit_copy (PikaImage *image,
|
||||
GList *drawables,
|
||||
PikaContext *context,
|
||||
GError **error);
|
||||
PikaBuffer * pika_edit_copy_visible (PikaImage *image,
|
||||
PikaContext *context,
|
||||
GError **error);
|
||||
|
||||
GList * pika_edit_paste (PikaImage *image,
|
||||
GList *drawables,
|
||||
PikaObject *paste,
|
||||
PikaPasteType paste_type,
|
||||
PikaContext *context,
|
||||
gboolean merged,
|
||||
gint viewport_x,
|
||||
gint viewport_y,
|
||||
gint viewport_width,
|
||||
gint viewport_height);
|
||||
PikaImage * pika_edit_paste_as_new_image (Pika *pika,
|
||||
PikaObject *paste,
|
||||
PikaContext *context);
|
||||
|
||||
const gchar * pika_edit_named_cut (PikaImage *image,
|
||||
const gchar *name,
|
||||
GList *drawables,
|
||||
PikaContext *context,
|
||||
GError **error);
|
||||
const gchar * pika_edit_named_copy (PikaImage *image,
|
||||
const gchar *name,
|
||||
GList *drawables,
|
||||
PikaContext *context,
|
||||
GError **error);
|
||||
const gchar * pika_edit_named_copy_visible (PikaImage *image,
|
||||
const gchar *name,
|
||||
PikaContext *context,
|
||||
GError **error);
|
||||
|
||||
|
||||
#endif /* __PIKA_EDIT_H__ */
|
||||
164
app/core/pika-filter-history.c
Normal file
164
app/core/pika-filter-history.c
Normal file
@ -0,0 +1,164 @@
|
||||
/* 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-2003 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pika-filter-history.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "config/pikacoreconfig.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pika-filter-history.h"
|
||||
|
||||
#include "pdb/pikaprocedure.h"
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static gint pika_filter_history_compare (PikaProcedure *proc1,
|
||||
PikaProcedure *proc2);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
gint
|
||||
pika_filter_history_size (Pika *pika)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), 0);
|
||||
|
||||
return MAX (1, pika->config->filter_history_size);
|
||||
}
|
||||
|
||||
gint
|
||||
pika_filter_history_length (Pika *pika)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), 0);
|
||||
|
||||
return g_list_length (pika->filter_history);
|
||||
}
|
||||
|
||||
PikaProcedure *
|
||||
pika_filter_history_nth (Pika *pika,
|
||||
gint n)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
|
||||
return g_list_nth_data (pika->filter_history, n);
|
||||
}
|
||||
|
||||
void
|
||||
pika_filter_history_add (Pika *pika,
|
||||
PikaProcedure *procedure)
|
||||
{
|
||||
GList *link;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (PIKA_IS_PROCEDURE (procedure));
|
||||
|
||||
/* return early if the procedure is already at the top */
|
||||
if (pika->filter_history &&
|
||||
pika_filter_history_compare (pika->filter_history->data, procedure) == 0)
|
||||
return;
|
||||
|
||||
/* ref new first then unref old, they might be the same */
|
||||
g_object_ref (procedure);
|
||||
|
||||
link = g_list_find_custom (pika->filter_history, procedure,
|
||||
(GCompareFunc) pika_filter_history_compare);
|
||||
|
||||
if (link)
|
||||
{
|
||||
g_object_unref (link->data);
|
||||
pika->filter_history = g_list_delete_link (pika->filter_history, link);
|
||||
}
|
||||
|
||||
pika->filter_history = g_list_prepend (pika->filter_history, procedure);
|
||||
|
||||
link = g_list_nth (pika->filter_history, pika_filter_history_size (pika));
|
||||
|
||||
if (link)
|
||||
{
|
||||
g_object_unref (link->data);
|
||||
pika->filter_history = g_list_delete_link (pika->filter_history, link);
|
||||
}
|
||||
|
||||
pika_filter_history_changed (pika);
|
||||
}
|
||||
|
||||
void
|
||||
pika_filter_history_remove (Pika *pika,
|
||||
PikaProcedure *procedure)
|
||||
{
|
||||
GList *link;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (PIKA_IS_PROCEDURE (procedure));
|
||||
|
||||
link = g_list_find_custom (pika->filter_history, procedure,
|
||||
(GCompareFunc) pika_filter_history_compare);
|
||||
|
||||
if (link)
|
||||
{
|
||||
g_object_unref (link->data);
|
||||
pika->filter_history = g_list_delete_link (pika->filter_history, link);
|
||||
|
||||
pika_filter_history_changed (pika);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_filter_history_clear (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
if (pika->filter_history)
|
||||
{
|
||||
g_list_free_full (pika->filter_history, (GDestroyNotify) g_object_unref);
|
||||
pika->filter_history = NULL;
|
||||
|
||||
pika_filter_history_changed (pika);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static gint
|
||||
pika_filter_history_compare (PikaProcedure *proc1,
|
||||
PikaProcedure *proc2)
|
||||
{
|
||||
/* the procedures can have the same name, but could still be two
|
||||
* different filters using the same operation, so also compare
|
||||
* their menu labels
|
||||
*/
|
||||
return (pika_procedure_name_compare (proc1, proc2) ||
|
||||
strcmp (pika_procedure_get_menu_label (proc1),
|
||||
pika_procedure_get_menu_label (proc2)));
|
||||
}
|
||||
39
app/core/pika-filter-history.h
Normal file
39
app/core/pika-filter-history.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* 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
|
||||
*
|
||||
* pika-filter-history.h
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_FILTER_HISTORY_H__
|
||||
#define __PIKA_FILTER_HISTORY_H__
|
||||
|
||||
|
||||
gint pika_filter_history_size (Pika *pika);
|
||||
gint pika_filter_history_length (Pika *pika);
|
||||
PikaProcedure * pika_filter_history_nth (Pika *pika,
|
||||
gint n);
|
||||
void pika_filter_history_add (Pika *pika,
|
||||
PikaProcedure *procedure);
|
||||
void pika_filter_history_remove (Pika *pika,
|
||||
PikaProcedure *procedure);
|
||||
void pika_filter_history_clear (Pika *pika);
|
||||
|
||||
|
||||
#endif /* __PIKA_FILTER_HISTORY_H__ */
|
||||
187
app/core/pika-gradients.c
Normal file
187
app/core/pika-gradients.c
Normal file
@ -0,0 +1,187 @@
|
||||
/* 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-2002 Spencer Kimball, Peter Mattis, and others
|
||||
*
|
||||
* pika-gradients.c
|
||||
* Copyright (C) 2002 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pika-gradients.h"
|
||||
#include "pikacontext.h"
|
||||
#include "pikacontainer.h"
|
||||
#include "pikadatafactory.h"
|
||||
#include "pikagradient.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
#define CUSTOM_KEY "pika-gradient-custom"
|
||||
#define FG_BG_RGB_KEY "pika-gradient-fg-bg-rgb"
|
||||
#define FG_BG_HARDEDGE_KEY "pika-gradient-fg-bg-rgb-hardedge"
|
||||
#define FG_BG_HSV_CCW_KEY "pika-gradient-fg-bg-hsv-ccw"
|
||||
#define FG_BG_HSV_CW_KEY "pika-gradient-fg-bg-hsv-cw"
|
||||
#define FG_TRANSPARENT_KEY "pika-gradient-fg-transparent"
|
||||
#define FG_TRANSPARENT_HARDEDGE_KEY "pika-gradient-fg-transparent-hardedge"
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static PikaGradient * pika_gradients_add_gradient (Pika *pika,
|
||||
const gchar *name,
|
||||
const gchar *id);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_gradients_init (Pika *pika)
|
||||
{
|
||||
PikaGradient *gradient;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
/* Custom */
|
||||
gradient = pika_gradients_add_gradient (pika,
|
||||
_("Custom"),
|
||||
CUSTOM_KEY);
|
||||
g_object_set (gradient,
|
||||
"writable", TRUE,
|
||||
NULL);
|
||||
gradient->segments->left_color_type = PIKA_GRADIENT_COLOR_FOREGROUND;
|
||||
gradient->segments->right_color_type = PIKA_GRADIENT_COLOR_BACKGROUND;
|
||||
|
||||
/* FG to BG (RGB) */
|
||||
gradient = pika_gradients_add_gradient (pika,
|
||||
_("FG to BG (RGB)"),
|
||||
FG_BG_RGB_KEY);
|
||||
gradient->segments->left_color_type = PIKA_GRADIENT_COLOR_FOREGROUND;
|
||||
gradient->segments->right_color_type = PIKA_GRADIENT_COLOR_BACKGROUND;
|
||||
pika_context_set_gradient (pika->user_context, gradient);
|
||||
|
||||
/* FG to BG (Hardedge) */
|
||||
gradient = pika_gradients_add_gradient (pika,
|
||||
_("FG to BG (Hardedge)"),
|
||||
FG_BG_HARDEDGE_KEY);
|
||||
gradient->segments->left_color_type = PIKA_GRADIENT_COLOR_FOREGROUND;
|
||||
gradient->segments->right_color_type = PIKA_GRADIENT_COLOR_BACKGROUND;
|
||||
gradient->segments->type = PIKA_GRADIENT_SEGMENT_STEP;
|
||||
|
||||
/* FG to BG (HSV counter-clockwise) */
|
||||
gradient = pika_gradients_add_gradient (pika,
|
||||
_("FG to BG (HSV counter-clockwise)"),
|
||||
FG_BG_HSV_CCW_KEY);
|
||||
gradient->segments->left_color_type = PIKA_GRADIENT_COLOR_FOREGROUND;
|
||||
gradient->segments->right_color_type = PIKA_GRADIENT_COLOR_BACKGROUND;
|
||||
gradient->segments->color = PIKA_GRADIENT_SEGMENT_HSV_CCW;
|
||||
|
||||
/* FG to BG (HSV clockwise hue) */
|
||||
gradient = pika_gradients_add_gradient (pika,
|
||||
_("FG to BG (HSV clockwise hue)"),
|
||||
FG_BG_HSV_CW_KEY);
|
||||
gradient->segments->left_color_type = PIKA_GRADIENT_COLOR_FOREGROUND;
|
||||
gradient->segments->right_color_type = PIKA_GRADIENT_COLOR_BACKGROUND;
|
||||
gradient->segments->color = PIKA_GRADIENT_SEGMENT_HSV_CW;
|
||||
|
||||
/* FG to Transparent */
|
||||
gradient = pika_gradients_add_gradient (pika,
|
||||
_("FG to Transparent"),
|
||||
FG_TRANSPARENT_KEY);
|
||||
gradient->segments->left_color_type = PIKA_GRADIENT_COLOR_FOREGROUND;
|
||||
gradient->segments->right_color_type = PIKA_GRADIENT_COLOR_FOREGROUND_TRANSPARENT;
|
||||
|
||||
/* FG to Transparent (Hardedge) */
|
||||
gradient = pika_gradients_add_gradient (pika,
|
||||
_("FG to Transparent (Hardedge)"),
|
||||
FG_TRANSPARENT_HARDEDGE_KEY);
|
||||
gradient->segments->left_color_type = PIKA_GRADIENT_COLOR_FOREGROUND;
|
||||
gradient->segments->right_color_type = PIKA_GRADIENT_COLOR_FOREGROUND_TRANSPARENT;
|
||||
gradient->segments->type = PIKA_GRADIENT_SEGMENT_STEP;
|
||||
}
|
||||
|
||||
PikaGradient *
|
||||
pika_gradients_get_custom (Pika *pika)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
|
||||
return g_object_get_data (G_OBJECT (pika), CUSTOM_KEY);
|
||||
}
|
||||
|
||||
PikaGradient *
|
||||
pika_gradients_get_fg_bg_rgb (Pika *pika)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
|
||||
return g_object_get_data (G_OBJECT (pika), FG_BG_RGB_KEY);
|
||||
}
|
||||
|
||||
PikaGradient *
|
||||
pika_gradients_get_fg_bg_hsv_ccw (Pika *pika)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
|
||||
return g_object_get_data (G_OBJECT (pika), FG_BG_HSV_CCW_KEY);
|
||||
}
|
||||
|
||||
PikaGradient *
|
||||
pika_gradients_get_fg_bg_hsv_cw (Pika *pika)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
|
||||
return g_object_get_data (G_OBJECT (pika), FG_BG_HSV_CW_KEY);
|
||||
}
|
||||
|
||||
PikaGradient *
|
||||
pika_gradients_get_fg_transparent (Pika *pika)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
|
||||
return g_object_get_data (G_OBJECT (pika), FG_TRANSPARENT_KEY);
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static PikaGradient *
|
||||
pika_gradients_add_gradient (Pika *pika,
|
||||
const gchar *name,
|
||||
const gchar *id)
|
||||
{
|
||||
PikaGradient *gradient;
|
||||
|
||||
gradient = PIKA_GRADIENT (pika_gradient_new (pika_get_user_context (pika),
|
||||
name));
|
||||
|
||||
pika_data_make_internal (PIKA_DATA (gradient), id);
|
||||
|
||||
pika_container_add (pika_data_factory_get_container (pika->gradient_factory),
|
||||
PIKA_OBJECT (gradient));
|
||||
g_object_unref (gradient);
|
||||
|
||||
g_object_set_data (G_OBJECT (pika), id, gradient);
|
||||
|
||||
return gradient;
|
||||
}
|
||||
38
app/core/pika-gradients.h
Normal file
38
app/core/pika-gradients.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* 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-2002 Spencer Kimball, Peter Mattis, and others
|
||||
*
|
||||
* pika-gradients.h
|
||||
* Copyright (C) 2002 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_GRADIENTS__
|
||||
#define __PIKA_GRADIENTS__
|
||||
|
||||
|
||||
void pika_gradients_init (Pika *pika);
|
||||
|
||||
PikaGradient * pika_gradients_get_custom (Pika *pika);
|
||||
PikaGradient * pika_gradients_get_fg_bg_rgb (Pika *pika);
|
||||
PikaGradient * pika_gradients_get_fg_bg_hsv_ccw (Pika *pika);
|
||||
PikaGradient * pika_gradients_get_fg_bg_hsv_cw (Pika *pika);
|
||||
PikaGradient * pika_gradients_get_fg_transparent (Pika *pika);
|
||||
|
||||
|
||||
#endif /* __PIKA_GRADIENTS__ */
|
||||
559
app/core/pika-gui.c
Normal file
559
app/core/pika-gui.c
Normal file
@ -0,0 +1,559 @@
|
||||
/* 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-2002 Spencer Kimball, Peter Mattis, and others
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pika-gui.h"
|
||||
#include "pikacontainer.h"
|
||||
#include "pikacontext.h"
|
||||
#include "pikadisplay.h"
|
||||
#include "pikaimage.h"
|
||||
#include "pikaprogress.h"
|
||||
#include "pikawaitable.h"
|
||||
|
||||
#include "about.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
void
|
||||
pika_gui_init (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
pika->gui.ungrab = NULL;
|
||||
pika->gui.set_busy = NULL;
|
||||
pika->gui.unset_busy = NULL;
|
||||
pika->gui.show_message = NULL;
|
||||
pika->gui.help = NULL;
|
||||
pika->gui.get_program_class = NULL;
|
||||
pika->gui.get_display_name = NULL;
|
||||
pika->gui.get_user_time = NULL;
|
||||
pika->gui.get_theme_dir = NULL;
|
||||
pika->gui.get_icon_theme_dir = NULL;
|
||||
pika->gui.display_get_window_id = NULL;
|
||||
pika->gui.display_create = NULL;
|
||||
pika->gui.display_delete = NULL;
|
||||
pika->gui.displays_reconnect = NULL;
|
||||
pika->gui.progress_new = NULL;
|
||||
pika->gui.progress_free = NULL;
|
||||
pika->gui.pdb_dialog_set = NULL;
|
||||
pika->gui.pdb_dialog_close = NULL;
|
||||
pika->gui.recent_list_add_file = NULL;
|
||||
pika->gui.recent_list_load = NULL;
|
||||
pika->gui.get_mount_operation = NULL;
|
||||
pika->gui.query_profile_policy = NULL;
|
||||
pika->gui.query_rotation_policy = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
pika_gui_ungrab (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
if (pika->gui.ungrab)
|
||||
pika->gui.ungrab (pika);
|
||||
}
|
||||
|
||||
void
|
||||
pika_set_busy (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
/* FIXME: pika_busy HACK */
|
||||
pika->busy++;
|
||||
|
||||
if (pika->busy == 1)
|
||||
{
|
||||
if (pika->gui.set_busy)
|
||||
pika->gui.set_busy (pika);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_idle_unset_busy (gpointer data)
|
||||
{
|
||||
Pika *pika = data;
|
||||
|
||||
pika_unset_busy (pika);
|
||||
|
||||
pika->busy_idle_id = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
pika_set_busy_until_idle (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
if (! pika->busy_idle_id)
|
||||
{
|
||||
pika_set_busy (pika);
|
||||
|
||||
pika->busy_idle_id = g_idle_add_full (G_PRIORITY_HIGH,
|
||||
pika_idle_unset_busy, pika,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_unset_busy (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (pika->busy > 0);
|
||||
|
||||
/* FIXME: pika_busy HACK */
|
||||
pika->busy--;
|
||||
|
||||
if (pika->busy == 0)
|
||||
{
|
||||
if (pika->gui.unset_busy)
|
||||
pika->gui.unset_busy (pika);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_show_message (Pika *pika,
|
||||
GObject *handler,
|
||||
PikaMessageSeverity severity,
|
||||
const gchar *domain,
|
||||
const gchar *message)
|
||||
{
|
||||
const gchar *desc = (severity == PIKA_MESSAGE_ERROR) ? "Error" : "Message";
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (handler == NULL || G_IS_OBJECT (handler));
|
||||
g_return_if_fail (message != NULL);
|
||||
|
||||
if (! domain)
|
||||
domain = PIKA_ACRONYM;
|
||||
|
||||
if (! pika->console_messages)
|
||||
{
|
||||
if (pika->gui.show_message)
|
||||
{
|
||||
pika->gui.show_message (pika, handler, severity,
|
||||
domain, message);
|
||||
return;
|
||||
}
|
||||
else if (PIKA_IS_PROGRESS (handler) &&
|
||||
pika_progress_message (PIKA_PROGRESS (handler), pika,
|
||||
severity, domain, message))
|
||||
{
|
||||
/* message has been handled by PikaProgress */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pika_enum_get_value (PIKA_TYPE_MESSAGE_SEVERITY, severity,
|
||||
NULL, NULL, &desc, NULL);
|
||||
g_printerr ("%s-%s: %s\n\n", domain, desc, message);
|
||||
}
|
||||
|
||||
void
|
||||
pika_wait (Pika *pika,
|
||||
PikaWaitable *waitable,
|
||||
const gchar *format,
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
gchar *message;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (PIKA_IS_WAITABLE (waitable));
|
||||
g_return_if_fail (format != NULL);
|
||||
|
||||
if (pika_waitable_wait_for (waitable, 0.5 * G_TIME_SPAN_SECOND))
|
||||
return;
|
||||
|
||||
va_start (args, format);
|
||||
|
||||
message = g_strdup_vprintf (format, args);
|
||||
|
||||
va_end (args);
|
||||
|
||||
if (! pika->console_messages &&
|
||||
pika->gui.wait &&
|
||||
pika->gui.wait (pika, waitable, message))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Translator: This message is displayed while PIKA is waiting for
|
||||
* some operation to finish. The %s argument is a message describing
|
||||
* the operation.
|
||||
*/
|
||||
g_printerr (_("Please wait: %s\n"), message);
|
||||
|
||||
pika_waitable_wait (waitable);
|
||||
|
||||
g_free (message);
|
||||
}
|
||||
|
||||
void
|
||||
pika_help (Pika *pika,
|
||||
PikaProgress *progress,
|
||||
const gchar *help_domain,
|
||||
const gchar *help_id)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress));
|
||||
|
||||
if (pika->gui.help)
|
||||
pika->gui.help (pika, progress, help_domain, help_id);
|
||||
}
|
||||
|
||||
const gchar *
|
||||
pika_get_program_class (Pika *pika)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
|
||||
if (pika->gui.get_program_class)
|
||||
return pika->gui.get_program_class (pika);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gchar *
|
||||
pika_get_display_name (Pika *pika,
|
||||
gint display_id,
|
||||
GObject **monitor,
|
||||
gint *monitor_number)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
g_return_val_if_fail (monitor != NULL, NULL);
|
||||
g_return_val_if_fail (monitor_number != NULL, NULL);
|
||||
|
||||
if (pika->gui.get_display_name)
|
||||
return pika->gui.get_display_name (pika, display_id,
|
||||
monitor, monitor_number);
|
||||
|
||||
*monitor = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_get_user_time:
|
||||
* @pika:
|
||||
*
|
||||
* Returns the timestamp of the last user interaction. The timestamp is
|
||||
* taken from events caused by user interaction such as key presses or
|
||||
* pointer movements. See gdk_x11_display_get_user_time().
|
||||
*
|
||||
* Returns: the timestamp of the last user interaction
|
||||
*/
|
||||
guint32
|
||||
pika_get_user_time (Pika *pika)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), 0);
|
||||
|
||||
if (pika->gui.get_user_time)
|
||||
return pika->gui.get_user_time (pika);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
GFile *
|
||||
pika_get_theme_dir (Pika *pika)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
|
||||
if (pika->gui.get_theme_dir)
|
||||
return pika->gui.get_theme_dir (pika);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GFile *
|
||||
pika_get_icon_theme_dir (Pika *pika)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
|
||||
if (pika->gui.get_icon_theme_dir)
|
||||
return pika->gui.get_icon_theme_dir (pika);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PikaObject *
|
||||
pika_get_window_strategy (Pika *pika)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
|
||||
if (pika->gui.get_window_strategy)
|
||||
return pika->gui.get_window_strategy (pika);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PikaDisplay *
|
||||
pika_get_empty_display (Pika *pika)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
|
||||
if (pika->gui.get_empty_display)
|
||||
return pika->gui.get_empty_display (pika);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
guint32
|
||||
pika_get_display_window_id (Pika *pika,
|
||||
PikaDisplay *display)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), -1);
|
||||
g_return_val_if_fail (PIKA_IS_DISPLAY (display), -1);
|
||||
|
||||
if (pika->gui.display_get_window_id)
|
||||
return pika->gui.display_get_window_id (display);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
PikaDisplay *
|
||||
pika_create_display (Pika *pika,
|
||||
PikaImage *image,
|
||||
PikaUnit unit,
|
||||
gdouble scale,
|
||||
GObject *monitor)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
g_return_val_if_fail (image == NULL || PIKA_IS_IMAGE (image), NULL);
|
||||
g_return_val_if_fail (monitor == NULL || G_IS_OBJECT (monitor), NULL);
|
||||
|
||||
if (pika->gui.display_create)
|
||||
return pika->gui.display_create (pika, image, unit, scale, monitor);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
pika_delete_display (Pika *pika,
|
||||
PikaDisplay *display)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (PIKA_IS_DISPLAY (display));
|
||||
|
||||
if (pika->gui.display_delete)
|
||||
pika->gui.display_delete (display);
|
||||
}
|
||||
|
||||
void
|
||||
pika_reconnect_displays (Pika *pika,
|
||||
PikaImage *old_image,
|
||||
PikaImage *new_image)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (PIKA_IS_IMAGE (old_image));
|
||||
g_return_if_fail (PIKA_IS_IMAGE (new_image));
|
||||
|
||||
if (pika->gui.displays_reconnect)
|
||||
pika->gui.displays_reconnect (pika, old_image, new_image);
|
||||
}
|
||||
|
||||
PikaProgress *
|
||||
pika_new_progress (Pika *pika,
|
||||
PikaDisplay *display)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
g_return_val_if_fail (display == NULL || PIKA_IS_DISPLAY (display), NULL);
|
||||
|
||||
if (pika->gui.progress_new)
|
||||
return pika->gui.progress_new (pika, display);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
pika_free_progress (Pika *pika,
|
||||
PikaProgress *progress)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (PIKA_IS_PROGRESS (progress));
|
||||
|
||||
if (pika->gui.progress_free)
|
||||
pika->gui.progress_free (pika, progress);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_pdb_dialog_new (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
PikaContainer *container,
|
||||
const gchar *title,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
...)
|
||||
{
|
||||
gboolean retval = FALSE;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (PIKA_IS_CONTEXT (context), FALSE);
|
||||
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), FALSE);
|
||||
g_return_val_if_fail (PIKA_IS_CONTAINER (container), FALSE);
|
||||
g_return_val_if_fail (title != NULL, FALSE);
|
||||
g_return_val_if_fail (callback_name != NULL, FALSE);
|
||||
|
||||
if (pika->gui.pdb_dialog_new)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, object_name);
|
||||
|
||||
retval = pika->gui.pdb_dialog_new (pika, context, progress,
|
||||
container, title,
|
||||
callback_name, object_name,
|
||||
args);
|
||||
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_pdb_dialog_set (Pika *pika,
|
||||
PikaContainer *container,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
...)
|
||||
{
|
||||
gboolean retval = FALSE;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (PIKA_IS_CONTAINER (container), FALSE);
|
||||
g_return_val_if_fail (callback_name != NULL, FALSE);
|
||||
g_return_val_if_fail (object_name != NULL, FALSE);
|
||||
|
||||
if (pika->gui.pdb_dialog_set)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, object_name);
|
||||
|
||||
retval = pika->gui.pdb_dialog_set (pika, container, callback_name,
|
||||
object_name, args);
|
||||
|
||||
va_end (args);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_pdb_dialog_close (Pika *pika,
|
||||
PikaContainer *container,
|
||||
const gchar *callback_name)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (PIKA_IS_CONTAINER (container), FALSE);
|
||||
g_return_val_if_fail (callback_name != NULL, FALSE);
|
||||
|
||||
if (pika->gui.pdb_dialog_close)
|
||||
return pika->gui.pdb_dialog_close (pika, container, callback_name);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_recent_list_add_file (Pika *pika,
|
||||
GFile *file,
|
||||
const gchar *mime_type)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (G_IS_FILE (file), FALSE);
|
||||
|
||||
if (pika->gui.recent_list_add_file)
|
||||
return pika->gui.recent_list_add_file (pika, file, mime_type);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
pika_recent_list_load (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
if (pika->gui.recent_list_load)
|
||||
pika->gui.recent_list_load (pika);
|
||||
}
|
||||
|
||||
GMountOperation *
|
||||
pika_get_mount_operation (Pika *pika,
|
||||
PikaProgress *progress)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), FALSE);
|
||||
|
||||
if (pika->gui.get_mount_operation)
|
||||
return pika->gui.get_mount_operation (pika, progress);
|
||||
|
||||
return g_mount_operation_new ();
|
||||
}
|
||||
|
||||
PikaColorProfilePolicy
|
||||
pika_query_profile_policy (Pika *pika,
|
||||
PikaImage *image,
|
||||
PikaContext *context,
|
||||
PikaColorProfile **dest_profile,
|
||||
PikaColorRenderingIntent *intent,
|
||||
gboolean *bpc,
|
||||
gboolean *dont_ask)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), PIKA_COLOR_PROFILE_POLICY_KEEP);
|
||||
g_return_val_if_fail (PIKA_IS_IMAGE (image), PIKA_COLOR_PROFILE_POLICY_KEEP);
|
||||
g_return_val_if_fail (PIKA_IS_CONTEXT (context), PIKA_COLOR_PROFILE_POLICY_KEEP);
|
||||
g_return_val_if_fail (dest_profile != NULL, PIKA_COLOR_PROFILE_POLICY_KEEP);
|
||||
|
||||
if (pika->gui.query_profile_policy)
|
||||
return pika->gui.query_profile_policy (pika, image, context,
|
||||
dest_profile,
|
||||
intent, bpc,
|
||||
dont_ask);
|
||||
|
||||
return PIKA_COLOR_PROFILE_POLICY_KEEP;
|
||||
}
|
||||
|
||||
PikaMetadataRotationPolicy
|
||||
pika_query_rotation_policy (Pika *pika,
|
||||
PikaImage *image,
|
||||
PikaContext *context,
|
||||
gboolean *dont_ask)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), PIKA_METADATA_ROTATION_POLICY_ROTATE);
|
||||
g_return_val_if_fail (PIKA_IS_IMAGE (image), PIKA_METADATA_ROTATION_POLICY_ROTATE);
|
||||
g_return_val_if_fail (PIKA_IS_CONTEXT (context), PIKA_METADATA_ROTATION_POLICY_ROTATE);
|
||||
|
||||
if (pika->gui.query_rotation_policy)
|
||||
return pika->gui.query_rotation_policy (pika, image, context, dont_ask);
|
||||
|
||||
return PIKA_METADATA_ROTATION_POLICY_ROTATE;
|
||||
}
|
||||
216
app/core/pika-gui.h
Normal file
216
app/core/pika-gui.h
Normal file
@ -0,0 +1,216 @@
|
||||
/* 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-1997 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_GUI_H__
|
||||
#define __PIKA_GUI_H__
|
||||
|
||||
|
||||
typedef struct _PikaGui PikaGui;
|
||||
|
||||
struct _PikaGui
|
||||
{
|
||||
void (* ungrab) (Pika *pika);
|
||||
|
||||
void (* set_busy) (Pika *pika);
|
||||
void (* unset_busy) (Pika *pika);
|
||||
|
||||
void (* show_message) (Pika *pika,
|
||||
GObject *handler,
|
||||
PikaMessageSeverity severity,
|
||||
const gchar *domain,
|
||||
const gchar *message);
|
||||
void (* help) (Pika *pika,
|
||||
PikaProgress *progress,
|
||||
const gchar *help_domain,
|
||||
const gchar *help_id);
|
||||
|
||||
gboolean (* wait) (Pika *pika,
|
||||
PikaWaitable *waitable,
|
||||
const gchar *message);
|
||||
|
||||
const gchar * (* get_program_class) (Pika *pika);
|
||||
gchar * (* get_display_name) (Pika *pika,
|
||||
gint display_id,
|
||||
GObject **monitor,
|
||||
gint *monitor_number);
|
||||
guint32 (* get_user_time) (Pika *pika);
|
||||
|
||||
GFile * (* get_theme_dir) (Pika *pika);
|
||||
GFile * (* get_icon_theme_dir) (Pika *pika);
|
||||
|
||||
PikaObject * (* get_window_strategy) (Pika *pika);
|
||||
PikaDisplay * (* get_empty_display) (Pika *pika);
|
||||
guint32 (* display_get_window_id) (PikaDisplay *display);
|
||||
PikaDisplay * (* display_create) (Pika *pika,
|
||||
PikaImage *image,
|
||||
PikaUnit unit,
|
||||
gdouble scale,
|
||||
GObject *monitor);
|
||||
void (* display_delete) (PikaDisplay *display);
|
||||
void (* displays_reconnect) (Pika *pika,
|
||||
PikaImage *old_image,
|
||||
PikaImage *new_image);
|
||||
|
||||
PikaProgress * (* progress_new) (Pika *pika,
|
||||
PikaDisplay *display);
|
||||
void (* progress_free) (Pika *pika,
|
||||
PikaProgress *progress);
|
||||
|
||||
gboolean (* pdb_dialog_new) (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
PikaContainer *container,
|
||||
const gchar *title,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
va_list args);
|
||||
gboolean (* pdb_dialog_set) (Pika *pika,
|
||||
PikaContainer *container,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
va_list args);
|
||||
gboolean (* pdb_dialog_close) (Pika *pika,
|
||||
PikaContainer *container,
|
||||
const gchar *callback_name);
|
||||
gboolean (* recent_list_add_file) (Pika *pika,
|
||||
GFile *file,
|
||||
const gchar *mime_type);
|
||||
void (* recent_list_load) (Pika *pika);
|
||||
|
||||
GMountOperation
|
||||
* (* get_mount_operation) (Pika *pika,
|
||||
PikaProgress *progress);
|
||||
|
||||
PikaColorProfilePolicy
|
||||
(* query_profile_policy) (Pika *pika,
|
||||
PikaImage *image,
|
||||
PikaContext *context,
|
||||
PikaColorProfile **dest_profile,
|
||||
PikaColorRenderingIntent *intent,
|
||||
gboolean *bpc,
|
||||
gboolean *dont_ask);
|
||||
|
||||
PikaMetadataRotationPolicy
|
||||
(* query_rotation_policy) (Pika *pika,
|
||||
PikaImage *image,
|
||||
PikaContext *context,
|
||||
gboolean *dont_ask);
|
||||
};
|
||||
|
||||
|
||||
void pika_gui_init (Pika *pika);
|
||||
|
||||
void pika_gui_ungrab (Pika *pika);
|
||||
|
||||
PikaObject * pika_get_window_strategy (Pika *pika);
|
||||
PikaDisplay * pika_get_empty_display (Pika *pika);
|
||||
PikaDisplay * pika_get_display_by_id (Pika *pika,
|
||||
gint ID);
|
||||
gint pika_get_display_id (Pika *pika,
|
||||
PikaDisplay *display);
|
||||
guint32 pika_get_display_window_id (Pika *pika,
|
||||
PikaDisplay *display);
|
||||
PikaDisplay * pika_create_display (Pika *pika,
|
||||
PikaImage *image,
|
||||
PikaUnit unit,
|
||||
gdouble scale,
|
||||
GObject *monitor);
|
||||
void pika_delete_display (Pika *pika,
|
||||
PikaDisplay *display);
|
||||
void pika_reconnect_displays (Pika *pika,
|
||||
PikaImage *old_image,
|
||||
PikaImage *new_image);
|
||||
|
||||
void pika_set_busy (Pika *pika);
|
||||
void pika_set_busy_until_idle (Pika *pika);
|
||||
void pika_unset_busy (Pika *pika);
|
||||
|
||||
void pika_show_message (Pika *pika,
|
||||
GObject *handler,
|
||||
PikaMessageSeverity severity,
|
||||
const gchar *domain,
|
||||
const gchar *message);
|
||||
void pika_help (Pika *pika,
|
||||
PikaProgress *progress,
|
||||
const gchar *help_domain,
|
||||
const gchar *help_id);
|
||||
|
||||
void pika_wait (Pika *pika,
|
||||
PikaWaitable *waitable,
|
||||
const gchar *format,
|
||||
...) G_GNUC_PRINTF (3, 4);
|
||||
|
||||
PikaProgress * pika_new_progress (Pika *pika,
|
||||
PikaDisplay *display);
|
||||
void pika_free_progress (Pika *pika,
|
||||
PikaProgress *progress);
|
||||
|
||||
const gchar * pika_get_program_class (Pika *pika);
|
||||
gchar * pika_get_display_name (Pika *pika,
|
||||
gint display_id,
|
||||
GObject **monitor,
|
||||
gint *monitor_number);
|
||||
guint32 pika_get_user_time (Pika *pika);
|
||||
GFile * pika_get_theme_dir (Pika *pika);
|
||||
GFile * pika_get_icon_theme_dir (Pika *pika);
|
||||
|
||||
gboolean pika_pdb_dialog_new (Pika *pika,
|
||||
PikaContext *context,
|
||||
PikaProgress *progress,
|
||||
PikaContainer *container,
|
||||
const gchar *title,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
gboolean pika_pdb_dialog_set (Pika *pika,
|
||||
PikaContainer *container,
|
||||
const gchar *callback_name,
|
||||
const gchar *object_name,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
gboolean pika_pdb_dialog_close (Pika *pika,
|
||||
PikaContainer *container,
|
||||
const gchar *callback_name);
|
||||
gboolean pika_recent_list_add_file (Pika *pika,
|
||||
GFile *file,
|
||||
const gchar *mime_type);
|
||||
void pika_recent_list_load (Pika *pika);
|
||||
|
||||
GMountOperation
|
||||
* pika_get_mount_operation (Pika *pika,
|
||||
PikaProgress *progress);
|
||||
|
||||
PikaColorProfilePolicy
|
||||
pika_query_profile_policy (Pika *pika,
|
||||
PikaImage *image,
|
||||
PikaContext *context,
|
||||
PikaColorProfile **dest_profile,
|
||||
PikaColorRenderingIntent *intent,
|
||||
gboolean *bpc,
|
||||
gboolean *dont_ask);
|
||||
|
||||
PikaMetadataRotationPolicy
|
||||
pika_query_rotation_policy (Pika *pika,
|
||||
PikaImage *image,
|
||||
PikaContext *context,
|
||||
gboolean *dont_ask);
|
||||
|
||||
|
||||
#endif /* __PIKA_GUI_H__ */
|
||||
350
app/core/pika-internal-data.c
Normal file
350
app/core/pika-internal-data.c
Normal file
@ -0,0 +1,350 @@
|
||||
/* 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-2002 Spencer Kimball, Peter Mattis, and others
|
||||
*
|
||||
* pika-internal-data.c
|
||||
* Copyright (C) 2017 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pika-gradients.h"
|
||||
#include "pika-internal-data.h"
|
||||
#include "pikadata.h"
|
||||
#include "pikadataloaderfactory.h"
|
||||
#include "pikaerror.h"
|
||||
#include "pikagradient-load.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
#define PIKA_INTERNAL_DATA_DIRECTORY "internal-data"
|
||||
|
||||
|
||||
typedef PikaData * (* PikaDataGetFunc) (Pika *pika);
|
||||
|
||||
|
||||
typedef struct _PikaInternalDataFile PikaInternalDataFile;
|
||||
|
||||
struct _PikaInternalDataFile
|
||||
{
|
||||
const gchar *name;
|
||||
PikaDataGetFunc get_func;
|
||||
PikaDataLoadFunc load_func;
|
||||
};
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static gboolean pika_internal_data_create_directory (GError **error);
|
||||
|
||||
static GFile * pika_internal_data_get_file (const PikaInternalDataFile *data_file);
|
||||
|
||||
static gboolean pika_internal_data_load_data_file (Pika *pika,
|
||||
const PikaInternalDataFile *data_file,
|
||||
GError **error);
|
||||
static gboolean pika_internal_data_save_data_file (Pika *pika,
|
||||
const PikaInternalDataFile *data_file,
|
||||
GError **error);
|
||||
static gboolean pika_internal_data_delete_data_file (Pika *pika,
|
||||
const PikaInternalDataFile *data_file,
|
||||
GError **error);
|
||||
|
||||
/* static variables */
|
||||
|
||||
static const PikaInternalDataFile internal_data_files[] =
|
||||
{
|
||||
/* Custom gradient */
|
||||
{
|
||||
.name = "custom" PIKA_GRADIENT_FILE_EXTENSION,
|
||||
.get_func = (PikaDataGetFunc) pika_gradients_get_custom,
|
||||
.load_func = pika_gradient_load
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
gboolean
|
||||
pika_internal_data_load (Pika *pika,
|
||||
GError **error)
|
||||
{
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (internal_data_files); i++)
|
||||
{
|
||||
const PikaInternalDataFile *data_file = &internal_data_files[i];
|
||||
|
||||
if (! pika_internal_data_load_data_file (pika, data_file, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_internal_data_save (Pika *pika,
|
||||
GError **error)
|
||||
{
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
if (! pika_internal_data_create_directory (error))
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (internal_data_files); i++)
|
||||
{
|
||||
const PikaInternalDataFile *data_file = &internal_data_files[i];
|
||||
|
||||
if (! pika_internal_data_save_data_file (pika, data_file, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_internal_data_clear (Pika *pika,
|
||||
GError **error)
|
||||
{
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (internal_data_files); i++)
|
||||
{
|
||||
const PikaInternalDataFile *data_file = &internal_data_files[i];
|
||||
|
||||
if (! pika_internal_data_delete_data_file (pika, data_file, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static gboolean
|
||||
pika_internal_data_create_directory (GError **error)
|
||||
{
|
||||
GFile *directory;
|
||||
GError *my_error = NULL;
|
||||
gboolean success;
|
||||
|
||||
directory = pika_directory_file (PIKA_INTERNAL_DATA_DIRECTORY, NULL);
|
||||
|
||||
success = g_file_make_directory (directory, NULL, &my_error);
|
||||
|
||||
g_object_unref (directory);
|
||||
|
||||
if (! success)
|
||||
{
|
||||
if (my_error->code == G_IO_ERROR_EXISTS)
|
||||
{
|
||||
g_clear_error (&my_error);
|
||||
success = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_propagate_error (error, my_error);
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static GFile *
|
||||
pika_internal_data_get_file (const PikaInternalDataFile *data_file)
|
||||
{
|
||||
return pika_directory_file (PIKA_INTERNAL_DATA_DIRECTORY,
|
||||
data_file->name,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_internal_data_load_data_file (Pika *pika,
|
||||
const PikaInternalDataFile *data_file,
|
||||
GError **error)
|
||||
{
|
||||
GFile *file;
|
||||
GInputStream *input;
|
||||
PikaData *data;
|
||||
GList *list;
|
||||
GError *my_error = NULL;
|
||||
|
||||
file = pika_internal_data_get_file (data_file);
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Parsing '%s'\n", pika_file_get_utf8_name (file));
|
||||
|
||||
input = G_INPUT_STREAM (g_file_read (file, NULL, &my_error));
|
||||
|
||||
if (! input)
|
||||
{
|
||||
g_object_unref (file);
|
||||
|
||||
if (my_error->code == G_IO_ERROR_NOT_FOUND)
|
||||
{
|
||||
g_clear_error (&my_error);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_propagate_error (error, my_error);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
list = data_file->load_func (pika->user_context, file, input, error);
|
||||
|
||||
g_object_unref (input);
|
||||
g_object_unref (file);
|
||||
|
||||
if (! list)
|
||||
return FALSE;
|
||||
|
||||
data = data_file->get_func (pika);
|
||||
|
||||
pika_data_copy (data, PIKA_DATA (list->data));
|
||||
|
||||
g_list_free_full (list, g_object_unref);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_internal_data_save_data_file (Pika *pika,
|
||||
const PikaInternalDataFile *data_file,
|
||||
GError **error)
|
||||
{
|
||||
GFile *file;
|
||||
GOutputStream *output;
|
||||
PikaData *data;
|
||||
gboolean success;
|
||||
|
||||
file = pika_internal_data_get_file (data_file);
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Writing '%s'\n", pika_file_get_utf8_name (file));
|
||||
|
||||
output = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE,
|
||||
G_FILE_CREATE_NONE,
|
||||
NULL, error));
|
||||
|
||||
if (! output)
|
||||
{
|
||||
g_object_unref (file);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
data = data_file->get_func (pika);
|
||||
|
||||
/* we bypass pika_data_save() and call the data's save() virtual function
|
||||
* directly, since pika_data_save() is a nop for internal data.
|
||||
*
|
||||
* FIXME: we save the data whether it's dirty or not, since it might not
|
||||
* exist on disk. currently, we only use this for cheap data, such as
|
||||
* gradients, so this is not a big concern, but if we save more expensive
|
||||
* data in the future, we should fix this.
|
||||
*/
|
||||
pika_assert (PIKA_DATA_GET_CLASS (data)->save);
|
||||
success = PIKA_DATA_GET_CLASS (data)->save (data, output, error);
|
||||
|
||||
if (success)
|
||||
{
|
||||
if (! g_output_stream_close (output, NULL, error))
|
||||
{
|
||||
g_prefix_error (error,
|
||||
_("Error saving '%s': "),
|
||||
pika_file_get_utf8_name (file));
|
||||
success = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GCancellable *cancellable = g_cancellable_new ();
|
||||
|
||||
g_cancellable_cancel (cancellable);
|
||||
if (error && *error)
|
||||
{
|
||||
g_prefix_error (error,
|
||||
_("Error saving '%s': "),
|
||||
pika_file_get_utf8_name (file));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (error, PIKA_DATA_ERROR, PIKA_DATA_ERROR_WRITE,
|
||||
_("Error saving '%s'"),
|
||||
pika_file_get_utf8_name (file));
|
||||
}
|
||||
g_output_stream_close (output, cancellable, NULL);
|
||||
g_object_unref (cancellable);
|
||||
}
|
||||
|
||||
g_object_unref (output);
|
||||
g_object_unref (file);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_internal_data_delete_data_file (Pika *pika,
|
||||
const PikaInternalDataFile *data_file,
|
||||
GError **error)
|
||||
{
|
||||
GFile *file;
|
||||
GError *my_error = NULL;
|
||||
gboolean success = TRUE;
|
||||
|
||||
file = pika_internal_data_get_file (data_file);
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Deleting '%s'\n", pika_file_get_utf8_name (file));
|
||||
|
||||
if (! g_file_delete (file, NULL, &my_error) &&
|
||||
my_error->code != G_IO_ERROR_NOT_FOUND)
|
||||
{
|
||||
success = FALSE;
|
||||
|
||||
g_set_error (error, PIKA_ERROR, PIKA_FAILED,
|
||||
_("Deleting \"%s\" failed: %s"),
|
||||
pika_file_get_utf8_name (file), my_error->message);
|
||||
}
|
||||
|
||||
g_clear_error (&my_error);
|
||||
g_object_unref (file);
|
||||
|
||||
return success;
|
||||
}
|
||||
38
app/core/pika-internal-data.h
Normal file
38
app/core/pika-internal-data.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* 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-2002 Spencer Kimball, Peter Mattis, and others
|
||||
*
|
||||
* pika-internal-data.h
|
||||
* Copyright (C) 2017 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_INTERNAL_DATA__
|
||||
#define __PIKA_INTERNAL_DATA__
|
||||
|
||||
|
||||
gboolean pika_internal_data_load (Pika *pika,
|
||||
GError **error);
|
||||
gboolean pika_internal_data_save (Pika *pika,
|
||||
GError **error);
|
||||
|
||||
gboolean pika_internal_data_clear (Pika *pika,
|
||||
GError **error);
|
||||
|
||||
|
||||
#endif /* __PIKA_INTERNAL_DATA__ */
|
||||
364
app/core/pika-memsize.c
Normal file
364
app/core/pika-memsize.c
Normal file
@ -0,0 +1,364 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <cairo.h>
|
||||
#include <gegl.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
#include "libpikacolor/pikacolor.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika-memsize.h"
|
||||
#include "pikaparamspecs.h"
|
||||
|
||||
|
||||
gint64
|
||||
pika_g_type_instance_get_memsize (GTypeInstance *instance)
|
||||
{
|
||||
if (instance)
|
||||
{
|
||||
GTypeQuery type_query;
|
||||
|
||||
g_type_query (G_TYPE_FROM_INSTANCE (instance), &type_query);
|
||||
|
||||
return type_query.instance_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint64
|
||||
pika_g_object_get_memsize (GObject *object)
|
||||
{
|
||||
if (object)
|
||||
return pika_g_type_instance_get_memsize ((GTypeInstance *) object);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint64
|
||||
pika_g_hash_table_get_memsize (GHashTable *hash,
|
||||
gint64 data_size)
|
||||
{
|
||||
if (hash)
|
||||
return (2 * sizeof (gint) +
|
||||
5 * sizeof (gpointer) +
|
||||
g_hash_table_size (hash) * (3 * sizeof (gpointer) + data_size));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PikaMemsizeFunc func;
|
||||
gint64 memsize;
|
||||
gint64 gui_size;
|
||||
} HashMemsize;
|
||||
|
||||
static void
|
||||
hash_memsize_foreach (gpointer key,
|
||||
gpointer value,
|
||||
HashMemsize *memsize)
|
||||
{
|
||||
gint64 gui_size = 0;
|
||||
|
||||
memsize->memsize += memsize->func (value, &gui_size);
|
||||
memsize->gui_size += gui_size;
|
||||
}
|
||||
|
||||
gint64
|
||||
pika_g_hash_table_get_memsize_foreach (GHashTable *hash,
|
||||
PikaMemsizeFunc func,
|
||||
gint64 *gui_size)
|
||||
{
|
||||
HashMemsize memsize;
|
||||
|
||||
g_return_val_if_fail (func != NULL, 0);
|
||||
|
||||
if (! hash)
|
||||
return 0;
|
||||
|
||||
memsize.func = func;
|
||||
memsize.memsize = 0;
|
||||
memsize.gui_size = 0;
|
||||
|
||||
g_hash_table_foreach (hash, (GHFunc) hash_memsize_foreach, &memsize);
|
||||
|
||||
if (gui_size)
|
||||
*gui_size = memsize.gui_size;
|
||||
|
||||
return memsize.memsize + pika_g_hash_table_get_memsize (hash, 0);
|
||||
}
|
||||
|
||||
gint64
|
||||
pika_g_slist_get_memsize (GSList *slist,
|
||||
gint64 data_size)
|
||||
{
|
||||
return g_slist_length (slist) * (data_size + sizeof (GSList));
|
||||
}
|
||||
|
||||
gint64
|
||||
pika_g_slist_get_memsize_foreach (GSList *slist,
|
||||
PikaMemsizeFunc func,
|
||||
gint64 *gui_size)
|
||||
{
|
||||
GSList *l;
|
||||
gint64 memsize = 0;
|
||||
|
||||
g_return_val_if_fail (func != NULL, 0);
|
||||
|
||||
for (l = slist; l; l = g_slist_next (l))
|
||||
memsize += sizeof (GSList) + func (l->data, gui_size);
|
||||
|
||||
return memsize;
|
||||
}
|
||||
|
||||
gint64
|
||||
pika_g_list_get_memsize (GList *list,
|
||||
gint64 data_size)
|
||||
{
|
||||
return g_list_length (list) * (data_size + sizeof (GList));
|
||||
}
|
||||
|
||||
gint64
|
||||
pika_g_list_get_memsize_foreach (GList *list,
|
||||
PikaMemsizeFunc func,
|
||||
gint64 *gui_size)
|
||||
{
|
||||
GList *l;
|
||||
gint64 memsize = 0;
|
||||
|
||||
g_return_val_if_fail (func != NULL, 0);
|
||||
|
||||
for (l = list; l; l = g_list_next (l))
|
||||
memsize += sizeof (GList) + func (l->data, gui_size);
|
||||
|
||||
return memsize;
|
||||
}
|
||||
|
||||
gint64
|
||||
pika_g_queue_get_memsize (GQueue *queue,
|
||||
gint64 data_size)
|
||||
{
|
||||
if (queue)
|
||||
{
|
||||
return sizeof (GQueue) +
|
||||
g_queue_get_length (queue) * (data_size + sizeof (GList));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint64
|
||||
pika_g_queue_get_memsize_foreach (GQueue *queue,
|
||||
PikaMemsizeFunc func,
|
||||
gint64 *gui_size)
|
||||
{
|
||||
gint64 memsize = 0;
|
||||
|
||||
g_return_val_if_fail (func != NULL, 0);
|
||||
|
||||
if (queue)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
memsize = sizeof (GQueue);
|
||||
|
||||
for (l = queue->head; l; l = g_list_next (l))
|
||||
memsize += sizeof (GList) + func (l->data, gui_size);
|
||||
}
|
||||
|
||||
return memsize;
|
||||
}
|
||||
|
||||
gint64
|
||||
pika_g_value_get_memsize (GValue *value)
|
||||
{
|
||||
gint64 memsize = 0;
|
||||
|
||||
if (! value)
|
||||
return 0;
|
||||
|
||||
if (G_VALUE_HOLDS_STRING (value))
|
||||
{
|
||||
memsize += pika_string_get_memsize (g_value_get_string (value));
|
||||
}
|
||||
else if (G_VALUE_HOLDS_BOXED (value))
|
||||
{
|
||||
if (PIKA_VALUE_HOLDS_RGB (value))
|
||||
{
|
||||
memsize += sizeof (PikaRGB);
|
||||
}
|
||||
else if (PIKA_VALUE_HOLDS_MATRIX2 (value))
|
||||
{
|
||||
memsize += sizeof (PikaMatrix2);
|
||||
}
|
||||
else if (PIKA_VALUE_HOLDS_PARASITE (value))
|
||||
{
|
||||
memsize += pika_parasite_get_memsize (g_value_get_boxed (value),
|
||||
NULL);
|
||||
}
|
||||
else if (PIKA_VALUE_HOLDS_ARRAY (value) ||
|
||||
PIKA_VALUE_HOLDS_INT32_ARRAY (value) ||
|
||||
PIKA_VALUE_HOLDS_FLOAT_ARRAY (value))
|
||||
{
|
||||
PikaArray *array = g_value_get_boxed (value);
|
||||
|
||||
if (array)
|
||||
memsize += sizeof (PikaArray) +
|
||||
(array->static_data ? 0 : array->length);
|
||||
}
|
||||
else if (G_VALUE_HOLDS (value, G_TYPE_BYTES))
|
||||
{
|
||||
GBytes *bytes = g_value_get_boxed (value);
|
||||
|
||||
if (bytes)
|
||||
{
|
||||
memsize += g_bytes_get_size (bytes);
|
||||
}
|
||||
}
|
||||
else if (G_VALUE_HOLDS (value, G_TYPE_STRV))
|
||||
{
|
||||
gchar **array = g_value_get_boxed (value);
|
||||
|
||||
if (array)
|
||||
{
|
||||
guint length = g_strv_length (array);
|
||||
|
||||
memsize += (length + 1) * sizeof (gchar *);
|
||||
for (gint i = 0; i < length; i++)
|
||||
memsize += pika_string_get_memsize (array[i]);
|
||||
}
|
||||
}
|
||||
else if (strcmp ("PikaValueArray", G_VALUE_TYPE_NAME (value)) == 0)
|
||||
{
|
||||
PikaValueArray *array = g_value_get_boxed (value);
|
||||
|
||||
if (array)
|
||||
{
|
||||
gint n_values = pika_value_array_length (array), i;
|
||||
|
||||
memsize += /* sizeof (PikaValueArray) */ sizeof (GValue *) + 3 * sizeof (gint);
|
||||
|
||||
for (i = 0; i < n_values; i++)
|
||||
memsize += pika_g_value_get_memsize (pika_value_array_index (array, i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_printerr ("%s: unhandled boxed value type: %s\n",
|
||||
G_STRFUNC, G_VALUE_TYPE_NAME (value));
|
||||
}
|
||||
}
|
||||
else if (G_VALUE_HOLDS_OBJECT (value))
|
||||
{
|
||||
if (strcmp ("PikaPattern", G_VALUE_TYPE_NAME (value)) == 0)
|
||||
memsize += pika_g_object_get_memsize (g_value_get_object (value));
|
||||
else if (strcmp ("PikaFont", G_VALUE_TYPE_NAME (value)) == 0)
|
||||
memsize += pika_g_object_get_memsize (g_value_get_object (value));
|
||||
else
|
||||
g_printerr ("%s: unhandled object value type: %s\n",
|
||||
G_STRFUNC, G_VALUE_TYPE_NAME (value));
|
||||
}
|
||||
|
||||
return memsize + sizeof (GValue);
|
||||
}
|
||||
|
||||
gint64
|
||||
pika_g_param_spec_get_memsize (GParamSpec *pspec)
|
||||
{
|
||||
gint64 memsize = 0;
|
||||
|
||||
if (! pspec)
|
||||
return 0;
|
||||
|
||||
if (! (pspec->flags & G_PARAM_STATIC_NAME))
|
||||
memsize += pika_string_get_memsize (g_param_spec_get_name (pspec));
|
||||
|
||||
if (! (pspec->flags & G_PARAM_STATIC_NICK))
|
||||
memsize += pika_string_get_memsize (g_param_spec_get_nick (pspec));
|
||||
|
||||
if (! (pspec->flags & G_PARAM_STATIC_BLURB))
|
||||
memsize += pika_string_get_memsize (g_param_spec_get_blurb (pspec));
|
||||
|
||||
return memsize + pika_g_type_instance_get_memsize ((GTypeInstance *) pspec);
|
||||
}
|
||||
|
||||
gint64
|
||||
pika_gegl_buffer_get_memsize (GeglBuffer *buffer)
|
||||
{
|
||||
if (buffer)
|
||||
{
|
||||
const Babl *format = gegl_buffer_get_format (buffer);
|
||||
|
||||
return ((gint64) babl_format_get_bytes_per_pixel (format) *
|
||||
(gint64) gegl_buffer_get_width (buffer) *
|
||||
(gint64) gegl_buffer_get_height (buffer) +
|
||||
pika_g_object_get_memsize (G_OBJECT (buffer)));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint64
|
||||
pika_gegl_pyramid_get_memsize (GeglBuffer *buffer)
|
||||
{
|
||||
if (buffer)
|
||||
{
|
||||
const Babl *format = gegl_buffer_get_format (buffer);
|
||||
|
||||
/* The pyramid levels constitute a geometric sum with a ratio of 1/4. */
|
||||
return ((gint64) babl_format_get_bytes_per_pixel (format) *
|
||||
(gint64) gegl_buffer_get_width (buffer) *
|
||||
(gint64) gegl_buffer_get_height (buffer) * 1.33 +
|
||||
pika_g_object_get_memsize (G_OBJECT (buffer)));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint64
|
||||
pika_string_get_memsize (const gchar *string)
|
||||
{
|
||||
if (string)
|
||||
return strlen (string) + 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint64
|
||||
pika_parasite_get_memsize (PikaParasite *parasite,
|
||||
gint64 *gui_size)
|
||||
{
|
||||
if (parasite)
|
||||
return (sizeof (PikaParasite) +
|
||||
pika_string_get_memsize (parasite->name) +
|
||||
parasite->size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
64
app/core/pika-memsize.h
Normal file
64
app/core/pika-memsize.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __APP_PIKA_MEMSIZE_H__
|
||||
#define __APP_PIKA_MEMSIZE_H__
|
||||
|
||||
|
||||
gint64 pika_g_type_instance_get_memsize (GTypeInstance *instance);
|
||||
gint64 pika_g_object_get_memsize (GObject *object);
|
||||
|
||||
gint64 pika_g_hash_table_get_memsize (GHashTable *hash,
|
||||
gint64 data_size);
|
||||
gint64 pika_g_hash_table_get_memsize_foreach (GHashTable *hash,
|
||||
PikaMemsizeFunc func,
|
||||
gint64 *gui_size);
|
||||
|
||||
gint64 pika_g_slist_get_memsize (GSList *slist,
|
||||
gint64 data_size);
|
||||
gint64 pika_g_slist_get_memsize_foreach (GSList *slist,
|
||||
PikaMemsizeFunc func,
|
||||
gint64 *gui_size);
|
||||
|
||||
gint64 pika_g_list_get_memsize (GList *list,
|
||||
gint64 data_size);
|
||||
gint64 pika_g_list_get_memsize_foreach (GList *list,
|
||||
PikaMemsizeFunc func,
|
||||
gint64 *gui_size);
|
||||
|
||||
gint64 pika_g_queue_get_memsize (GQueue *queue,
|
||||
gint64 data_size);
|
||||
gint64 pika_g_queue_get_memsize_foreach (GQueue *queue,
|
||||
PikaMemsizeFunc func,
|
||||
gint64 *gui_size);
|
||||
|
||||
gint64 pika_g_value_get_memsize (GValue *value);
|
||||
gint64 pika_g_param_spec_get_memsize (GParamSpec *pspec);
|
||||
|
||||
gint64 pika_gegl_buffer_get_memsize (GeglBuffer *buffer);
|
||||
gint64 pika_gegl_pyramid_get_memsize (GeglBuffer *buffer);
|
||||
|
||||
gint64 pika_string_get_memsize (const gchar *string);
|
||||
gint64 pika_parasite_get_memsize (PikaParasite *parasite,
|
||||
gint64 *gui_size);
|
||||
|
||||
|
||||
#endif /* __APP_PIKA_MEMSIZE_H__ */
|
||||
237
app/core/pika-modules.c
Normal file
237
app/core/pika-modules.c
Normal file
@ -0,0 +1,237 @@
|
||||
/* 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
|
||||
*
|
||||
* pikamodules.c
|
||||
* (C) 1999 Austin Donnelly <austin@gimp.org>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamodule/pikamodule.h"
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "config/pikacoreconfig.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pika-modules.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
void
|
||||
pika_modules_init (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
if (! pika->no_interface)
|
||||
{
|
||||
pika->module_db = pika_module_db_new (pika->be_verbose);
|
||||
pika->write_modulerc = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_modules_exit (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
g_clear_object (&pika->module_db);
|
||||
}
|
||||
|
||||
void
|
||||
pika_modules_load (Pika *pika)
|
||||
{
|
||||
GFile *file;
|
||||
GScanner *scanner;
|
||||
gchar *module_load_inhibit = NULL;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
if (pika->no_interface)
|
||||
return;
|
||||
|
||||
pika_module_db_set_verbose (pika->module_db, pika->be_verbose);
|
||||
|
||||
file = pika_directory_file ("modulerc", NULL);
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Parsing '%s'\n", pika_file_get_utf8_name (file));
|
||||
|
||||
scanner = pika_scanner_new_file (file, NULL);
|
||||
g_object_unref (file);
|
||||
|
||||
if (scanner)
|
||||
{
|
||||
GTokenType token;
|
||||
GError *error = NULL;
|
||||
|
||||
#define MODULE_LOAD_INHIBIT 1
|
||||
|
||||
g_scanner_scope_add_symbol (scanner, 0, "module-load-inhibit",
|
||||
GINT_TO_POINTER (MODULE_LOAD_INHIBIT));
|
||||
|
||||
token = G_TOKEN_LEFT_PAREN;
|
||||
|
||||
while (g_scanner_peek_next_token (scanner) == token)
|
||||
{
|
||||
token = g_scanner_get_next_token (scanner);
|
||||
|
||||
switch (token)
|
||||
{
|
||||
case G_TOKEN_LEFT_PAREN:
|
||||
token = G_TOKEN_SYMBOL;
|
||||
break;
|
||||
|
||||
case G_TOKEN_SYMBOL:
|
||||
if (scanner->value.v_symbol == GINT_TO_POINTER (MODULE_LOAD_INHIBIT))
|
||||
{
|
||||
token = G_TOKEN_STRING;
|
||||
|
||||
if (! pika_scanner_parse_string_no_validate (scanner,
|
||||
&module_load_inhibit))
|
||||
goto error;
|
||||
}
|
||||
token = G_TOKEN_RIGHT_PAREN;
|
||||
break;
|
||||
|
||||
case G_TOKEN_RIGHT_PAREN:
|
||||
token = G_TOKEN_LEFT_PAREN;
|
||||
break;
|
||||
|
||||
default: /* do nothing */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#undef MODULE_LOAD_INHIBIT
|
||||
|
||||
if (token != G_TOKEN_LEFT_PAREN)
|
||||
{
|
||||
g_scanner_get_next_token (scanner);
|
||||
g_scanner_unexp_token (scanner, token, NULL, NULL, NULL,
|
||||
_("fatal parse error"), TRUE);
|
||||
}
|
||||
|
||||
error:
|
||||
|
||||
if (error)
|
||||
{
|
||||
pika_message_literal (pika, NULL, PIKA_MESSAGE_ERROR, error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
pika_scanner_unref (scanner);
|
||||
}
|
||||
|
||||
if (module_load_inhibit)
|
||||
{
|
||||
pika_module_db_set_load_inhibit (pika->module_db, module_load_inhibit);
|
||||
g_free (module_load_inhibit);
|
||||
}
|
||||
|
||||
pika_module_db_load (pika->module_db, pika->config->module_path);
|
||||
}
|
||||
|
||||
void
|
||||
pika_modules_unload (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
if (! pika->no_interface && pika->write_modulerc)
|
||||
{
|
||||
PikaConfigWriter *writer;
|
||||
GString *str;
|
||||
GListModel *modules = G_LIST_MODEL (pika->module_db);
|
||||
guint i;
|
||||
const gchar *p;
|
||||
GFile *file;
|
||||
GError *error = NULL;
|
||||
|
||||
str = g_string_new (NULL);
|
||||
for (i = 0; i < g_list_model_get_n_items (modules); i++)
|
||||
{
|
||||
PikaModule *module;
|
||||
|
||||
module = g_list_model_get_item (modules, i);
|
||||
if (! pika_module_get_auto_load (module))
|
||||
{
|
||||
GFile *file = pika_module_get_file (module);
|
||||
gchar *path = g_file_get_path (file);
|
||||
|
||||
g_string_append_c (str, G_SEARCHPATH_SEPARATOR);
|
||||
g_string_append (str, path);
|
||||
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
g_clear_object (&module);
|
||||
}
|
||||
if (str->len > 0)
|
||||
p = str->str + 1;
|
||||
else
|
||||
p = "";
|
||||
|
||||
file = pika_directory_file ("modulerc", NULL);
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Writing '%s'\n", pika_file_get_utf8_name (file));
|
||||
|
||||
writer = pika_config_writer_new_from_file (file,
|
||||
TRUE,
|
||||
"PIKA modulerc",
|
||||
&error);
|
||||
g_object_unref (file);
|
||||
|
||||
if (writer)
|
||||
{
|
||||
pika_config_writer_open (writer, "module-load-inhibit");
|
||||
pika_config_writer_string (writer, p);
|
||||
pika_config_writer_close (writer);
|
||||
|
||||
pika_config_writer_finish (writer, "end of modulerc", &error);
|
||||
|
||||
pika->write_modulerc = FALSE;
|
||||
}
|
||||
|
||||
g_string_free (str, TRUE);
|
||||
|
||||
if (error)
|
||||
{
|
||||
pika_message_literal (pika, NULL, PIKA_MESSAGE_ERROR, error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_modules_refresh (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
if (! pika->no_interface)
|
||||
{
|
||||
pika_module_db_refresh (pika->module_db, pika->config->module_path);
|
||||
}
|
||||
}
|
||||
38
app/core/pika-modules.h
Normal file
38
app/core/pika-modules.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* 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
|
||||
*
|
||||
* pikamodules.h
|
||||
* (C) 1999 Austin Donnelly <austin@gimp.org>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_MODULES_H__
|
||||
#define __PIKA_MODULES_H__
|
||||
|
||||
|
||||
void pika_modules_init (Pika *pika);
|
||||
void pika_modules_exit (Pika *pika);
|
||||
|
||||
void pika_modules_load (Pika *pika);
|
||||
void pika_modules_unload (Pika *pika);
|
||||
|
||||
void pika_modules_refresh (Pika *pika);
|
||||
|
||||
|
||||
#endif /* __PIKA_MODULES_H__ */
|
||||
147
app/core/pika-palettes.c
Normal file
147
app/core/pika-palettes.c
Normal file
@ -0,0 +1,147 @@
|
||||
/* 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-2002 Spencer Kimball, Peter Mattis, and others
|
||||
*
|
||||
* pika-gradients.c
|
||||
* Copyright (C) 2014 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pika-palettes.h"
|
||||
#include "pikacontext.h"
|
||||
#include "pikacontainer.h"
|
||||
#include "pikadatafactory.h"
|
||||
#include "pikapalettemru.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
#define COLOR_HISTORY_KEY "pika-palette-color-history"
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static PikaPalette * pika_palettes_add_palette (Pika *pika,
|
||||
const gchar *name,
|
||||
const gchar *id);
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_palettes_init (Pika *pika)
|
||||
{
|
||||
PikaPalette *palette;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
palette = pika_palettes_add_palette (pika,
|
||||
_("Color History"),
|
||||
COLOR_HISTORY_KEY);
|
||||
pika_context_set_palette (pika->user_context, palette);
|
||||
}
|
||||
|
||||
void
|
||||
pika_palettes_load (Pika *pika)
|
||||
{
|
||||
PikaPalette *palette;
|
||||
GFile *file;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
palette = pika_palettes_get_color_history (pika);
|
||||
|
||||
file = pika_directory_file ("colorrc", NULL);
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Parsing '%s'\n", pika_file_get_utf8_name (file));
|
||||
|
||||
pika_palette_mru_load (PIKA_PALETTE_MRU (palette), file);
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
void
|
||||
pika_palettes_save (Pika *pika)
|
||||
{
|
||||
PikaPalette *palette;
|
||||
GFile *file;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
palette = pika_palettes_get_color_history (pika);
|
||||
|
||||
file = pika_directory_file ("colorrc", NULL);
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Writing '%s'\n", pika_file_get_utf8_name (file));
|
||||
|
||||
pika_palette_mru_save (PIKA_PALETTE_MRU (palette), file);
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
PikaPalette *
|
||||
pika_palettes_get_color_history (Pika *pika)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
|
||||
return g_object_get_data (G_OBJECT (pika), COLOR_HISTORY_KEY);
|
||||
}
|
||||
|
||||
void
|
||||
pika_palettes_add_color_history (Pika *pika,
|
||||
const PikaRGB *color)
|
||||
{
|
||||
PikaPalette *history;
|
||||
|
||||
history = pika_palettes_get_color_history (pika);
|
||||
pika_palette_mru_add (PIKA_PALETTE_MRU (history), color);
|
||||
}
|
||||
|
||||
/* private functions */
|
||||
|
||||
static PikaPalette *
|
||||
pika_palettes_add_palette (Pika *pika,
|
||||
const gchar *name,
|
||||
const gchar *id)
|
||||
{
|
||||
PikaData *palette;
|
||||
|
||||
palette = pika_palette_mru_new (name);
|
||||
|
||||
pika_data_make_internal (palette, id);
|
||||
|
||||
pika_container_add (pika_data_factory_get_container (pika->palette_factory),
|
||||
PIKA_OBJECT (palette));
|
||||
g_object_unref (palette);
|
||||
|
||||
g_object_set_data (G_OBJECT (pika), id, palette);
|
||||
|
||||
return PIKA_PALETTE (palette);
|
||||
}
|
||||
39
app/core/pika-palettes.h
Normal file
39
app/core/pika-palettes.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* 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-2002 Spencer Kimball, Peter Mattis, and others
|
||||
*
|
||||
* pika-palettes.h
|
||||
* Copyright (C) 2014 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_PALETTES__
|
||||
#define __PIKA_PALETTES__
|
||||
|
||||
|
||||
void pika_palettes_init (Pika *pika);
|
||||
|
||||
void pika_palettes_load (Pika *pika);
|
||||
void pika_palettes_save (Pika *pika);
|
||||
|
||||
PikaPalette * pika_palettes_get_color_history (Pika *pika);
|
||||
void pika_palettes_add_color_history (Pika *pika,
|
||||
const PikaRGB *color);
|
||||
|
||||
|
||||
#endif /* __PIKA_PALETTES__ */
|
||||
556
app/core/pika-parallel.cc
Normal file
556
app/core/pika-parallel.cc
Normal file
@ -0,0 +1,556 @@
|
||||
/* 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
|
||||
*
|
||||
* pika-parallel.c
|
||||
* Copyright (C) 2018 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "config/pikageglconfig.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pika-parallel.h"
|
||||
#include "pikaasync.h"
|
||||
#include "pikacancelable.h"
|
||||
|
||||
|
||||
#define PIKA_PARALLEL_MAX_THREADS 64
|
||||
#define PIKA_PARALLEL_RUN_ASYNC_MAX_THREADS 1
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PikaAsync *async;
|
||||
gint priority;
|
||||
PikaRunAsyncFunc func;
|
||||
gpointer user_data;
|
||||
GDestroyNotify user_data_destroy_func;
|
||||
} PikaParallelRunAsyncTask;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GThread *thread;
|
||||
|
||||
gboolean quit;
|
||||
|
||||
PikaAsync *current_async;
|
||||
} PikaParallelRunAsyncThread;
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_parallel_notify_num_processors (PikaGeglConfig *config);
|
||||
|
||||
static void pika_parallel_set_n_threads (gint n_threads,
|
||||
gboolean finish_tasks);
|
||||
|
||||
static void pika_parallel_run_async_set_n_threads (gint n_threads,
|
||||
gboolean finish_tasks);
|
||||
static gpointer pika_parallel_run_async_thread_func (PikaParallelRunAsyncThread *thread);
|
||||
static void pika_parallel_run_async_enqueue_task (PikaParallelRunAsyncTask *task);
|
||||
static PikaParallelRunAsyncTask * pika_parallel_run_async_dequeue_task (void);
|
||||
static gboolean pika_parallel_run_async_execute_task (PikaParallelRunAsyncTask *task);
|
||||
static void pika_parallel_run_async_abort_task (PikaParallelRunAsyncTask *task);
|
||||
static void pika_parallel_run_async_cancel (PikaAsync *async);
|
||||
static void pika_parallel_run_async_waiting (PikaAsync *async);
|
||||
|
||||
|
||||
/* local variables */
|
||||
|
||||
static gint pika_parallel_run_async_n_threads = 0;
|
||||
static PikaParallelRunAsyncThread pika_parallel_run_async_threads[PIKA_PARALLEL_RUN_ASYNC_MAX_THREADS];
|
||||
|
||||
static GMutex pika_parallel_run_async_mutex;
|
||||
static GCond pika_parallel_run_async_cond;
|
||||
static GQueue pika_parallel_run_async_queue = G_QUEUE_INIT;
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
|
||||
void
|
||||
pika_parallel_init (Pika *pika)
|
||||
{
|
||||
PikaGeglConfig *config;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
config = PIKA_GEGL_CONFIG (pika->config);
|
||||
|
||||
g_signal_connect (config, "notify::num-processors",
|
||||
G_CALLBACK (pika_parallel_notify_num_processors),
|
||||
NULL);
|
||||
|
||||
pika_parallel_notify_num_processors (config);
|
||||
}
|
||||
|
||||
void
|
||||
pika_parallel_exit (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
g_signal_handlers_disconnect_by_func (pika->config,
|
||||
(gpointer) pika_parallel_notify_num_processors,
|
||||
NULL);
|
||||
|
||||
/* stop all threads */
|
||||
pika_parallel_set_n_threads (0, /* finish_tasks = */ FALSE);
|
||||
}
|
||||
|
||||
PikaAsync *
|
||||
pika_parallel_run_async (PikaRunAsyncFunc func,
|
||||
gpointer user_data)
|
||||
{
|
||||
return pika_parallel_run_async_full (0, func, user_data, NULL);
|
||||
}
|
||||
|
||||
PikaAsync *
|
||||
pika_parallel_run_async_full (gint priority,
|
||||
PikaRunAsyncFunc func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_destroy_func)
|
||||
{
|
||||
PikaAsync *async;
|
||||
PikaParallelRunAsyncTask *task;
|
||||
|
||||
g_return_val_if_fail (func != NULL, NULL);
|
||||
|
||||
async = pika_async_new ();
|
||||
|
||||
task = g_slice_new (PikaParallelRunAsyncTask);
|
||||
|
||||
task->async = PIKA_ASYNC (g_object_ref (async));
|
||||
task->priority = priority;
|
||||
task->func = func;
|
||||
task->user_data = user_data;
|
||||
task->user_data_destroy_func = user_data_destroy_func;
|
||||
|
||||
if (pika_parallel_run_async_n_threads > 0)
|
||||
{
|
||||
g_signal_connect_after (async, "cancel",
|
||||
G_CALLBACK (pika_parallel_run_async_cancel),
|
||||
NULL);
|
||||
g_signal_connect_after (async, "waiting",
|
||||
G_CALLBACK (pika_parallel_run_async_waiting),
|
||||
NULL);
|
||||
|
||||
g_mutex_lock (&pika_parallel_run_async_mutex);
|
||||
|
||||
pika_parallel_run_async_enqueue_task (task);
|
||||
|
||||
g_cond_signal (&pika_parallel_run_async_cond);
|
||||
|
||||
g_mutex_unlock (&pika_parallel_run_async_mutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (pika_parallel_run_async_execute_task (task));
|
||||
}
|
||||
|
||||
return async;
|
||||
}
|
||||
|
||||
PikaAsync *
|
||||
pika_parallel_run_async_independent (PikaRunAsyncFunc func,
|
||||
gpointer user_data)
|
||||
{
|
||||
return pika_parallel_run_async_independent_full (0, func, user_data);
|
||||
}
|
||||
|
||||
PikaAsync *
|
||||
pika_parallel_run_async_independent_full (gint priority,
|
||||
PikaRunAsyncFunc func,
|
||||
gpointer user_data)
|
||||
{
|
||||
PikaAsync *async;
|
||||
PikaParallelRunAsyncTask *task;
|
||||
GThread *thread;
|
||||
|
||||
g_return_val_if_fail (func != NULL, NULL);
|
||||
|
||||
async = pika_async_new ();
|
||||
|
||||
task = g_slice_new0 (PikaParallelRunAsyncTask);
|
||||
|
||||
task->async = PIKA_ASYNC (g_object_ref (async));
|
||||
task->priority = priority;
|
||||
task->func = func;
|
||||
task->user_data = user_data;
|
||||
|
||||
thread = g_thread_new (
|
||||
"async-ind",
|
||||
[] (gpointer data) -> gpointer
|
||||
{
|
||||
PikaParallelRunAsyncTask *task = (PikaParallelRunAsyncTask *) data;
|
||||
|
||||
/* adjust the thread's priority */
|
||||
#if defined (G_OS_WIN32)
|
||||
if (task->priority < 0)
|
||||
{
|
||||
SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_ABOVE_NORMAL);
|
||||
}
|
||||
else if (task->priority > 0)
|
||||
{
|
||||
SetThreadPriority (GetCurrentThread (), THREAD_MODE_BACKGROUND_BEGIN);
|
||||
}
|
||||
#elif defined (HAVE_UNISTD_H) && defined (__gnu_linux__)
|
||||
if (task->priority)
|
||||
{
|
||||
nice (task->priority);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (pika_parallel_run_async_execute_task (task));
|
||||
|
||||
return NULL;
|
||||
},
|
||||
task);
|
||||
|
||||
pika_async_add_callback (async,
|
||||
[] (PikaAsync *async,
|
||||
gpointer thread)
|
||||
{
|
||||
g_thread_join ((GThread *) thread);
|
||||
},
|
||||
thread);
|
||||
|
||||
return async;
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
|
||||
static void
|
||||
pika_parallel_notify_num_processors (PikaGeglConfig *config)
|
||||
{
|
||||
pika_parallel_set_n_threads (config->num_processors,
|
||||
/* finish_tasks = */ TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_parallel_set_n_threads (gint n_threads,
|
||||
gboolean finish_tasks)
|
||||
{
|
||||
pika_parallel_run_async_set_n_threads (n_threads, finish_tasks);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_parallel_run_async_set_n_threads (gint n_threads,
|
||||
gboolean finish_tasks)
|
||||
{
|
||||
gint i;
|
||||
|
||||
n_threads = CLAMP (n_threads, 0, PIKA_PARALLEL_RUN_ASYNC_MAX_THREADS);
|
||||
|
||||
if (n_threads > pika_parallel_run_async_n_threads) /* need more threads */
|
||||
{
|
||||
for (i = pika_parallel_run_async_n_threads; i < n_threads; i++)
|
||||
{
|
||||
PikaParallelRunAsyncThread *thread =
|
||||
&pika_parallel_run_async_threads[i];
|
||||
|
||||
thread->quit = FALSE;
|
||||
|
||||
thread->thread = g_thread_new (
|
||||
"async",
|
||||
(GThreadFunc) pika_parallel_run_async_thread_func,
|
||||
thread);
|
||||
}
|
||||
}
|
||||
else if (n_threads < pika_parallel_run_async_n_threads) /* need less threads */
|
||||
{
|
||||
g_mutex_lock (&pika_parallel_run_async_mutex);
|
||||
|
||||
for (i = n_threads; i < pika_parallel_run_async_n_threads; i++)
|
||||
{
|
||||
PikaParallelRunAsyncThread *thread =
|
||||
&pika_parallel_run_async_threads[i];
|
||||
|
||||
thread->quit = TRUE;
|
||||
|
||||
if (thread->current_async && ! finish_tasks)
|
||||
pika_cancelable_cancel (PIKA_CANCELABLE (thread->current_async));
|
||||
}
|
||||
|
||||
g_cond_broadcast (&pika_parallel_run_async_cond);
|
||||
|
||||
g_mutex_unlock (&pika_parallel_run_async_mutex);
|
||||
|
||||
for (i = n_threads; i < pika_parallel_run_async_n_threads; i++)
|
||||
{
|
||||
PikaParallelRunAsyncThread *thread =
|
||||
&pika_parallel_run_async_threads[i];
|
||||
|
||||
g_thread_join (thread->thread);
|
||||
}
|
||||
}
|
||||
|
||||
pika_parallel_run_async_n_threads = n_threads;
|
||||
|
||||
if (n_threads == 0)
|
||||
{
|
||||
PikaParallelRunAsyncTask *task;
|
||||
|
||||
/* finish remaining tasks */
|
||||
while ((task = pika_parallel_run_async_dequeue_task ()))
|
||||
{
|
||||
if (finish_tasks)
|
||||
while (pika_parallel_run_async_execute_task (task));
|
||||
else
|
||||
pika_parallel_run_async_abort_task (task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gpointer
|
||||
pika_parallel_run_async_thread_func (PikaParallelRunAsyncThread *thread)
|
||||
{
|
||||
g_mutex_lock (&pika_parallel_run_async_mutex);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
PikaParallelRunAsyncTask *task;
|
||||
|
||||
while (! thread->quit &&
|
||||
(task = pika_parallel_run_async_dequeue_task ()))
|
||||
{
|
||||
gboolean resume;
|
||||
|
||||
thread->current_async = PIKA_ASYNC (g_object_ref (task->async));
|
||||
|
||||
do
|
||||
{
|
||||
g_mutex_unlock (&pika_parallel_run_async_mutex);
|
||||
|
||||
resume = pika_parallel_run_async_execute_task (task);
|
||||
|
||||
g_mutex_lock (&pika_parallel_run_async_mutex);
|
||||
}
|
||||
while (resume &&
|
||||
(g_queue_is_empty (&pika_parallel_run_async_queue) ||
|
||||
task->priority <
|
||||
((PikaParallelRunAsyncTask *)
|
||||
g_queue_peek_head (
|
||||
&pika_parallel_run_async_queue))->priority));
|
||||
|
||||
g_clear_object (&thread->current_async);
|
||||
|
||||
if (resume)
|
||||
pika_parallel_run_async_enqueue_task (task);
|
||||
}
|
||||
|
||||
if (thread->quit)
|
||||
break;
|
||||
|
||||
g_cond_wait (&pika_parallel_run_async_cond,
|
||||
&pika_parallel_run_async_mutex);
|
||||
}
|
||||
|
||||
g_mutex_unlock (&pika_parallel_run_async_mutex);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_parallel_run_async_enqueue_task (PikaParallelRunAsyncTask *task)
|
||||
{
|
||||
GList *link;
|
||||
GList *iter;
|
||||
|
||||
if (pika_async_is_canceled (task->async))
|
||||
{
|
||||
pika_parallel_run_async_abort_task (task);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
link = g_list_alloc ();
|
||||
link->data = task;
|
||||
|
||||
g_object_set_data (G_OBJECT (task->async),
|
||||
"pika-parallel-run-async-link", link);
|
||||
|
||||
for (iter = g_queue_peek_tail_link (&pika_parallel_run_async_queue);
|
||||
iter;
|
||||
iter = g_list_previous (iter))
|
||||
{
|
||||
PikaParallelRunAsyncTask *other_task =
|
||||
(PikaParallelRunAsyncTask *) iter->data;
|
||||
|
||||
if (other_task->priority <= task->priority)
|
||||
break;
|
||||
}
|
||||
|
||||
if (iter)
|
||||
{
|
||||
link->prev = iter;
|
||||
link->next = iter->next;
|
||||
|
||||
iter->next = link;
|
||||
|
||||
if (link->next)
|
||||
link->next->prev = link;
|
||||
else
|
||||
pika_parallel_run_async_queue.tail = link;
|
||||
|
||||
pika_parallel_run_async_queue.length++;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_queue_push_head_link (&pika_parallel_run_async_queue, link);
|
||||
}
|
||||
}
|
||||
|
||||
static PikaParallelRunAsyncTask *
|
||||
pika_parallel_run_async_dequeue_task (void)
|
||||
{
|
||||
PikaParallelRunAsyncTask *task;
|
||||
|
||||
task = (PikaParallelRunAsyncTask *) g_queue_pop_head (
|
||||
&pika_parallel_run_async_queue);
|
||||
|
||||
if (task)
|
||||
{
|
||||
g_object_set_data (G_OBJECT (task->async),
|
||||
"pika-parallel-run-async-link", NULL);
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_parallel_run_async_execute_task (PikaParallelRunAsyncTask *task)
|
||||
{
|
||||
if (pika_async_is_canceled (task->async))
|
||||
{
|
||||
pika_parallel_run_async_abort_task (task);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
task->func (task->async, task->user_data);
|
||||
|
||||
if (pika_async_is_stopped (task->async))
|
||||
{
|
||||
g_object_unref (task->async);
|
||||
|
||||
g_slice_free (PikaParallelRunAsyncTask, task);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_parallel_run_async_abort_task (PikaParallelRunAsyncTask *task)
|
||||
{
|
||||
if (task->user_data && task->user_data_destroy_func)
|
||||
task->user_data_destroy_func (task->user_data);
|
||||
|
||||
pika_async_abort (task->async);
|
||||
|
||||
g_object_unref (task->async);
|
||||
|
||||
g_slice_free (PikaParallelRunAsyncTask, task);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_parallel_run_async_cancel (PikaAsync *async)
|
||||
{
|
||||
GList *link;
|
||||
PikaParallelRunAsyncTask *task = NULL;
|
||||
|
||||
link = (GList *) g_object_get_data (G_OBJECT (async),
|
||||
"pika-parallel-run-async-link");
|
||||
|
||||
if (! link)
|
||||
return;
|
||||
|
||||
g_mutex_lock (&pika_parallel_run_async_mutex);
|
||||
|
||||
link = (GList *) g_object_get_data (G_OBJECT (async),
|
||||
"pika-parallel-run-async-link");
|
||||
|
||||
if (link)
|
||||
{
|
||||
g_object_set_data (G_OBJECT (async),
|
||||
"pika-parallel-run-async-link", NULL);
|
||||
|
||||
task = (PikaParallelRunAsyncTask *) link->data;
|
||||
|
||||
g_queue_delete_link (&pika_parallel_run_async_queue, link);
|
||||
}
|
||||
|
||||
g_mutex_unlock (&pika_parallel_run_async_mutex);
|
||||
|
||||
if (task)
|
||||
pika_parallel_run_async_abort_task (task);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_parallel_run_async_waiting (PikaAsync *async)
|
||||
{
|
||||
GList *link;
|
||||
|
||||
link = (GList *) g_object_get_data (G_OBJECT (async),
|
||||
"pika-parallel-run-async-link");
|
||||
|
||||
if (! link)
|
||||
return;
|
||||
|
||||
g_mutex_lock (&pika_parallel_run_async_mutex);
|
||||
|
||||
link = (GList *) g_object_get_data (G_OBJECT (async),
|
||||
"pika-parallel-run-async-link");
|
||||
|
||||
if (link)
|
||||
{
|
||||
PikaParallelRunAsyncTask *task = (PikaParallelRunAsyncTask *) link->data;
|
||||
|
||||
task->priority = G_MININT;
|
||||
|
||||
g_queue_unlink (&pika_parallel_run_async_queue, link);
|
||||
g_queue_push_head_link (&pika_parallel_run_async_queue, link);
|
||||
}
|
||||
|
||||
g_mutex_unlock (&pika_parallel_run_async_mutex);
|
||||
}
|
||||
|
||||
} /* extern "C" */
|
||||
161
app/core/pika-parallel.h
Normal file
161
app/core/pika-parallel.h
Normal file
@ -0,0 +1,161 @@
|
||||
/* 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
|
||||
*
|
||||
* pika-parallel.h
|
||||
* Copyright (C) 2018 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_PARALLEL_H__
|
||||
#define __PIKA_PARALLEL_H__
|
||||
|
||||
|
||||
void pika_parallel_init (Pika *pika);
|
||||
void pika_parallel_exit (Pika *pika);
|
||||
|
||||
PikaAsync * pika_parallel_run_async (PikaRunAsyncFunc func,
|
||||
gpointer user_data);
|
||||
PikaAsync * pika_parallel_run_async_full (gint priority,
|
||||
PikaRunAsyncFunc func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_destroy_func);
|
||||
PikaAsync * pika_parallel_run_async_independent (PikaRunAsyncFunc func,
|
||||
gpointer user_data);
|
||||
PikaAsync * pika_parallel_run_async_independent_full (gint priority,
|
||||
PikaRunAsyncFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
extern "C++"
|
||||
{
|
||||
|
||||
#include <new>
|
||||
|
||||
template <class RunAsyncFunc>
|
||||
inline PikaAsync *
|
||||
pika_parallel_run_async (RunAsyncFunc func)
|
||||
{
|
||||
RunAsyncFunc *func_copy = g_new (RunAsyncFunc, 1);
|
||||
|
||||
new (func_copy) RunAsyncFunc (func);
|
||||
|
||||
return pika_parallel_run_async_full (0,
|
||||
[] (PikaAsync *async,
|
||||
gpointer user_data)
|
||||
{
|
||||
RunAsyncFunc *func_copy =
|
||||
(RunAsyncFunc *) user_data;
|
||||
|
||||
(*func_copy) (async);
|
||||
|
||||
func_copy->~RunAsyncFunc ();
|
||||
g_free (func_copy);
|
||||
},
|
||||
func_copy,
|
||||
[] (gpointer user_data)
|
||||
{
|
||||
RunAsyncFunc *func_copy =
|
||||
(RunAsyncFunc *) user_data;
|
||||
|
||||
func_copy->~RunAsyncFunc ();
|
||||
g_free (func_copy);
|
||||
});
|
||||
}
|
||||
|
||||
template <class RunAsyncFunc,
|
||||
class DestroyFunc>
|
||||
inline PikaAsync *
|
||||
pika_parallel_run_async_full (gint priority,
|
||||
RunAsyncFunc func,
|
||||
DestroyFunc destroy_func)
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
RunAsyncFunc func;
|
||||
DestroyFunc destroy_func;
|
||||
} Funcs;
|
||||
|
||||
Funcs *funcs_copy = g_new (Funcs, 1);
|
||||
|
||||
new (funcs_copy) Funcs {func, destroy_func};
|
||||
|
||||
return pika_parallel_run_async_full (priority,
|
||||
[] (PikaAsync *async,
|
||||
gpointer user_data)
|
||||
{
|
||||
Funcs *funcs_copy =
|
||||
(Funcs *) user_data;
|
||||
|
||||
funcs_copy->func (async);
|
||||
|
||||
funcs_copy->~Funcs ();
|
||||
g_free (funcs_copy);
|
||||
},
|
||||
funcs_copy,
|
||||
[] (gpointer user_data)
|
||||
{
|
||||
Funcs *funcs_copy =
|
||||
(Funcs *) user_data;
|
||||
|
||||
funcs_copy->destroy_func ();
|
||||
|
||||
funcs_copy->~Funcs ();
|
||||
g_free (funcs_copy);
|
||||
});
|
||||
}
|
||||
|
||||
template <class RunAsyncFunc>
|
||||
inline PikaAsync *
|
||||
pika_parallel_run_async_independent_full (gint priority,
|
||||
RunAsyncFunc func)
|
||||
{
|
||||
RunAsyncFunc *func_copy = g_new (RunAsyncFunc, 1);
|
||||
|
||||
new (func_copy) RunAsyncFunc (func);
|
||||
|
||||
return pika_parallel_run_async_independent_full (priority,
|
||||
[] (PikaAsync *async,
|
||||
gpointer user_data)
|
||||
{
|
||||
RunAsyncFunc *func_copy =
|
||||
(RunAsyncFunc *) user_data;
|
||||
|
||||
(*func_copy) (async);
|
||||
|
||||
func_copy->~RunAsyncFunc ();
|
||||
g_free (func_copy);
|
||||
},
|
||||
func_copy);
|
||||
}
|
||||
|
||||
template <class RunAsyncFunc>
|
||||
inline PikaAsync *
|
||||
pika_parallel_run_async_independent (RunAsyncFunc func)
|
||||
{
|
||||
return pika_parallel_run_async_independent_full (0, func);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#endif /* __PIKA_PARALLEL_H__ */
|
||||
169
app/core/pika-parasites.c
Normal file
169
app/core/pika-parasites.c
Normal file
@ -0,0 +1,169 @@
|
||||
/* gimpparasite.c: Copyright 1998 Jay Cox <jaycox@gimp.org>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pika-parasites.h"
|
||||
#include "pikaparasitelist.h"
|
||||
|
||||
|
||||
gboolean
|
||||
pika_parasite_validate (Pika *pika,
|
||||
const PikaParasite *parasite,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
|
||||
g_return_val_if_fail (parasite != NULL, FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
pika_parasite_attach (Pika *pika,
|
||||
const PikaParasite *parasite)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (parasite != NULL);
|
||||
|
||||
pika_parasite_list_add (pika->parasites, parasite);
|
||||
}
|
||||
|
||||
void
|
||||
pika_parasite_detach (Pika *pika,
|
||||
const gchar *name)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (name != NULL);
|
||||
|
||||
pika_parasite_list_remove (pika->parasites, name);
|
||||
}
|
||||
|
||||
const PikaParasite *
|
||||
pika_parasite_find (Pika *pika,
|
||||
const gchar *name)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
g_return_val_if_fail (name != NULL, NULL);
|
||||
|
||||
return pika_parasite_list_find (pika->parasites, name);
|
||||
}
|
||||
|
||||
static void
|
||||
list_func (const gchar *key,
|
||||
PikaParasite *parasite,
|
||||
gchar ***current)
|
||||
{
|
||||
*(*current)++ = g_strdup (key);
|
||||
}
|
||||
|
||||
gchar **
|
||||
pika_parasite_list (Pika *pika)
|
||||
{
|
||||
gint count;
|
||||
gchar **list;
|
||||
gchar **current;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
|
||||
count = pika_parasite_list_length (pika->parasites);
|
||||
|
||||
list = current = g_new0 (gchar *, count + 1);
|
||||
|
||||
pika_parasite_list_foreach (pika->parasites, (GHFunc) list_func, ¤t);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
/* FIXME: this doesn't belong here */
|
||||
|
||||
void
|
||||
pika_parasite_shift_parent (PikaParasite *parasite)
|
||||
{
|
||||
g_return_if_fail (parasite != NULL);
|
||||
|
||||
parasite->flags = (parasite->flags >> 8);
|
||||
}
|
||||
|
||||
|
||||
/* parasiterc functions */
|
||||
|
||||
void
|
||||
pika_parasiterc_load (Pika *pika)
|
||||
{
|
||||
GFile *file;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
file = pika_directory_file ("parasiterc", NULL);
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Parsing '%s'\n", pika_file_get_utf8_name (file));
|
||||
|
||||
if (! pika_config_deserialize_file (PIKA_CONFIG (pika->parasites),
|
||||
file, NULL, &error))
|
||||
{
|
||||
if (error->code != PIKA_CONFIG_ERROR_OPEN_ENOENT)
|
||||
pika_message_literal (pika, NULL, PIKA_MESSAGE_ERROR, error->message);
|
||||
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
void
|
||||
pika_parasiterc_save (Pika *pika)
|
||||
{
|
||||
const gchar *header =
|
||||
"PIKA parasiterc\n"
|
||||
"\n"
|
||||
"This file will be entirely rewritten each time you exit.";
|
||||
const gchar *footer =
|
||||
"end of parasiterc";
|
||||
|
||||
GFile *file;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (PIKA_IS_PARASITE_LIST (pika->parasites));
|
||||
|
||||
file = pika_directory_file ("parasiterc", NULL);
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Writing '%s'\n", pika_file_get_utf8_name (file));
|
||||
|
||||
if (! pika_config_serialize_to_file (PIKA_CONFIG (pika->parasites),
|
||||
file,
|
||||
header, footer, NULL,
|
||||
&error))
|
||||
{
|
||||
pika_message_literal (pika, NULL, PIKA_MESSAGE_ERROR, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
40
app/core/pika-parasites.h
Normal file
40
app/core/pika-parasites.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* gimpparasite.h: Copyright 1998 Jay Cox <jaycox@gimp.org>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_PARASITES_H__
|
||||
#define __PIKA_PARASITES_H__
|
||||
|
||||
|
||||
/* some wrappers to access pika->parasites, mainly for the PDB */
|
||||
|
||||
gboolean pika_parasite_validate (Pika *pika,
|
||||
const PikaParasite *parasite,
|
||||
GError **error);
|
||||
void pika_parasite_attach (Pika *pika,
|
||||
const PikaParasite *parasite);
|
||||
void pika_parasite_detach (Pika *pika,
|
||||
const gchar *name);
|
||||
const PikaParasite * pika_parasite_find (Pika *pika,
|
||||
const gchar *name);
|
||||
gchar ** pika_parasite_list (Pika *pika);
|
||||
|
||||
void pika_parasite_shift_parent (PikaParasite *parasite);
|
||||
|
||||
void pika_parasiterc_load (Pika *pika);
|
||||
void pika_parasiterc_save (Pika *pika);
|
||||
|
||||
|
||||
#endif /* __PIKA_PARASITES_H__ */
|
||||
254
app/core/pika-spawn.c
Normal file
254
app/core/pika-spawn.c
Normal file
@ -0,0 +1,254 @@
|
||||
/* 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
|
||||
*
|
||||
* pika-spawn.c
|
||||
* Copyright (C) 2018 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#ifdef HAVE_VFORK
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika-spawn.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
#ifdef HAVE_VFORK
|
||||
|
||||
/* copied from glib */
|
||||
static gint
|
||||
exec_err_to_g_error (gint en)
|
||||
{
|
||||
switch (en)
|
||||
{
|
||||
#ifdef EACCES
|
||||
case EACCES:
|
||||
return G_SPAWN_ERROR_ACCES;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef EPERM
|
||||
case EPERM:
|
||||
return G_SPAWN_ERROR_PERM;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef E2BIG
|
||||
case E2BIG:
|
||||
return G_SPAWN_ERROR_TOO_BIG;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef ENOEXEC
|
||||
case ENOEXEC:
|
||||
return G_SPAWN_ERROR_NOEXEC;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef ENAMETOOLONG
|
||||
case ENAMETOOLONG:
|
||||
return G_SPAWN_ERROR_NAMETOOLONG;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef ENOENT
|
||||
case ENOENT:
|
||||
return G_SPAWN_ERROR_NOENT;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef ENOMEM
|
||||
case ENOMEM:
|
||||
return G_SPAWN_ERROR_NOMEM;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef ENOTDIR
|
||||
case ENOTDIR:
|
||||
return G_SPAWN_ERROR_NOTDIR;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef ELOOP
|
||||
case ELOOP:
|
||||
return G_SPAWN_ERROR_LOOP;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef ETXTBUSY
|
||||
case ETXTBUSY:
|
||||
return G_SPAWN_ERROR_TXTBUSY;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef EIO
|
||||
case EIO:
|
||||
return G_SPAWN_ERROR_IO;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef ENFILE
|
||||
case ENFILE:
|
||||
return G_SPAWN_ERROR_NFILE;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef EMFILE
|
||||
case EMFILE:
|
||||
return G_SPAWN_ERROR_MFILE;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef EINVAL
|
||||
case EINVAL:
|
||||
return G_SPAWN_ERROR_INVAL;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef EISDIR
|
||||
case EISDIR:
|
||||
return G_SPAWN_ERROR_ISDIR;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef ELIBBAD
|
||||
case ELIBBAD:
|
||||
return G_SPAWN_ERROR_LIBBAD;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
return G_SPAWN_ERROR_FAILED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_VFORK */
|
||||
|
||||
gboolean
|
||||
pika_spawn_async (gchar **argv,
|
||||
gchar **envp,
|
||||
GSpawnFlags flags,
|
||||
GPid *child_pid,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (argv != NULL, FALSE);
|
||||
g_return_val_if_fail (argv[0] != NULL, FALSE);
|
||||
|
||||
#ifdef HAVE_VFORK
|
||||
if (flags == (G_SPAWN_LEAVE_DESCRIPTORS_OPEN |
|
||||
G_SPAWN_DO_NOT_REAP_CHILD |
|
||||
G_SPAWN_CHILD_INHERITS_STDIN))
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
pid = vfork ();
|
||||
|
||||
if (pid < 0)
|
||||
{
|
||||
gint errsv = errno;
|
||||
|
||||
g_set_error (error,
|
||||
G_SPAWN_ERROR,
|
||||
G_SPAWN_ERROR_FORK,
|
||||
_("Failed to fork (%s)"),
|
||||
g_strerror (errsv));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
if (envp)
|
||||
execve (argv[0], argv, envp);
|
||||
else
|
||||
execv (argv[0], argv);
|
||||
|
||||
_exit (errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
int status = -1;
|
||||
pid_t result;
|
||||
|
||||
result = waitpid (pid, &status, WNOHANG);
|
||||
|
||||
if (result)
|
||||
{
|
||||
if (result < 0)
|
||||
{
|
||||
g_warning ("waitpid() should not fail in "
|
||||
"pika_spawn_async()");
|
||||
}
|
||||
|
||||
if (WIFEXITED (status))
|
||||
status = WEXITSTATUS (status);
|
||||
else
|
||||
status = -1;
|
||||
|
||||
g_set_error (error,
|
||||
G_SPAWN_ERROR,
|
||||
exec_err_to_g_error (status),
|
||||
_("Failed to execute child process “%s” (%s)"),
|
||||
argv[0],
|
||||
g_strerror (status));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (child_pid) *child_pid = pid;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_VFORK */
|
||||
|
||||
return g_spawn_async (NULL, argv, envp, flags, NULL, NULL, child_pid, error);
|
||||
}
|
||||
|
||||
void
|
||||
pika_spawn_set_cloexec (gint fd)
|
||||
{
|
||||
#if defined (G_OS_WIN32)
|
||||
SetHandleInformation ((HANDLE) _get_osfhandle (fd), HANDLE_FLAG_INHERIT, 0);
|
||||
#elif defined (HAVE_FCNTL_H)
|
||||
fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC);
|
||||
#elif defined (__GNUC__)
|
||||
#warning pika_spawn_set_cloexec() is not implemented for the target platform
|
||||
#endif
|
||||
}
|
||||
38
app/core/pika-spawn.h
Normal file
38
app/core/pika-spawn.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* 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
|
||||
*
|
||||
* pika-spawn.h
|
||||
* Copyright (C) 2018 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_SPAWN_H__
|
||||
#define __PIKA_SPAWN_H__
|
||||
|
||||
|
||||
gboolean pika_spawn_async (gchar **argv,
|
||||
gchar **envp,
|
||||
GSpawnFlags flags,
|
||||
GPid *child_pid,
|
||||
GError **error);
|
||||
|
||||
void pika_spawn_set_cloexec (gint fd);
|
||||
|
||||
|
||||
#endif /* __PIKA_SPAWN_H__ */
|
||||
275
app/core/pika-tags.c
Normal file
275
app/core/pika-tags.c
Normal file
@ -0,0 +1,275 @@
|
||||
/* 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
|
||||
*
|
||||
* pika-tags.c
|
||||
* Copyright (C) 2009 Aurimas Juška <aurisj@svn.gnome.org>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "config/pikaxmlparser.h"
|
||||
|
||||
#include "pika-utils.h"
|
||||
#include "pika-tags.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
#define PIKA_TAGS_FILE "tags.xml"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const gchar *locale;
|
||||
GString *buf;
|
||||
gboolean locale_matches;
|
||||
} PikaTagsInstaller;
|
||||
|
||||
|
||||
static void pika_tags_installer_load_start_element (GMarkupParseContext *context,
|
||||
const gchar *element_name,
|
||||
const gchar **attribute_names,
|
||||
const gchar **attribute_values,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
static void pika_tags_installer_load_end_element (GMarkupParseContext *context,
|
||||
const gchar *element_name,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
static void pika_tags_installer_load_text (GMarkupParseContext *context,
|
||||
const gchar *text,
|
||||
gsize text_len,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
static const gchar* attribute_name_to_value (const gchar **attribute_names,
|
||||
const gchar **attribute_values,
|
||||
const gchar *name);
|
||||
|
||||
|
||||
gboolean
|
||||
pika_tags_user_install (void)
|
||||
{
|
||||
GFile *file;
|
||||
GOutputStream *output;
|
||||
GMarkupParser markup_parser;
|
||||
PikaXmlParser *xml_parser;
|
||||
const char *tags_locale;
|
||||
PikaTagsInstaller tags_installer = { 0, };
|
||||
GError *error = NULL;
|
||||
gboolean result = TRUE;
|
||||
|
||||
/* This is a special string to specify the language identifier to
|
||||
* look for in the pika-tags-default.xml file. Please translate the
|
||||
* C in it according to the name of the po file used for
|
||||
* pika-tags-default.xml. E.g. lithuanian for the translation,
|
||||
* that would be "tags-locale:lt".
|
||||
*/
|
||||
tags_locale = _("tags-locale:C");
|
||||
|
||||
if (g_str_has_prefix (tags_locale, "tags-locale:"))
|
||||
{
|
||||
tags_locale += strlen ("tags-locale:");
|
||||
|
||||
if (*tags_locale && *tags_locale != 'C')
|
||||
tags_installer.locale = tags_locale;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Wrong translation for 'tags-locale:', fix the translation!");
|
||||
}
|
||||
|
||||
tags_installer.buf = g_string_new (NULL);
|
||||
|
||||
g_string_append (tags_installer.buf, "<?xml version='1.0' encoding='UTF-8'?>\n");
|
||||
g_string_append (tags_installer.buf, "<tags>\n");
|
||||
|
||||
markup_parser.start_element = pika_tags_installer_load_start_element;
|
||||
markup_parser.end_element = pika_tags_installer_load_end_element;
|
||||
markup_parser.text = pika_tags_installer_load_text;
|
||||
markup_parser.passthrough = NULL;
|
||||
markup_parser.error = NULL;
|
||||
|
||||
xml_parser = pika_xml_parser_new (&markup_parser, &tags_installer);
|
||||
|
||||
file = pika_data_directory_file ("tags", "pika-tags-default.xml", NULL);
|
||||
result = pika_xml_parser_parse_gfile (xml_parser, file, &error);
|
||||
g_object_unref (file);
|
||||
|
||||
pika_xml_parser_free (xml_parser);
|
||||
|
||||
if (! result)
|
||||
{
|
||||
g_string_free (tags_installer.buf, TRUE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_string_append (tags_installer.buf, "\n</tags>\n");
|
||||
|
||||
file = pika_directory_file (PIKA_TAGS_FILE, NULL);
|
||||
|
||||
output = G_OUTPUT_STREAM (g_file_replace (file,
|
||||
NULL, FALSE, G_FILE_CREATE_NONE,
|
||||
NULL, &error));
|
||||
if (! output)
|
||||
{
|
||||
g_printerr ("%s\n", error->message);
|
||||
result = FALSE;
|
||||
}
|
||||
else if (! g_output_stream_write_all (output,
|
||||
tags_installer.buf->str,
|
||||
tags_installer.buf->len,
|
||||
NULL, NULL, &error))
|
||||
{
|
||||
GCancellable *cancellable = g_cancellable_new ();
|
||||
|
||||
g_printerr (_("Error writing '%s': %s"),
|
||||
pika_file_get_utf8_name (file), error->message);
|
||||
result = FALSE;
|
||||
|
||||
/* Cancel the overwrite initiated by g_file_replace(). */
|
||||
g_cancellable_cancel (cancellable);
|
||||
g_output_stream_close (output, cancellable, NULL);
|
||||
g_object_unref (cancellable);
|
||||
}
|
||||
else if (! g_output_stream_close (output, NULL, &error))
|
||||
{
|
||||
g_printerr (_("Error closing '%s': %s"),
|
||||
pika_file_get_utf8_name (file), error->message);
|
||||
result = FALSE;
|
||||
}
|
||||
|
||||
if (output)
|
||||
g_object_unref (output);
|
||||
|
||||
g_clear_error (&error);
|
||||
g_object_unref (file);
|
||||
g_string_free (tags_installer.buf, TRUE);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_tags_installer_load_start_element (GMarkupParseContext *context,
|
||||
const gchar *element_name,
|
||||
const gchar **attribute_names,
|
||||
const gchar **attribute_values,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
PikaTagsInstaller *tags_installer = user_data;
|
||||
|
||||
if (! strcmp (element_name, "resource"))
|
||||
{
|
||||
g_string_append_printf (tags_installer->buf, "\n <resource");
|
||||
|
||||
while (*attribute_names)
|
||||
{
|
||||
g_string_append_printf (tags_installer->buf, " %s=\"%s\"",
|
||||
*attribute_names, *attribute_values);
|
||||
|
||||
attribute_names++;
|
||||
attribute_values++;
|
||||
}
|
||||
|
||||
g_string_append_printf (tags_installer->buf, ">\n");
|
||||
}
|
||||
else if (! strcmp (element_name, "thetag"))
|
||||
{
|
||||
const char *current_locale;
|
||||
|
||||
current_locale = attribute_name_to_value (attribute_names, attribute_values,
|
||||
"xml:lang");
|
||||
|
||||
if (current_locale && tags_installer->locale)
|
||||
{
|
||||
tags_installer->locale_matches = ! strcmp (current_locale,
|
||||
tags_installer->locale);
|
||||
}
|
||||
else
|
||||
{
|
||||
tags_installer->locale_matches = (current_locale ==
|
||||
tags_installer->locale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_tags_installer_load_end_element (GMarkupParseContext *context,
|
||||
const gchar *element_name,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
PikaTagsInstaller *tags_installer = user_data;
|
||||
|
||||
if (strcmp (element_name, "resource") == 0)
|
||||
{
|
||||
g_string_append (tags_installer->buf, " </resource>\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_tags_installer_load_text (GMarkupParseContext *context,
|
||||
const gchar *text,
|
||||
gsize text_len,
|
||||
gpointer user_data,
|
||||
GError **error)
|
||||
{
|
||||
PikaTagsInstaller *tags_installer = user_data;
|
||||
const gchar *current_element;
|
||||
gchar *tag_string;
|
||||
|
||||
current_element = g_markup_parse_context_get_element (context);
|
||||
|
||||
if (tags_installer->locale_matches &&
|
||||
current_element &&
|
||||
strcmp (current_element, "thetag") == 0)
|
||||
{
|
||||
tag_string = g_markup_escape_text (text, text_len);
|
||||
g_string_append_printf (tags_installer->buf, " <tag>%s</tag>\n",
|
||||
tag_string);
|
||||
g_free (tag_string);
|
||||
}
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
attribute_name_to_value (const gchar **attribute_names,
|
||||
const gchar **attribute_values,
|
||||
const gchar *name)
|
||||
{
|
||||
while (*attribute_names)
|
||||
{
|
||||
if (! strcmp (*attribute_names, name))
|
||||
{
|
||||
return *attribute_values;
|
||||
}
|
||||
|
||||
attribute_names++;
|
||||
attribute_values++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
29
app/core/pika-tags.h
Normal file
29
app/core/pika-tags.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* 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-1997 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_TAGS_H__
|
||||
#define __PIKA_TAGS_H__
|
||||
|
||||
|
||||
gboolean pika_tags_user_install (void);
|
||||
|
||||
|
||||
#endif /* __PIKA_TAGS_H__ */
|
||||
228
app/core/pika-templates.c
Normal file
228
app/core/pika-templates.c
Normal file
@ -0,0 +1,228 @@
|
||||
/* 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-1997 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pika-templates.h"
|
||||
#include "pikalist.h"
|
||||
#include "pikatemplate.h"
|
||||
|
||||
|
||||
/* functions to load and save the pika templates files */
|
||||
|
||||
void
|
||||
pika_templates_load (Pika *pika)
|
||||
{
|
||||
GFile *file;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (PIKA_IS_LIST (pika->templates));
|
||||
|
||||
file = pika_directory_file ("templaterc", NULL);
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Parsing '%s'\n", pika_file_get_utf8_name (file));
|
||||
|
||||
if (! pika_config_deserialize_file (PIKA_CONFIG (pika->templates),
|
||||
file, NULL, &error))
|
||||
{
|
||||
if (error->code == PIKA_CONFIG_ERROR_OPEN_ENOENT)
|
||||
{
|
||||
g_clear_error (&error);
|
||||
g_object_unref (file);
|
||||
|
||||
if (g_getenv ("PIKA_TESTING_ABS_TOP_SRCDIR"))
|
||||
{
|
||||
gchar *path;
|
||||
path = g_build_filename (g_getenv ("PIKA_TESTING_ABS_TOP_SRCDIR"),
|
||||
"etc", "templaterc", NULL);
|
||||
file = g_file_new_for_path (path);
|
||||
g_free (path);
|
||||
}
|
||||
else
|
||||
{
|
||||
file = pika_sysconf_directory_file ("templaterc", NULL);
|
||||
}
|
||||
|
||||
if (! pika_config_deserialize_file (PIKA_CONFIG (pika->templates),
|
||||
file, NULL, &error))
|
||||
{
|
||||
pika_message_literal (pika, NULL, PIKA_MESSAGE_ERROR,
|
||||
error->message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_message_literal (pika, NULL, PIKA_MESSAGE_ERROR, error->message);
|
||||
}
|
||||
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
pika_list_reverse (PIKA_LIST (pika->templates));
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
void
|
||||
pika_templates_save (Pika *pika)
|
||||
{
|
||||
const gchar *header =
|
||||
"PIKA templaterc\n"
|
||||
"\n"
|
||||
"This file will be entirely rewritten each time you exit.";
|
||||
const gchar *footer =
|
||||
"end of templaterc";
|
||||
|
||||
GFile *file;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (PIKA_IS_LIST (pika->templates));
|
||||
|
||||
file = pika_directory_file ("templaterc", NULL);
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Writing '%s'\n", pika_file_get_utf8_name (file));
|
||||
|
||||
if (! pika_config_serialize_to_file (PIKA_CONFIG (pika->templates),
|
||||
file,
|
||||
header, footer, NULL,
|
||||
&error))
|
||||
{
|
||||
pika_message_literal (pika, NULL, PIKA_MESSAGE_ERROR, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
|
||||
/* just like pika_list_get_child_by_name() but matches case-insensitive
|
||||
* and dpi/ppi-insensitive
|
||||
*/
|
||||
static PikaObject *
|
||||
pika_templates_migrate_get_child_by_name (PikaContainer *container,
|
||||
const gchar *name)
|
||||
{
|
||||
PikaList *list = PIKA_LIST (container);
|
||||
PikaObject *retval = NULL;
|
||||
GList *glist;
|
||||
|
||||
for (glist = list->queue->head; glist; glist = g_list_next (glist))
|
||||
{
|
||||
PikaObject *object = glist->data;
|
||||
gchar *str1 = g_ascii_strdown (pika_object_get_name (object), -1);
|
||||
gchar *str2 = g_ascii_strdown (name, -1);
|
||||
|
||||
if (! strcmp (str1, str2))
|
||||
{
|
||||
retval = object;
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar *dpi = strstr (str1, "dpi");
|
||||
|
||||
if (dpi)
|
||||
{
|
||||
memcpy (dpi, "ppi", 3);
|
||||
|
||||
g_print ("replaced: %s\n", str1);
|
||||
|
||||
if (! strcmp (str1, str2))
|
||||
retval = object;
|
||||
}
|
||||
}
|
||||
|
||||
g_free (str1);
|
||||
g_free (str2);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* pika_templates_migrate:
|
||||
* @olddir: the old user directory
|
||||
*
|
||||
* Migrating the templaterc from PIKA 2.0 to PIKA 2.2 needs this special
|
||||
* hack since we changed the way that units are handled. This function
|
||||
* merges the user's templaterc with the systemwide templaterc. The goal
|
||||
* is to replace the unit for a couple of default templates with "pixels".
|
||||
**/
|
||||
void
|
||||
pika_templates_migrate (const gchar *olddir)
|
||||
{
|
||||
PikaContainer *templates = pika_list_new (PIKA_TYPE_TEMPLATE, TRUE);
|
||||
GFile *file = pika_directory_file ("templaterc", NULL);
|
||||
|
||||
if (pika_config_deserialize_file (PIKA_CONFIG (templates), file,
|
||||
NULL, NULL))
|
||||
{
|
||||
GFile *sysconf_file;
|
||||
|
||||
sysconf_file = pika_sysconf_directory_file ("templaterc", NULL);
|
||||
|
||||
if (olddir && (strstr (olddir, "2.0") || strstr (olddir, "2.2")))
|
||||
{
|
||||
/* We changed the spelling of a couple of template names:
|
||||
*
|
||||
* - from upper to lower case between 2.0 and 2.2
|
||||
* - from "dpi" to "ppi" between 2.2 and 2.4
|
||||
*/
|
||||
PikaContainerClass *class = PIKA_CONTAINER_GET_CLASS (templates);
|
||||
gpointer func = class->get_child_by_name;
|
||||
|
||||
class->get_child_by_name = pika_templates_migrate_get_child_by_name;
|
||||
|
||||
pika_config_deserialize_file (PIKA_CONFIG (templates),
|
||||
sysconf_file, NULL, NULL);
|
||||
|
||||
class->get_child_by_name = func;
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_config_deserialize_file (PIKA_CONFIG (templates),
|
||||
sysconf_file, NULL, NULL);
|
||||
}
|
||||
|
||||
g_object_unref (sysconf_file);
|
||||
|
||||
pika_list_reverse (PIKA_LIST (templates));
|
||||
|
||||
pika_config_serialize_to_file (PIKA_CONFIG (templates), file,
|
||||
NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
32
app/core/pika-templates.h
Normal file
32
app/core/pika-templates.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* 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-1997 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_TEMPLATES_H__
|
||||
#define __PIKA_TEMPLATES_H__
|
||||
|
||||
|
||||
void pika_templates_load (Pika *pika);
|
||||
void pika_templates_save (Pika *pika);
|
||||
|
||||
void pika_templates_migrate (const gchar *olddir);
|
||||
|
||||
|
||||
#endif /* __PIKA_TEMPLATES_H__ */
|
||||
363
app/core/pika-transform-3d-utils.c
Normal file
363
app/core/pika-transform-3d-utils.c
Normal file
@ -0,0 +1,363 @@
|
||||
/* 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
|
||||
*
|
||||
* pika-3d-transform-utils.c
|
||||
* Copyright (C) 2019 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika-transform-3d-utils.h"
|
||||
|
||||
|
||||
#define MIN_FOCAL_LENGTH 0.01
|
||||
|
||||
|
||||
gdouble
|
||||
pika_transform_3d_angle_of_view_to_focal_length (gdouble angle_of_view,
|
||||
gdouble width,
|
||||
gdouble height)
|
||||
{
|
||||
return MAX (width, height) / (2.0 * tan (angle_of_view / 2.0));
|
||||
}
|
||||
|
||||
gdouble
|
||||
pika_transform_3d_focal_length_to_angle_of_view (gdouble focal_length,
|
||||
gdouble width,
|
||||
gdouble height)
|
||||
{
|
||||
return 2.0 * atan (MAX (width, height) / (2.0 * focal_length));
|
||||
}
|
||||
|
||||
gint
|
||||
pika_transform_3d_permutation_to_rotation_order (const gint permutation[3])
|
||||
{
|
||||
if (permutation[1] == (permutation[0] + 1) % 3)
|
||||
return permutation[0] << 1;
|
||||
else
|
||||
return (permutation[2] << 1) + 1;
|
||||
}
|
||||
|
||||
void
|
||||
pika_transform_3d_rotation_order_to_permutation (gint rotation_order,
|
||||
gint permutation[3])
|
||||
{
|
||||
gboolean reverse = rotation_order & 1;
|
||||
gint shift = rotation_order >> 1;
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
permutation[reverse ? 2 - i : i] = (i + shift) % 3;
|
||||
}
|
||||
|
||||
gint
|
||||
pika_transform_3d_rotation_order_reverse (gint rotation_order)
|
||||
{
|
||||
return rotation_order ^ 1;
|
||||
}
|
||||
|
||||
void
|
||||
pika_transform_3d_vector3_rotate (PikaVector3 *vector,
|
||||
const PikaVector3 *axis)
|
||||
{
|
||||
PikaVector3 normal;
|
||||
PikaVector3 proj;
|
||||
PikaVector3 u, v;
|
||||
gdouble angle;
|
||||
|
||||
angle = pika_vector3_length (axis);
|
||||
|
||||
if (angle == 0.0)
|
||||
return;
|
||||
|
||||
normal = pika_vector3_mul_val (*axis, 1.0 / angle);
|
||||
|
||||
proj = pika_vector3_mul_val (normal,
|
||||
pika_vector3_inner_product_val (*vector,
|
||||
normal));
|
||||
|
||||
u = pika_vector3_sub_val (*vector, proj);
|
||||
v = pika_vector3_cross_product_val (u, normal);
|
||||
|
||||
pika_vector3_mul (&u, cos (angle));
|
||||
pika_vector3_mul (&v, sin (angle));
|
||||
|
||||
*vector = proj;
|
||||
|
||||
pika_vector3_add (vector, vector, &u);
|
||||
pika_vector3_add (vector, vector, &v);
|
||||
}
|
||||
|
||||
PikaVector3
|
||||
pika_transform_3d_vector3_rotate_val (PikaVector3 vector,
|
||||
PikaVector3 axis)
|
||||
{
|
||||
pika_transform_3d_vector3_rotate (&vector, &axis);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
void
|
||||
pika_transform_3d_matrix3_to_matrix4 (const PikaMatrix3 *matrix3,
|
||||
PikaMatrix4 *matrix4,
|
||||
gint axis)
|
||||
{
|
||||
gint i, j;
|
||||
gint k, l;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (i == axis)
|
||||
{
|
||||
matrix4->coeff[i][i] = 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
matrix4->coeff[axis][i] = 0.0;
|
||||
matrix4->coeff[i][axis] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
k = i + (i >= axis);
|
||||
|
||||
for (j = 0; j < 3; j++)
|
||||
{
|
||||
l = j + (j >= axis);
|
||||
|
||||
matrix4->coeff[k][l] = matrix3->coeff[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_transform_3d_matrix4_to_matrix3 (const PikaMatrix4 *matrix4,
|
||||
PikaMatrix3 *matrix3,
|
||||
gint axis)
|
||||
{
|
||||
gint i, j;
|
||||
gint k, l;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
k = i + (i >= axis);
|
||||
|
||||
for (j = 0; j < 3; j++)
|
||||
{
|
||||
l = j + (j >= axis);
|
||||
|
||||
matrix3->coeff[i][j] = matrix4->coeff[k][l];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_transform_3d_matrix4_translate (PikaMatrix4 *matrix,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble z)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
matrix->coeff[0][i] += x * matrix->coeff[3][i];
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
matrix->coeff[1][i] += y * matrix->coeff[3][i];
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
matrix->coeff[2][i] += z * matrix->coeff[3][i];
|
||||
}
|
||||
|
||||
void
|
||||
pika_transform_3d_matrix4_rotate (PikaMatrix4 *matrix,
|
||||
const PikaVector3 *axis)
|
||||
{
|
||||
PikaMatrix4 rotation;
|
||||
PikaVector3 v;
|
||||
|
||||
v = pika_transform_3d_vector3_rotate_val ((PikaVector3) {1.0, 0.0, 0.0},
|
||||
*axis);
|
||||
|
||||
rotation.coeff[0][0] = v.x;
|
||||
rotation.coeff[1][0] = v.y;
|
||||
rotation.coeff[2][0] = v.z;
|
||||
rotation.coeff[3][0] = 0.0;
|
||||
|
||||
v = pika_transform_3d_vector3_rotate_val ((PikaVector3) {0.0, 1.0, 0.0},
|
||||
*axis);
|
||||
|
||||
rotation.coeff[0][1] = v.x;
|
||||
rotation.coeff[1][1] = v.y;
|
||||
rotation.coeff[2][1] = v.z;
|
||||
rotation.coeff[3][1] = 0.0;
|
||||
|
||||
v = pika_transform_3d_vector3_rotate_val ((PikaVector3) {0.0, 0.0, 1.0},
|
||||
*axis);
|
||||
|
||||
rotation.coeff[0][2] = v.x;
|
||||
rotation.coeff[1][2] = v.y;
|
||||
rotation.coeff[2][2] = v.z;
|
||||
rotation.coeff[3][2] = 0.0;
|
||||
|
||||
rotation.coeff[0][3] = 0.0;
|
||||
rotation.coeff[1][3] = 0.0;
|
||||
rotation.coeff[2][3] = 0.0;
|
||||
rotation.coeff[3][3] = 1.0;
|
||||
|
||||
pika_matrix4_mult (&rotation, matrix);
|
||||
}
|
||||
|
||||
void
|
||||
pika_transform_3d_matrix4_rotate_standard (PikaMatrix4 *matrix,
|
||||
gint axis,
|
||||
gdouble angle)
|
||||
{
|
||||
gdouble v[3] = {};
|
||||
|
||||
v[axis] = angle;
|
||||
|
||||
pika_transform_3d_matrix4_rotate (matrix, &(PikaVector3) {v[0], v[1], v[2]});
|
||||
}
|
||||
|
||||
void
|
||||
pika_transform_3d_matrix4_rotate_euler (PikaMatrix4 *matrix,
|
||||
gint rotation_order,
|
||||
gdouble angle_x,
|
||||
gdouble angle_y,
|
||||
gdouble angle_z,
|
||||
gdouble pivot_x,
|
||||
gdouble pivot_y,
|
||||
gdouble pivot_z)
|
||||
{
|
||||
const gdouble angles[3] = {angle_x, angle_y, angle_z};
|
||||
gint permutation[3];
|
||||
gint i;
|
||||
|
||||
pika_transform_3d_rotation_order_to_permutation (rotation_order, permutation);
|
||||
|
||||
pika_transform_3d_matrix4_translate (matrix, -pivot_x, -pivot_y, -pivot_z);
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
pika_transform_3d_matrix4_rotate_standard (matrix,
|
||||
permutation[i],
|
||||
angles[permutation[i]]);
|
||||
}
|
||||
|
||||
pika_transform_3d_matrix4_translate (matrix, +pivot_x, +pivot_y, +pivot_z);
|
||||
}
|
||||
|
||||
void
|
||||
pika_transform_3d_matrix4_rotate_euler_decompose (PikaMatrix4 *matrix,
|
||||
gint rotation_order,
|
||||
gdouble *angle_x,
|
||||
gdouble *angle_y,
|
||||
gdouble *angle_z)
|
||||
{
|
||||
PikaMatrix4 m = *matrix;
|
||||
gdouble * const angles[3] = {angle_x, angle_y, angle_z};
|
||||
gint permutation[3];
|
||||
gboolean forward;
|
||||
|
||||
pika_transform_3d_rotation_order_to_permutation (rotation_order, permutation);
|
||||
|
||||
forward = permutation[1] == (permutation[0] + 1) % 3;
|
||||
|
||||
*angles[permutation[2]] = atan2 (m.coeff[permutation[1]][permutation[0]],
|
||||
m.coeff[permutation[0]][permutation[0]]);
|
||||
|
||||
if (forward)
|
||||
*angles[permutation[2]] *= -1.0;
|
||||
|
||||
pika_transform_3d_matrix4_rotate_standard (&m,
|
||||
permutation[2],
|
||||
-*angles[permutation[2]]);
|
||||
|
||||
*angles[permutation[1]] = atan2 (m.coeff[permutation[2]][permutation[0]],
|
||||
m.coeff[permutation[0]][permutation[0]]);
|
||||
|
||||
if (! forward)
|
||||
*angles[permutation[1]] *= -1.0;
|
||||
|
||||
pika_transform_3d_matrix4_rotate_standard (&m,
|
||||
permutation[1],
|
||||
-*angles[permutation[1]]);
|
||||
|
||||
*angles[permutation[0]] = atan2 (m.coeff[permutation[2]][permutation[1]],
|
||||
m.coeff[permutation[1]][permutation[1]]);
|
||||
|
||||
if (forward)
|
||||
*angles[permutation[0]] *= -1.0;
|
||||
}
|
||||
|
||||
void
|
||||
pika_transform_3d_matrix4_perspective (PikaMatrix4 *matrix,
|
||||
gdouble camera_x,
|
||||
gdouble camera_y,
|
||||
gdouble camera_z)
|
||||
{
|
||||
gint i;
|
||||
|
||||
camera_z = MIN (camera_z, -MIN_FOCAL_LENGTH);
|
||||
|
||||
pika_transform_3d_matrix4_translate (matrix, -camera_x, -camera_y, 0.0);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
matrix->coeff[3][i] += matrix->coeff[2][i] / -camera_z;
|
||||
|
||||
pika_transform_3d_matrix4_translate (matrix, +camera_x, +camera_y, 0.0);
|
||||
}
|
||||
|
||||
void
|
||||
pika_transform_3d_matrix (PikaMatrix3 *matrix,
|
||||
gdouble camera_x,
|
||||
gdouble camera_y,
|
||||
gdouble camera_z,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y,
|
||||
gdouble offset_z,
|
||||
gint rotation_order,
|
||||
gdouble angle_x,
|
||||
gdouble angle_y,
|
||||
gdouble angle_z,
|
||||
gdouble pivot_x,
|
||||
gdouble pivot_y,
|
||||
gdouble pivot_z)
|
||||
{
|
||||
PikaMatrix4 m;
|
||||
|
||||
pika_matrix4_identity (&m);
|
||||
pika_transform_3d_matrix4_rotate_euler (&m,
|
||||
rotation_order,
|
||||
angle_x, angle_y, angle_z,
|
||||
pivot_x, pivot_y, pivot_z);
|
||||
pika_transform_3d_matrix4_translate (&m, offset_x, offset_y, offset_z);
|
||||
pika_transform_3d_matrix4_perspective (&m, camera_x, camera_y, camera_z);
|
||||
|
||||
pika_transform_3d_matrix4_to_matrix3 (&m, matrix, 2);
|
||||
}
|
||||
99
app/core/pika-transform-3d-utils.h
Normal file
99
app/core/pika-transform-3d-utils.h
Normal file
@ -0,0 +1,99 @@
|
||||
/* 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
|
||||
*
|
||||
* pika-3d-transform-utils.h
|
||||
* Copyright (C) 2019 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_TRANSFORM_3D_UTILS_H__
|
||||
#define __PIKA_TRANSFORM_3D_UTILS_H__
|
||||
|
||||
|
||||
gdouble pika_transform_3d_angle_of_view_to_focal_length (gdouble angle_of_view,
|
||||
gdouble width,
|
||||
gdouble height);
|
||||
gdouble pika_transform_3d_focal_length_to_angle_of_view (gdouble focal_length,
|
||||
gdouble width,
|
||||
gdouble height);
|
||||
|
||||
gint pika_transform_3d_permutation_to_rotation_order (const gint permutation[3]);
|
||||
void pika_transform_3d_rotation_order_to_permutation (gint rotation_order,
|
||||
gint permutation[3]);
|
||||
gint pika_transform_3d_rotation_order_reverse (gint rotation_order);
|
||||
|
||||
void pika_transform_3d_vector3_rotate (PikaVector3 *vector,
|
||||
const PikaVector3 *axis);
|
||||
PikaVector3 pika_transform_3d_vector3_rotate_val (PikaVector3 vector,
|
||||
PikaVector3 axis);
|
||||
|
||||
void pika_transform_3d_matrix3_to_matrix4 (const PikaMatrix3 *matrix3,
|
||||
PikaMatrix4 *matrix4,
|
||||
gint axis);
|
||||
void pika_transform_3d_matrix4_to_matrix3 (const PikaMatrix4 *matrix4,
|
||||
PikaMatrix3 *matrix3,
|
||||
gint axis);
|
||||
|
||||
void pika_transform_3d_matrix4_translate (PikaMatrix4 *matrix,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
gdouble z);
|
||||
|
||||
void pika_transform_3d_matrix4_rotate (PikaMatrix4 *matrix,
|
||||
const PikaVector3 *axis);
|
||||
void pika_transform_3d_matrix4_rotate_standard (PikaMatrix4 *matrix,
|
||||
gint axis,
|
||||
gdouble angle);
|
||||
|
||||
void pika_transform_3d_matrix4_rotate_euler (PikaMatrix4 *matrix,
|
||||
gint rotation_order,
|
||||
gdouble angle_x,
|
||||
gdouble angle_y,
|
||||
gdouble angle_z,
|
||||
gdouble pivot_x,
|
||||
gdouble pivot_y,
|
||||
gdouble pivot_z);
|
||||
void pika_transform_3d_matrix4_rotate_euler_decompose (PikaMatrix4 *matrix,
|
||||
gint rotation_order,
|
||||
gdouble *angle_x,
|
||||
gdouble *angle_y,
|
||||
gdouble *angle_z);
|
||||
|
||||
void pika_transform_3d_matrix4_perspective (PikaMatrix4 *matrix,
|
||||
gdouble camera_x,
|
||||
gdouble camera_y,
|
||||
gdouble camera_z);
|
||||
|
||||
void pika_transform_3d_matrix (PikaMatrix3 *matrix,
|
||||
gdouble camera_x,
|
||||
gdouble camera_y,
|
||||
gdouble camera_z,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y,
|
||||
gdouble offset_z,
|
||||
gint rotation_order,
|
||||
gdouble angle_x,
|
||||
gdouble angle_y,
|
||||
gdouble angle_z,
|
||||
gdouble pivot_x,
|
||||
gdouble pivot_y,
|
||||
gdouble pivot_z);
|
||||
|
||||
|
||||
#endif /* __PIKA_TRANSFORM_3D_UTILS_H__ */
|
||||
835
app/core/pika-transform-resize.c
Normal file
835
app/core/pika-transform-resize.c
Normal file
@ -0,0 +1,835 @@
|
||||
/* 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-2001 Spencer Kimball, Peter Mattis, and others
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika-transform-resize.h"
|
||||
#include "pika-transform-utils.h"
|
||||
#include "pika-utils.h"
|
||||
|
||||
|
||||
#define EPSILON 0.00000001
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PikaVector2 a, b, c, d;
|
||||
gdouble area;
|
||||
gdouble aspect;
|
||||
} Rectangle;
|
||||
|
||||
|
||||
static void pika_transform_resize_adjust (const PikaVector2 *points,
|
||||
gint n_points,
|
||||
gint *x1,
|
||||
gint *y1,
|
||||
gint *x2,
|
||||
gint *y2);
|
||||
static void pika_transform_resize_crop (const PikaVector2 *points,
|
||||
gint n_points,
|
||||
gdouble aspect,
|
||||
gint *x1,
|
||||
gint *y1,
|
||||
gint *x2,
|
||||
gint *y2);
|
||||
|
||||
static void add_rectangle (const PikaVector2 *points,
|
||||
gint n_points,
|
||||
Rectangle *r,
|
||||
PikaVector2 a,
|
||||
PikaVector2 b,
|
||||
PikaVector2 c,
|
||||
PikaVector2 d);
|
||||
static gboolean intersect (PikaVector2 a,
|
||||
PikaVector2 b,
|
||||
PikaVector2 c,
|
||||
PikaVector2 d,
|
||||
PikaVector2 *i);
|
||||
static gboolean intersect_x (PikaVector2 a,
|
||||
PikaVector2 b,
|
||||
PikaVector2 c,
|
||||
PikaVector2 *i);
|
||||
static gboolean intersect_y (PikaVector2 a,
|
||||
PikaVector2 b,
|
||||
PikaVector2 c,
|
||||
PikaVector2 *i);
|
||||
static gboolean in_poly (const PikaVector2 *points,
|
||||
gint n_points,
|
||||
PikaVector2 p);
|
||||
static gboolean point_on_border (const PikaVector2 *points,
|
||||
gint n_points,
|
||||
PikaVector2 p);
|
||||
|
||||
static void find_two_point_rectangle (Rectangle *r,
|
||||
const PikaVector2 *points,
|
||||
gint n_points,
|
||||
gint p);
|
||||
static void find_three_point_rectangle_corner (Rectangle *r,
|
||||
const PikaVector2 *points,
|
||||
gint n_points,
|
||||
gint p);
|
||||
static void find_three_point_rectangle (Rectangle *r,
|
||||
const PikaVector2 *points,
|
||||
gint n_points,
|
||||
gint p);
|
||||
static void find_three_point_rectangle_triangle (Rectangle *r,
|
||||
const PikaVector2 *points,
|
||||
gint n_points,
|
||||
gint p);
|
||||
static void find_maximum_aspect_rectangle (Rectangle *r,
|
||||
const PikaVector2 *points,
|
||||
gint n_points,
|
||||
gint p);
|
||||
|
||||
|
||||
/*
|
||||
* This function wants to be passed the inverse transformation matrix!!
|
||||
*/
|
||||
gboolean
|
||||
pika_transform_resize_boundary (const PikaMatrix3 *inv,
|
||||
PikaTransformResize resize,
|
||||
gdouble u1,
|
||||
gdouble v1,
|
||||
gdouble u2,
|
||||
gdouble v2,
|
||||
gint *x1,
|
||||
gint *y1,
|
||||
gint *x2,
|
||||
gint *y2)
|
||||
{
|
||||
PikaVector2 bounds[4];
|
||||
PikaVector2 points[5];
|
||||
gint n_points;
|
||||
gboolean valid;
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (inv != NULL, FALSE);
|
||||
|
||||
/* initialize with the original boundary */
|
||||
*x1 = floor (u1);
|
||||
*y1 = floor (v1);
|
||||
*x2 = ceil (u2);
|
||||
*y2 = ceil (v2);
|
||||
|
||||
/* if clipping then just return the original rectangle */
|
||||
if (resize == PIKA_TRANSFORM_RESIZE_CLIP)
|
||||
return TRUE;
|
||||
|
||||
bounds[0] = (PikaVector2) { u1, v1 };
|
||||
bounds[1] = (PikaVector2) { u2, v1 };
|
||||
bounds[2] = (PikaVector2) { u2, v2 };
|
||||
bounds[3] = (PikaVector2) { u1, v2 };
|
||||
|
||||
pika_transform_polygon (inv, bounds, 4, TRUE,
|
||||
points, &n_points);
|
||||
|
||||
valid = (n_points >= 2);
|
||||
|
||||
/* check if the transformation matrix is valid at all */
|
||||
for (i = 0; i < n_points && valid; i++)
|
||||
valid = (isfinite (points[i].x) && isfinite (points[i].y));
|
||||
|
||||
if (! valid)
|
||||
{
|
||||
/* since there is no sensible way to deal with this, just do the same as
|
||||
* with PIKA_TRANSFORM_RESIZE_CLIP: return
|
||||
*/
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (resize)
|
||||
{
|
||||
case PIKA_TRANSFORM_RESIZE_ADJUST:
|
||||
/* return smallest rectangle (with sides parallel to x- and y-axis)
|
||||
* that surrounds the new points */
|
||||
pika_transform_resize_adjust (points, n_points,
|
||||
x1, y1, x2, y2);
|
||||
break;
|
||||
|
||||
case PIKA_TRANSFORM_RESIZE_CROP:
|
||||
pika_transform_resize_crop (points, n_points,
|
||||
0.0,
|
||||
x1, y1, x2, y2);
|
||||
break;
|
||||
|
||||
case PIKA_TRANSFORM_RESIZE_CROP_WITH_ASPECT:
|
||||
pika_transform_resize_crop (points, n_points,
|
||||
(u2 - u1) / (v2 - v1),
|
||||
x1, y1, x2, y2);
|
||||
break;
|
||||
|
||||
case PIKA_TRANSFORM_RESIZE_CLIP:
|
||||
/* Remove warning about not handling all enum values. We handle
|
||||
* this case in the beginning of the function
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
/* ensure that resulting rectangle has at least area 1 */
|
||||
if (*x1 == *x2)
|
||||
(*x2)++;
|
||||
|
||||
if (*y1 == *y2)
|
||||
(*y2)++;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* this calculates the smallest rectangle (with sides parallel to x- and
|
||||
* y-axis) that contains the points d1 to d4
|
||||
*/
|
||||
static void
|
||||
pika_transform_resize_adjust (const PikaVector2 *points,
|
||||
gint n_points,
|
||||
gint *x1,
|
||||
gint *y1,
|
||||
gint *x2,
|
||||
gint *y2)
|
||||
{
|
||||
PikaVector2 top_left;
|
||||
PikaVector2 bottom_right;
|
||||
gint i;
|
||||
|
||||
top_left = bottom_right = points[0];
|
||||
|
||||
for (i = 1; i < n_points; i++)
|
||||
{
|
||||
top_left.x = MIN (top_left.x, points[i].x);
|
||||
top_left.y = MIN (top_left.y, points[i].y);
|
||||
|
||||
bottom_right.x = MAX (bottom_right.x, points[i].x);
|
||||
bottom_right.y = MAX (bottom_right.y, points[i].y);
|
||||
}
|
||||
|
||||
*x1 = (gint) floor (top_left.x + EPSILON);
|
||||
*y1 = (gint) floor (top_left.y + EPSILON);
|
||||
|
||||
*x2 = (gint) ceil (bottom_right.x - EPSILON);
|
||||
*y2 = (gint) ceil (bottom_right.y - EPSILON);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_transform_resize_crop (const PikaVector2 *orig_points,
|
||||
gint n_points,
|
||||
gdouble aspect,
|
||||
gint *x1,
|
||||
gint *y1,
|
||||
gint *x2,
|
||||
gint *y2)
|
||||
{
|
||||
PikaVector2 points[5];
|
||||
Rectangle r;
|
||||
PikaVector2 t,a;
|
||||
gint i, j;
|
||||
gint min;
|
||||
|
||||
memcpy (points, orig_points, sizeof (PikaVector2) * n_points);
|
||||
|
||||
/* find lowest, rightmost corner of surrounding rectangle */
|
||||
a.x = 0;
|
||||
a.y = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (points[i].x < a.x)
|
||||
a.x = points[i].x;
|
||||
|
||||
if (points[i].y < a.y)
|
||||
a.y = points[i].y;
|
||||
}
|
||||
|
||||
/* and translate all the points to the first quadrant */
|
||||
for (i = 0; i < n_points; i++)
|
||||
{
|
||||
points[i].x += (-a.x) * 2;
|
||||
points[i].y += (-a.y) * 2;
|
||||
}
|
||||
|
||||
/* find the convex hull using Jarvis's March as the points are passed
|
||||
* in different orders due to pika_matrix3_transform_point()
|
||||
*/
|
||||
min = 0;
|
||||
for (i = 0; i < n_points; i++)
|
||||
{
|
||||
if (points[i].y < points[min].y)
|
||||
min = i;
|
||||
}
|
||||
|
||||
t = points[0];
|
||||
points[0] = points[min];
|
||||
points[min] = t;
|
||||
|
||||
for (i = 1; i < n_points - 1; i++)
|
||||
{
|
||||
gdouble min_theta;
|
||||
gdouble min_mag;
|
||||
int next;
|
||||
|
||||
next = n_points - 1;
|
||||
min_theta = 2.0 * G_PI;
|
||||
min_mag = DBL_MAX;
|
||||
|
||||
for (j = i; j < n_points; j++)
|
||||
{
|
||||
gdouble theta;
|
||||
gdouble sy;
|
||||
gdouble sx;
|
||||
gdouble mag;
|
||||
|
||||
sy = points[j].y - points[i - 1].y;
|
||||
sx = points[j].x - points[i - 1].x;
|
||||
|
||||
if ((sx == 0.0) && (sy == 0.0))
|
||||
{
|
||||
next = j;
|
||||
break;
|
||||
}
|
||||
|
||||
theta = atan2 (-sy, -sx);
|
||||
mag = (sx * sx) + (sy * sy);
|
||||
|
||||
if ((theta < min_theta) ||
|
||||
((theta == min_theta) && (mag < min_mag)))
|
||||
{
|
||||
min_theta = theta;
|
||||
min_mag = mag;
|
||||
next = j;
|
||||
}
|
||||
}
|
||||
|
||||
t = points[i];
|
||||
points[i] = points[next];
|
||||
points[next] = t;
|
||||
}
|
||||
|
||||
/* reverse the order of points */
|
||||
for (i = 0; i < n_points / 2; i++)
|
||||
{
|
||||
t = points[i];
|
||||
points[i] = points[n_points - i - 1];
|
||||
points[n_points - i - 1] = t;
|
||||
}
|
||||
|
||||
r.a.x = r.a.y = r.b.x = r.b.y = r.c.x = r.c.y = r.d.x = r.d.y = r.area = 0;
|
||||
r.aspect = aspect;
|
||||
|
||||
if (aspect != 0)
|
||||
{
|
||||
for (i = 0; i < n_points; i++)
|
||||
find_maximum_aspect_rectangle (&r, points, n_points, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < n_points; i++)
|
||||
{
|
||||
find_three_point_rectangle (&r, points, n_points, i);
|
||||
find_three_point_rectangle_corner (&r, points, n_points, i);
|
||||
find_two_point_rectangle (&r, points, n_points, i);
|
||||
find_three_point_rectangle_triangle (&r, points, n_points, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (r.area == 0)
|
||||
{
|
||||
/* saveguard if something went wrong, adjust and give warning */
|
||||
pika_transform_resize_adjust (orig_points, n_points,
|
||||
x1, y1, x2, y2);
|
||||
g_printerr ("no rectangle found by algorithm, no cropping done\n");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* round and translate the calculated points back */
|
||||
*x1 = floor (r.a.x + 0.5);
|
||||
*y1 = floor (r.a.y + 0.5);
|
||||
*x2 = ceil (r.c.x - 0.5);
|
||||
*y2 = ceil (r.c.y - 0.5);
|
||||
|
||||
*x1 = *x1 - ((-a.x) * 2);
|
||||
*y1 = *y1 - ((-a.y) * 2);
|
||||
*x2 = *x2 - ((-a.x) * 2);
|
||||
*y2 = *y2 - ((-a.y) * 2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
find_three_point_rectangle (Rectangle *r,
|
||||
const PikaVector2 *points,
|
||||
gint n_points,
|
||||
gint p)
|
||||
{
|
||||
PikaVector2 a = points[p % n_points]; /* 0 1 2 3 */
|
||||
PikaVector2 b = points[(p + 1) % n_points]; /* 1 2 3 0 */
|
||||
PikaVector2 c = points[(p + 2) % n_points]; /* 2 3 0 1 */
|
||||
PikaVector2 d = points[(p + 3) % n_points]; /* 3 0 1 2 */
|
||||
PikaVector2 i1; /* intersection point */
|
||||
PikaVector2 i2; /* intersection point */
|
||||
PikaVector2 i3; /* intersection point */
|
||||
|
||||
if (intersect_x (b, c, a, &i1) &&
|
||||
intersect_y (c, d, i1, &i2) &&
|
||||
intersect_x (d, a, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i3, i3, i1, i1);
|
||||
|
||||
if (intersect_y (b, c, a, &i1) &&
|
||||
intersect_x (c, d, i1, &i2) &&
|
||||
intersect_y (d, a, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i3, i3, i1, i1);
|
||||
|
||||
if (intersect_x (d, c, a, &i1) &&
|
||||
intersect_y (c, b, i1, &i2) &&
|
||||
intersect_x (b, a, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i3, i3, i1, i1);
|
||||
|
||||
if (intersect_y (d, c, a, &i1) &&
|
||||
intersect_x (c, b, i1, &i2) &&
|
||||
intersect_y (b, a, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i3, i3, i1, i1);
|
||||
}
|
||||
|
||||
static void
|
||||
find_three_point_rectangle_corner (Rectangle *r,
|
||||
const PikaVector2 *points,
|
||||
gint n_points,
|
||||
gint p)
|
||||
{
|
||||
PikaVector2 a = points[p % n_points]; /* 0 1 2 3 */
|
||||
PikaVector2 b = points[(p + 1) % n_points]; /* 1 2 3 0 */
|
||||
PikaVector2 c = points[(p + 2) % n_points]; /* 2 3 0 2 */
|
||||
PikaVector2 d = points[(p + 3) % n_points]; /* 3 0 2 1 */
|
||||
PikaVector2 i1; /* intersection point */
|
||||
PikaVector2 i2; /* intersection point */
|
||||
|
||||
if (intersect_x (b, c, a , &i1) &&
|
||||
intersect_y (c, d, i1, &i2))
|
||||
add_rectangle (points, n_points, r, a, a, i1, i2);
|
||||
|
||||
if (intersect_y (b, c, a , &i1) &&
|
||||
intersect_x (c, d, i1, &i2))
|
||||
add_rectangle (points, n_points, r, a, a, i1, i2);
|
||||
|
||||
if (intersect_x (c, d, a , &i1) &&
|
||||
intersect_y (b, c, i1, &i2))
|
||||
add_rectangle (points, n_points, r, a, a, i1, i2);
|
||||
|
||||
if (intersect_y (c, d, a , &i1) &&
|
||||
intersect_x (b, c, i1, &i2))
|
||||
add_rectangle (points, n_points, r, a, a, i1, i2);
|
||||
}
|
||||
|
||||
static void
|
||||
find_two_point_rectangle (Rectangle *r,
|
||||
const PikaVector2 *points,
|
||||
gint n_points,
|
||||
gint p)
|
||||
{
|
||||
PikaVector2 a = points[ p % n_points]; /* 0 1 2 3 */
|
||||
PikaVector2 b = points[(p + 1) % n_points]; /* 1 2 3 0 */
|
||||
PikaVector2 c = points[(p + 2) % n_points]; /* 2 3 0 1 */
|
||||
PikaVector2 d = points[(p + 3) % n_points]; /* 3 0 1 2 */
|
||||
PikaVector2 i1; /* intersection point */
|
||||
PikaVector2 i2; /* intersection point */
|
||||
PikaVector2 mid; /* Mid point */
|
||||
|
||||
add_rectangle (points, n_points, r, a, a, c, c);
|
||||
add_rectangle (points, n_points, r, b, b, d, d);
|
||||
|
||||
if (intersect_x (c, b, a, &i1) &&
|
||||
intersect_y (c, b, a, &i2))
|
||||
{
|
||||
mid.x = ( i1.x + i2.x ) / 2.0;
|
||||
mid.y = ( i1.y + i2.y ) / 2.0;
|
||||
|
||||
add_rectangle (points, n_points, r, a, a, mid, mid);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
find_three_point_rectangle_triangle (Rectangle *r,
|
||||
const PikaVector2 *points,
|
||||
gint n_points,
|
||||
gint p)
|
||||
{
|
||||
PikaVector2 a = points[p % n_points]; /* 0 1 2 3 */
|
||||
PikaVector2 b = points[(p + 1) % n_points]; /* 1 2 3 0 */
|
||||
PikaVector2 c = points[(p + 2) % n_points]; /* 2 3 0 1 */
|
||||
PikaVector2 d = points[(p + 3) % n_points]; /* 3 0 1 2 */
|
||||
PikaVector2 i1; /* intersection point */
|
||||
PikaVector2 i2; /* intersection point */
|
||||
PikaVector2 mid;
|
||||
|
||||
mid.x = (a.x + b.x) / 2.0;
|
||||
mid.y = (a.y + b.y) / 2.0;
|
||||
|
||||
if (intersect_x (b, c, mid, &i1) &&
|
||||
intersect_y (a, d, mid, &i2))
|
||||
add_rectangle (points, n_points, r, mid, mid, i1, i2);
|
||||
|
||||
if (intersect_y (b, c, mid, &i1) &&
|
||||
intersect_x (a, d, mid, &i2))
|
||||
add_rectangle (points, n_points, r, mid, mid, i1, i2);
|
||||
|
||||
if (intersect_x (a, d, mid, &i1) &&
|
||||
intersect_y (b, c, mid, &i2))
|
||||
add_rectangle (points, n_points, r, mid, mid, i1, i2);
|
||||
|
||||
if (intersect_y (a, d, mid, &i1) &&
|
||||
intersect_x (b, c, mid, &i2))
|
||||
add_rectangle (points, n_points, r, mid, mid, i1, i2);
|
||||
}
|
||||
|
||||
static void
|
||||
find_maximum_aspect_rectangle (Rectangle *r,
|
||||
const PikaVector2 *points,
|
||||
gint n_points,
|
||||
gint p)
|
||||
{
|
||||
PikaVector2 a = points[ p % n_points]; /* 0 1 2 3 */
|
||||
PikaVector2 b = points[(p + 1) % n_points]; /* 1 2 3 0 */
|
||||
PikaVector2 c = points[(p + 2) % n_points]; /* 2 3 0 1 */
|
||||
PikaVector2 d = points[(p + 3) % n_points]; /* 3 0 1 2 */
|
||||
PikaVector2 i1; /* intersection point */
|
||||
PikaVector2 i2; /* intersection point */
|
||||
PikaVector2 i3; /* intersection point */
|
||||
|
||||
if (intersect_x (b, c, a, &i1))
|
||||
{
|
||||
i2.x = i1.x + 1.0 * r->aspect;
|
||||
i2.y = i1.y + 1.0;
|
||||
|
||||
if (intersect (d, a, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
if (intersect (a, b, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
if (intersect (c, d, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
i2.x = i1.x - 1.0 * r->aspect;
|
||||
i2.y = i1.y + 1.0;
|
||||
|
||||
if (intersect (d, a, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
if (intersect (a, b, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
if (intersect (c, d, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
}
|
||||
|
||||
if (intersect_y (b, c, a, &i1))
|
||||
{
|
||||
i2.x = i1.x + 1.0 * r->aspect;
|
||||
i2.y = i1.y + 1.0;
|
||||
|
||||
if (intersect (d, a, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
if (intersect (a, b, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
if (intersect (c, d, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
i2.x = i1.x - 1.0 * r->aspect;
|
||||
i2.y = i1.y + 1.0;
|
||||
|
||||
if (intersect (d, a, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
if (intersect (a, b, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
if (intersect (c, d, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
}
|
||||
|
||||
if (intersect_x (c, d, a, &i1))
|
||||
{
|
||||
i2.x = i1.x + 1.0 * r->aspect;
|
||||
i2.y = i1.y + 1.0;
|
||||
|
||||
if (intersect (d, a, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
if (intersect (a, b, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
if (intersect (b, c, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
i2.x = i1.x - 1.0 * r->aspect;
|
||||
i2.y = i1.y + 1.0;
|
||||
|
||||
if (intersect (d, a, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
if (intersect (a, b, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
if (intersect (b, c, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
}
|
||||
|
||||
if (intersect_y (c, d, a, &i1))
|
||||
{
|
||||
i2.x = i1.x + 1.0 * r->aspect;
|
||||
i2.y = i1.y + 1.0;
|
||||
|
||||
if (intersect (d, a, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
if (intersect (a, b, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
if (intersect (b, c, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
i2.x = i1.x - 1.0 * r->aspect;
|
||||
i2.y = i1.y + 1.0;
|
||||
|
||||
if (intersect (d, a, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
if (intersect (a, b, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
|
||||
if (intersect (b, c, i1, i2, &i3))
|
||||
add_rectangle (points, n_points, r, i1, i3, i1, i3);
|
||||
}
|
||||
}
|
||||
|
||||
/* check if point is inside the polygon "points", if point is on border
|
||||
* its still inside.
|
||||
*/
|
||||
static gboolean
|
||||
in_poly (const PikaVector2 *points,
|
||||
gint n_points,
|
||||
PikaVector2 p)
|
||||
{
|
||||
PikaVector2 p1, p2;
|
||||
gint counter = 0;
|
||||
gint i;
|
||||
|
||||
p1 = points[0];
|
||||
|
||||
for (i = 1; i <= n_points; i++)
|
||||
{
|
||||
p2 = points[i % n_points];
|
||||
|
||||
if (p.y > MIN (p1.y, p2.y))
|
||||
{
|
||||
if (p.y <= MAX (p1.y, p2.y))
|
||||
{
|
||||
if (p.x <= MAX (p1.x, p2.x))
|
||||
{
|
||||
if (p1.y != p2.y)
|
||||
{
|
||||
gdouble xinters = ((p.y - p1.y) * (p2.x - p1.x) /
|
||||
(p2.y - p1.y) + p1.x);
|
||||
|
||||
if (p1.x == p2.x || p.x <= xinters)
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p1 = p2;
|
||||
}
|
||||
|
||||
/* border check */
|
||||
if (point_on_border (points, n_points, p))
|
||||
return TRUE;
|
||||
|
||||
return (counter % 2 != 0);
|
||||
}
|
||||
|
||||
/* check if the point p lies on the polygon "points"
|
||||
*/
|
||||
static gboolean
|
||||
point_on_border (const PikaVector2 *points,
|
||||
gint n_points,
|
||||
PikaVector2 p)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i <= n_points; i++)
|
||||
{
|
||||
PikaVector2 a = points[i % n_points];
|
||||
PikaVector2 b = points[(i + 1) % n_points];
|
||||
gdouble a1 = (b.y - a.y);
|
||||
gdouble b1 = (a.x - b.x);
|
||||
gdouble c1 = a1 * a.x + b1 * a.y;
|
||||
gdouble c2 = a1 * p.x + b1 * p.y;
|
||||
|
||||
if (ABS (c1 - c2) < EPSILON &&
|
||||
MIN (a.x, b.x) <= p.x &&
|
||||
MAX (a.x, b.x) >= p.x &&
|
||||
MIN (a.y, b.y) <= p.y &&
|
||||
MAX (a.y, b.y) >= p.y)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* calculate the intersection point of the line a-b with the line c-d
|
||||
* and write it to i, if existing.
|
||||
*/
|
||||
static gboolean
|
||||
intersect (PikaVector2 a,
|
||||
PikaVector2 b,
|
||||
PikaVector2 c,
|
||||
PikaVector2 d,
|
||||
PikaVector2 *i)
|
||||
{
|
||||
gdouble a1 = (b.y - a.y);
|
||||
gdouble b1 = (a.x - b.x);
|
||||
gdouble c1 = a1 * a.x + b1 * a.y;
|
||||
|
||||
gdouble a2 = (d.y - c.y);
|
||||
gdouble b2 = (c.x - d.x);
|
||||
gdouble c2 = a2 * c.x + b2 * c.y;
|
||||
gdouble det = a1 * b2 - a2 * b1;
|
||||
|
||||
if (det == 0)
|
||||
return FALSE;
|
||||
|
||||
i->x = (b2 * c1 - b1 * c2) / det;
|
||||
i->y = (a1 * c2 - a2 * c1) / det;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* calculate the intersection point of the line a-b with the vertical line
|
||||
* through c and write it to i, if existing.
|
||||
*/
|
||||
static gboolean
|
||||
intersect_x (PikaVector2 a,
|
||||
PikaVector2 b,
|
||||
PikaVector2 c,
|
||||
PikaVector2 *i)
|
||||
{
|
||||
PikaVector2 d = c;
|
||||
d.y += 1;
|
||||
|
||||
return intersect(a,b,c,d,i);
|
||||
}
|
||||
|
||||
/* calculate the intersection point of the line a-b with the horizontal line
|
||||
* through c and write it to i, if existing.
|
||||
*/
|
||||
static gboolean
|
||||
intersect_y (PikaVector2 a,
|
||||
PikaVector2 b,
|
||||
PikaVector2 c,
|
||||
PikaVector2 *i)
|
||||
{
|
||||
PikaVector2 d = c;
|
||||
d.x += 1;
|
||||
|
||||
return intersect(a,b,c,d,i);
|
||||
}
|
||||
|
||||
/* this takes the smallest ortho-aligned (the sides of the rectangle are
|
||||
* parallel to the x- and y-axis) rectangle fitting around the points a to d,
|
||||
* checks if the whole rectangle is inside the polygon described by points and
|
||||
* writes it to r if the area is bigger than the rectangle already stored in r.
|
||||
*/
|
||||
static void
|
||||
add_rectangle (const PikaVector2 *points,
|
||||
gint n_points,
|
||||
Rectangle *r,
|
||||
PikaVector2 a,
|
||||
PikaVector2 b,
|
||||
PikaVector2 c,
|
||||
PikaVector2 d)
|
||||
{
|
||||
gdouble width;
|
||||
gdouble height;
|
||||
gdouble minx, maxx;
|
||||
gdouble miny, maxy;
|
||||
|
||||
/* get the orthoaligned (the sides of the rectangle are parallel to the x-
|
||||
* and y-axis) rectangle surrounding the points a to d.
|
||||
*/
|
||||
minx = MIN4 (a.x, b.x, c.x, d.x);
|
||||
maxx = MAX4 (a.x, b.x, c.x, d.x);
|
||||
miny = MIN4 (a.y, b.y, c.y, d.y);
|
||||
maxy = MAX4 (a.y, b.y, c.y, d.y);
|
||||
|
||||
a.x = minx;
|
||||
a.y = miny;
|
||||
|
||||
b.x = maxx;
|
||||
b.y = miny;
|
||||
|
||||
c.x = maxx;
|
||||
c.y = maxy;
|
||||
|
||||
d.x = minx;
|
||||
d.y = maxy;
|
||||
|
||||
width = maxx - minx;
|
||||
height = maxy - miny;
|
||||
|
||||
/* check if this rectangle is inside the polygon "points" */
|
||||
if (in_poly (points, n_points, a) &&
|
||||
in_poly (points, n_points, b) &&
|
||||
in_poly (points, n_points, c) &&
|
||||
in_poly (points, n_points, d))
|
||||
{
|
||||
gdouble area = width * height;
|
||||
|
||||
/* check if the new rectangle is larger (in terms of area)
|
||||
* than the currently stored rectangle in r, if yes store
|
||||
* new rectangle to r
|
||||
*/
|
||||
if (r->area <= area)
|
||||
{
|
||||
r->a.x = a.x;
|
||||
r->a.y = a.y;
|
||||
|
||||
r->b.x = b.x;
|
||||
r->b.y = b.y;
|
||||
|
||||
r->c.x = c.x;
|
||||
r->c.y = c.y;
|
||||
|
||||
r->d.x = d.x;
|
||||
r->d.y = d.y;
|
||||
|
||||
r->area = area;
|
||||
}
|
||||
}
|
||||
}
|
||||
38
app/core/pika-transform-resize.h
Normal file
38
app/core/pika-transform-resize.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* 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-2001 Spencer Kimball, Peter Mattis, and others
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_TRANSFORM_RESIZE_H__
|
||||
#define __PIKA_TRANSFORM_RESIZE_H__
|
||||
|
||||
|
||||
gboolean pika_transform_resize_boundary (const PikaMatrix3 *inv,
|
||||
PikaTransformResize resize,
|
||||
gdouble u1,
|
||||
gdouble v1,
|
||||
gdouble u2,
|
||||
gdouble v2,
|
||||
gint *x1,
|
||||
gint *y1,
|
||||
gint *x2,
|
||||
gint *y2);
|
||||
|
||||
|
||||
#endif /* __PIKA_TRANSFORM_RESIZE_H__ */
|
||||
1215
app/core/pika-transform-utils.c
Normal file
1215
app/core/pika-transform-utils.c
Normal file
File diff suppressed because it is too large
Load Diff
129
app/core/pika-transform-utils.h
Normal file
129
app/core/pika-transform-utils.h
Normal file
@ -0,0 +1,129 @@
|
||||
/* 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-2001 Spencer Kimball, Peter Mattis, and others
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_TRANSFORM_UTILS_H__
|
||||
#define __PIKA_TRANSFORM_UTILS_H__
|
||||
|
||||
|
||||
#define PIKA_TRANSFORM_NEAR_Z 0.02
|
||||
|
||||
|
||||
void pika_transform_get_rotate_center (gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height,
|
||||
gboolean auto_center,
|
||||
gdouble *center_x,
|
||||
gdouble *center_y);
|
||||
void pika_transform_get_flip_axis (gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height,
|
||||
PikaOrientationType flip_type,
|
||||
gboolean auto_center,
|
||||
gdouble *axis);
|
||||
|
||||
void pika_transform_matrix_flip (PikaMatrix3 *matrix,
|
||||
PikaOrientationType flip_type,
|
||||
gdouble axis);
|
||||
void pika_transform_matrix_flip_free (PikaMatrix3 *matrix,
|
||||
gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2);
|
||||
void pika_transform_matrix_rotate (PikaMatrix3 *matrix,
|
||||
PikaRotationType rotate_type,
|
||||
gdouble center_x,
|
||||
gdouble center_y);
|
||||
void pika_transform_matrix_rotate_rect (PikaMatrix3 *matrix,
|
||||
gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height,
|
||||
gdouble angle);
|
||||
void pika_transform_matrix_rotate_center (PikaMatrix3 *matrix,
|
||||
gdouble center_x,
|
||||
gdouble center_y,
|
||||
gdouble angle);
|
||||
void pika_transform_matrix_scale (PikaMatrix3 *matrix,
|
||||
gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height,
|
||||
gdouble t_x,
|
||||
gdouble t_y,
|
||||
gdouble t_width,
|
||||
gdouble t_height);
|
||||
void pika_transform_matrix_shear (PikaMatrix3 *matrix,
|
||||
gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height,
|
||||
PikaOrientationType orientation,
|
||||
gdouble amount);
|
||||
void pika_transform_matrix_perspective (PikaMatrix3 *matrix,
|
||||
gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height,
|
||||
gdouble t_x1,
|
||||
gdouble t_y1,
|
||||
gdouble t_x2,
|
||||
gdouble t_y2,
|
||||
gdouble t_x3,
|
||||
gdouble t_y3,
|
||||
gdouble t_x4,
|
||||
gdouble t_y4);
|
||||
gboolean pika_transform_matrix_generic (PikaMatrix3 *matrix,
|
||||
const PikaVector2 input_points[4],
|
||||
const PikaVector2 output_points[4]);
|
||||
|
||||
gboolean pika_transform_polygon_is_convex (gdouble x1,
|
||||
gdouble y1,
|
||||
gdouble x2,
|
||||
gdouble y2,
|
||||
gdouble x3,
|
||||
gdouble y3,
|
||||
gdouble x4,
|
||||
gdouble y4);
|
||||
|
||||
void pika_transform_polygon (const PikaMatrix3 *matrix,
|
||||
const PikaVector2 *vertices,
|
||||
gint n_vertices,
|
||||
gboolean closed,
|
||||
PikaVector2 *t_vertices,
|
||||
gint *n_t_vertices);
|
||||
void pika_transform_polygon_coords (const PikaMatrix3 *matrix,
|
||||
const PikaCoords *vertices,
|
||||
gint n_vertices,
|
||||
gboolean closed,
|
||||
PikaCoords *t_vertices,
|
||||
gint *n_t_vertices);
|
||||
|
||||
void pika_transform_bezier_coords (const PikaMatrix3 *matrix,
|
||||
const PikaCoords bezier[4],
|
||||
GQueue *t_beziers[2],
|
||||
gint *n_t_beziers,
|
||||
gboolean *start_in,
|
||||
gboolean *end_in);
|
||||
|
||||
|
||||
#endif /* __PIKA_TRANSFORM_UTILS_H__ */
|
||||
492
app/core/pika-units.c
Normal file
492
app/core/pika-units.c
Normal file
@ -0,0 +1,492 @@
|
||||
/* 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-1999 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikaunit.c
|
||||
* Copyright (C) 1999-2000 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This file contains functions to load & save the file containing the
|
||||
* user-defined size units, when the application starts/finished.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikabase/pikabase-private.h"
|
||||
#include "libpikaconfig/pikaconfig.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pika-units.h"
|
||||
#include "pikaunit.h"
|
||||
|
||||
#include "config/pikaconfig-file.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
/*
|
||||
* All deserialize functions return G_TOKEN_LEFT_PAREN on success,
|
||||
* or the GTokenType they would have expected but didn't get.
|
||||
*/
|
||||
|
||||
static GTokenType pika_unitrc_unit_info_deserialize (GScanner *scanner,
|
||||
Pika *pika);
|
||||
|
||||
|
||||
static Pika *the_unit_pika = NULL;
|
||||
|
||||
|
||||
static gint
|
||||
pika_units_get_number_of_units (void)
|
||||
{
|
||||
return _pika_unit_get_number_of_units (the_unit_pika);
|
||||
}
|
||||
|
||||
static gint
|
||||
pika_units_get_number_of_built_in_units (void)
|
||||
{
|
||||
return PIKA_UNIT_END;
|
||||
}
|
||||
|
||||
static PikaUnit
|
||||
pika_units_unit_new (gchar *identifier,
|
||||
gdouble factor,
|
||||
gint digits,
|
||||
gchar *symbol,
|
||||
gchar *abbreviation,
|
||||
gchar *singular,
|
||||
gchar *plural)
|
||||
{
|
||||
return _pika_unit_new (the_unit_pika,
|
||||
identifier,
|
||||
factor,
|
||||
digits,
|
||||
symbol,
|
||||
abbreviation,
|
||||
singular,
|
||||
plural);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_units_unit_get_deletion_flag (PikaUnit unit)
|
||||
{
|
||||
return _pika_unit_get_deletion_flag (the_unit_pika, unit);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_units_unit_set_deletion_flag (PikaUnit unit,
|
||||
gboolean deletion_flag)
|
||||
{
|
||||
_pika_unit_set_deletion_flag (the_unit_pika, unit, deletion_flag);
|
||||
}
|
||||
|
||||
static gdouble
|
||||
pika_units_unit_get_factor (PikaUnit unit)
|
||||
{
|
||||
return _pika_unit_get_factor (the_unit_pika, unit);
|
||||
}
|
||||
|
||||
static gint
|
||||
pika_units_unit_get_digits (PikaUnit unit)
|
||||
{
|
||||
return _pika_unit_get_digits (the_unit_pika, unit);
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
pika_units_unit_get_identifier (PikaUnit unit)
|
||||
{
|
||||
return _pika_unit_get_identifier (the_unit_pika, unit);
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
pika_units_unit_get_symbol (PikaUnit unit)
|
||||
{
|
||||
return _pika_unit_get_symbol (the_unit_pika, unit);
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
pika_units_unit_get_abbreviation (PikaUnit unit)
|
||||
{
|
||||
return _pika_unit_get_abbreviation (the_unit_pika, unit);
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
pika_units_unit_get_singular (PikaUnit unit)
|
||||
{
|
||||
return _pika_unit_get_singular (the_unit_pika, unit);
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
pika_units_unit_get_plural (PikaUnit unit)
|
||||
{
|
||||
return _pika_unit_get_plural (the_unit_pika, unit);
|
||||
}
|
||||
|
||||
void
|
||||
pika_units_init (Pika *pika)
|
||||
{
|
||||
PikaUnitVtable vtable;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
g_return_if_fail (the_unit_pika == NULL);
|
||||
|
||||
the_unit_pika = pika;
|
||||
|
||||
vtable.unit_get_number_of_units = pika_units_get_number_of_units;
|
||||
vtable.unit_get_number_of_built_in_units = pika_units_get_number_of_built_in_units;
|
||||
vtable.unit_new = pika_units_unit_new;
|
||||
vtable.unit_get_deletion_flag = pika_units_unit_get_deletion_flag;
|
||||
vtable.unit_set_deletion_flag = pika_units_unit_set_deletion_flag;
|
||||
vtable.unit_get_factor = pika_units_unit_get_factor;
|
||||
vtable.unit_get_digits = pika_units_unit_get_digits;
|
||||
vtable.unit_get_identifier = pika_units_unit_get_identifier;
|
||||
vtable.unit_get_symbol = pika_units_unit_get_symbol;
|
||||
vtable.unit_get_abbreviation = pika_units_unit_get_abbreviation;
|
||||
vtable.unit_get_singular = pika_units_unit_get_singular;
|
||||
vtable.unit_get_plural = pika_units_unit_get_plural;
|
||||
|
||||
pika_base_init (&vtable);
|
||||
|
||||
pika->user_units = NULL;
|
||||
pika->n_user_units = 0;
|
||||
}
|
||||
|
||||
void
|
||||
pika_units_exit (Pika *pika)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
pika_user_units_free (pika);
|
||||
}
|
||||
|
||||
|
||||
/* unitrc functions **********/
|
||||
|
||||
enum
|
||||
{
|
||||
UNIT_INFO = 1,
|
||||
UNIT_FACTOR,
|
||||
UNIT_DIGITS,
|
||||
UNIT_SYMBOL,
|
||||
UNIT_ABBREV,
|
||||
UNIT_SINGULAR,
|
||||
UNIT_PLURAL
|
||||
};
|
||||
|
||||
void
|
||||
pika_unitrc_load (Pika *pika)
|
||||
{
|
||||
GFile *file;
|
||||
GScanner *scanner;
|
||||
GTokenType token;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
file = pika_directory_file ("unitrc", NULL);
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Parsing '%s'\n", pika_file_get_utf8_name (file));
|
||||
|
||||
scanner = pika_scanner_new_file (file, &error);
|
||||
|
||||
if (! scanner && error->code == PIKA_CONFIG_ERROR_OPEN_ENOENT)
|
||||
{
|
||||
g_clear_error (&error);
|
||||
g_object_unref (file);
|
||||
|
||||
file = pika_sysconf_directory_file ("unitrc", NULL);
|
||||
|
||||
scanner = pika_scanner_new_file (file, NULL);
|
||||
}
|
||||
|
||||
if (! scanner)
|
||||
{
|
||||
g_clear_error (&error);
|
||||
g_object_unref (file);
|
||||
return;
|
||||
}
|
||||
|
||||
g_scanner_scope_add_symbol (scanner, 0,
|
||||
"unit-info", GINT_TO_POINTER (UNIT_INFO));
|
||||
g_scanner_scope_add_symbol (scanner, UNIT_INFO,
|
||||
"factor", GINT_TO_POINTER (UNIT_FACTOR));
|
||||
g_scanner_scope_add_symbol (scanner, UNIT_INFO,
|
||||
"digits", GINT_TO_POINTER (UNIT_DIGITS));
|
||||
g_scanner_scope_add_symbol (scanner, UNIT_INFO,
|
||||
"symbol", GINT_TO_POINTER (UNIT_SYMBOL));
|
||||
g_scanner_scope_add_symbol (scanner, UNIT_INFO,
|
||||
"abbreviation", GINT_TO_POINTER (UNIT_ABBREV));
|
||||
g_scanner_scope_add_symbol (scanner, UNIT_INFO,
|
||||
"singular", GINT_TO_POINTER (UNIT_SINGULAR));
|
||||
g_scanner_scope_add_symbol (scanner, UNIT_INFO,
|
||||
"plural", GINT_TO_POINTER (UNIT_PLURAL));
|
||||
|
||||
token = G_TOKEN_LEFT_PAREN;
|
||||
|
||||
while (g_scanner_peek_next_token (scanner) == token)
|
||||
{
|
||||
token = g_scanner_get_next_token (scanner);
|
||||
|
||||
switch (token)
|
||||
{
|
||||
case G_TOKEN_LEFT_PAREN:
|
||||
token = G_TOKEN_SYMBOL;
|
||||
break;
|
||||
|
||||
case G_TOKEN_SYMBOL:
|
||||
if (scanner->value.v_symbol == GINT_TO_POINTER (UNIT_INFO))
|
||||
{
|
||||
g_scanner_set_scope (scanner, UNIT_INFO);
|
||||
token = pika_unitrc_unit_info_deserialize (scanner, pika);
|
||||
|
||||
if (token == G_TOKEN_RIGHT_PAREN)
|
||||
g_scanner_set_scope (scanner, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case G_TOKEN_RIGHT_PAREN:
|
||||
token = G_TOKEN_LEFT_PAREN;
|
||||
break;
|
||||
|
||||
default: /* do nothing */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (token != G_TOKEN_LEFT_PAREN)
|
||||
{
|
||||
g_scanner_get_next_token (scanner);
|
||||
g_scanner_unexp_token (scanner, token, NULL, NULL, NULL,
|
||||
_("fatal parse error"), TRUE);
|
||||
|
||||
pika_message_literal (pika, NULL, PIKA_MESSAGE_ERROR, error->message);
|
||||
g_clear_error (&error);
|
||||
|
||||
pika_config_file_backup_on_error (file, "unitrc", NULL);
|
||||
}
|
||||
|
||||
pika_scanner_unref (scanner);
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
void
|
||||
pika_unitrc_save (Pika *pika)
|
||||
{
|
||||
PikaConfigWriter *writer;
|
||||
GFile *file;
|
||||
gint i;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (PIKA_IS_PIKA (pika));
|
||||
|
||||
file = pika_directory_file ("unitrc", NULL);
|
||||
|
||||
if (pika->be_verbose)
|
||||
g_print ("Writing '%s'\n", pika_file_get_utf8_name (file));
|
||||
|
||||
writer =
|
||||
pika_config_writer_new_from_file (file,
|
||||
TRUE,
|
||||
"PIKA units\n\n"
|
||||
"This file contains the user unit database. "
|
||||
"You can edit this list with the unit "
|
||||
"editor. You are not supposed to edit it "
|
||||
"manually, but of course you can do.\n"
|
||||
"This file will be entirely rewritten each "
|
||||
"time you exit.",
|
||||
NULL);
|
||||
|
||||
g_object_unref (file);
|
||||
|
||||
if (!writer)
|
||||
return;
|
||||
|
||||
/* save user defined units */
|
||||
for (i = _pika_unit_get_number_of_built_in_units (pika);
|
||||
i < _pika_unit_get_number_of_units (pika);
|
||||
i++)
|
||||
{
|
||||
if (_pika_unit_get_deletion_flag (pika, i) == FALSE)
|
||||
{
|
||||
gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
|
||||
|
||||
pika_config_writer_open (writer, "unit-info");
|
||||
pika_config_writer_string (writer,
|
||||
_pika_unit_get_identifier (pika, i));
|
||||
|
||||
pika_config_writer_open (writer, "factor");
|
||||
pika_config_writer_print (writer,
|
||||
g_ascii_dtostr (buf, sizeof (buf),
|
||||
_pika_unit_get_factor (pika, i)),
|
||||
-1);
|
||||
pika_config_writer_close (writer);
|
||||
|
||||
pika_config_writer_open (writer, "digits");
|
||||
pika_config_writer_printf (writer,
|
||||
"%d", _pika_unit_get_digits (pika, i));
|
||||
pika_config_writer_close (writer);
|
||||
|
||||
pika_config_writer_open (writer, "symbol");
|
||||
pika_config_writer_string (writer,
|
||||
_pika_unit_get_symbol (pika, i));
|
||||
pika_config_writer_close (writer);
|
||||
|
||||
pika_config_writer_open (writer, "abbreviation");
|
||||
pika_config_writer_string (writer,
|
||||
_pika_unit_get_abbreviation (pika, i));
|
||||
pika_config_writer_close (writer);
|
||||
|
||||
pika_config_writer_open (writer, "singular");
|
||||
pika_config_writer_string (writer,
|
||||
_pika_unit_get_singular (pika, i));
|
||||
pika_config_writer_close (writer);
|
||||
|
||||
pika_config_writer_open (writer, "plural");
|
||||
pika_config_writer_string (writer,
|
||||
_pika_unit_get_plural (pika, i));
|
||||
pika_config_writer_close (writer);
|
||||
|
||||
pika_config_writer_close (writer);
|
||||
}
|
||||
}
|
||||
|
||||
if (! pika_config_writer_finish (writer, "end of units", &error))
|
||||
{
|
||||
pika_message_literal (pika, NULL, PIKA_MESSAGE_ERROR, error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static GTokenType
|
||||
pika_unitrc_unit_info_deserialize (GScanner *scanner,
|
||||
Pika *pika)
|
||||
{
|
||||
gchar *identifier = NULL;
|
||||
gdouble factor = 1.0;
|
||||
gint digits = 2.0;
|
||||
gchar *symbol = NULL;
|
||||
gchar *abbreviation = NULL;
|
||||
gchar *singular = NULL;
|
||||
gchar *plural = NULL;
|
||||
GTokenType token;
|
||||
|
||||
if (! pika_scanner_parse_string (scanner, &identifier))
|
||||
return G_TOKEN_STRING;
|
||||
|
||||
token = G_TOKEN_LEFT_PAREN;
|
||||
|
||||
while (g_scanner_peek_next_token (scanner) == token)
|
||||
{
|
||||
token = g_scanner_get_next_token (scanner);
|
||||
|
||||
switch (token)
|
||||
{
|
||||
case G_TOKEN_LEFT_PAREN:
|
||||
token = G_TOKEN_SYMBOL;
|
||||
break;
|
||||
|
||||
case G_TOKEN_SYMBOL:
|
||||
switch (GPOINTER_TO_INT (scanner->value.v_symbol))
|
||||
{
|
||||
case UNIT_FACTOR:
|
||||
token = G_TOKEN_FLOAT;
|
||||
if (! pika_scanner_parse_float (scanner, &factor))
|
||||
goto cleanup;
|
||||
break;
|
||||
|
||||
case UNIT_DIGITS:
|
||||
token = G_TOKEN_INT;
|
||||
if (! pika_scanner_parse_int (scanner, &digits))
|
||||
goto cleanup;
|
||||
break;
|
||||
|
||||
case UNIT_SYMBOL:
|
||||
token = G_TOKEN_STRING;
|
||||
if (! pika_scanner_parse_string (scanner, &symbol))
|
||||
goto cleanup;
|
||||
break;
|
||||
|
||||
case UNIT_ABBREV:
|
||||
token = G_TOKEN_STRING;
|
||||
if (! pika_scanner_parse_string (scanner, &abbreviation))
|
||||
goto cleanup;
|
||||
break;
|
||||
|
||||
case UNIT_SINGULAR:
|
||||
token = G_TOKEN_STRING;
|
||||
if (! pika_scanner_parse_string (scanner, &singular))
|
||||
goto cleanup;
|
||||
break;
|
||||
|
||||
case UNIT_PLURAL:
|
||||
token = G_TOKEN_STRING;
|
||||
if (! pika_scanner_parse_string (scanner, &plural))
|
||||
goto cleanup;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
token = G_TOKEN_RIGHT_PAREN;
|
||||
break;
|
||||
|
||||
case G_TOKEN_RIGHT_PAREN:
|
||||
token = G_TOKEN_LEFT_PAREN;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (token == G_TOKEN_LEFT_PAREN)
|
||||
{
|
||||
token = G_TOKEN_RIGHT_PAREN;
|
||||
|
||||
if (g_scanner_peek_next_token (scanner) == token)
|
||||
{
|
||||
PikaUnit unit = _pika_unit_new (pika,
|
||||
identifier, factor, digits,
|
||||
symbol, abbreviation,
|
||||
singular, plural);
|
||||
|
||||
/* make the unit definition persistent */
|
||||
_pika_unit_set_deletion_flag (pika, unit, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
|
||||
g_free (identifier);
|
||||
g_free (symbol);
|
||||
g_free (abbreviation);
|
||||
g_free (singular);
|
||||
g_free (plural);
|
||||
|
||||
return token;
|
||||
}
|
||||
33
app/core/pika-units.h
Normal file
33
app/core/pika-units.h
Normal file
@ -0,0 +1,33 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_UNITS_H__
|
||||
#define __PIKA_UNITS_H__
|
||||
|
||||
|
||||
void pika_units_init (Pika *pika);
|
||||
void pika_units_exit (Pika *pika);
|
||||
|
||||
void pika_unitrc_load (Pika *pika);
|
||||
void pika_unitrc_save (Pika *pika);
|
||||
|
||||
|
||||
#endif /* __PIKA_UNITS_H__ */
|
||||
1114
app/core/pika-user-install.c
Normal file
1114
app/core/pika-user-install.c
Normal file
File diff suppressed because it is too large
Load Diff
44
app/core/pika-user-install.h
Normal file
44
app/core/pika-user-install.h
Normal file
@ -0,0 +1,44 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_USER_INSTALL_H__
|
||||
#define __PIKA_USER_INSTALL_H__
|
||||
|
||||
|
||||
typedef struct _PikaUserInstall PikaUserInstall;
|
||||
|
||||
typedef void (* PikaUserInstallLogFunc) (const gchar *message,
|
||||
gboolean error,
|
||||
gpointer user_data);
|
||||
|
||||
|
||||
PikaUserInstall * pika_user_install_new (GObject *pika,
|
||||
gboolean verbose);
|
||||
gboolean pika_user_install_run (PikaUserInstall *install,
|
||||
gint scale_factor);
|
||||
void pika_user_install_free (PikaUserInstall *install);
|
||||
|
||||
void pika_user_install_set_log_handler (PikaUserInstall *install,
|
||||
PikaUserInstallLogFunc log,
|
||||
gpointer user_data);
|
||||
|
||||
|
||||
#endif /* __USER_INSTALL_H__ */
|
||||
1595
app/core/pika-utils.c
Normal file
1595
app/core/pika-utils.c
Normal file
File diff suppressed because it is too large
Load Diff
145
app/core/pika-utils.h
Normal file
145
app/core/pika-utils.h
Normal file
@ -0,0 +1,145 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __APP_PIKA_UTILS_H__
|
||||
#define __APP_PIKA_UTILS_H__
|
||||
|
||||
|
||||
#ifdef PIKA_RELEASE
|
||||
#define PIKA_TIMER_START()
|
||||
#define PIKA_TIMER_END(message)
|
||||
#else
|
||||
#define PIKA_TIMER_START() \
|
||||
{ GTimer *_timer = g_timer_new ();
|
||||
|
||||
#define PIKA_TIMER_END(message) \
|
||||
g_printerr ("%s: %s took %0.4f seconds\n", \
|
||||
G_STRFUNC, message, g_timer_elapsed (_timer, NULL)); \
|
||||
g_timer_destroy (_timer); }
|
||||
#endif
|
||||
|
||||
|
||||
#define MIN4(a,b,c,d) MIN (MIN ((a), (b)), MIN ((c), (d)))
|
||||
#define MAX4(a,b,c,d) MAX (MAX ((a), (b)), MAX ((c), (d)))
|
||||
|
||||
|
||||
gint pika_get_pid (void);
|
||||
guint64 pika_get_physical_memory_size (void);
|
||||
gchar * pika_get_default_language (const gchar *category);
|
||||
PikaUnit pika_get_default_unit (void);
|
||||
|
||||
gchar ** pika_properties_append (GType object_type,
|
||||
gint *n_properties,
|
||||
gchar **names,
|
||||
GValue **values,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
gchar ** pika_properties_append_valist (GType object_type,
|
||||
gint *n_properties,
|
||||
gchar **names,
|
||||
GValue **values,
|
||||
va_list args);
|
||||
void pika_properties_free (gint n_properties,
|
||||
gchar **names,
|
||||
GValue *values);
|
||||
|
||||
gchar * pika_markup_extract_text (const gchar *markup);
|
||||
|
||||
const gchar* pika_enum_get_value_name (GType enum_type,
|
||||
gint value);
|
||||
|
||||
gboolean pika_get_fill_params (PikaContext *context,
|
||||
PikaFillType fill_type,
|
||||
PikaRGB *color,
|
||||
PikaPattern **pattern,
|
||||
GError **error);
|
||||
|
||||
/* Common values for the n_snap_lines parameter of
|
||||
* pika_constrain_line.
|
||||
*/
|
||||
#define PIKA_CONSTRAIN_LINE_90_DEGREES 2
|
||||
#define PIKA_CONSTRAIN_LINE_45_DEGREES 4
|
||||
#define PIKA_CONSTRAIN_LINE_15_DEGREES 12
|
||||
|
||||
void pika_constrain_line (gdouble start_x,
|
||||
gdouble start_y,
|
||||
gdouble *end_x,
|
||||
gdouble *end_y,
|
||||
gint n_snap_lines,
|
||||
gdouble offset_angle,
|
||||
gdouble xres,
|
||||
gdouble yres);
|
||||
|
||||
gint pika_file_compare (GFile *file1,
|
||||
GFile *file2);
|
||||
gboolean pika_file_is_executable (GFile *file);
|
||||
gchar * pika_file_get_extension (GFile *file);
|
||||
GFile * pika_file_with_new_extension (GFile *file,
|
||||
GFile *ext_file);
|
||||
gboolean pika_file_delete_recursive (GFile *file,
|
||||
GError **error);
|
||||
|
||||
gchar * pika_data_input_stream_read_line_always
|
||||
(GDataInputStream *stream,
|
||||
gsize *length,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean pika_ascii_strtoi (const gchar *nptr,
|
||||
gchar **endptr,
|
||||
gint base,
|
||||
gint *result);
|
||||
gboolean pika_ascii_strtod (const gchar *nptr,
|
||||
gchar **endptr,
|
||||
gdouble *result);
|
||||
|
||||
gchar * pika_appstream_to_pango_markup (const gchar *as_text);
|
||||
void pika_appstream_to_pango_markups (const gchar *as_text,
|
||||
gchar **introduction,
|
||||
GList **release_items);
|
||||
|
||||
gint pika_g_list_compare (GList *list1,
|
||||
GList *list2);
|
||||
|
||||
PikaTRCType pika_suggest_trc_for_component_type (PikaComponentType component_type,
|
||||
PikaTRCType old_trc);
|
||||
|
||||
PikaAsync * pika_idle_run_async (PikaRunAsyncFunc func,
|
||||
gpointer user_data);
|
||||
PikaAsync * pika_idle_run_async_full (gint priority,
|
||||
PikaRunAsyncFunc func,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_destroy_func);
|
||||
|
||||
PikaImage * pika_create_image_from_buffer (Pika *pika,
|
||||
GeglBuffer *buffer,
|
||||
const gchar *image_name);
|
||||
|
||||
gint pika_view_size_get_larger (gint view_size);
|
||||
gint pika_view_size_get_smaller (gint view_size);
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
|
||||
gboolean pika_win32_have_wintab (void);
|
||||
gboolean pika_win32_have_windows_ink (void);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __APP_PIKA_UTILS_H__ */
|
||||
1243
app/core/pika.c
Normal file
1243
app/core/pika.c
Normal file
File diff suppressed because it is too large
Load Diff
256
app/core/pika.h
Normal file
256
app/core/pika.h
Normal file
@ -0,0 +1,256 @@
|
||||
/* 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-1997 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_H__
|
||||
#define __PIKA_H__
|
||||
|
||||
|
||||
#include "pikaobject.h"
|
||||
#include "pika-gui.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_PIKA (pika_get_type ())
|
||||
#define PIKA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_PIKA, Pika))
|
||||
#define PIKA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_PIKA, PikaClass))
|
||||
#define PIKA_IS_PIKA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_PIKA))
|
||||
#define PIKA_IS_PIKA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_PIKA))
|
||||
|
||||
|
||||
typedef struct _PikaClass PikaClass;
|
||||
|
||||
struct _Pika
|
||||
{
|
||||
PikaObject parent_instance;
|
||||
|
||||
GApplication *app;
|
||||
|
||||
PikaCoreConfig *config;
|
||||
PikaCoreConfig *edit_config; /* don't use this one, it's just
|
||||
* for the preferences dialog
|
||||
*/
|
||||
gchar *session_name;
|
||||
GFile *default_folder;
|
||||
|
||||
gboolean be_verbose;
|
||||
gboolean no_data;
|
||||
gboolean no_fonts;
|
||||
gboolean no_interface;
|
||||
gboolean show_gui;
|
||||
gboolean use_shm;
|
||||
gboolean use_cpu_accel;
|
||||
PikaMessageHandlerType message_handler;
|
||||
gboolean console_messages;
|
||||
gboolean show_playground;
|
||||
gboolean show_debug_menu;
|
||||
PikaStackTraceMode stack_trace_mode;
|
||||
PikaPDBCompatMode pdb_compat_mode;
|
||||
|
||||
PikaGui gui; /* gui vtable */
|
||||
|
||||
gboolean restored; /* becomes TRUE in pika_restore() */
|
||||
gboolean initialized; /* Fully initialized (only set once at start). */
|
||||
gboolean query_all; /* Force query all plug-ins. */
|
||||
|
||||
gint busy;
|
||||
guint busy_idle_id;
|
||||
|
||||
GList *user_units;
|
||||
gint n_user_units;
|
||||
|
||||
PikaParasiteList *parasites;
|
||||
|
||||
PikaContainer *paint_info_list;
|
||||
PikaPaintInfo *standard_paint_info;
|
||||
|
||||
PikaModuleDB *module_db;
|
||||
gboolean write_modulerc;
|
||||
|
||||
PikaExtensionManager *extension_manager;
|
||||
PikaPlugInManager *plug_in_manager;
|
||||
|
||||
GList *filter_history;
|
||||
|
||||
PikaContainer *images;
|
||||
guint32 next_guide_id;
|
||||
guint32 next_sample_point_id;
|
||||
PikaIdTable *image_table;
|
||||
PikaIdTable *item_table;
|
||||
|
||||
PikaContainer *displays;
|
||||
gint next_display_id;
|
||||
|
||||
GList *image_windows;
|
||||
|
||||
PikaImage *clipboard_image;
|
||||
PikaBuffer *clipboard_buffer;
|
||||
PikaContainer *named_buffers;
|
||||
|
||||
PikaDataFactory *brush_factory;
|
||||
PikaDataFactory *dynamics_factory;
|
||||
PikaDataFactory *mybrush_factory;
|
||||
PikaDataFactory *pattern_factory;
|
||||
PikaDataFactory *gradient_factory;
|
||||
PikaDataFactory *palette_factory;
|
||||
PikaDataFactory *font_factory;
|
||||
PikaDataFactory *tool_preset_factory;
|
||||
|
||||
PikaTagCache *tag_cache;
|
||||
|
||||
PikaPDB *pdb;
|
||||
|
||||
PikaContainer *tool_info_list;
|
||||
PikaToolInfo *standard_tool_info;
|
||||
|
||||
PikaContainer *tool_item_list;
|
||||
PikaContainer *tool_item_ui_list;
|
||||
|
||||
/* the opened and saved images in MRU order */
|
||||
PikaContainer *documents;
|
||||
|
||||
/* image_new values */
|
||||
PikaContainer *templates;
|
||||
PikaTemplate *image_new_last_template;
|
||||
|
||||
/* the list of all contexts */
|
||||
GList *context_list;
|
||||
|
||||
/* the default context which is initialized from pikarc */
|
||||
PikaContext *default_context;
|
||||
|
||||
/* the context used by the interface */
|
||||
PikaContext *user_context;
|
||||
};
|
||||
|
||||
struct _PikaClass
|
||||
{
|
||||
PikaObjectClass parent_class;
|
||||
|
||||
void (* initialize) (Pika *pika,
|
||||
PikaInitStatusFunc status_callback);
|
||||
void (* restore) (Pika *pika,
|
||||
PikaInitStatusFunc status_callback);
|
||||
gboolean (* exit) (Pika *pika,
|
||||
gboolean force);
|
||||
|
||||
void (* clipboard_changed) (Pika *pika);
|
||||
|
||||
void (* filter_history_changed) (Pika *pika);
|
||||
|
||||
/* emitted if an image is loaded and opened with a display */
|
||||
void (* image_opened) (Pika *pika,
|
||||
GFile *file);
|
||||
};
|
||||
|
||||
|
||||
GType pika_get_type (void) G_GNUC_CONST;
|
||||
|
||||
Pika * pika_new (const gchar *name,
|
||||
const gchar *session_name,
|
||||
GFile *default_folder,
|
||||
gboolean be_verbose,
|
||||
gboolean no_data,
|
||||
gboolean no_fonts,
|
||||
gboolean no_interface,
|
||||
gboolean use_shm,
|
||||
gboolean use_cpu_accel,
|
||||
gboolean console_messages,
|
||||
gboolean show_playground,
|
||||
gboolean show_debug_menu,
|
||||
PikaStackTraceMode stack_trace_mode,
|
||||
PikaPDBCompatMode pdb_compat_mode);
|
||||
void pika_set_show_gui (Pika *pika,
|
||||
gboolean show_gui);
|
||||
gboolean pika_get_show_gui (Pika *pika);
|
||||
|
||||
void pika_load_config (Pika *pika,
|
||||
GFile *alternate_system_pikarc,
|
||||
GFile *alternate_pikarc);
|
||||
void pika_initialize (Pika *pika,
|
||||
PikaInitStatusFunc status_callback);
|
||||
void pika_restore (Pika *pika,
|
||||
PikaInitStatusFunc status_callback,
|
||||
GError **error);
|
||||
gboolean pika_is_restored (Pika *pika);
|
||||
|
||||
void pika_exit (Pika *pika,
|
||||
gboolean force);
|
||||
|
||||
GList * pika_get_image_iter (Pika *pika);
|
||||
GList * pika_get_display_iter (Pika *pika);
|
||||
GList * pika_get_image_windows (Pika *pika);
|
||||
GList * pika_get_paint_info_iter (Pika *pika);
|
||||
GList * pika_get_tool_info_iter (Pika *pika);
|
||||
GList * pika_get_tool_item_iter (Pika *pika);
|
||||
GList * pika_get_tool_item_ui_iter (Pika *pika);
|
||||
|
||||
PikaObject * pika_get_clipboard_object (Pika *pika);
|
||||
|
||||
void pika_set_clipboard_image (Pika *pika,
|
||||
PikaImage *image);
|
||||
PikaImage * pika_get_clipboard_image (Pika *pika);
|
||||
|
||||
void pika_set_clipboard_buffer (Pika *pika,
|
||||
PikaBuffer *buffer);
|
||||
PikaBuffer * pika_get_clipboard_buffer (Pika *pika);
|
||||
|
||||
PikaImage * pika_create_image (Pika *pika,
|
||||
gint width,
|
||||
gint height,
|
||||
PikaImageBaseType type,
|
||||
PikaPrecision precision,
|
||||
gboolean attach_comment);
|
||||
|
||||
void pika_set_default_context (Pika *pika,
|
||||
PikaContext *context);
|
||||
PikaContext * pika_get_default_context (Pika *pika);
|
||||
|
||||
void pika_set_user_context (Pika *pika,
|
||||
PikaContext *context);
|
||||
PikaContext * pika_get_user_context (Pika *pika);
|
||||
|
||||
PikaToolInfo * pika_get_tool_info (Pika *pika,
|
||||
const gchar *tool_name);
|
||||
|
||||
void pika_message (Pika *pika,
|
||||
GObject *handler,
|
||||
PikaMessageSeverity severity,
|
||||
const gchar *format,
|
||||
...) G_GNUC_PRINTF (4, 5);
|
||||
void pika_message_valist (Pika *pika,
|
||||
GObject *handler,
|
||||
PikaMessageSeverity severity,
|
||||
const gchar *format,
|
||||
va_list args) G_GNUC_PRINTF (4, 0);
|
||||
void pika_message_literal (Pika *pika,
|
||||
GObject *handler,
|
||||
PikaMessageSeverity severity,
|
||||
const gchar *message);
|
||||
|
||||
void pika_filter_history_changed (Pika *pika);
|
||||
|
||||
void pika_image_opened (Pika *pika,
|
||||
GFile *file);
|
||||
|
||||
GFile * pika_get_temp_file (Pika *pika,
|
||||
const gchar *extension);
|
||||
|
||||
|
||||
#endif /* __PIKA_H__ */
|
||||
754
app/core/pikaasync.c
Normal file
754
app/core/pikaasync.c
Normal file
@ -0,0 +1,754 @@
|
||||
/* 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
|
||||
*
|
||||
* pikaasync.c
|
||||
* Copyright (C) 2018 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikaasync.h"
|
||||
#include "pikacancelable.h"
|
||||
#include "pikawaitable.h"
|
||||
|
||||
|
||||
/* PikaAsync represents an asynchronous task. Both the public and the
|
||||
* protected interfaces are intentionally minimal at this point, to keep things
|
||||
* simple. They may be extended in the future as needed.
|
||||
*
|
||||
* PikaAsync implements the PikaWaitable and PikaCancelable interfaces.
|
||||
*
|
||||
* Upon creation, a PikaAsync object is in the "running" state. Once the task
|
||||
* is complete (and before the object's destruction), it should be transitioned
|
||||
* to the "stopped" state, using either 'pika_async_finish()' or
|
||||
* 'pika_async_abort()'.
|
||||
*
|
||||
* Similarly, upon creation, a PikaAsync object is said to be "unsynced". It
|
||||
* becomes synced once the execution of any of the completion callbacks added
|
||||
* through 'pika_async_add_callback()' had started, or after a successful call
|
||||
* to one of the 'pika_waitable_wait()' family of functions.
|
||||
*
|
||||
* Note that certain PikaAsync functions may only be called during a certain
|
||||
* state, on a certain thread, or depending on whether or not the object is
|
||||
* synced, as detailed for each function. When referring to threads, the "main
|
||||
* thread" is the thread running the main loop, or any thread whose execution
|
||||
* is synchronized with the main thread, and the "async thread" is the thread
|
||||
* calling 'pika_async_finish()' or 'pika_async_abort()' (which may also be the
|
||||
* main thread), or any thread whose execution is synchronized with the async
|
||||
* thread.
|
||||
*/
|
||||
|
||||
|
||||
/* #define TIME_ASYNC_OPS */
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
WAITING,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaAsyncCallbackInfo PikaAsyncCallbackInfo;
|
||||
|
||||
|
||||
struct _PikaAsyncCallbackInfo
|
||||
{
|
||||
PikaAsync *async;
|
||||
PikaAsyncCallback callback;
|
||||
gpointer data;
|
||||
gpointer gobject;
|
||||
};
|
||||
|
||||
struct _PikaAsyncPrivate
|
||||
{
|
||||
GMutex mutex;
|
||||
GCond cond;
|
||||
|
||||
GQueue callbacks;
|
||||
|
||||
gpointer result;
|
||||
GDestroyNotify result_destroy_func;
|
||||
|
||||
guint idle_id;
|
||||
|
||||
gboolean stopped;
|
||||
gboolean finished;
|
||||
gboolean synced;
|
||||
gboolean canceled;
|
||||
|
||||
#ifdef TIME_ASYNC_OPS
|
||||
guint64 start_time;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_async_waitable_iface_init (PikaWaitableInterface *iface);
|
||||
|
||||
static void pika_async_cancelable_iface_init (PikaCancelableInterface *iface);
|
||||
|
||||
static void pika_async_finalize (GObject *object);
|
||||
|
||||
static void pika_async_wait (PikaWaitable *waitable);
|
||||
static gboolean pika_async_try_wait (PikaWaitable *waitable);
|
||||
static gboolean pika_async_wait_until (PikaWaitable *waitable,
|
||||
gint64 end_time);
|
||||
|
||||
static void pika_async_cancel (PikaCancelable *cancelable);
|
||||
|
||||
static gboolean pika_async_idle (PikaAsync *async);
|
||||
|
||||
static void pika_async_callback_weak_notify (PikaAsyncCallbackInfo *callback_info,
|
||||
GObject *gobject);
|
||||
|
||||
static void pika_async_stop (PikaAsync *async);
|
||||
static void pika_async_run_callbacks (PikaAsync *async);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (PikaAsync, pika_async, G_TYPE_OBJECT,
|
||||
G_ADD_PRIVATE (PikaAsync)
|
||||
G_IMPLEMENT_INTERFACE (PIKA_TYPE_WAITABLE,
|
||||
pika_async_waitable_iface_init)
|
||||
G_IMPLEMENT_INTERFACE (PIKA_TYPE_CANCELABLE,
|
||||
pika_async_cancelable_iface_init))
|
||||
|
||||
#define parent_class pika_async_parent_class
|
||||
|
||||
static guint async_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
||||
/* local variables */
|
||||
|
||||
static volatile gint pika_async_n_running = 0;
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
|
||||
static void
|
||||
pika_async_class_init (PikaAsyncClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
async_signals[WAITING] =
|
||||
g_signal_new ("waiting",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (PikaAsyncClass, waiting),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
object_class->finalize = pika_async_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_async_waitable_iface_init (PikaWaitableInterface *iface)
|
||||
{
|
||||
iface->wait = pika_async_wait;
|
||||
iface->try_wait = pika_async_try_wait;
|
||||
iface->wait_until = pika_async_wait_until;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_async_cancelable_iface_init (PikaCancelableInterface *iface)
|
||||
{
|
||||
iface->cancel = pika_async_cancel;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_async_init (PikaAsync *async)
|
||||
{
|
||||
async->priv = pika_async_get_instance_private (async);
|
||||
|
||||
g_mutex_init (&async->priv->mutex);
|
||||
g_cond_init (&async->priv->cond);
|
||||
|
||||
g_queue_init (&async->priv->callbacks);
|
||||
|
||||
g_atomic_int_inc (&pika_async_n_running);
|
||||
|
||||
#ifdef TIME_ASYNC_OPS
|
||||
async->priv->start_time = g_get_monotonic_time ();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
pika_async_finalize (GObject *object)
|
||||
{
|
||||
PikaAsync *async = PIKA_ASYNC (object);
|
||||
|
||||
g_warn_if_fail (async->priv->stopped);
|
||||
g_warn_if_fail (async->priv->idle_id == 0);
|
||||
g_warn_if_fail (g_queue_is_empty (&async->priv->callbacks));
|
||||
|
||||
if (async->priv->finished &&
|
||||
async->priv->result &&
|
||||
async->priv->result_destroy_func)
|
||||
{
|
||||
async->priv->result_destroy_func (async->priv->result);
|
||||
|
||||
async->priv->result = NULL;
|
||||
}
|
||||
|
||||
g_cond_clear (&async->priv->cond);
|
||||
g_mutex_clear (&async->priv->mutex);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
/* waits for 'waitable' to transition to the "stopped" state. if 'waitable' is
|
||||
* already stopped, returns immediately.
|
||||
*
|
||||
* after the call, all callbacks previously added through
|
||||
* 'pika_async_add_callback()' are guaranteed to have been called.
|
||||
*
|
||||
* may only be called on the main thread.
|
||||
*/
|
||||
static void
|
||||
pika_async_wait (PikaWaitable *waitable)
|
||||
{
|
||||
PikaAsync *async = PIKA_ASYNC (waitable);
|
||||
|
||||
g_mutex_lock (&async->priv->mutex);
|
||||
|
||||
if (! async->priv->stopped)
|
||||
{
|
||||
g_signal_emit (async, async_signals[WAITING], 0);
|
||||
|
||||
while (! async->priv->stopped)
|
||||
g_cond_wait (&async->priv->cond, &async->priv->mutex);
|
||||
}
|
||||
|
||||
g_mutex_unlock (&async->priv->mutex);
|
||||
|
||||
pika_async_run_callbacks (async);
|
||||
}
|
||||
|
||||
/* same as 'pika_async_wait()', but returns immediately if 'waitable' is not in
|
||||
* the "stopped" state.
|
||||
*
|
||||
* returns TRUE if 'waitable' has transitioned to the "stopped" state, or FALSE
|
||||
* otherwise.
|
||||
*/
|
||||
static gboolean
|
||||
pika_async_try_wait (PikaWaitable *waitable)
|
||||
{
|
||||
PikaAsync *async = PIKA_ASYNC (waitable);
|
||||
|
||||
g_mutex_lock (&async->priv->mutex);
|
||||
|
||||
if (! async->priv->stopped)
|
||||
{
|
||||
g_mutex_unlock (&async->priv->mutex);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_mutex_unlock (&async->priv->mutex);
|
||||
|
||||
pika_async_run_callbacks (async);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* same as 'pika_async_wait()', taking an additional 'end_time' parameter,
|
||||
* specifying the maximal monotonic time until which to wait for 'waitable' to
|
||||
* stop.
|
||||
*
|
||||
* returns TRUE if 'waitable' has transitioned to the "stopped" state, or FALSE
|
||||
* if the wait was interrupted before the transition.
|
||||
*/
|
||||
static gboolean
|
||||
pika_async_wait_until (PikaWaitable *waitable,
|
||||
gint64 end_time)
|
||||
{
|
||||
PikaAsync *async = PIKA_ASYNC (waitable);
|
||||
|
||||
g_mutex_lock (&async->priv->mutex);
|
||||
|
||||
if (! async->priv->stopped)
|
||||
{
|
||||
g_signal_emit (async, async_signals[WAITING], 0);
|
||||
|
||||
while (! async->priv->stopped)
|
||||
{
|
||||
if (! g_cond_wait_until (&async->priv->cond, &async->priv->mutex,
|
||||
end_time))
|
||||
{
|
||||
g_mutex_unlock (&async->priv->mutex);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_mutex_unlock (&async->priv->mutex);
|
||||
|
||||
pika_async_run_callbacks (async);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* requests the cancellation of the task managed by 'cancelable'.
|
||||
*
|
||||
* note that 'pika_async_cancel()' doesn't directly cause 'cancelable' to be
|
||||
* stopped, nor synced. furthermore, 'cancelable' may still complete
|
||||
* successfully even when cancellation has been requested.
|
||||
*
|
||||
* may only be called on the main thread.
|
||||
*/
|
||||
static void
|
||||
pika_async_cancel (PikaCancelable *cancelable)
|
||||
{
|
||||
PikaAsync *async = PIKA_ASYNC (cancelable);
|
||||
|
||||
async->priv->canceled = TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_async_idle (PikaAsync *async)
|
||||
{
|
||||
pika_waitable_wait (PIKA_WAITABLE (async));
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_async_callback_weak_notify (PikaAsyncCallbackInfo *callback_info,
|
||||
GObject *gobject)
|
||||
{
|
||||
PikaAsync *async = callback_info->async;
|
||||
gboolean unref_async = FALSE;
|
||||
|
||||
g_mutex_lock (&async->priv->mutex);
|
||||
|
||||
g_queue_remove (&async->priv->callbacks, callback_info);
|
||||
|
||||
g_slice_free (PikaAsyncCallbackInfo, callback_info);
|
||||
|
||||
if (g_queue_is_empty (&async->priv->callbacks) && async->priv->idle_id)
|
||||
{
|
||||
g_source_remove (async->priv->idle_id);
|
||||
async->priv->idle_id = 0;
|
||||
|
||||
unref_async = TRUE;
|
||||
}
|
||||
|
||||
g_mutex_unlock (&async->priv->mutex);
|
||||
|
||||
if (unref_async)
|
||||
g_object_unref (async);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_async_stop (PikaAsync *async)
|
||||
{
|
||||
#ifdef TIME_ASYNC_OPS
|
||||
{
|
||||
guint64 time = g_get_monotonic_time ();
|
||||
|
||||
g_printerr ("Asynchronous operation took %g seconds%s\n",
|
||||
(time - async->priv->start_time) / 1000000.0,
|
||||
async->priv->finished ? "" : " (aborted)");
|
||||
}
|
||||
#endif
|
||||
|
||||
g_atomic_int_dec_and_test (&pika_async_n_running);
|
||||
|
||||
if (! g_queue_is_empty (&async->priv->callbacks))
|
||||
{
|
||||
g_object_ref (async);
|
||||
|
||||
async->priv->idle_id = g_idle_add_full (G_PRIORITY_DEFAULT,
|
||||
(GSourceFunc) pika_async_idle,
|
||||
async, NULL);
|
||||
}
|
||||
|
||||
async->priv->stopped = TRUE;
|
||||
|
||||
g_cond_broadcast (&async->priv->cond);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_async_run_callbacks (PikaAsync *async)
|
||||
{
|
||||
PikaAsyncCallbackInfo *callback_info;
|
||||
gboolean unref_async = FALSE;
|
||||
|
||||
if (async->priv->idle_id)
|
||||
{
|
||||
g_source_remove (async->priv->idle_id);
|
||||
async->priv->idle_id = 0;
|
||||
|
||||
unref_async = TRUE;
|
||||
}
|
||||
|
||||
async->priv->synced = TRUE;
|
||||
|
||||
while ((callback_info = g_queue_pop_head (&async->priv->callbacks)))
|
||||
{
|
||||
if (callback_info->gobject)
|
||||
{
|
||||
g_object_ref (callback_info->gobject);
|
||||
|
||||
g_object_weak_unref (callback_info->gobject,
|
||||
(GWeakNotify) pika_async_callback_weak_notify,
|
||||
callback_info);
|
||||
}
|
||||
|
||||
callback_info->callback (async, callback_info->data);
|
||||
|
||||
if (callback_info->gobject)
|
||||
g_object_unref (callback_info->gobject);
|
||||
|
||||
g_slice_free (PikaAsyncCallbackInfo, callback_info);
|
||||
}
|
||||
|
||||
if (unref_async)
|
||||
g_object_unref (async);
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
|
||||
/* creates a new PikaAsync object, initially unsynced and placed in the
|
||||
* "running" state.
|
||||
*/
|
||||
PikaAsync *
|
||||
pika_async_new (void)
|
||||
{
|
||||
return g_object_new (PIKA_TYPE_ASYNC,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* checks if 'async' is synced.
|
||||
*
|
||||
* may only be called on the main thread.
|
||||
*/
|
||||
gboolean
|
||||
pika_async_is_synced (PikaAsync *async)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_ASYNC (async), FALSE);
|
||||
|
||||
return async->priv->synced;
|
||||
}
|
||||
|
||||
/* registers a callback to be called when 'async' transitions to the "stopped"
|
||||
* state. if 'async' is already stopped, the callback may be called directly.
|
||||
*
|
||||
* callbacks are called in the order in which they were added. 'async' is
|
||||
* guaranteed to be kept alive, even without an external reference, between the
|
||||
* point where it was stopped, and until all callbacks added while 'async' was
|
||||
* externally referenced have been called.
|
||||
*
|
||||
* the callback is guaranteed to be called on the main thread.
|
||||
*
|
||||
* may only be called on the main thread.
|
||||
*/
|
||||
void
|
||||
pika_async_add_callback (PikaAsync *async,
|
||||
PikaAsyncCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
PikaAsyncCallbackInfo *callback_info;
|
||||
|
||||
g_return_if_fail (PIKA_IS_ASYNC (async));
|
||||
g_return_if_fail (callback != NULL);
|
||||
|
||||
g_mutex_lock (&async->priv->mutex);
|
||||
|
||||
if (async->priv->stopped && g_queue_is_empty (&async->priv->callbacks))
|
||||
{
|
||||
async->priv->synced = TRUE;
|
||||
|
||||
g_mutex_unlock (&async->priv->mutex);
|
||||
|
||||
callback (async, data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
callback_info = g_slice_new0 (PikaAsyncCallbackInfo);
|
||||
callback_info->async = async;
|
||||
callback_info->callback = callback;
|
||||
callback_info->data = data;
|
||||
|
||||
g_queue_push_tail (&async->priv->callbacks, callback_info);
|
||||
|
||||
g_mutex_unlock (&async->priv->mutex);
|
||||
}
|
||||
|
||||
/* same as 'pika_async_add_callback()', however, takes an additional 'gobject'
|
||||
* argument, which should be a GObject.
|
||||
*
|
||||
* 'gobject' is guaranteed to remain alive for the duration of the callback.
|
||||
*
|
||||
* When 'gobject' is destroyed, the callback is automatically removed.
|
||||
*/
|
||||
void
|
||||
pika_async_add_callback_for_object (PikaAsync *async,
|
||||
PikaAsyncCallback callback,
|
||||
gpointer data,
|
||||
gpointer gobject)
|
||||
{
|
||||
PikaAsyncCallbackInfo *callback_info;
|
||||
|
||||
g_return_if_fail (PIKA_IS_ASYNC (async));
|
||||
g_return_if_fail (callback != NULL);
|
||||
g_return_if_fail (G_IS_OBJECT (gobject));
|
||||
|
||||
g_mutex_lock (&async->priv->mutex);
|
||||
|
||||
if (async->priv->stopped && g_queue_is_empty (&async->priv->callbacks))
|
||||
{
|
||||
async->priv->synced = TRUE;
|
||||
|
||||
g_mutex_unlock (&async->priv->mutex);
|
||||
|
||||
g_object_ref (gobject);
|
||||
|
||||
callback (async, data);
|
||||
|
||||
g_object_unref (gobject);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
callback_info = g_slice_new0 (PikaAsyncCallbackInfo);
|
||||
callback_info->async = async;
|
||||
callback_info->callback = callback;
|
||||
callback_info->data = data;
|
||||
callback_info->gobject = gobject;
|
||||
|
||||
g_queue_push_tail (&async->priv->callbacks, callback_info);
|
||||
|
||||
g_object_weak_ref (gobject,
|
||||
(GWeakNotify) pika_async_callback_weak_notify,
|
||||
callback_info);
|
||||
|
||||
g_mutex_unlock (&async->priv->mutex);
|
||||
}
|
||||
|
||||
/* removes all callbacks previously registered through
|
||||
* 'pika_async_add_callback()', matching 'callback' and 'data', which hasn't
|
||||
* been called yet.
|
||||
*
|
||||
* may only be called on the main thread.
|
||||
*/
|
||||
void
|
||||
pika_async_remove_callback (PikaAsync *async,
|
||||
PikaAsyncCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
GList *iter;
|
||||
gboolean unref_async = FALSE;
|
||||
|
||||
g_return_if_fail (PIKA_IS_ASYNC (async));
|
||||
g_return_if_fail (callback != NULL);
|
||||
|
||||
g_mutex_lock (&async->priv->mutex);
|
||||
|
||||
iter = g_queue_peek_head_link (&async->priv->callbacks);
|
||||
|
||||
while (iter)
|
||||
{
|
||||
PikaAsyncCallbackInfo *callback_info = iter->data;
|
||||
GList *next = g_list_next (iter);
|
||||
|
||||
if (callback_info->callback == callback &&
|
||||
callback_info->data == data)
|
||||
{
|
||||
if (callback_info->gobject)
|
||||
{
|
||||
g_object_weak_unref (
|
||||
callback_info->gobject,
|
||||
(GWeakNotify) pika_async_callback_weak_notify,
|
||||
callback_info);
|
||||
}
|
||||
|
||||
g_queue_delete_link (&async->priv->callbacks, iter);
|
||||
|
||||
g_slice_free (PikaAsyncCallbackInfo, callback_info);
|
||||
}
|
||||
|
||||
iter = next;
|
||||
}
|
||||
|
||||
if (g_queue_is_empty (&async->priv->callbacks) && async->priv->idle_id)
|
||||
{
|
||||
g_source_remove (async->priv->idle_id);
|
||||
async->priv->idle_id = 0;
|
||||
|
||||
unref_async = TRUE;
|
||||
}
|
||||
|
||||
g_mutex_unlock (&async->priv->mutex);
|
||||
|
||||
if (unref_async)
|
||||
g_object_unref (async);
|
||||
}
|
||||
|
||||
/* checks if 'async' is in the "stopped" state.
|
||||
*
|
||||
* may only be called on the async thread.
|
||||
*/
|
||||
gboolean
|
||||
pika_async_is_stopped (PikaAsync *async)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_ASYNC (async), FALSE);
|
||||
|
||||
return async->priv->stopped;
|
||||
}
|
||||
|
||||
/* transitions 'async' to the "stopped" state, indicating that the task
|
||||
* completed normally, possibly providing a result.
|
||||
*
|
||||
* 'async' shall be in the "running" state.
|
||||
*
|
||||
* may only be called on the async thread.
|
||||
*/
|
||||
void
|
||||
pika_async_finish (PikaAsync *async,
|
||||
gpointer result)
|
||||
{
|
||||
pika_async_finish_full (async, result, NULL);
|
||||
}
|
||||
|
||||
/* same as 'pika_async_finish()', taking an additional GDestroyNotify function,
|
||||
* used for freeing the result when 'async' is destroyed.
|
||||
*/
|
||||
void
|
||||
pika_async_finish_full (PikaAsync *async,
|
||||
gpointer result,
|
||||
GDestroyNotify result_destroy_func)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_ASYNC (async));
|
||||
g_return_if_fail (! async->priv->stopped);
|
||||
|
||||
g_mutex_lock (&async->priv->mutex);
|
||||
|
||||
async->priv->finished = TRUE;
|
||||
async->priv->result = result;
|
||||
async->priv->result_destroy_func = result_destroy_func;
|
||||
|
||||
pika_async_stop (async);
|
||||
|
||||
g_mutex_unlock (&async->priv->mutex);
|
||||
}
|
||||
|
||||
/* checks if 'async' completed normally, using 'pika_async_finish()' (in
|
||||
* contrast to 'pika_async_abort()').
|
||||
*
|
||||
* 'async' shall be in the "stopped" state.
|
||||
*
|
||||
* may only be called on the async thread, or on the main thread when 'async'
|
||||
* is synced.
|
||||
*/
|
||||
gboolean
|
||||
pika_async_is_finished (PikaAsync *async)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_ASYNC (async), FALSE);
|
||||
g_return_val_if_fail (async->priv->stopped, FALSE);
|
||||
|
||||
return async->priv->finished;
|
||||
}
|
||||
|
||||
/* returns the result of 'async', as passed to 'pika_async_finish()'.
|
||||
*
|
||||
* 'async' shall be in the "stopped" state, and should have completed normally.
|
||||
*
|
||||
* may only be called on the async thread, or on the main thread when 'async'
|
||||
* is synced.
|
||||
*/
|
||||
gpointer
|
||||
pika_async_get_result (PikaAsync *async)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_ASYNC (async), NULL);
|
||||
g_return_val_if_fail (async->priv->stopped, NULL);
|
||||
g_return_val_if_fail (async->priv->finished, NULL);
|
||||
|
||||
return async->priv->result;
|
||||
}
|
||||
|
||||
/* transitions 'async' to the "stopped" state, indicating that the task
|
||||
* was stopped before completion (normally, in response to a
|
||||
* 'pika_cancelable_cancel()' call).
|
||||
*
|
||||
* 'async' shall be in the "running" state.
|
||||
*
|
||||
* may only be called on the async thread.
|
||||
*/
|
||||
void
|
||||
pika_async_abort (PikaAsync *async)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_ASYNC (async));
|
||||
g_return_if_fail (! async->priv->stopped);
|
||||
|
||||
g_mutex_lock (&async->priv->mutex);
|
||||
|
||||
pika_async_stop (async);
|
||||
|
||||
g_mutex_unlock (&async->priv->mutex);
|
||||
}
|
||||
|
||||
/* checks if cancellation of 'async' has been requested.
|
||||
*
|
||||
* note that a return value of TRUE only indicates that
|
||||
* 'pika_cancelable_cancel()' has been called for 'async', and not that 'async'
|
||||
* is stopped, or, if it is stopped, that it was aborted.
|
||||
*/
|
||||
gboolean
|
||||
pika_async_is_canceled (PikaAsync *async)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_ASYNC (async), FALSE);
|
||||
|
||||
return async->priv->canceled;
|
||||
}
|
||||
|
||||
/* a convenience function, canceling 'async' and waiting for it to stop.
|
||||
*
|
||||
* may only be called on the main thread.
|
||||
*/
|
||||
void
|
||||
pika_async_cancel_and_wait (PikaAsync *async)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_ASYNC (async));
|
||||
|
||||
pika_cancelable_cancel (PIKA_CANCELABLE (async));
|
||||
pika_waitable_wait (PIKA_WAITABLE (async));
|
||||
}
|
||||
|
||||
|
||||
/* public functions (stats) */
|
||||
|
||||
|
||||
gint
|
||||
pika_async_get_n_running (void)
|
||||
{
|
||||
return pika_async_n_running;
|
||||
}
|
||||
99
app/core/pikaasync.h
Normal file
99
app/core/pikaasync.h
Normal file
@ -0,0 +1,99 @@
|
||||
/* 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
|
||||
*
|
||||
* pikaasync.h
|
||||
* Copyright (C) 2018 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_ASYNC_H__
|
||||
#define __PIKA_ASYNC_H__
|
||||
|
||||
|
||||
#define PIKA_TYPE_ASYNC (pika_async_get_type ())
|
||||
#define PIKA_ASYNC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_ASYNC, PikaAsync))
|
||||
#define PIKA_ASYNC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_ASYNC, PikaAsyncClass))
|
||||
#define PIKA_IS_ASYNC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_ASYNC))
|
||||
#define PIKA_IS_ASYNC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_ASYNC))
|
||||
#define PIKA_ASYNC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_ASYNC, PikaAsyncClass))
|
||||
|
||||
|
||||
typedef void (* PikaAsyncCallback) (PikaAsync *async,
|
||||
gpointer data);
|
||||
|
||||
|
||||
typedef struct _PikaAsyncPrivate PikaAsyncPrivate;
|
||||
typedef struct _PikaAsyncClass PikaAsyncClass;
|
||||
|
||||
struct _PikaAsync
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
PikaAsyncPrivate *priv;
|
||||
};
|
||||
|
||||
struct _PikaAsyncClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (* waiting) (PikaAsync *async);
|
||||
};
|
||||
|
||||
|
||||
GType pika_async_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaAsync * pika_async_new (void);
|
||||
|
||||
gboolean pika_async_is_synced (PikaAsync *async);
|
||||
|
||||
void pika_async_add_callback (PikaAsync *async,
|
||||
PikaAsyncCallback callback,
|
||||
gpointer data);
|
||||
void pika_async_add_callback_for_object (PikaAsync *async,
|
||||
PikaAsyncCallback callback,
|
||||
gpointer data,
|
||||
gpointer gobject);
|
||||
void pika_async_remove_callback (PikaAsync *async,
|
||||
PikaAsyncCallback callback,
|
||||
gpointer data);
|
||||
|
||||
gboolean pika_async_is_stopped (PikaAsync *async);
|
||||
|
||||
void pika_async_finish (PikaAsync *async,
|
||||
gpointer result);
|
||||
void pika_async_finish_full (PikaAsync *async,
|
||||
gpointer result,
|
||||
GDestroyNotify result_destroy_func);
|
||||
gboolean pika_async_is_finished (PikaAsync *async);
|
||||
gpointer pika_async_get_result (PikaAsync *async);
|
||||
|
||||
void pika_async_abort (PikaAsync *async);
|
||||
|
||||
gboolean pika_async_is_canceled (PikaAsync *async);
|
||||
|
||||
void pika_async_cancel_and_wait (PikaAsync *async);
|
||||
|
||||
|
||||
/* stats */
|
||||
|
||||
gint pika_async_get_n_running (void);
|
||||
|
||||
|
||||
#endif /* __PIKA_ASYNC_H__ */
|
||||
354
app/core/pikaasyncset.c
Normal file
354
app/core/pikaasyncset.c
Normal file
@ -0,0 +1,354 @@
|
||||
/* 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
|
||||
*
|
||||
* pikaasyncset.c
|
||||
* Copyright (C) 2018 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikaasync.h"
|
||||
#include "pikaasyncset.h"
|
||||
#include "pikacancelable.h"
|
||||
#include "pikawaitable.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_EMPTY
|
||||
};
|
||||
|
||||
|
||||
struct _PikaAsyncSetPrivate
|
||||
{
|
||||
GHashTable *asyncs;
|
||||
};
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_async_set_waitable_iface_init (PikaWaitableInterface *iface);
|
||||
|
||||
static void pika_async_set_cancelable_iface_init (PikaCancelableInterface *iface);
|
||||
|
||||
static void pika_async_set_dispose (GObject *object);
|
||||
static void pika_async_set_finalize (GObject *object);
|
||||
static void pika_async_set_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_async_set_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void pika_async_set_wait (PikaWaitable *waitable);
|
||||
static gboolean pika_async_set_try_wait (PikaWaitable *waitable);
|
||||
static gboolean pika_async_set_wait_until (PikaWaitable *waitable,
|
||||
gint64 end_time);
|
||||
|
||||
static void pika_async_set_cancel (PikaCancelable *cancelable);
|
||||
|
||||
static void pika_async_set_async_callback (PikaAsync *async,
|
||||
PikaAsyncSet *async_set);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (PikaAsyncSet, pika_async_set, G_TYPE_OBJECT,
|
||||
G_ADD_PRIVATE (PikaAsyncSet)
|
||||
G_IMPLEMENT_INTERFACE (PIKA_TYPE_WAITABLE,
|
||||
pika_async_set_waitable_iface_init)
|
||||
G_IMPLEMENT_INTERFACE (PIKA_TYPE_CANCELABLE,
|
||||
pika_async_set_cancelable_iface_init))
|
||||
|
||||
#define parent_class pika_async_set_parent_class
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
|
||||
static void
|
||||
pika_async_set_class_init (PikaAsyncSetClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = pika_async_set_dispose;
|
||||
object_class->finalize = pika_async_set_finalize;
|
||||
object_class->set_property = pika_async_set_set_property;
|
||||
object_class->get_property = pika_async_set_get_property;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_EMPTY,
|
||||
g_param_spec_boolean ("empty",
|
||||
NULL, NULL,
|
||||
FALSE,
|
||||
PIKA_PARAM_READABLE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_async_set_waitable_iface_init (PikaWaitableInterface *iface)
|
||||
{
|
||||
iface->wait = pika_async_set_wait;
|
||||
iface->try_wait = pika_async_set_try_wait;
|
||||
iface->wait_until = pika_async_set_wait_until;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_async_set_cancelable_iface_init (PikaCancelableInterface *iface)
|
||||
{
|
||||
iface->cancel = pika_async_set_cancel;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_async_set_init (PikaAsyncSet *async_set)
|
||||
{
|
||||
async_set->priv = pika_async_set_get_instance_private (async_set);
|
||||
|
||||
async_set->priv->asyncs = g_hash_table_new (NULL, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_async_set_dispose (GObject *object)
|
||||
{
|
||||
PikaAsyncSet *async_set = PIKA_ASYNC_SET (object);
|
||||
|
||||
pika_async_set_clear (async_set);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_async_set_finalize (GObject *object)
|
||||
{
|
||||
PikaAsyncSet *async_set = PIKA_ASYNC_SET (object);
|
||||
|
||||
g_hash_table_unref (async_set->priv->asyncs);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_async_set_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
switch (property_id)
|
||||
{
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_async_set_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaAsyncSet *async_set = PIKA_ASYNC_SET (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_EMPTY:
|
||||
g_value_set_boolean (value, pika_async_set_is_empty (async_set));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_async_set_wait (PikaWaitable *waitable)
|
||||
{
|
||||
PikaAsyncSet *async_set = PIKA_ASYNC_SET (waitable);
|
||||
|
||||
while (! pika_async_set_is_empty (async_set))
|
||||
{
|
||||
PikaAsync *async;
|
||||
GHashTableIter iter;
|
||||
|
||||
g_hash_table_iter_init (&iter, async_set->priv->asyncs);
|
||||
|
||||
g_hash_table_iter_next (&iter, (gpointer *) &async, NULL);
|
||||
|
||||
pika_waitable_wait (PIKA_WAITABLE (async));
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_async_set_try_wait (PikaWaitable *waitable)
|
||||
{
|
||||
PikaAsyncSet *async_set = PIKA_ASYNC_SET (waitable);
|
||||
|
||||
while (! pika_async_set_is_empty (async_set))
|
||||
{
|
||||
PikaAsync *async;
|
||||
GHashTableIter iter;
|
||||
|
||||
g_hash_table_iter_init (&iter, async_set->priv->asyncs);
|
||||
|
||||
g_hash_table_iter_next (&iter, (gpointer *) &async, NULL);
|
||||
|
||||
if (! pika_waitable_try_wait (PIKA_WAITABLE (async)))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_async_set_wait_until (PikaWaitable *waitable,
|
||||
gint64 end_time)
|
||||
{
|
||||
PikaAsyncSet *async_set = PIKA_ASYNC_SET (waitable);
|
||||
|
||||
while (! pika_async_set_is_empty (async_set))
|
||||
{
|
||||
PikaAsync *async;
|
||||
GHashTableIter iter;
|
||||
|
||||
g_hash_table_iter_init (&iter, async_set->priv->asyncs);
|
||||
|
||||
g_hash_table_iter_next (&iter, (gpointer *) &async, NULL);
|
||||
|
||||
if (! pika_waitable_wait_until (PIKA_WAITABLE (async), end_time))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_async_set_cancel (PikaCancelable *cancelable)
|
||||
{
|
||||
PikaAsyncSet *async_set = PIKA_ASYNC_SET (cancelable);
|
||||
GList *list;
|
||||
|
||||
list = g_hash_table_get_keys (async_set->priv->asyncs);
|
||||
|
||||
g_list_foreach (list, (GFunc) g_object_ref, NULL);
|
||||
|
||||
g_list_foreach (list, (GFunc) pika_cancelable_cancel, NULL);
|
||||
|
||||
g_list_free_full (list, g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_async_set_async_callback (PikaAsync *async,
|
||||
PikaAsyncSet *async_set)
|
||||
{
|
||||
g_hash_table_remove (async_set->priv->asyncs, async);
|
||||
|
||||
if (pika_async_set_is_empty (async_set))
|
||||
g_object_notify (G_OBJECT (async_set), "empty");
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
|
||||
PikaAsyncSet *
|
||||
pika_async_set_new (void)
|
||||
{
|
||||
return g_object_new (PIKA_TYPE_ASYNC_SET,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void
|
||||
pika_async_set_add (PikaAsyncSet *async_set,
|
||||
PikaAsync *async)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_ASYNC_SET (async_set));
|
||||
g_return_if_fail (PIKA_IS_ASYNC (async));
|
||||
|
||||
if (g_hash_table_add (async_set->priv->asyncs, async))
|
||||
{
|
||||
if (g_hash_table_size (async_set->priv->asyncs) == 1)
|
||||
g_object_notify (G_OBJECT (async_set), "empty");
|
||||
|
||||
pika_async_add_callback (
|
||||
async,
|
||||
(PikaAsyncCallback) pika_async_set_async_callback,
|
||||
async_set);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_async_set_remove (PikaAsyncSet *async_set,
|
||||
PikaAsync *async)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_ASYNC_SET (async_set));
|
||||
g_return_if_fail (PIKA_IS_ASYNC (async));
|
||||
|
||||
if (g_hash_table_remove (async_set->priv->asyncs, async))
|
||||
{
|
||||
pika_async_remove_callback (
|
||||
async,
|
||||
(PikaAsyncCallback) pika_async_set_async_callback,
|
||||
async_set);
|
||||
|
||||
if (g_hash_table_size (async_set->priv->asyncs) == 0)
|
||||
g_object_notify (G_OBJECT (async_set), "empty");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pika_async_set_clear (PikaAsyncSet *async_set)
|
||||
{
|
||||
PikaAsync *async;
|
||||
GHashTableIter iter;
|
||||
|
||||
g_return_if_fail (PIKA_IS_ASYNC_SET (async_set));
|
||||
|
||||
if (pika_async_set_is_empty (async_set))
|
||||
return;
|
||||
|
||||
g_hash_table_iter_init (&iter, async_set->priv->asyncs);
|
||||
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &async, NULL))
|
||||
{
|
||||
pika_async_remove_callback (
|
||||
async,
|
||||
(PikaAsyncCallback) pika_async_set_async_callback,
|
||||
async_set);
|
||||
}
|
||||
|
||||
g_hash_table_remove_all (async_set->priv->asyncs);
|
||||
|
||||
g_object_notify (G_OBJECT (async_set), "empty");
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_async_set_is_empty (PikaAsyncSet *async_set)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_ASYNC_SET (async_set), FALSE);
|
||||
|
||||
return g_hash_table_size (async_set->priv->asyncs) == 0;
|
||||
}
|
||||
65
app/core/pikaasyncset.h
Normal file
65
app/core/pikaasyncset.h
Normal file
@ -0,0 +1,65 @@
|
||||
/* 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
|
||||
*
|
||||
* pikaasyncset.h
|
||||
* Copyright (C) 2018 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_ASYNC_SET_H__
|
||||
#define __PIKA_ASYNC_SET_H__
|
||||
|
||||
|
||||
#define PIKA_TYPE_ASYNC_SET (pika_async_set_get_type ())
|
||||
#define PIKA_ASYNC_SET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_ASYNC_SET, PikaAsyncSet))
|
||||
#define PIKA_ASYNC_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_ASYNC_SET, PikaAsyncSetClass))
|
||||
#define PIKA_IS_ASYNC_SET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_ASYNC_SET))
|
||||
#define PIKA_IS_ASYNC_SET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_ASYNC_SET))
|
||||
#define PIKA_ASYNC_SET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_ASYNC_SET, PikaAsyncSetClass))
|
||||
|
||||
|
||||
typedef struct _PikaAsyncSetPrivate PikaAsyncSetPrivate;
|
||||
typedef struct _PikaAsyncSetClass PikaAsyncSetClass;
|
||||
|
||||
struct _PikaAsyncSet
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
PikaAsyncSetPrivate *priv;
|
||||
};
|
||||
|
||||
struct _PikaAsyncSetClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_async_set_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaAsyncSet * pika_async_set_new (void);
|
||||
|
||||
void pika_async_set_add (PikaAsyncSet *async_set,
|
||||
PikaAsync *async);
|
||||
void pika_async_set_remove (PikaAsyncSet *async_set,
|
||||
PikaAsync *async);
|
||||
void pika_async_set_clear (PikaAsyncSet *async_set);
|
||||
gboolean pika_async_set_is_empty (PikaAsyncSet *async_set);
|
||||
|
||||
|
||||
#endif /* __PIKA_ASYNC_SET_H__ */
|
||||
152
app/core/pikaauxitem.c
Normal file
152
app/core/pikaauxitem.c
Normal file
@ -0,0 +1,152 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikaauxitem.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
REMOVED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_ID
|
||||
};
|
||||
|
||||
|
||||
struct _PikaAuxItemPrivate
|
||||
{
|
||||
guint32 aux_item_id;
|
||||
};
|
||||
|
||||
|
||||
static void pika_aux_item_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_aux_item_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (PikaAuxItem, pika_aux_item, G_TYPE_OBJECT)
|
||||
|
||||
static guint pika_aux_item_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
||||
static void
|
||||
pika_aux_item_class_init (PikaAuxItemClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
pika_aux_item_signals[REMOVED] =
|
||||
g_signal_new ("removed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (PikaAuxItemClass, removed),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
object_class->get_property = pika_aux_item_get_property;
|
||||
object_class->set_property = pika_aux_item_set_property;
|
||||
|
||||
klass->removed = NULL;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_ID,
|
||||
g_param_spec_uint ("id", NULL, NULL,
|
||||
0, G_MAXUINT32, 0,
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
PIKA_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_aux_item_init (PikaAuxItem *aux_item)
|
||||
{
|
||||
aux_item->priv = pika_aux_item_get_instance_private (aux_item);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_aux_item_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaAuxItem *aux_item = PIKA_AUX_ITEM (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_ID:
|
||||
g_value_set_uint (value, aux_item->priv->aux_item_id);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_aux_item_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaAuxItem *aux_item = PIKA_AUX_ITEM (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_ID:
|
||||
aux_item->priv->aux_item_id = g_value_get_uint (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
guint32
|
||||
pika_aux_item_get_id (PikaAuxItem *aux_item)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_AUX_ITEM (aux_item), 0);
|
||||
|
||||
return aux_item->priv->aux_item_id;
|
||||
}
|
||||
|
||||
void
|
||||
pika_aux_item_removed (PikaAuxItem *aux_item)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_AUX_ITEM (aux_item));
|
||||
|
||||
g_signal_emit (aux_item, pika_aux_item_signals[REMOVED], 0);
|
||||
}
|
||||
60
app/core/pikaauxitem.h
Normal file
60
app/core/pikaauxitem.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_AUX_ITEM_H__
|
||||
#define __PIKA_AUX_ITEM_H__
|
||||
|
||||
|
||||
#define PIKA_TYPE_AUX_ITEM (pika_aux_item_get_type ())
|
||||
#define PIKA_AUX_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_AUX_ITEM, PikaAuxItem))
|
||||
#define PIKA_AUX_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_AUX_ITEM, PikaAuxItemClass))
|
||||
#define PIKA_IS_AUX_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_AUX_ITEM))
|
||||
#define PIKA_IS_AUX_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_AUX_ITEM))
|
||||
#define PIKA_AUX_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_AUX_ITEM, PikaAuxItemClass))
|
||||
|
||||
|
||||
typedef struct _PikaAuxItemPrivate PikaAuxItemPrivate;
|
||||
typedef struct _PikaAuxItemClass PikaAuxItemClass;
|
||||
|
||||
struct _PikaAuxItem
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
PikaAuxItemPrivate *priv;
|
||||
};
|
||||
|
||||
struct _PikaAuxItemClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (* removed) (PikaAuxItem *aux_item);
|
||||
};
|
||||
|
||||
|
||||
GType pika_aux_item_get_type (void) G_GNUC_CONST;
|
||||
|
||||
guint32 pika_aux_item_get_id (PikaAuxItem *aux_item);
|
||||
|
||||
void pika_aux_item_removed (PikaAuxItem *aux_item);
|
||||
|
||||
|
||||
#endif /* __PIKA_AUX_ITEM_H__ */
|
||||
144
app/core/pikaauxitemundo.c
Normal file
144
app/core/pikaauxitemundo.c
Normal file
@ -0,0 +1,144 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikaauxitem.h"
|
||||
#include "pikaauxitemundo.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_AUX_ITEM
|
||||
};
|
||||
|
||||
|
||||
static void pika_aux_item_undo_constructed (GObject *object);
|
||||
static void pika_aux_item_undo_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_aux_item_undo_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void pika_aux_item_undo_free (PikaUndo *undo,
|
||||
PikaUndoMode undo_mode);
|
||||
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE (PikaAuxItemUndo, pika_aux_item_undo, PIKA_TYPE_UNDO)
|
||||
|
||||
#define parent_class pika_aux_item_undo_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_aux_item_undo_class_init (PikaAuxItemUndoClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaUndoClass *undo_class = PIKA_UNDO_CLASS (klass);
|
||||
|
||||
object_class->constructed = pika_aux_item_undo_constructed;
|
||||
object_class->set_property = pika_aux_item_undo_set_property;
|
||||
object_class->get_property = pika_aux_item_undo_get_property;
|
||||
|
||||
undo_class->free = pika_aux_item_undo_free;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_AUX_ITEM,
|
||||
g_param_spec_object ("aux-item", NULL, NULL,
|
||||
PIKA_TYPE_AUX_ITEM,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_aux_item_undo_init (PikaAuxItemUndo *undo)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_aux_item_undo_constructed (GObject *object)
|
||||
{
|
||||
PikaAuxItemUndo *aux_item_undo = PIKA_AUX_ITEM_UNDO (object);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->constructed (object);
|
||||
|
||||
pika_assert (PIKA_IS_AUX_ITEM (aux_item_undo->aux_item));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_aux_item_undo_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaAuxItemUndo *aux_item_undo = PIKA_AUX_ITEM_UNDO (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_AUX_ITEM:
|
||||
aux_item_undo->aux_item = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_aux_item_undo_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaAuxItemUndo *aux_item_undo = PIKA_AUX_ITEM_UNDO (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_AUX_ITEM:
|
||||
g_value_set_object (value, aux_item_undo->aux_item);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_aux_item_undo_free (PikaUndo *undo,
|
||||
PikaUndoMode undo_mode)
|
||||
{
|
||||
PikaAuxItemUndo *aux_item_undo = PIKA_AUX_ITEM_UNDO (undo);
|
||||
|
||||
g_clear_object (&aux_item_undo->aux_item);
|
||||
|
||||
PIKA_UNDO_CLASS (parent_class)->free (undo, undo_mode);
|
||||
}
|
||||
56
app/core/pikaauxitemundo.h
Normal file
56
app/core/pikaauxitemundo.h
Normal file
@ -0,0 +1,56 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_AUX_ITEM_UNDO_H__
|
||||
#define __PIKA_AUX_ITEM_UNDO_H__
|
||||
|
||||
|
||||
#include "pikaundo.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_AUX_ITEM_UNDO (pika_aux_item_undo_get_type ())
|
||||
#define PIKA_AUX_ITEM_UNDO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_AUX_ITEM_UNDO, PikaAuxItemUndo))
|
||||
#define PIKA_AUX_ITEM_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_AUX_ITEM_UNDO, PikaAuxItemUndoClass))
|
||||
#define PIKA_IS_AUX_ITEM_UNDO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_AUX_ITEM_UNDO))
|
||||
#define PIKA_IS_AUX_ITEM_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_AUX_ITEM_UNDO))
|
||||
#define PIKA_AUX_ITEM_UNDO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_AUX_ITEM_UNDO, PikaAuxItemUndoClass))
|
||||
|
||||
|
||||
typedef struct _PikaAuxItemUndo PikaAuxItemUndo;
|
||||
typedef struct _PikaAuxItemUndoClass PikaAuxItemUndoClass;
|
||||
|
||||
struct _PikaAuxItemUndo
|
||||
{
|
||||
PikaUndo parent_instance;
|
||||
|
||||
PikaAuxItem *aux_item;
|
||||
};
|
||||
|
||||
struct _PikaAuxItemUndoClass
|
||||
{
|
||||
PikaUndoClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_aux_item_undo_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __PIKA_AUX_ITEM_UNDO_H__ */
|
||||
38
app/core/pikabacktrace-backend.h
Normal file
38
app/core/pikabacktrace-backend.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* 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
|
||||
*
|
||||
* pikabacktrace-backend.h
|
||||
* Copyright (C) 2018 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BACKTRACE_BACKEND_H__
|
||||
#define __PIKA_BACKTRACE_BACKEND_H__
|
||||
|
||||
|
||||
#ifdef __gnu_linux__
|
||||
# define PIKA_BACKTRACE_BACKEND_LINUX
|
||||
#elif defined (G_OS_WIN32) && defined (ARCH_X86)
|
||||
# define PIKA_BACKTRACE_BACKEND_WINDOWS
|
||||
#else
|
||||
# define PIKA_BACKTRACE_BACKEND_NONE
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __PIKA_BACKTRACE_BACKEND_H__ */
|
||||
729
app/core/pikabacktrace-linux.c
Normal file
729
app/core/pikabacktrace-linux.c
Normal file
@ -0,0 +1,729 @@
|
||||
/* 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-1999 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikabacktrace-linux.c
|
||||
* Copyright (C) 2018 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "pikabacktrace-backend.h"
|
||||
|
||||
|
||||
#ifdef PIKA_BACKTRACE_BACKEND_LINUX
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <signal.h>
|
||||
#include <execinfo.h>
|
||||
#include <dlfcn.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_LIBBACKTRACE
|
||||
#include <backtrace.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBUNWIND
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include <libunwind.h>
|
||||
#endif
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikabacktrace.h"
|
||||
|
||||
|
||||
#define MAX_N_THREADS 256
|
||||
#define MAX_N_FRAMES 256
|
||||
#define MAX_THREAD_NAME_SIZE 32
|
||||
#define N_SKIPPED_FRAMES 2
|
||||
#define MAX_WAIT_TIME (G_TIME_SPAN_SECOND / 20)
|
||||
#define BACKTRACE_SIGNAL SIGUSR1
|
||||
|
||||
|
||||
typedef struct _PikaBacktraceThread PikaBacktraceThread;
|
||||
|
||||
|
||||
struct _PikaBacktraceThread
|
||||
{
|
||||
pid_t tid;
|
||||
gchar name[MAX_THREAD_NAME_SIZE];
|
||||
gchar state;
|
||||
|
||||
guintptr frames[MAX_N_FRAMES];
|
||||
gint n_frames;
|
||||
};
|
||||
|
||||
struct _PikaBacktrace
|
||||
{
|
||||
PikaBacktraceThread *threads;
|
||||
gint n_threads;
|
||||
};
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static inline gint pika_backtrace_normalize_frame (PikaBacktrace *backtrace,
|
||||
gint thread,
|
||||
gint frame);
|
||||
|
||||
static gint pika_backtrace_enumerate_threads (gboolean include_current_thread,
|
||||
pid_t *threads,
|
||||
gint size);
|
||||
static void pika_backtrace_read_thread_name (pid_t tid,
|
||||
gchar *name,
|
||||
gint size);
|
||||
static gchar pika_backtrace_read_thread_state (pid_t tid);
|
||||
|
||||
static void pika_backtrace_signal_handler (gint signum);
|
||||
|
||||
|
||||
/* static variables */
|
||||
|
||||
static GMutex mutex;
|
||||
static gint n_initializations;
|
||||
static gboolean initialized;
|
||||
static struct sigaction orig_action;
|
||||
static pid_t blacklisted_threads[MAX_N_THREADS];
|
||||
static gint n_blacklisted_threads;
|
||||
static PikaBacktrace *handler_backtrace;
|
||||
static gint handler_n_remaining_threads;
|
||||
static gint handler_lock;
|
||||
|
||||
#ifdef HAVE_LIBBACKTRACE
|
||||
static struct backtrace_state *backtrace_state;
|
||||
#endif
|
||||
|
||||
static const gchar * const blacklisted_thread_names[] =
|
||||
{
|
||||
"gmain",
|
||||
"threaded-ml"
|
||||
};
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
|
||||
static inline gint
|
||||
pika_backtrace_normalize_frame (PikaBacktrace *backtrace,
|
||||
gint thread,
|
||||
gint frame)
|
||||
{
|
||||
if (frame >= 0)
|
||||
return frame + N_SKIPPED_FRAMES;
|
||||
else
|
||||
return backtrace->threads[thread].n_frames + frame;
|
||||
}
|
||||
|
||||
static gint
|
||||
pika_backtrace_enumerate_threads (gboolean include_current_thread,
|
||||
pid_t *threads,
|
||||
gint size)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *dirent;
|
||||
pid_t tid;
|
||||
gint n_threads;
|
||||
|
||||
dir = opendir ("/proc/self/task");
|
||||
|
||||
if (! dir)
|
||||
return 0;
|
||||
|
||||
tid = syscall (SYS_gettid);
|
||||
|
||||
n_threads = 0;
|
||||
|
||||
while (n_threads < size && (dirent = readdir (dir)))
|
||||
{
|
||||
pid_t id = g_ascii_strtoull (dirent->d_name, NULL, 10);
|
||||
|
||||
if (id)
|
||||
{
|
||||
if (! include_current_thread && id == tid)
|
||||
id = 0;
|
||||
}
|
||||
|
||||
if (id)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < n_blacklisted_threads; i++)
|
||||
{
|
||||
if (id == blacklisted_threads[i])
|
||||
{
|
||||
id = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (id)
|
||||
threads[n_threads++] = id;
|
||||
}
|
||||
|
||||
closedir (dir);
|
||||
|
||||
return n_threads;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_backtrace_read_thread_name (pid_t tid,
|
||||
gchar *name,
|
||||
gint size)
|
||||
{
|
||||
gchar filename[64];
|
||||
gint fd;
|
||||
|
||||
if (size <= 0)
|
||||
return;
|
||||
|
||||
name[0] = '\0';
|
||||
|
||||
g_snprintf (filename, sizeof (filename),
|
||||
"/proc/self/task/%llu/comm",
|
||||
(unsigned long long) tid);
|
||||
|
||||
fd = open (filename, O_RDONLY);
|
||||
|
||||
if (fd >= 0)
|
||||
{
|
||||
gint n = read (fd, name, size);
|
||||
|
||||
if (n > 0)
|
||||
name[n - 1] = '\0';
|
||||
|
||||
close (fd);
|
||||
}
|
||||
}
|
||||
|
||||
static gchar
|
||||
pika_backtrace_read_thread_state (pid_t tid)
|
||||
{
|
||||
gchar buffer[64];
|
||||
gint fd;
|
||||
gchar state = '\0';
|
||||
|
||||
g_snprintf (buffer, sizeof (buffer),
|
||||
"/proc/self/task/%llu/stat",
|
||||
(unsigned long long) tid);
|
||||
|
||||
fd = open (buffer, O_RDONLY);
|
||||
|
||||
if (fd >= 0)
|
||||
{
|
||||
gint n = read (fd, buffer, sizeof (buffer));
|
||||
|
||||
if (n > 0)
|
||||
buffer[n - 1] = '\0';
|
||||
|
||||
sscanf (buffer, "%*d %*s %c", &state);
|
||||
|
||||
close (fd);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_backtrace_signal_handler (gint signum)
|
||||
{
|
||||
PikaBacktrace *curr_backtrace;
|
||||
gint lock;
|
||||
|
||||
do
|
||||
{
|
||||
lock = g_atomic_int_get (&handler_lock);
|
||||
|
||||
if (lock < 0)
|
||||
continue;
|
||||
}
|
||||
while (! g_atomic_int_compare_and_exchange (&handler_lock, lock, lock + 1));
|
||||
|
||||
curr_backtrace = g_atomic_pointer_get (&handler_backtrace);
|
||||
|
||||
if (curr_backtrace)
|
||||
{
|
||||
pid_t tid = syscall (SYS_gettid);
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < curr_backtrace->n_threads; i++)
|
||||
{
|
||||
PikaBacktraceThread *thread = &curr_backtrace->threads[i];
|
||||
|
||||
if (thread->tid == tid)
|
||||
{
|
||||
thread->n_frames = backtrace ((gpointer *) thread->frames,
|
||||
MAX_N_FRAMES);
|
||||
|
||||
g_atomic_int_dec_and_test (&handler_n_remaining_threads);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_atomic_int_dec_and_test (&handler_lock);
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
|
||||
void
|
||||
pika_backtrace_init (void)
|
||||
{
|
||||
#ifdef HAVE_LIBBACKTRACE
|
||||
backtrace_state = backtrace_create_state (NULL, 0, NULL, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_backtrace_start (void)
|
||||
{
|
||||
g_mutex_lock (&mutex);
|
||||
|
||||
if (n_initializations == 0)
|
||||
{
|
||||
struct sigaction action = {};
|
||||
|
||||
action.sa_handler = pika_backtrace_signal_handler;
|
||||
action.sa_flags = SA_RESTART;
|
||||
|
||||
sigemptyset (&action.sa_mask);
|
||||
|
||||
if (sigaction (BACKTRACE_SIGNAL, &action, &orig_action) == 0)
|
||||
{
|
||||
pid_t *threads;
|
||||
gint n_threads;
|
||||
gint i;
|
||||
|
||||
n_blacklisted_threads = 0;
|
||||
|
||||
threads = g_new (pid_t, MAX_N_THREADS);
|
||||
|
||||
n_threads = pika_backtrace_enumerate_threads (TRUE,
|
||||
threads, MAX_N_THREADS);
|
||||
|
||||
for (i = 0; i < n_threads; i++)
|
||||
{
|
||||
gchar name[MAX_THREAD_NAME_SIZE];
|
||||
gint j;
|
||||
|
||||
pika_backtrace_read_thread_name (threads[i],
|
||||
name, MAX_THREAD_NAME_SIZE);
|
||||
|
||||
for (j = 0; j < G_N_ELEMENTS (blacklisted_thread_names); j++)
|
||||
{
|
||||
if (! strcmp (name, blacklisted_thread_names[j]))
|
||||
{
|
||||
blacklisted_threads[n_blacklisted_threads++] = threads[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_free (threads);
|
||||
|
||||
initialized = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
n_initializations++;
|
||||
|
||||
g_mutex_unlock (&mutex);
|
||||
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void
|
||||
pika_backtrace_stop (void)
|
||||
{
|
||||
g_return_if_fail (n_initializations > 0);
|
||||
|
||||
g_mutex_lock (&mutex);
|
||||
|
||||
n_initializations--;
|
||||
|
||||
if (n_initializations == 0 && initialized)
|
||||
{
|
||||
if (sigaction (BACKTRACE_SIGNAL, &orig_action, NULL) < 0)
|
||||
g_warning ("failed to restore original backtrace signal handler");
|
||||
|
||||
initialized = FALSE;
|
||||
}
|
||||
|
||||
g_mutex_unlock (&mutex);
|
||||
}
|
||||
|
||||
PikaBacktrace *
|
||||
pika_backtrace_new (gboolean include_current_thread)
|
||||
{
|
||||
PikaBacktrace *backtrace;
|
||||
pid_t pid;
|
||||
pid_t *threads;
|
||||
gint n_threads;
|
||||
gint64 start_time;
|
||||
gint i;
|
||||
|
||||
if (! initialized)
|
||||
return NULL;
|
||||
|
||||
pid = getpid ();
|
||||
|
||||
threads = g_new (pid_t, MAX_N_THREADS);
|
||||
|
||||
n_threads = pika_backtrace_enumerate_threads (include_current_thread,
|
||||
threads, MAX_N_THREADS);
|
||||
|
||||
if (n_threads == 0)
|
||||
{
|
||||
g_free (threads);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_mutex_lock (&mutex);
|
||||
|
||||
backtrace = g_slice_new (PikaBacktrace);
|
||||
|
||||
backtrace->threads = g_new (PikaBacktraceThread, n_threads);
|
||||
backtrace->n_threads = n_threads;
|
||||
|
||||
while (! g_atomic_int_compare_and_exchange (&handler_lock, 0, -1));
|
||||
|
||||
g_atomic_pointer_set (&handler_backtrace, backtrace);
|
||||
g_atomic_int_set (&handler_n_remaining_threads, n_threads);
|
||||
|
||||
g_atomic_int_set (&handler_lock, 0);
|
||||
|
||||
for (i = 0; i < n_threads; i++)
|
||||
{
|
||||
PikaBacktraceThread *thread = &backtrace->threads[i];
|
||||
|
||||
thread->tid = threads[i];
|
||||
thread->n_frames = 0;
|
||||
|
||||
pika_backtrace_read_thread_name (thread->tid,
|
||||
thread->name, MAX_THREAD_NAME_SIZE);
|
||||
|
||||
thread->state = pika_backtrace_read_thread_state (thread->tid);
|
||||
|
||||
syscall (SYS_tgkill, pid, threads[i], BACKTRACE_SIGNAL);
|
||||
}
|
||||
|
||||
g_free (threads);
|
||||
|
||||
start_time = g_get_monotonic_time ();
|
||||
|
||||
while (g_atomic_int_get (&handler_n_remaining_threads) > 0)
|
||||
{
|
||||
gint64 time = g_get_monotonic_time ();
|
||||
|
||||
if (time - start_time > MAX_WAIT_TIME)
|
||||
break;
|
||||
|
||||
g_usleep (1000);
|
||||
}
|
||||
|
||||
while (! g_atomic_int_compare_and_exchange (&handler_lock, 0, -1));
|
||||
|
||||
g_atomic_pointer_set (&handler_backtrace, NULL);
|
||||
|
||||
g_atomic_int_set (&handler_lock, 0);
|
||||
|
||||
#if 0
|
||||
if (handler_n_remaining_threads > 0)
|
||||
{
|
||||
gint j = 0;
|
||||
|
||||
for (i = 0; i < n_threads; i++)
|
||||
{
|
||||
if (backtrace->threads[i].n_frames == 0)
|
||||
{
|
||||
if (n_blacklisted_threads < MAX_N_THREADS)
|
||||
{
|
||||
blacklisted_threads[n_blacklisted_threads++] =
|
||||
backtrace->threads[i].tid;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (j < i)
|
||||
backtrace->threads[j] = backtrace->threads[i];
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
n_threads = j;
|
||||
}
|
||||
#endif
|
||||
|
||||
g_mutex_unlock (&mutex);
|
||||
|
||||
if (n_threads == 0)
|
||||
{
|
||||
pika_backtrace_free (backtrace);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return backtrace;
|
||||
}
|
||||
|
||||
void
|
||||
pika_backtrace_free (PikaBacktrace *backtrace)
|
||||
{
|
||||
if (! backtrace)
|
||||
return;
|
||||
|
||||
g_free (backtrace->threads);
|
||||
|
||||
g_slice_free (PikaBacktrace, backtrace);
|
||||
}
|
||||
|
||||
gint
|
||||
pika_backtrace_get_n_threads (PikaBacktrace *backtrace)
|
||||
{
|
||||
g_return_val_if_fail (backtrace != NULL, 0);
|
||||
|
||||
return backtrace->n_threads;
|
||||
}
|
||||
|
||||
guintptr
|
||||
pika_backtrace_get_thread_id (PikaBacktrace *backtrace,
|
||||
gint thread)
|
||||
{
|
||||
g_return_val_if_fail (backtrace != NULL, 0);
|
||||
g_return_val_if_fail (thread >= 0 && thread < backtrace->n_threads, 0);
|
||||
|
||||
return backtrace->threads[thread].tid;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
pika_backtrace_get_thread_name (PikaBacktrace *backtrace,
|
||||
gint thread)
|
||||
{
|
||||
g_return_val_if_fail (backtrace != NULL, NULL);
|
||||
g_return_val_if_fail (thread >= 0 && thread < backtrace->n_threads, NULL);
|
||||
|
||||
if (backtrace->threads[thread].name[0])
|
||||
return backtrace->threads[thread].name;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_backtrace_is_thread_running (PikaBacktrace *backtrace,
|
||||
gint thread)
|
||||
{
|
||||
g_return_val_if_fail (backtrace != NULL, FALSE);
|
||||
g_return_val_if_fail (thread >= 0 && thread < backtrace->n_threads, FALSE);
|
||||
|
||||
return backtrace->threads[thread].state == 'R';
|
||||
}
|
||||
|
||||
gint
|
||||
pika_backtrace_find_thread_by_id (PikaBacktrace *backtrace,
|
||||
guintptr thread_id,
|
||||
gint thread_hint)
|
||||
{
|
||||
pid_t tid = thread_id;
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (backtrace != NULL, -1);
|
||||
|
||||
if (thread_hint >= 0 &&
|
||||
thread_hint < backtrace->n_threads &&
|
||||
backtrace->threads[thread_hint].tid == tid)
|
||||
{
|
||||
return thread_hint;
|
||||
}
|
||||
|
||||
for (i = 0; i < backtrace->n_threads; i++)
|
||||
{
|
||||
if (backtrace->threads[i].tid == tid)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
gint
|
||||
pika_backtrace_get_n_frames (PikaBacktrace *backtrace,
|
||||
gint thread)
|
||||
{
|
||||
g_return_val_if_fail (backtrace != NULL, 0);
|
||||
g_return_val_if_fail (thread >= 0 && thread < backtrace->n_threads, 0);
|
||||
|
||||
return MAX (backtrace->threads[thread].n_frames - N_SKIPPED_FRAMES, 0);
|
||||
}
|
||||
|
||||
guintptr
|
||||
pika_backtrace_get_frame_address (PikaBacktrace *backtrace,
|
||||
gint thread,
|
||||
gint frame)
|
||||
{
|
||||
g_return_val_if_fail (backtrace != NULL, 0);
|
||||
g_return_val_if_fail (thread >= 0 && thread < backtrace->n_threads, 0);
|
||||
|
||||
frame = pika_backtrace_normalize_frame (backtrace, thread, frame);
|
||||
|
||||
g_return_val_if_fail (frame >= N_SKIPPED_FRAMES &&
|
||||
frame < backtrace->threads[thread].n_frames, 0);
|
||||
|
||||
return backtrace->threads[thread].frames[frame];
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBBACKTRACE
|
||||
static void
|
||||
pika_backtrace_syminfo_callback (PikaBacktraceAddressInfo *info,
|
||||
guintptr pc,
|
||||
const gchar *symname,
|
||||
guintptr symval,
|
||||
guintptr symsize)
|
||||
{
|
||||
if (symname)
|
||||
g_strlcpy (info->symbol_name, symname, sizeof (info->symbol_name));
|
||||
|
||||
info->symbol_address = symval;
|
||||
}
|
||||
|
||||
static gint
|
||||
pika_backtrace_pcinfo_callback (PikaBacktraceAddressInfo *info,
|
||||
guintptr pc,
|
||||
const gchar *filename,
|
||||
gint lineno,
|
||||
const gchar *function)
|
||||
{
|
||||
if (function)
|
||||
g_strlcpy (info->symbol_name, function, sizeof (info->symbol_name));
|
||||
|
||||
if (filename)
|
||||
g_strlcpy (info->source_file, filename, sizeof (info->source_file));
|
||||
|
||||
info->source_line = lineno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_LIBBACKTRACE */
|
||||
|
||||
gboolean
|
||||
pika_backtrace_get_address_info (guintptr address,
|
||||
PikaBacktraceAddressInfo *info)
|
||||
{
|
||||
Dl_info dl_info;
|
||||
gboolean result = FALSE;
|
||||
|
||||
g_return_val_if_fail (info != NULL, FALSE);
|
||||
|
||||
info->object_name[0] = '\0';
|
||||
|
||||
info->symbol_name[0] = '\0';
|
||||
info->symbol_address = 0;
|
||||
|
||||
info->source_file[0] = '\0';
|
||||
info->source_line = 0;
|
||||
|
||||
if (dladdr ((gpointer) address, &dl_info))
|
||||
{
|
||||
if (dl_info.dli_fname)
|
||||
{
|
||||
g_strlcpy (info->object_name, dl_info.dli_fname,
|
||||
sizeof (info->object_name));
|
||||
}
|
||||
|
||||
if (dl_info.dli_sname)
|
||||
{
|
||||
g_strlcpy (info->symbol_name, dl_info.dli_sname,
|
||||
sizeof (info->symbol_name));
|
||||
}
|
||||
|
||||
info->symbol_address = (guintptr) dl_info.dli_saddr;
|
||||
|
||||
result = TRUE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBBACKTRACE
|
||||
if (backtrace_state)
|
||||
{
|
||||
backtrace_syminfo (
|
||||
backtrace_state, address,
|
||||
(backtrace_syminfo_callback) pika_backtrace_syminfo_callback,
|
||||
NULL,
|
||||
info);
|
||||
|
||||
backtrace_pcinfo (
|
||||
backtrace_state, address,
|
||||
(backtrace_full_callback) pika_backtrace_pcinfo_callback,
|
||||
NULL,
|
||||
info);
|
||||
|
||||
result = TRUE;
|
||||
}
|
||||
#endif /* HAVE_LIBBACKTRACE */
|
||||
|
||||
#ifdef HAVE_LIBUNWIND
|
||||
/* we use libunwind to get the symbol name, when available, even if dladdr() or
|
||||
* libbacktrace already found one, since it provides more descriptive names in
|
||||
* some cases, and, in particular, full symbol names for C++ lambdas.
|
||||
*
|
||||
* note that, in some cases, this can result in a discrepancy between the
|
||||
* symbol name, and the corresponding source location.
|
||||
*/
|
||||
#if 0
|
||||
if (! info->symbol_name[0])
|
||||
#endif
|
||||
{
|
||||
unw_context_t context = {};
|
||||
unw_cursor_t cursor;
|
||||
unw_word_t offset;
|
||||
|
||||
if (unw_init_local (&cursor, &context) == 0 &&
|
||||
unw_set_reg (&cursor, UNW_REG_IP, address) == 0 &&
|
||||
unw_get_proc_name (&cursor,
|
||||
info->symbol_name, sizeof (info->symbol_name),
|
||||
&offset) == 0)
|
||||
{
|
||||
info->symbol_address = address - offset;
|
||||
|
||||
result = TRUE;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_LIBUNWIND */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#endif /* PIKA_BACKTRACE_BACKEND_LINUX */
|
||||
130
app/core/pikabacktrace-none.c
Normal file
130
app/core/pikabacktrace-none.c
Normal file
@ -0,0 +1,130 @@
|
||||
/* 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-1999 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikabacktrace-none.c
|
||||
* Copyright (C) 2018 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "pikabacktrace-backend.h"
|
||||
|
||||
|
||||
#ifdef PIKA_BACKTRACE_BACKEND_NONE
|
||||
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikabacktrace.h"
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
|
||||
void
|
||||
pika_backtrace_init (void)
|
||||
{
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_backtrace_start (void)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
pika_backtrace_stop (void)
|
||||
{
|
||||
}
|
||||
|
||||
PikaBacktrace *
|
||||
pika_backtrace_new (gboolean include_current_thread)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
pika_backtrace_free (PikaBacktrace *backtrace)
|
||||
{
|
||||
g_return_if_fail (backtrace == NULL);
|
||||
}
|
||||
|
||||
gint
|
||||
pika_backtrace_get_n_threads (PikaBacktrace *backtrace)
|
||||
{
|
||||
g_return_val_if_reached (0);
|
||||
}
|
||||
|
||||
guintptr
|
||||
pika_backtrace_get_thread_id (PikaBacktrace *backtrace,
|
||||
gint thread)
|
||||
{
|
||||
g_return_val_if_reached (0);
|
||||
}
|
||||
|
||||
const gchar *
|
||||
pika_backtrace_get_thread_name (PikaBacktrace *backtrace,
|
||||
gint thread)
|
||||
{
|
||||
g_return_val_if_reached (NULL);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_backtrace_is_thread_running (PikaBacktrace *backtrace,
|
||||
gint thread)
|
||||
{
|
||||
g_return_val_if_reached (FALSE);
|
||||
}
|
||||
|
||||
gint
|
||||
pika_backtrace_find_thread_by_id (PikaBacktrace *backtrace,
|
||||
guintptr thread_id,
|
||||
gint thread_hint)
|
||||
{
|
||||
g_return_val_if_reached (-1);
|
||||
}
|
||||
|
||||
gint
|
||||
pika_backtrace_get_n_frames (PikaBacktrace *backtrace,
|
||||
gint thread)
|
||||
{
|
||||
g_return_val_if_reached (0);
|
||||
}
|
||||
|
||||
guintptr
|
||||
pika_backtrace_get_frame_address (PikaBacktrace *backtrace,
|
||||
gint thread,
|
||||
gint frame)
|
||||
{
|
||||
g_return_val_if_reached (0);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_backtrace_get_address_info (guintptr address,
|
||||
PikaBacktraceAddressInfo *info)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
#endif /* PIKA_BACKTRACE_BACKEND_NONE */
|
||||
744
app/core/pikabacktrace-windows.c
Normal file
744
app/core/pikabacktrace-windows.c
Normal file
@ -0,0 +1,744 @@
|
||||
/* 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-1999 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* pikabacktrace-windows.c
|
||||
* Copyright (C) 2018 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "pikabacktrace-backend.h"
|
||||
|
||||
|
||||
#ifdef PIKA_BACKTRACE_BACKEND_WINDOWS
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#include <tlhelp32.h>
|
||||
#include <dbghelp.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikabacktrace.h"
|
||||
|
||||
|
||||
#define MAX_N_THREADS 256
|
||||
#define MAX_N_FRAMES 256
|
||||
#define THREAD_ENUMERATION_INTERVAL G_TIME_SPAN_SECOND
|
||||
|
||||
|
||||
typedef struct _Thread Thread;
|
||||
typedef struct _PikaBacktraceThread PikaBacktraceThread;
|
||||
|
||||
|
||||
struct _Thread
|
||||
{
|
||||
DWORD tid;
|
||||
|
||||
union
|
||||
{
|
||||
gchar *name;
|
||||
guint64 time;
|
||||
};
|
||||
};
|
||||
|
||||
struct _PikaBacktraceThread
|
||||
{
|
||||
DWORD tid;
|
||||
const gchar *name;
|
||||
guint64 time;
|
||||
guint64 last_time;
|
||||
|
||||
guintptr frames[MAX_N_FRAMES];
|
||||
gint n_frames;
|
||||
};
|
||||
|
||||
struct _PikaBacktrace
|
||||
{
|
||||
PikaBacktraceThread *threads;
|
||||
gint n_threads;
|
||||
};
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static inline gint pika_backtrace_normalize_frame (PikaBacktrace *backtrace,
|
||||
gint thread,
|
||||
gint frame);
|
||||
|
||||
static void pika_backtrace_set_thread_name (DWORD tid,
|
||||
const gchar *name);
|
||||
|
||||
static gboolean pika_backtrace_enumerate_threads (void);
|
||||
|
||||
static LONG WINAPI pika_backtrace_exception_handler (PEXCEPTION_POINTERS info);
|
||||
|
||||
|
||||
/* static variables */
|
||||
|
||||
static GMutex mutex;
|
||||
static gint n_initializations;
|
||||
static gboolean initialized;
|
||||
Thread threads[MAX_N_THREADS];
|
||||
gint n_threads;
|
||||
gint64 last_thread_enumeration_time;
|
||||
Thread thread_names[MAX_N_THREADS];
|
||||
gint n_thread_names;
|
||||
gint thread_names_spinlock;
|
||||
Thread thread_times[MAX_N_THREADS];
|
||||
gint n_thread_times;
|
||||
|
||||
DWORD WINAPI (* pika_backtrace_SymSetOptions) (DWORD SymOptions);
|
||||
BOOL WINAPI (* pika_backtrace_SymInitialize) (HANDLE hProcess,
|
||||
PCSTR UserSearchPath,
|
||||
BOOL fInvadeProcess);
|
||||
BOOL WINAPI (* pika_backtrace_SymCleanup) (HANDLE hProcess);
|
||||
BOOL WINAPI (* pika_backtrace_SymFromAddr) (HANDLE hProcess,
|
||||
DWORD64 Address,
|
||||
PDWORD64 Displacement,
|
||||
PSYMBOL_INFO Symbol);
|
||||
BOOL WINAPI (* pika_backtrace_SymGetLineFromAddr64) (HANDLE hProcess,
|
||||
DWORD64 qwAddr,
|
||||
PDWORD pdwDisplacement,
|
||||
PIMAGEHLP_LINE64 Line64);
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
|
||||
static inline gint
|
||||
pika_backtrace_normalize_frame (PikaBacktrace *backtrace,
|
||||
gint thread,
|
||||
gint frame)
|
||||
{
|
||||
if (frame >= 0)
|
||||
return frame;
|
||||
else
|
||||
return backtrace->threads[thread].n_frames + frame;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_backtrace_set_thread_name (DWORD tid,
|
||||
const gchar *name)
|
||||
{
|
||||
while (! g_atomic_int_compare_and_exchange (&thread_names_spinlock,
|
||||
0, 1));
|
||||
|
||||
if (n_thread_names < MAX_N_THREADS)
|
||||
{
|
||||
Thread *thread = &thread_names[n_thread_names++];
|
||||
|
||||
thread->tid = tid;
|
||||
thread->name = g_strdup (name);
|
||||
}
|
||||
|
||||
g_atomic_int_set (&thread_names_spinlock, 0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_backtrace_enumerate_threads (void)
|
||||
{
|
||||
HANDLE hThreadSnap;
|
||||
THREADENTRY32 te32;
|
||||
DWORD pid;
|
||||
gint64 time;
|
||||
|
||||
time = g_get_monotonic_time ();
|
||||
|
||||
if (time - last_thread_enumeration_time < THREAD_ENUMERATION_INTERVAL)
|
||||
return n_threads > 0;
|
||||
|
||||
last_thread_enumeration_time = time;
|
||||
|
||||
n_threads = 0;
|
||||
|
||||
hThreadSnap = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0);
|
||||
|
||||
if (hThreadSnap == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
te32.dwSize = sizeof (te32);
|
||||
|
||||
if (! Thread32First (hThreadSnap, &te32))
|
||||
{
|
||||
CloseHandle (hThreadSnap);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pid = GetCurrentProcessId ();
|
||||
|
||||
while (! g_atomic_int_compare_and_exchange (&thread_names_spinlock, 0, 1));
|
||||
|
||||
do
|
||||
{
|
||||
if (n_threads == MAX_N_THREADS)
|
||||
break;
|
||||
|
||||
if (te32.th32OwnerProcessID == pid)
|
||||
{
|
||||
Thread *thread = &threads[n_threads++];
|
||||
gint i;
|
||||
|
||||
thread->tid = te32.th32ThreadID;
|
||||
thread->name = NULL;
|
||||
|
||||
for (i = n_thread_names - 1; i >= 0; i--)
|
||||
{
|
||||
if (thread->tid == thread_names[i].tid)
|
||||
{
|
||||
thread->name = thread_names[i].name;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (Thread32Next (hThreadSnap, &te32));
|
||||
|
||||
g_atomic_int_set (&thread_names_spinlock, 0);
|
||||
|
||||
CloseHandle (hThreadSnap);
|
||||
|
||||
return n_threads > 0;
|
||||
}
|
||||
|
||||
static LONG WINAPI
|
||||
pika_backtrace_exception_handler (PEXCEPTION_POINTERS info)
|
||||
{
|
||||
#define EXCEPTION_SET_THREAD_NAME ((DWORD) 0x406D1388)
|
||||
|
||||
typedef struct _THREADNAME_INFO
|
||||
{
|
||||
DWORD dwType; /* must be 0x1000 */
|
||||
LPCSTR szName; /* pointer to name (in user addr space) */
|
||||
DWORD dwThreadID; /* thread ID (-1=caller thread) */
|
||||
DWORD dwFlags; /* reserved for future use, must be zero */
|
||||
} THREADNAME_INFO;
|
||||
|
||||
if (info->ExceptionRecord != NULL &&
|
||||
info->ExceptionRecord->ExceptionCode == EXCEPTION_SET_THREAD_NAME &&
|
||||
info->ExceptionRecord->NumberParameters *
|
||||
sizeof (ULONG_PTR) == sizeof (THREADNAME_INFO))
|
||||
{
|
||||
THREADNAME_INFO name_info;
|
||||
|
||||
memcpy (&name_info, info->ExceptionRecord->ExceptionInformation,
|
||||
sizeof (name_info));
|
||||
|
||||
if (name_info.dwType == 0x1000)
|
||||
{
|
||||
DWORD tid = name_info.dwThreadID;
|
||||
|
||||
if (tid == -1)
|
||||
tid = GetCurrentThreadId ();
|
||||
|
||||
pika_backtrace_set_thread_name (tid, name_info.szName);
|
||||
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
}
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
#undef EXCEPTION_SET_THREAD_NAME
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
|
||||
void
|
||||
pika_backtrace_init (void)
|
||||
{
|
||||
pika_backtrace_set_thread_name (GetCurrentThreadId (), g_get_prgname ());
|
||||
|
||||
AddVectoredExceptionHandler (TRUE, pika_backtrace_exception_handler);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_backtrace_start (void)
|
||||
{
|
||||
g_mutex_lock (&mutex);
|
||||
|
||||
if (n_initializations == 0)
|
||||
{
|
||||
HMODULE hModule;
|
||||
DWORD options;
|
||||
|
||||
hModule = LoadLibraryW (L"mgwhelp.dll");
|
||||
|
||||
#define INIT_PROC(name) \
|
||||
G_STMT_START \
|
||||
{ \
|
||||
pika_backtrace_##name = name; \
|
||||
\
|
||||
if (hModule) \
|
||||
{ \
|
||||
gpointer proc = GetProcAddress (hModule, #name); \
|
||||
\
|
||||
if (proc) \
|
||||
pika_backtrace_##name = proc; \
|
||||
} \
|
||||
} \
|
||||
G_STMT_END
|
||||
|
||||
INIT_PROC (SymSetOptions);
|
||||
INIT_PROC (SymInitialize);
|
||||
INIT_PROC (SymCleanup);
|
||||
INIT_PROC (SymFromAddr);
|
||||
INIT_PROC (SymGetLineFromAddr64);
|
||||
|
||||
#undef INIT_PROC
|
||||
|
||||
options = SymGetOptions ();
|
||||
|
||||
options &= ~SYMOPT_UNDNAME;
|
||||
options |= SYMOPT_OMAP_FIND_NEAREST |
|
||||
SYMOPT_DEFERRED_LOADS |
|
||||
SYMOPT_DEBUG;
|
||||
|
||||
#ifdef ARCH_X86_64
|
||||
options |= SYMOPT_INCLUDE_32BIT_MODULES;
|
||||
#endif
|
||||
|
||||
pika_backtrace_SymSetOptions (options);
|
||||
|
||||
if (pika_backtrace_SymInitialize (GetCurrentProcess (), NULL, TRUE))
|
||||
{
|
||||
n_threads = 0;
|
||||
last_thread_enumeration_time = 0;
|
||||
n_thread_times = 0;
|
||||
|
||||
initialized = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
n_initializations++;
|
||||
|
||||
g_mutex_unlock (&mutex);
|
||||
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void
|
||||
pika_backtrace_stop (void)
|
||||
{
|
||||
g_return_if_fail (n_initializations > 0);
|
||||
|
||||
g_mutex_lock (&mutex);
|
||||
|
||||
n_initializations--;
|
||||
|
||||
if (n_initializations == 0)
|
||||
{
|
||||
if (initialized)
|
||||
{
|
||||
pika_backtrace_SymCleanup (GetCurrentProcess ());
|
||||
|
||||
initialized = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
g_mutex_unlock (&mutex);
|
||||
}
|
||||
|
||||
PikaBacktrace *
|
||||
pika_backtrace_new (gboolean include_current_thread)
|
||||
{
|
||||
PikaBacktrace *backtrace;
|
||||
HANDLE hProcess;
|
||||
DWORD tid;
|
||||
gint i;
|
||||
|
||||
if (! initialized)
|
||||
return NULL;
|
||||
|
||||
g_mutex_lock (&mutex);
|
||||
|
||||
if (! pika_backtrace_enumerate_threads ())
|
||||
{
|
||||
g_mutex_unlock (&mutex);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hProcess = GetCurrentProcess ();
|
||||
tid = GetCurrentThreadId ();
|
||||
|
||||
backtrace = g_slice_new (PikaBacktrace);
|
||||
|
||||
backtrace->threads = g_new (PikaBacktraceThread, n_threads);
|
||||
backtrace->n_threads = 0;
|
||||
|
||||
for (i = 0; i < n_threads; i++)
|
||||
{
|
||||
PikaBacktraceThread *thread = &backtrace->threads[backtrace->n_threads];
|
||||
HANDLE hThread;
|
||||
CONTEXT context = {};
|
||||
STACKFRAME64 frame = {};
|
||||
DWORD machine_type;
|
||||
FILETIME creation_time;
|
||||
FILETIME exit_time;
|
||||
FILETIME kernel_time;
|
||||
FILETIME user_time;
|
||||
|
||||
if (! include_current_thread && threads[i].tid == tid)
|
||||
continue;
|
||||
|
||||
hThread = OpenThread (THREAD_QUERY_INFORMATION |
|
||||
THREAD_GET_CONTEXT |
|
||||
THREAD_SUSPEND_RESUME,
|
||||
FALSE,
|
||||
threads[i].tid);
|
||||
|
||||
if (hThread == INVALID_HANDLE_VALUE)
|
||||
continue;
|
||||
|
||||
if (threads[i].tid != tid && SuspendThread (hThread) == (DWORD) -1)
|
||||
{
|
||||
CloseHandle (hThread);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
|
||||
if (! GetThreadContext (hThread, &context))
|
||||
{
|
||||
if (threads[i].tid != tid)
|
||||
ResumeThread (hThread);
|
||||
|
||||
CloseHandle (hThread);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef ARCH_X86_64
|
||||
machine_type = IMAGE_FILE_MACHINE_AMD64;
|
||||
frame.AddrPC.Offset = context.Rip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.Rsp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Rbp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
#elif defined (ARCH_X86)
|
||||
machine_type = IMAGE_FILE_MACHINE_I386;
|
||||
frame.AddrPC.Offset = context.Eip;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Offset = context.Esp;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Offset = context.Ebp;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
#else
|
||||
#error unsupported architecture
|
||||
#endif
|
||||
|
||||
thread->tid = threads[i].tid;
|
||||
thread->name = threads[i].name;
|
||||
thread->last_time = 0;
|
||||
thread->time = 0;
|
||||
|
||||
thread->n_frames = 0;
|
||||
|
||||
while (thread->n_frames < MAX_N_FRAMES &&
|
||||
StackWalk64 (machine_type, hProcess, hThread, &frame, &context,
|
||||
NULL,
|
||||
SymFunctionTableAccess64,
|
||||
SymGetModuleBase64,
|
||||
NULL))
|
||||
{
|
||||
thread->frames[thread->n_frames++] = frame.AddrPC.Offset;
|
||||
|
||||
if (frame.AddrPC.Offset == frame.AddrReturn.Offset)
|
||||
break;
|
||||
}
|
||||
|
||||
if (GetThreadTimes (hThread,
|
||||
&creation_time, &exit_time,
|
||||
&kernel_time, &user_time))
|
||||
{
|
||||
thread->time = (((guint64) kernel_time.dwHighDateTime << 32) |
|
||||
((guint64) kernel_time.dwLowDateTime)) +
|
||||
(((guint64) user_time.dwHighDateTime << 32) |
|
||||
((guint64) user_time.dwLowDateTime));
|
||||
|
||||
if (i < n_thread_times && thread->tid == thread_times[i].tid)
|
||||
{
|
||||
thread->last_time = thread_times[i].time;
|
||||
}
|
||||
else
|
||||
{
|
||||
gint j;
|
||||
|
||||
for (j = 0; j < n_thread_times; j++)
|
||||
{
|
||||
if (thread->tid == thread_times[j].tid)
|
||||
{
|
||||
thread->last_time = thread_times[j].time;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (threads[i].tid != tid)
|
||||
ResumeThread (hThread);
|
||||
|
||||
CloseHandle (hThread);
|
||||
|
||||
if (thread->n_frames > 0)
|
||||
backtrace->n_threads++;
|
||||
}
|
||||
|
||||
n_thread_times = backtrace->n_threads;
|
||||
|
||||
for (i = 0; i < backtrace->n_threads; i++)
|
||||
{
|
||||
thread_times[i].tid = backtrace->threads[i].tid;
|
||||
thread_times[i].time = backtrace->threads[i].time;
|
||||
}
|
||||
|
||||
g_mutex_unlock (&mutex);
|
||||
|
||||
if (backtrace->n_threads == 0)
|
||||
{
|
||||
pika_backtrace_free (backtrace);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return backtrace;
|
||||
}
|
||||
|
||||
void
|
||||
pika_backtrace_free (PikaBacktrace *backtrace)
|
||||
{
|
||||
if (backtrace)
|
||||
{
|
||||
g_free (backtrace->threads);
|
||||
|
||||
g_slice_free (PikaBacktrace, backtrace);
|
||||
}
|
||||
}
|
||||
|
||||
gint
|
||||
pika_backtrace_get_n_threads (PikaBacktrace *backtrace)
|
||||
{
|
||||
g_return_val_if_fail (backtrace != NULL, 0);
|
||||
|
||||
return backtrace->n_threads;
|
||||
}
|
||||
|
||||
guintptr
|
||||
pika_backtrace_get_thread_id (PikaBacktrace *backtrace,
|
||||
gint thread)
|
||||
{
|
||||
g_return_val_if_fail (backtrace != NULL, 0);
|
||||
g_return_val_if_fail (thread >= 0 && thread < backtrace->n_threads, 0);
|
||||
|
||||
return backtrace->threads[thread].tid;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
pika_backtrace_get_thread_name (PikaBacktrace *backtrace,
|
||||
gint thread)
|
||||
{
|
||||
g_return_val_if_fail (backtrace != NULL, NULL);
|
||||
g_return_val_if_fail (thread >= 0 && thread < backtrace->n_threads, NULL);
|
||||
|
||||
return backtrace->threads[thread].name;
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_backtrace_is_thread_running (PikaBacktrace *backtrace,
|
||||
gint thread)
|
||||
{
|
||||
g_return_val_if_fail (backtrace != NULL, FALSE);
|
||||
g_return_val_if_fail (thread >= 0 && thread < backtrace->n_threads, FALSE);
|
||||
|
||||
return backtrace->threads[thread].time >
|
||||
backtrace->threads[thread].last_time;
|
||||
}
|
||||
|
||||
gint
|
||||
pika_backtrace_find_thread_by_id (PikaBacktrace *backtrace,
|
||||
guintptr thread_id,
|
||||
gint thread_hint)
|
||||
{
|
||||
DWORD tid = thread_id;
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (backtrace != NULL, -1);
|
||||
|
||||
if (thread_hint >= 0 &&
|
||||
thread_hint < backtrace->n_threads &&
|
||||
backtrace->threads[thread_hint].tid == tid)
|
||||
{
|
||||
return thread_hint;
|
||||
}
|
||||
|
||||
for (i = 0; i < backtrace->n_threads; i++)
|
||||
{
|
||||
if (backtrace->threads[i].tid == tid)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
gint
|
||||
pika_backtrace_get_n_frames (PikaBacktrace *backtrace,
|
||||
gint thread)
|
||||
{
|
||||
g_return_val_if_fail (backtrace != NULL, 0);
|
||||
g_return_val_if_fail (thread >= 0 && thread < backtrace->n_threads, 0);
|
||||
|
||||
return backtrace->threads[thread].n_frames;
|
||||
}
|
||||
|
||||
guintptr
|
||||
pika_backtrace_get_frame_address (PikaBacktrace *backtrace,
|
||||
gint thread,
|
||||
gint frame)
|
||||
{
|
||||
g_return_val_if_fail (backtrace != NULL, 0);
|
||||
g_return_val_if_fail (thread >= 0 && thread < backtrace->n_threads, 0);
|
||||
|
||||
frame = pika_backtrace_normalize_frame (backtrace, thread, frame);
|
||||
|
||||
g_return_val_if_fail (frame >= 0 &&
|
||||
frame < backtrace->threads[thread].n_frames, 0);
|
||||
|
||||
return backtrace->threads[thread].frames[frame];
|
||||
}
|
||||
|
||||
#define IN_MIDDLE_OF_UTF8_CODEPOINT(c) \
|
||||
((c & 0xc0) == 0x80)
|
||||
|
||||
static void
|
||||
utf8_copy_sized (char *dest,
|
||||
const char *src,
|
||||
size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
strncpy (dest, src, size);
|
||||
|
||||
if (dest[size - 1] != 0)
|
||||
{
|
||||
char *p = &dest[size - 1];
|
||||
|
||||
/* Checking for p > dest is not actually needed, but
|
||||
* it's useful in case of malformed source string. */
|
||||
while (IN_MIDDLE_OF_UTF8_CODEPOINT (*p) && G_LIKELY (p > dest))
|
||||
*p-- = 0;
|
||||
|
||||
*p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#undef IN_MIDDLE_OF_UTF8_CODEPOINT
|
||||
|
||||
gboolean
|
||||
pika_backtrace_get_address_info (guintptr address,
|
||||
PikaBacktraceAddressInfo *info)
|
||||
{
|
||||
SYMBOL_INFO *symbol_info;
|
||||
HANDLE hProcess;
|
||||
HMODULE hModule;
|
||||
DWORD64 offset = 0;
|
||||
IMAGEHLP_LINE64 line = {};
|
||||
DWORD line_offset = 0;
|
||||
gboolean result = FALSE;
|
||||
wchar_t buf[MAX_PATH];
|
||||
DWORD wchars_count;
|
||||
|
||||
hProcess = GetCurrentProcess ();
|
||||
hModule = (HMODULE) (guintptr) SymGetModuleBase64 (hProcess, address);
|
||||
|
||||
info->object_name[0] = '\0';
|
||||
wchars_count = sizeof (buf) / sizeof (buf[0]);
|
||||
if (hModule && GetModuleFileNameExW (hProcess, hModule, buf, wchars_count))
|
||||
{
|
||||
char *object_name;
|
||||
|
||||
if ((object_name = g_utf16_to_utf8 (buf, -1, NULL, NULL, NULL)))
|
||||
{
|
||||
utf8_copy_sized (info->object_name, object_name, sizeof (info->object_name));
|
||||
|
||||
result = TRUE;
|
||||
g_free (object_name);
|
||||
}
|
||||
}
|
||||
|
||||
symbol_info = g_malloc (sizeof (SYMBOL_INFO) +
|
||||
sizeof (info->symbol_name) - 1);
|
||||
|
||||
symbol_info->SizeOfStruct = sizeof (SYMBOL_INFO);
|
||||
symbol_info->MaxNameLen = sizeof (info->symbol_name);
|
||||
|
||||
if (pika_backtrace_SymFromAddr (hProcess, address,
|
||||
&offset, symbol_info))
|
||||
{
|
||||
g_strlcpy (info->symbol_name, symbol_info->Name,
|
||||
sizeof (info->symbol_name));
|
||||
|
||||
info->symbol_address = offset ? address - offset : 0;
|
||||
|
||||
result = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->symbol_name[0] = '\0';
|
||||
info->symbol_address = 0;
|
||||
}
|
||||
|
||||
g_free (symbol_info);
|
||||
|
||||
if (pika_backtrace_SymGetLineFromAddr64 (hProcess, address,
|
||||
&line_offset, &line))
|
||||
{
|
||||
g_strlcpy (info->source_file, line.FileName,
|
||||
sizeof (info->source_file));
|
||||
|
||||
info->source_line = line.LineNumber;
|
||||
|
||||
result = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->source_file[0] = '\0';
|
||||
info->source_line = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#endif /* PIKA_BACKTRACE_BACKEND_WINDOWS */
|
||||
74
app/core/pikabacktrace.h
Normal file
74
app/core/pikabacktrace.h
Normal file
@ -0,0 +1,74 @@
|
||||
/* 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
|
||||
*
|
||||
* pikabacktrace.h
|
||||
* Copyright (C) 2018 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BACKTRACE_H__
|
||||
#define __PIKA_BACKTRACE_H__
|
||||
|
||||
|
||||
typedef struct _PikaBacktraceAddressInfo PikaBacktraceAddressInfo;
|
||||
|
||||
|
||||
struct _PikaBacktraceAddressInfo
|
||||
{
|
||||
gchar object_name[256];
|
||||
|
||||
gchar symbol_name[256];
|
||||
guintptr symbol_address;
|
||||
|
||||
gchar source_file[256];
|
||||
gint source_line;
|
||||
};
|
||||
|
||||
|
||||
void pika_backtrace_init (void);
|
||||
|
||||
gboolean pika_backtrace_start (void);
|
||||
void pika_backtrace_stop (void);
|
||||
|
||||
PikaBacktrace * pika_backtrace_new (gboolean include_current_thread);
|
||||
void pika_backtrace_free (PikaBacktrace *backtrace);
|
||||
|
||||
gint pika_backtrace_get_n_threads (PikaBacktrace *backtrace);
|
||||
guintptr pika_backtrace_get_thread_id (PikaBacktrace *backtrace,
|
||||
gint thread);
|
||||
const gchar * pika_backtrace_get_thread_name (PikaBacktrace *backtrace,
|
||||
gint thread);
|
||||
gboolean pika_backtrace_is_thread_running (PikaBacktrace *backtrace,
|
||||
gint thread);
|
||||
|
||||
gint pika_backtrace_find_thread_by_id (PikaBacktrace *backtrace,
|
||||
guintptr thread_id,
|
||||
gint thread_hint);
|
||||
|
||||
gint pika_backtrace_get_n_frames (PikaBacktrace *backtrace,
|
||||
gint thread);
|
||||
guintptr pika_backtrace_get_frame_address (PikaBacktrace *backtrace,
|
||||
gint thread,
|
||||
gint frame);
|
||||
|
||||
gboolean pika_backtrace_get_address_info (guintptr address,
|
||||
PikaBacktraceAddressInfo *info);
|
||||
|
||||
|
||||
#endif /* __PIKA_BACKTRACE_H__ */
|
||||
195
app/core/pikabezierdesc.c
Normal file
195
app/core/pikabezierdesc.c
Normal file
@ -0,0 +1,195 @@
|
||||
/* 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
|
||||
*
|
||||
* pikabezierdesc.c
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gegl.h>
|
||||
#include <cairo.h>
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikabezierdesc.h"
|
||||
#include "pikaboundary.h"
|
||||
|
||||
|
||||
G_DEFINE_BOXED_TYPE (PikaBezierDesc, pika_bezier_desc, pika_bezier_desc_copy, pika_bezier_desc_free)
|
||||
|
||||
PikaBezierDesc *
|
||||
pika_bezier_desc_new (cairo_path_data_t *data,
|
||||
gint n_data)
|
||||
{
|
||||
PikaBezierDesc *desc;
|
||||
|
||||
g_return_val_if_fail (n_data == 0 || data != NULL, NULL);
|
||||
|
||||
desc = g_slice_new (PikaBezierDesc);
|
||||
|
||||
desc->status = CAIRO_STATUS_SUCCESS;
|
||||
desc->num_data = n_data;
|
||||
desc->data = data;
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
static void
|
||||
add_polyline (GArray *path_data,
|
||||
const PikaVector2 *points,
|
||||
gint n_points,
|
||||
gboolean closed)
|
||||
{
|
||||
PikaVector2 prev = { 0.0, 0.0, };
|
||||
cairo_path_data_t pd;
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < n_points; i++)
|
||||
{
|
||||
/* compress multiple identical coordinates */
|
||||
if (i == 0 ||
|
||||
prev.x != points[i].x ||
|
||||
prev.y != points[i].y)
|
||||
{
|
||||
pd.header.type = (i == 0) ? CAIRO_PATH_MOVE_TO : CAIRO_PATH_LINE_TO;
|
||||
pd.header.length = 2;
|
||||
|
||||
g_array_append_val (path_data, pd);
|
||||
|
||||
pd.point.x = points[i].x;
|
||||
pd.point.y = points[i].y;
|
||||
|
||||
g_array_append_val (path_data, pd);
|
||||
|
||||
prev = points[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* close the polyline when needed */
|
||||
if (closed)
|
||||
{
|
||||
pd.header.type = CAIRO_PATH_CLOSE_PATH;
|
||||
pd.header.length = 1;
|
||||
|
||||
g_array_append_val (path_data, pd);
|
||||
}
|
||||
}
|
||||
|
||||
PikaBezierDesc *
|
||||
pika_bezier_desc_new_from_bound_segs (PikaBoundSeg *bound_segs,
|
||||
gint n_bound_segs,
|
||||
gint n_bound_groups)
|
||||
{
|
||||
GArray *path_data;
|
||||
PikaVector2 *points;
|
||||
gint n_points;
|
||||
gint seg;
|
||||
gint i;
|
||||
guint path_data_len;
|
||||
|
||||
g_return_val_if_fail (bound_segs != NULL, NULL);
|
||||
g_return_val_if_fail (n_bound_segs > 0, NULL);
|
||||
|
||||
path_data = g_array_new (FALSE, FALSE, sizeof (cairo_path_data_t));
|
||||
|
||||
points = g_new0 (PikaVector2, n_bound_segs + 4);
|
||||
|
||||
seg = 0;
|
||||
n_points = 0;
|
||||
|
||||
points[n_points].x = (gdouble) (bound_segs[0].x1);
|
||||
points[n_points].y = (gdouble) (bound_segs[0].y1);
|
||||
|
||||
n_points++;
|
||||
|
||||
for (i = 0; i < n_bound_groups; i++)
|
||||
{
|
||||
while (bound_segs[seg].x1 != -1 ||
|
||||
bound_segs[seg].x2 != -1 ||
|
||||
bound_segs[seg].y1 != -1 ||
|
||||
bound_segs[seg].y2 != -1)
|
||||
{
|
||||
points[n_points].x = (gdouble) (bound_segs[seg].x1);
|
||||
points[n_points].y = (gdouble) (bound_segs[seg].y1);
|
||||
|
||||
n_points++;
|
||||
seg++;
|
||||
}
|
||||
|
||||
/* Close the stroke points up */
|
||||
points[n_points] = points[0];
|
||||
|
||||
n_points++;
|
||||
|
||||
add_polyline (path_data, points, n_points, TRUE);
|
||||
|
||||
n_points = 0;
|
||||
seg++;
|
||||
|
||||
points[n_points].x = (gdouble) (bound_segs[seg].x1);
|
||||
points[n_points].y = (gdouble) (bound_segs[seg].y1);
|
||||
|
||||
n_points++;
|
||||
}
|
||||
|
||||
g_free (points);
|
||||
|
||||
path_data_len = path_data->len;
|
||||
|
||||
return pika_bezier_desc_new ((cairo_path_data_t *) g_array_free (path_data, FALSE),
|
||||
path_data_len);
|
||||
}
|
||||
|
||||
void
|
||||
pika_bezier_desc_translate (PikaBezierDesc *desc,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y)
|
||||
{
|
||||
gint i, j;
|
||||
|
||||
g_return_if_fail (desc != NULL);
|
||||
|
||||
for (i = 0; i < desc->num_data; i += desc->data[i].header.length)
|
||||
for (j = 1; j < desc->data[i].header.length; ++j)
|
||||
{
|
||||
desc->data[i+j].point.x += offset_x;
|
||||
desc->data[i+j].point.y += offset_y;
|
||||
}
|
||||
}
|
||||
|
||||
PikaBezierDesc *
|
||||
pika_bezier_desc_copy (const PikaBezierDesc *desc)
|
||||
{
|
||||
g_return_val_if_fail (desc != NULL, NULL);
|
||||
|
||||
return pika_bezier_desc_new (g_memdup2 (desc->data,
|
||||
desc->num_data * sizeof (cairo_path_data_t)),
|
||||
desc->num_data);
|
||||
}
|
||||
|
||||
void
|
||||
pika_bezier_desc_free (PikaBezierDesc *desc)
|
||||
{
|
||||
g_return_if_fail (desc != NULL);
|
||||
|
||||
g_free (desc->data);
|
||||
g_slice_free (PikaBezierDesc, desc);
|
||||
}
|
||||
51
app/core/pikabezierdesc.h
Normal file
51
app/core/pikabezierdesc.h
Normal file
@ -0,0 +1,51 @@
|
||||
/* 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
|
||||
*
|
||||
* pikabezierdesc.h
|
||||
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BEZIER_DESC_H__
|
||||
#define __PIKA_BEZIER_DESC_H__
|
||||
|
||||
|
||||
#define PIKA_TYPE_BEZIER_DESC (pika_bezier_desc_get_type ())
|
||||
|
||||
GType pika_bezier_desc_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
/* takes ownership of "data" */
|
||||
PikaBezierDesc * pika_bezier_desc_new (cairo_path_data_t *data,
|
||||
gint n_data);
|
||||
|
||||
/* expects sorted PikaBoundSegs */
|
||||
PikaBezierDesc * pika_bezier_desc_new_from_bound_segs (PikaBoundSeg *bound_segs,
|
||||
gint n_bound_segs,
|
||||
gint n_bound_groups);
|
||||
|
||||
void pika_bezier_desc_translate (PikaBezierDesc *desc,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y);
|
||||
|
||||
PikaBezierDesc * pika_bezier_desc_copy (const PikaBezierDesc *desc);
|
||||
void pika_bezier_desc_free (PikaBezierDesc *desc);
|
||||
|
||||
|
||||
#endif /* __PIKA_BEZIER_DESC_H__ */
|
||||
1020
app/core/pikaboundary.c
Normal file
1020
app/core/pikaboundary.c
Normal file
File diff suppressed because it is too large
Load Diff
72
app/core/pikaboundary.h
Normal file
72
app/core/pikaboundary.h
Normal file
@ -0,0 +1,72 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BOUNDARY_H__
|
||||
#define __PIKA_BOUNDARY_H__
|
||||
|
||||
|
||||
/* half intensity for mask */
|
||||
#define PIKA_BOUNDARY_HALF_WAY 0.5
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PIKA_BOUNDARY_WITHIN_BOUNDS,
|
||||
PIKA_BOUNDARY_IGNORE_BOUNDS
|
||||
} PikaBoundaryType;
|
||||
|
||||
|
||||
struct _PikaBoundSeg
|
||||
{
|
||||
gint x1;
|
||||
gint y1;
|
||||
gint x2;
|
||||
gint y2;
|
||||
guint open : 1;
|
||||
guint visited : 1;
|
||||
};
|
||||
|
||||
|
||||
PikaBoundSeg * pika_boundary_find (GeglBuffer *buffer,
|
||||
const GeglRectangle *region,
|
||||
const Babl *format,
|
||||
PikaBoundaryType type,
|
||||
gint x1,
|
||||
gint y1,
|
||||
gint x2,
|
||||
gint y2,
|
||||
gfloat threshold,
|
||||
gint *num_segs);
|
||||
PikaBoundSeg * pika_boundary_sort (const PikaBoundSeg *segs,
|
||||
gint num_segs,
|
||||
gint *num_groups);
|
||||
PikaBoundSeg * pika_boundary_simplify (PikaBoundSeg *sorted_segs,
|
||||
gint num_groups,
|
||||
gint *num_segs);
|
||||
|
||||
/* offsets in-place */
|
||||
void pika_boundary_offset (PikaBoundSeg *segs,
|
||||
gint num_segs,
|
||||
gint off_x,
|
||||
gint off_y);
|
||||
|
||||
|
||||
#endif /* __PIKA_BOUNDARY_H__ */
|
||||
134
app/core/pikabrush-boundary.c
Normal file
134
app/core/pikabrush-boundary.c
Normal file
@ -0,0 +1,134 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikabezierdesc.h"
|
||||
#include "pikaboundary.h"
|
||||
#include "pikabrush.h"
|
||||
#include "pikabrush-boundary.h"
|
||||
#include "pikatempbuf.h"
|
||||
|
||||
|
||||
static PikaBezierDesc *
|
||||
pika_brush_transform_boundary_exact (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness)
|
||||
{
|
||||
const PikaTempBuf *mask;
|
||||
|
||||
mask = pika_brush_transform_mask (brush,
|
||||
scale, aspect_ratio,
|
||||
angle, reflect, hardness);
|
||||
|
||||
if (mask)
|
||||
{
|
||||
GeglBuffer *buffer;
|
||||
PikaBoundSeg *bound_segs;
|
||||
gint n_bound_segs;
|
||||
|
||||
buffer = pika_temp_buf_create_buffer ((PikaTempBuf *) mask);
|
||||
|
||||
bound_segs = pika_boundary_find (buffer, NULL,
|
||||
babl_format ("Y float"),
|
||||
PIKA_BOUNDARY_WITHIN_BOUNDS,
|
||||
0, 0,
|
||||
gegl_buffer_get_width (buffer),
|
||||
gegl_buffer_get_height (buffer),
|
||||
0.0,
|
||||
&n_bound_segs);
|
||||
|
||||
g_object_unref (buffer);
|
||||
|
||||
if (bound_segs)
|
||||
{
|
||||
PikaBoundSeg *stroke_segs;
|
||||
gint n_stroke_groups;
|
||||
|
||||
stroke_segs = pika_boundary_sort (bound_segs, n_bound_segs,
|
||||
&n_stroke_groups);
|
||||
|
||||
g_free (bound_segs);
|
||||
|
||||
if (stroke_segs)
|
||||
{
|
||||
PikaBezierDesc *path;
|
||||
|
||||
path = pika_bezier_desc_new_from_bound_segs (stroke_segs,
|
||||
n_bound_segs,
|
||||
n_stroke_groups);
|
||||
|
||||
g_free (stroke_segs);
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PikaBezierDesc *
|
||||
pika_brush_transform_boundary_approx (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness)
|
||||
{
|
||||
return pika_brush_transform_boundary_exact (brush,
|
||||
scale, aspect_ratio,
|
||||
angle, reflect, hardness);
|
||||
}
|
||||
|
||||
PikaBezierDesc *
|
||||
pika_brush_real_transform_boundary (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness,
|
||||
gint *width,
|
||||
gint *height)
|
||||
{
|
||||
pika_brush_transform_size (brush, scale, aspect_ratio, angle, reflect,
|
||||
width, height);
|
||||
|
||||
if (*width < 256 && *height < 256)
|
||||
{
|
||||
return pika_brush_transform_boundary_exact (brush,
|
||||
scale, aspect_ratio,
|
||||
angle, reflect, hardness);
|
||||
}
|
||||
|
||||
return pika_brush_transform_boundary_approx (brush,
|
||||
scale, aspect_ratio,
|
||||
angle, reflect, hardness);
|
||||
}
|
||||
36
app/core/pikabrush-boundary.h
Normal file
36
app/core/pikabrush-boundary.h
Normal file
@ -0,0 +1,36 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BRUSH_BOUNDARY_H__
|
||||
#define __PIKA_BRUSH_BOUNDARY_H__
|
||||
|
||||
|
||||
PikaBezierDesc * pika_brush_real_transform_boundary (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness,
|
||||
gint *width,
|
||||
gint *height);
|
||||
|
||||
|
||||
#endif /* __PIKA_BRUSH_BOUNDARY_H__ */
|
||||
53
app/core/pikabrush-header.h
Normal file
53
app/core/pikabrush-header.h
Normal file
@ -0,0 +1,53 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BRUSH_HEADER_H__
|
||||
#define __PIKA_BRUSH_HEADER_H__
|
||||
|
||||
|
||||
#define PIKA_BRUSH_MAGIC (('G' << 24) + ('I' << 16) + \
|
||||
('M' << 8) + ('P' << 0))
|
||||
#define PIKA_BRUSH_MAX_SIZE 10000 /* Max size in either dimension in px */
|
||||
#define PIKA_BRUSH_MAX_NAME 256 /* Max length of the brush's name */
|
||||
|
||||
|
||||
/* All field entries are MSB */
|
||||
|
||||
typedef struct _PikaBrushHeader PikaBrushHeader;
|
||||
|
||||
struct _PikaBrushHeader
|
||||
{
|
||||
guint32 header_size; /* = sizeof (PikaBrushHeader) + brush name */
|
||||
guint32 version; /* brush file version # */
|
||||
guint32 width; /* width of brush */
|
||||
guint32 height; /* height of brush */
|
||||
guint32 bytes; /* depth of brush in bytes */
|
||||
guint32 magic_number; /* PIKA brush magic number */
|
||||
guint32 spacing; /* brush spacing */
|
||||
};
|
||||
|
||||
/* In a brush file, next comes the brush name, null-terminated.
|
||||
* After that comes the brush data -- width * height * bytes bytes of
|
||||
* it...
|
||||
*/
|
||||
|
||||
|
||||
#endif /* __PIKA_BRUSH_HEADER_H__ */
|
||||
1217
app/core/pikabrush-load.c
Normal file
1217
app/core/pikabrush-load.c
Normal file
File diff suppressed because it is too large
Load Diff
47
app/core/pikabrush-load.h
Normal file
47
app/core/pikabrush-load.h
Normal file
@ -0,0 +1,47 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BRUSH_LOAD_H__
|
||||
#define __PIKA_BRUSH_LOAD_H__
|
||||
|
||||
|
||||
#define PIKA_BRUSH_FILE_EXTENSION ".gbr"
|
||||
#define PIKA_BRUSH_PIXMAP_FILE_EXTENSION ".gpb"
|
||||
#define PIKA_BRUSH_PS_FILE_EXTENSION ".abr"
|
||||
#define PIKA_BRUSH_PSP_FILE_EXTENSION ".jbr"
|
||||
|
||||
|
||||
GList * pika_brush_load (PikaContext *context,
|
||||
GFile *file,
|
||||
GInputStream *input,
|
||||
GError **error);
|
||||
PikaBrush * pika_brush_load_brush (PikaContext *context,
|
||||
GFile *file,
|
||||
GInputStream *input,
|
||||
GError **error);
|
||||
|
||||
GList * pika_brush_load_abr (PikaContext *context,
|
||||
GFile *file,
|
||||
GInputStream *input,
|
||||
GError **error);
|
||||
|
||||
|
||||
#endif /* __PIKA_BRUSH_LOAD_H__ */
|
||||
518
app/core/pikabrush-mipmap.cc
Normal file
518
app/core/pikabrush-mipmap.cc
Normal file
@ -0,0 +1,518 @@
|
||||
/* 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
|
||||
*
|
||||
* pikabrush-mipmap.c
|
||||
* Copyright (C) 2020 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikabrush.h"
|
||||
#include "pikabrush-mipmap.h"
|
||||
#include "pikabrush-private.h"
|
||||
#include "pikatempbuf.h"
|
||||
|
||||
} /* extern "C" */
|
||||
|
||||
|
||||
#define PIXELS_PER_THREAD \
|
||||
(/* each thread costs as much as */ 64.0 * 64.0 /* pixels */)
|
||||
|
||||
#define PIKA_BRUSH_MIPMAP(brush, mipmaps, x, y) \
|
||||
((*(mipmaps))[(y) * (brush)->priv->n_horz_mipmaps + (x)])
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_brush_mipmap_clear (PikaBrush *brush,
|
||||
PikaTempBuf ***mipmaps);
|
||||
|
||||
static const PikaTempBuf * pika_brush_mipmap_get (PikaBrush *brush,
|
||||
const PikaTempBuf *source,
|
||||
PikaTempBuf ***mipmaps,
|
||||
gdouble *scale_x,
|
||||
gdouble *scale_y);
|
||||
|
||||
static PikaTempBuf * pika_brush_mipmap_downscale (const PikaTempBuf *source);
|
||||
static PikaTempBuf * pika_brush_mipmap_downscale_horz (const PikaTempBuf *source);
|
||||
static PikaTempBuf * pika_brush_mipmap_downscale_vert (const PikaTempBuf *source);
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static void
|
||||
pika_brush_mipmap_clear (PikaBrush *brush,
|
||||
PikaTempBuf ***mipmaps)
|
||||
{
|
||||
if (*mipmaps)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0;
|
||||
i < brush->priv->n_horz_mipmaps * brush->priv->n_vert_mipmaps;
|
||||
i++)
|
||||
{
|
||||
g_clear_pointer (&(*mipmaps)[i], pika_temp_buf_unref);
|
||||
}
|
||||
|
||||
g_clear_pointer (mipmaps, g_free);
|
||||
}
|
||||
}
|
||||
|
||||
static const PikaTempBuf *
|
||||
pika_brush_mipmap_get (PikaBrush *brush,
|
||||
const PikaTempBuf *source,
|
||||
PikaTempBuf ***mipmaps,
|
||||
gdouble *scale_x,
|
||||
gdouble *scale_y)
|
||||
{
|
||||
gint x;
|
||||
gint y;
|
||||
gint i;
|
||||
|
||||
if (! source)
|
||||
return NULL;
|
||||
|
||||
if (! *mipmaps)
|
||||
{
|
||||
gint width = pika_temp_buf_get_width (source);
|
||||
gint height = pika_temp_buf_get_height (source);
|
||||
|
||||
brush->priv->n_horz_mipmaps = floor (log (width) / M_LN2) + 1;
|
||||
brush->priv->n_vert_mipmaps = floor (log (height) / M_LN2) + 1;
|
||||
|
||||
*mipmaps = g_new0 (PikaTempBuf *, brush->priv->n_horz_mipmaps *
|
||||
brush->priv->n_vert_mipmaps);
|
||||
|
||||
PIKA_BRUSH_MIPMAP (brush, mipmaps, 0, 0) = pika_temp_buf_ref (source);
|
||||
}
|
||||
|
||||
x = floor (SAFE_CLAMP (log (1.0 / MAX (*scale_x, 0.0)) / M_LN2,
|
||||
0, brush->priv->n_horz_mipmaps - 1));
|
||||
y = floor (SAFE_CLAMP (log (1.0 / MAX (*scale_y, 0.0)) / M_LN2,
|
||||
0, brush->priv->n_vert_mipmaps - 1));
|
||||
|
||||
*scale_x *= pow (2.0, x);
|
||||
*scale_y *= pow (2.0, y);
|
||||
|
||||
if (PIKA_BRUSH_MIPMAP (brush, mipmaps, x, y))
|
||||
return PIKA_BRUSH_MIPMAP (brush, mipmaps, x, y);
|
||||
|
||||
g_return_val_if_fail (x >= 0 || y >= 0, NULL);
|
||||
|
||||
for (i = 1; i <= x + y; i++)
|
||||
{
|
||||
gint u = x - i;
|
||||
gint v = y;
|
||||
|
||||
if (u < 0)
|
||||
{
|
||||
v += u;
|
||||
u = 0;
|
||||
}
|
||||
|
||||
while (u <= x && v >= 0)
|
||||
{
|
||||
if (PIKA_BRUSH_MIPMAP (brush, mipmaps, u, v))
|
||||
{
|
||||
for (; x - u > y - v; u++)
|
||||
{
|
||||
PIKA_BRUSH_MIPMAP (brush, mipmaps, u + 1, v) =
|
||||
pika_brush_mipmap_downscale_horz (
|
||||
PIKA_BRUSH_MIPMAP (brush, mipmaps, u, v));
|
||||
}
|
||||
|
||||
for (; y - v > x - u; v++)
|
||||
{
|
||||
PIKA_BRUSH_MIPMAP (brush, mipmaps, u, v + 1) =
|
||||
pika_brush_mipmap_downscale_vert (
|
||||
PIKA_BRUSH_MIPMAP (brush, mipmaps, u, v));
|
||||
}
|
||||
|
||||
for (; u < x; u++, v++)
|
||||
{
|
||||
PIKA_BRUSH_MIPMAP (brush, mipmaps, u + 1, v + 1) =
|
||||
pika_brush_mipmap_downscale (
|
||||
PIKA_BRUSH_MIPMAP (brush, mipmaps, u, v));
|
||||
}
|
||||
|
||||
return PIKA_BRUSH_MIPMAP (brush, mipmaps, u, v);
|
||||
}
|
||||
|
||||
u++;
|
||||
v--;
|
||||
}
|
||||
}
|
||||
|
||||
g_return_val_if_reached (NULL);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct MipmapTraits;
|
||||
|
||||
template <>
|
||||
struct MipmapTraits<guint8>
|
||||
{
|
||||
static guint8
|
||||
mix (guint8 a,
|
||||
guint8 b)
|
||||
{
|
||||
return ((guint32) a + (guint32) b + 1) / 2;
|
||||
}
|
||||
|
||||
static guint8
|
||||
mix (guint8 a,
|
||||
guint8 b,
|
||||
guint8 c,
|
||||
guint8 d)
|
||||
{
|
||||
return ((guint32) a + (guint32) b + (guint32) c + (guint32) d + 2) / 4;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MipmapTraits<gfloat>
|
||||
{
|
||||
static gfloat
|
||||
mix (gfloat a,
|
||||
gfloat b)
|
||||
{
|
||||
return (a + b) / 2.0;
|
||||
}
|
||||
|
||||
static gfloat
|
||||
mix (gfloat a,
|
||||
gfloat b,
|
||||
gfloat c,
|
||||
gfloat d)
|
||||
{
|
||||
return (a + b + c + d) / 4.0;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T,
|
||||
gint N>
|
||||
struct MipmapAlgorithms
|
||||
{
|
||||
static PikaTempBuf *
|
||||
downscale (const PikaTempBuf *source)
|
||||
{
|
||||
PikaTempBuf *destination;
|
||||
gint width = pika_temp_buf_get_width (source);
|
||||
gint height = pika_temp_buf_get_height (source);
|
||||
|
||||
width /= 2;
|
||||
height /= 2;
|
||||
|
||||
destination = pika_temp_buf_new (width, height,
|
||||
pika_temp_buf_get_format (source));
|
||||
|
||||
gegl_parallel_distribute_area (
|
||||
GEGL_RECTANGLE (0, 0, width, height), PIXELS_PER_THREAD,
|
||||
[=] (const GeglRectangle *area)
|
||||
{
|
||||
const T *src0 = (const T *) pika_temp_buf_get_data (source);
|
||||
T *dest0 = (T *) pika_temp_buf_get_data (destination);
|
||||
gint src_stride = N * pika_temp_buf_get_width (source);
|
||||
gint dest_stride = N * pika_temp_buf_get_width (destination);
|
||||
gint y;
|
||||
|
||||
src0 += 2 * (area->y * src_stride + N * area->x);
|
||||
dest0 += area->y * dest_stride + N * area->x;
|
||||
|
||||
for (y = 0; y < area->height; y++)
|
||||
{
|
||||
const T *src = src0;
|
||||
T *dest = dest0;
|
||||
gint x;
|
||||
|
||||
for (x = 0; x < area->width; x++)
|
||||
{
|
||||
gint c;
|
||||
|
||||
for (c = 0; c < N; c++)
|
||||
{
|
||||
dest[c] = MipmapTraits<T>::mix (src[c],
|
||||
src[N + c],
|
||||
src[src_stride + c],
|
||||
src[src_stride + N + c]);
|
||||
}
|
||||
|
||||
src += 2 * N;
|
||||
dest += N;
|
||||
}
|
||||
|
||||
src0 += 2 * src_stride;
|
||||
dest0 += dest_stride;
|
||||
}
|
||||
});
|
||||
|
||||
return destination;
|
||||
}
|
||||
|
||||
static PikaTempBuf *
|
||||
downscale_horz (const PikaTempBuf *source)
|
||||
{
|
||||
PikaTempBuf *destination;
|
||||
gint width = pika_temp_buf_get_width (source);
|
||||
gint height = pika_temp_buf_get_height (source);
|
||||
|
||||
width /= 2;
|
||||
|
||||
destination = pika_temp_buf_new (width, height,
|
||||
pika_temp_buf_get_format (source));
|
||||
|
||||
gegl_parallel_distribute_range (
|
||||
height, PIXELS_PER_THREAD / width,
|
||||
[=] (gint offset,
|
||||
gint size)
|
||||
{
|
||||
const T *src0 = (const T *) pika_temp_buf_get_data (source);
|
||||
T *dest0 = (T *) pika_temp_buf_get_data (destination);
|
||||
gint src_stride = N * pika_temp_buf_get_width (source);
|
||||
gint dest_stride = N * pika_temp_buf_get_width (destination);
|
||||
gint y;
|
||||
|
||||
src0 += offset * src_stride;
|
||||
dest0 += offset * dest_stride;
|
||||
|
||||
for (y = 0; y < size; y++)
|
||||
{
|
||||
const T *src = src0;
|
||||
T *dest = dest0;
|
||||
gint x;
|
||||
|
||||
for (x = 0; x < width; x++)
|
||||
{
|
||||
gint c;
|
||||
|
||||
for (c = 0; c < N; c++)
|
||||
dest[c] = MipmapTraits<T>::mix (src[c], src[N + c]);
|
||||
|
||||
src += 2 * N;
|
||||
dest += N;
|
||||
}
|
||||
|
||||
src0 += src_stride;
|
||||
dest0 += dest_stride;
|
||||
}
|
||||
});
|
||||
|
||||
return destination;
|
||||
}
|
||||
|
||||
static PikaTempBuf *
|
||||
downscale_vert (const PikaTempBuf *source)
|
||||
{
|
||||
PikaTempBuf *destination;
|
||||
gint width = pika_temp_buf_get_width (source);
|
||||
gint height = pika_temp_buf_get_height (source);
|
||||
|
||||
height /= 2;
|
||||
|
||||
destination = pika_temp_buf_new (width, height,
|
||||
pika_temp_buf_get_format (source));
|
||||
|
||||
gegl_parallel_distribute_range (
|
||||
width, PIXELS_PER_THREAD / height,
|
||||
[=] (gint offset,
|
||||
gint size)
|
||||
{
|
||||
const T *src0 = (const T *) pika_temp_buf_get_data (source);
|
||||
T *dest0 = (T *) pika_temp_buf_get_data (destination);
|
||||
gint src_stride = N * pika_temp_buf_get_width (source);
|
||||
gint dest_stride = N * pika_temp_buf_get_width (destination);
|
||||
gint x;
|
||||
|
||||
src0 += offset * N;
|
||||
dest0 += offset * N;
|
||||
|
||||
for (x = 0; x < size; x++)
|
||||
{
|
||||
const T *src = src0;
|
||||
T *dest = dest0;
|
||||
gint y;
|
||||
|
||||
for (y = 0; y < height; y++)
|
||||
{
|
||||
gint c;
|
||||
|
||||
for (c = 0; c < N; c++)
|
||||
dest[c] = MipmapTraits<T>::mix (src[c], src[src_stride + c]);
|
||||
|
||||
src += 2 * src_stride;
|
||||
dest += dest_stride;
|
||||
}
|
||||
|
||||
src0 += N;
|
||||
dest0 += N;
|
||||
}
|
||||
});
|
||||
|
||||
return destination;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Func>
|
||||
static PikaTempBuf *
|
||||
pika_brush_mipmap_dispatch (const PikaTempBuf *source,
|
||||
Func func)
|
||||
{
|
||||
const Babl *format = pika_temp_buf_get_format (source);
|
||||
const Babl *type;
|
||||
gint n_components;
|
||||
|
||||
type = babl_format_get_type (format, 0);
|
||||
n_components = babl_format_get_n_components (format);
|
||||
|
||||
if (type == babl_type ("u8"))
|
||||
{
|
||||
switch (n_components)
|
||||
{
|
||||
case 1:
|
||||
return func (MipmapAlgorithms<guint8, 1> ());
|
||||
|
||||
case 3:
|
||||
return func (MipmapAlgorithms<guint8, 3> ());
|
||||
}
|
||||
}
|
||||
else if (type == babl_type ("float"))
|
||||
{
|
||||
switch (n_components)
|
||||
{
|
||||
case 1:
|
||||
return func (MipmapAlgorithms<gfloat, 1> ());
|
||||
|
||||
case 3:
|
||||
return func (MipmapAlgorithms<gfloat, 3> ());
|
||||
}
|
||||
}
|
||||
|
||||
g_return_val_if_reached (NULL);
|
||||
}
|
||||
|
||||
static PikaTempBuf *
|
||||
pika_brush_mipmap_downscale (const PikaTempBuf *source)
|
||||
{
|
||||
return pika_brush_mipmap_dispatch (
|
||||
source,
|
||||
[&] (auto algorithms)
|
||||
{
|
||||
return algorithms.downscale (source);
|
||||
});
|
||||
}
|
||||
|
||||
static PikaTempBuf *
|
||||
pika_brush_mipmap_downscale_horz (const PikaTempBuf *source)
|
||||
{
|
||||
return pika_brush_mipmap_dispatch (
|
||||
source,
|
||||
[&] (auto algorithms)
|
||||
{
|
||||
return algorithms.downscale_horz (source);
|
||||
});
|
||||
}
|
||||
|
||||
static PikaTempBuf *
|
||||
pika_brush_mipmap_downscale_vert (const PikaTempBuf *source)
|
||||
{
|
||||
return pika_brush_mipmap_dispatch (
|
||||
source,
|
||||
[&] (auto algorithms)
|
||||
{
|
||||
return algorithms.downscale_vert (source);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
void
|
||||
pika_brush_mipmap_clear (PikaBrush *brush)
|
||||
{
|
||||
pika_brush_mipmap_clear (brush, &brush->priv->mask_mipmaps);
|
||||
pika_brush_mipmap_clear (brush, &brush->priv->pixmap_mipmaps);
|
||||
}
|
||||
|
||||
const PikaTempBuf *
|
||||
pika_brush_mipmap_get_mask (PikaBrush *brush,
|
||||
gdouble *scale_x,
|
||||
gdouble *scale_y)
|
||||
{
|
||||
return pika_brush_mipmap_get (brush,
|
||||
brush->priv->mask,
|
||||
&brush->priv->mask_mipmaps,
|
||||
scale_x, scale_y);
|
||||
}
|
||||
|
||||
const PikaTempBuf *
|
||||
pika_brush_mipmap_get_pixmap (PikaBrush *brush,
|
||||
gdouble *scale_x,
|
||||
gdouble *scale_y)
|
||||
{
|
||||
return pika_brush_mipmap_get (brush,
|
||||
brush->priv->pixmap,
|
||||
&brush->priv->pixmap_mipmaps,
|
||||
scale_x, scale_y);
|
||||
}
|
||||
|
||||
gsize
|
||||
pika_brush_mipmap_get_memsize (PikaBrush *brush)
|
||||
{
|
||||
gsize memsize = 0;
|
||||
|
||||
if (brush->priv->mask_mipmaps)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 1;
|
||||
i < brush->priv->n_horz_mipmaps * brush->priv->n_vert_mipmaps;
|
||||
i++)
|
||||
{
|
||||
memsize += pika_temp_buf_get_memsize (brush->priv->mask_mipmaps[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (brush->priv->pixmap_mipmaps)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 1;
|
||||
i < brush->priv->n_horz_mipmaps * brush->priv->n_vert_mipmaps;
|
||||
i++)
|
||||
{
|
||||
memsize += pika_temp_buf_get_memsize (brush->priv->pixmap_mipmaps[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return memsize;
|
||||
}
|
||||
42
app/core/pikabrush-mipmap.h
Normal file
42
app/core/pikabrush-mipmap.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* 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
|
||||
*
|
||||
* pikabrush-mipmap.h
|
||||
* Copyright (C) 2020 Ell
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BRUSH_MIPMAP_H__
|
||||
#define __PIKA_BRUSH_MIPMAP_H__
|
||||
|
||||
|
||||
void pika_brush_mipmap_clear (PikaBrush *brush);
|
||||
|
||||
const PikaTempBuf * pika_brush_mipmap_get_mask (PikaBrush *brush,
|
||||
gdouble *scale_x,
|
||||
gdouble *scale_y);
|
||||
|
||||
const PikaTempBuf * pika_brush_mipmap_get_pixmap (PikaBrush *brush,
|
||||
gdouble *scale_x,
|
||||
gdouble *scale_y);
|
||||
|
||||
gsize pika_brush_mipmap_get_memsize (PikaBrush *brush);
|
||||
|
||||
|
||||
#endif /* __PIKA_BRUSH_MIPMAP_H__ */
|
||||
51
app/core/pikabrush-private.h
Normal file
51
app/core/pikabrush-private.h
Normal file
@ -0,0 +1,51 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BRUSH_PRIVATE_H__
|
||||
#define __PIKA_BRUSH_PRIVATE_H__
|
||||
|
||||
|
||||
struct _PikaBrushPrivate
|
||||
{
|
||||
PikaTempBuf *mask; /* the actual mask */
|
||||
PikaTempBuf *blurred_mask; /* blurred actual mask cached */
|
||||
PikaTempBuf *pixmap; /* optional pixmap data */
|
||||
PikaTempBuf *blurred_pixmap; /* optional pixmap data blurred cache */
|
||||
|
||||
gdouble blur_hardness;
|
||||
|
||||
gint n_horz_mipmaps;
|
||||
gint n_vert_mipmaps;
|
||||
PikaTempBuf **mask_mipmaps;
|
||||
PikaTempBuf **pixmap_mipmaps;
|
||||
|
||||
gint spacing; /* brush's spacing */
|
||||
PikaVector2 x_axis; /* for calculating brush spacing */
|
||||
PikaVector2 y_axis; /* for calculating brush spacing */
|
||||
|
||||
gint use_count; /* for keeping the caches alive */
|
||||
PikaBrushCache *mask_cache;
|
||||
PikaBrushCache *pixmap_cache;
|
||||
PikaBrushCache *boundary_cache;
|
||||
};
|
||||
|
||||
|
||||
#endif /* __PIKA_BRUSH_PRIVATE_H__ */
|
||||
111
app/core/pikabrush-save.c
Normal file
111
app/core/pikabrush-save.c
Normal file
@ -0,0 +1,111 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikabrush.h"
|
||||
#include "pikabrush-header.h"
|
||||
#include "pikabrush-save.h"
|
||||
#include "pikatempbuf.h"
|
||||
|
||||
|
||||
gboolean
|
||||
pika_brush_save (PikaData *data,
|
||||
GOutputStream *output,
|
||||
GError **error)
|
||||
{
|
||||
PikaBrush *brush = PIKA_BRUSH (data);
|
||||
PikaTempBuf *mask = pika_brush_get_mask (brush);
|
||||
PikaTempBuf *pixmap = pika_brush_get_pixmap (brush);
|
||||
PikaBrushHeader header;
|
||||
const gchar *name;
|
||||
gint width;
|
||||
gint height;
|
||||
|
||||
name = pika_object_get_name (brush);
|
||||
width = pika_temp_buf_get_width (mask);
|
||||
height = pika_temp_buf_get_height (mask);
|
||||
|
||||
header.header_size = g_htonl (sizeof (PikaBrushHeader) +
|
||||
strlen (name) + 1);
|
||||
header.version = g_htonl (2);
|
||||
header.width = g_htonl (width);
|
||||
header.height = g_htonl (height);
|
||||
header.bytes = g_htonl (pixmap ? 4 : 1);
|
||||
header.magic_number = g_htonl (PIKA_BRUSH_MAGIC);
|
||||
header.spacing = g_htonl (pika_brush_get_spacing (brush));
|
||||
|
||||
if (! g_output_stream_write_all (output, &header, sizeof (header),
|
||||
NULL, NULL, error))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (! g_output_stream_write_all (output, name, strlen (name) + 1,
|
||||
NULL, NULL, error))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (pixmap)
|
||||
{
|
||||
gsize size = width * height * 4;
|
||||
guchar *data = g_malloc (size);
|
||||
guchar *p = pika_temp_buf_get_data (pixmap);
|
||||
guchar *m = pika_temp_buf_get_data (mask);
|
||||
guchar *d = data;
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < width * height; i++)
|
||||
{
|
||||
*d++ = *p++;
|
||||
*d++ = *p++;
|
||||
*d++ = *p++;
|
||||
*d++ = *m++;
|
||||
}
|
||||
|
||||
if (! g_output_stream_write_all (output, data, size,
|
||||
NULL, NULL, error))
|
||||
{
|
||||
g_free (data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_free (data);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! g_output_stream_write_all (output,
|
||||
pika_temp_buf_get_data (mask),
|
||||
pika_temp_buf_get_data_size (mask),
|
||||
NULL, NULL, error))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
32
app/core/pikabrush-save.h
Normal file
32
app/core/pikabrush-save.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BRUSH_SAVE_H__
|
||||
#define __PIKA_BRUSH_SAVE_H__
|
||||
|
||||
|
||||
/* don't call this function directly, use pika_data_save() instead */
|
||||
gboolean pika_brush_save (PikaData *data,
|
||||
GOutputStream *output,
|
||||
GError **error);
|
||||
|
||||
|
||||
#endif /* __PIKA_BRUSH_SAVE_H__ */
|
||||
1047
app/core/pikabrush-transform.cc
Normal file
1047
app/core/pikabrush-transform.cc
Normal file
File diff suppressed because it is too large
Load Diff
63
app/core/pikabrush-transform.h
Normal file
63
app/core/pikabrush-transform.h
Normal file
@ -0,0 +1,63 @@
|
||||
/* 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
|
||||
*
|
||||
* pikabrush-transform.h
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BRUSH_TRANSFORM_H__
|
||||
#define __PIKA_BRUSH_TRANSFORM_H__
|
||||
|
||||
|
||||
/* virtual functions of PikaBrush, don't call directly */
|
||||
|
||||
void pika_brush_real_transform_size (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gint *scaled_width,
|
||||
gint *scaled_height);
|
||||
PikaTempBuf * pika_brush_real_transform_mask (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness);
|
||||
PikaTempBuf * pika_brush_real_transform_pixmap (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness);
|
||||
|
||||
void pika_brush_transform_get_scale (gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble *scale_x,
|
||||
gdouble *scale_y);
|
||||
void pika_brush_transform_matrix (gdouble width,
|
||||
gdouble height,
|
||||
gdouble scale_x,
|
||||
gdouble scale_y,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
PikaMatrix3 *matrix);
|
||||
|
||||
|
||||
#endif /* __PIKA_BRUSH_TRANSFORM_H__ */
|
||||
942
app/core/pikabrush.c
Normal file
942
app/core/pikabrush.c
Normal file
@ -0,0 +1,942 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cairo.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikabezierdesc.h"
|
||||
#include "pikabrush.h"
|
||||
#include "pikabrush-boundary.h"
|
||||
#include "pikabrush-load.h"
|
||||
#include "pikabrush-mipmap.h"
|
||||
#include "pikabrush-private.h"
|
||||
#include "pikabrush-save.h"
|
||||
#include "pikabrush-transform.h"
|
||||
#include "pikabrushcache.h"
|
||||
#include "pikabrushgenerated.h"
|
||||
#include "pikabrushpipe.h"
|
||||
#include "pikatagged.h"
|
||||
#include "pikatempbuf.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
SPACING_CHANGED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_SPACING
|
||||
};
|
||||
|
||||
|
||||
static void pika_brush_tagged_iface_init (PikaTaggedInterface *iface);
|
||||
|
||||
static void pika_brush_finalize (GObject *object);
|
||||
static void pika_brush_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_brush_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static gint64 pika_brush_get_memsize (PikaObject *object,
|
||||
gint64 *gui_size);
|
||||
|
||||
static gboolean pika_brush_get_size (PikaViewable *viewable,
|
||||
gint *width,
|
||||
gint *height);
|
||||
static PikaTempBuf * pika_brush_get_new_preview (PikaViewable *viewable,
|
||||
PikaContext *context,
|
||||
gint width,
|
||||
gint height);
|
||||
static gchar * pika_brush_get_description (PikaViewable *viewable,
|
||||
gchar **tooltip);
|
||||
|
||||
static void pika_brush_dirty (PikaData *data);
|
||||
static const gchar * pika_brush_get_extension (PikaData *data);
|
||||
static void pika_brush_copy (PikaData *data,
|
||||
PikaData *src_data);
|
||||
|
||||
static void pika_brush_real_begin_use (PikaBrush *brush);
|
||||
static void pika_brush_real_end_use (PikaBrush *brush);
|
||||
static PikaBrush * pika_brush_real_select_brush (PikaBrush *brush,
|
||||
const PikaCoords *last_coords,
|
||||
const PikaCoords *current_coords);
|
||||
static gboolean pika_brush_real_want_null_motion (PikaBrush *brush,
|
||||
const PikaCoords *last_coords,
|
||||
const PikaCoords *current_coords);
|
||||
|
||||
static gchar * pika_brush_get_checksum (PikaTagged *tagged);
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (PikaBrush, pika_brush, PIKA_TYPE_DATA,
|
||||
G_ADD_PRIVATE (PikaBrush)
|
||||
G_IMPLEMENT_INTERFACE (PIKA_TYPE_TAGGED,
|
||||
pika_brush_tagged_iface_init))
|
||||
|
||||
#define parent_class pika_brush_parent_class
|
||||
|
||||
static guint brush_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
||||
static void
|
||||
pika_brush_class_init (PikaBrushClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaObjectClass *pika_object_class = PIKA_OBJECT_CLASS (klass);
|
||||
PikaViewableClass *viewable_class = PIKA_VIEWABLE_CLASS (klass);
|
||||
PikaDataClass *data_class = PIKA_DATA_CLASS (klass);
|
||||
|
||||
brush_signals[SPACING_CHANGED] =
|
||||
g_signal_new ("spacing-changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (PikaBrushClass, spacing_changed),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
object_class->finalize = pika_brush_finalize;
|
||||
object_class->get_property = pika_brush_get_property;
|
||||
object_class->set_property = pika_brush_set_property;
|
||||
|
||||
pika_object_class->get_memsize = pika_brush_get_memsize;
|
||||
|
||||
viewable_class->default_icon_name = "pika-tool-paintbrush";
|
||||
viewable_class->get_size = pika_brush_get_size;
|
||||
viewable_class->get_new_preview = pika_brush_get_new_preview;
|
||||
viewable_class->get_description = pika_brush_get_description;
|
||||
|
||||
data_class->dirty = pika_brush_dirty;
|
||||
data_class->save = pika_brush_save;
|
||||
data_class->get_extension = pika_brush_get_extension;
|
||||
data_class->copy = pika_brush_copy;
|
||||
|
||||
klass->begin_use = pika_brush_real_begin_use;
|
||||
klass->end_use = pika_brush_real_end_use;
|
||||
klass->select_brush = pika_brush_real_select_brush;
|
||||
klass->want_null_motion = pika_brush_real_want_null_motion;
|
||||
klass->transform_size = pika_brush_real_transform_size;
|
||||
klass->transform_mask = pika_brush_real_transform_mask;
|
||||
klass->transform_pixmap = pika_brush_real_transform_pixmap;
|
||||
klass->transform_boundary = pika_brush_real_transform_boundary;
|
||||
klass->spacing_changed = NULL;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SPACING,
|
||||
g_param_spec_double ("spacing", NULL,
|
||||
_("Brush Spacing"),
|
||||
1.0, 5000.0, 20.0,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_tagged_iface_init (PikaTaggedInterface *iface)
|
||||
{
|
||||
iface->get_checksum = pika_brush_get_checksum;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_init (PikaBrush *brush)
|
||||
{
|
||||
brush->priv = pika_brush_get_instance_private (brush);
|
||||
|
||||
brush->priv->spacing = 20;
|
||||
brush->priv->x_axis.x = 15.0;
|
||||
brush->priv->x_axis.y = 0.0;
|
||||
brush->priv->y_axis.x = 0.0;
|
||||
brush->priv->y_axis.y = 15.0;
|
||||
|
||||
brush->priv->blur_hardness = 1.0;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_finalize (GObject *object)
|
||||
{
|
||||
PikaBrush *brush = PIKA_BRUSH (object);
|
||||
|
||||
g_clear_pointer (&brush->priv->mask, pika_temp_buf_unref);
|
||||
g_clear_pointer (&brush->priv->pixmap, pika_temp_buf_unref);
|
||||
g_clear_pointer (&brush->priv->blurred_mask, pika_temp_buf_unref);
|
||||
g_clear_pointer (&brush->priv->blurred_pixmap, pika_temp_buf_unref);
|
||||
|
||||
pika_brush_mipmap_clear (brush);
|
||||
|
||||
g_clear_object (&brush->priv->mask_cache);
|
||||
g_clear_object (&brush->priv->pixmap_cache);
|
||||
g_clear_object (&brush->priv->boundary_cache);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaBrush *brush = PIKA_BRUSH (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_SPACING:
|
||||
pika_brush_set_spacing (brush, g_value_get_double (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaBrush *brush = PIKA_BRUSH (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_SPACING:
|
||||
g_value_set_double (value, pika_brush_get_spacing (brush));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gint64
|
||||
pika_brush_get_memsize (PikaObject *object,
|
||||
gint64 *gui_size)
|
||||
{
|
||||
PikaBrush *brush = PIKA_BRUSH (object);
|
||||
gint64 memsize = 0;
|
||||
|
||||
memsize += pika_temp_buf_get_memsize (brush->priv->mask);
|
||||
memsize += pika_temp_buf_get_memsize (brush->priv->pixmap);
|
||||
|
||||
memsize += pika_brush_mipmap_get_memsize (brush);
|
||||
|
||||
return memsize + PIKA_OBJECT_CLASS (parent_class)->get_memsize (object,
|
||||
gui_size);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_brush_get_size (PikaViewable *viewable,
|
||||
gint *width,
|
||||
gint *height)
|
||||
{
|
||||
PikaBrush *brush = PIKA_BRUSH (viewable);
|
||||
|
||||
*width = pika_temp_buf_get_width (brush->priv->mask);
|
||||
*height = pika_temp_buf_get_height (brush->priv->mask);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static PikaTempBuf *
|
||||
pika_brush_get_new_preview (PikaViewable *viewable,
|
||||
PikaContext *context,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
PikaBrush *brush = PIKA_BRUSH (viewable);
|
||||
const PikaTempBuf *mask_buf = brush->priv->mask;
|
||||
const PikaTempBuf *pixmap_buf = brush->priv->pixmap;
|
||||
PikaTempBuf *return_buf = NULL;
|
||||
gint mask_width;
|
||||
gint mask_height;
|
||||
guchar *mask_data;
|
||||
guchar *mask;
|
||||
guchar *buf;
|
||||
gint x, y;
|
||||
gboolean scaled = FALSE;
|
||||
|
||||
mask_width = pika_temp_buf_get_width (mask_buf);
|
||||
mask_height = pika_temp_buf_get_height (mask_buf);
|
||||
|
||||
if (mask_width > width || mask_height > height)
|
||||
{
|
||||
gdouble ratio_x = (gdouble) width / (gdouble) mask_width;
|
||||
gdouble ratio_y = (gdouble) height / (gdouble) mask_height;
|
||||
gdouble scale = MIN (ratio_x, ratio_y);
|
||||
|
||||
if (scale != 1.0)
|
||||
{
|
||||
pika_brush_begin_use (brush);
|
||||
|
||||
if (PIKA_IS_BRUSH_GENERATED (brush))
|
||||
{
|
||||
PikaBrushGenerated *gen_brush = PIKA_BRUSH_GENERATED (brush);
|
||||
|
||||
mask_buf = pika_brush_transform_mask (brush, scale,
|
||||
(pika_brush_generated_get_aspect_ratio (gen_brush) - 1.0) * 20.0 / 19.0,
|
||||
pika_brush_generated_get_angle (gen_brush) / 360.0,
|
||||
FALSE,
|
||||
pika_brush_generated_get_hardness (gen_brush));
|
||||
}
|
||||
else
|
||||
mask_buf = pika_brush_transform_mask (brush, scale,
|
||||
0.0, 0.0, FALSE, 1.0);
|
||||
|
||||
if (! mask_buf)
|
||||
{
|
||||
mask_buf = pika_temp_buf_new (1, 1, babl_format ("Y u8"));
|
||||
pika_temp_buf_data_clear ((PikaTempBuf *) mask_buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
pika_temp_buf_ref ((PikaTempBuf *) mask_buf);
|
||||
}
|
||||
|
||||
if (pixmap_buf)
|
||||
pixmap_buf = pika_brush_transform_pixmap (brush, scale,
|
||||
0.0, 0.0, FALSE, 1.0);
|
||||
|
||||
mask_width = pika_temp_buf_get_width (mask_buf);
|
||||
mask_height = pika_temp_buf_get_height (mask_buf);
|
||||
|
||||
scaled = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return_buf = pika_temp_buf_new (mask_width, mask_height,
|
||||
babl_format ("R'G'B'A u8"));
|
||||
|
||||
mask = mask_data = pika_temp_buf_lock (mask_buf, babl_format ("Y u8"),
|
||||
GEGL_ACCESS_READ);
|
||||
buf = pika_temp_buf_get_data (return_buf);
|
||||
|
||||
if (pixmap_buf)
|
||||
{
|
||||
guchar *pixmap_data;
|
||||
guchar *pixmap;
|
||||
|
||||
pixmap = pixmap_data = pika_temp_buf_lock (pixmap_buf,
|
||||
babl_format ("R'G'B' u8"),
|
||||
GEGL_ACCESS_READ);
|
||||
|
||||
for (y = 0; y < mask_height; y++)
|
||||
{
|
||||
for (x = 0; x < mask_width ; x++)
|
||||
{
|
||||
*buf++ = *pixmap++;
|
||||
*buf++ = *pixmap++;
|
||||
*buf++ = *pixmap++;
|
||||
*buf++ = *mask++;
|
||||
}
|
||||
}
|
||||
|
||||
pika_temp_buf_unlock (pixmap_buf, pixmap_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (y = 0; y < mask_height; y++)
|
||||
{
|
||||
for (x = 0; x < mask_width ; x++)
|
||||
{
|
||||
*buf++ = 0;
|
||||
*buf++ = 0;
|
||||
*buf++ = 0;
|
||||
*buf++ = *mask++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pika_temp_buf_unlock (mask_buf, mask_data);
|
||||
|
||||
if (scaled)
|
||||
{
|
||||
pika_temp_buf_unref ((PikaTempBuf *) mask_buf);
|
||||
|
||||
pika_brush_end_use (brush);
|
||||
}
|
||||
|
||||
return return_buf;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
pika_brush_get_description (PikaViewable *viewable,
|
||||
gchar **tooltip)
|
||||
{
|
||||
PikaBrush *brush = PIKA_BRUSH (viewable);
|
||||
|
||||
return g_strdup_printf ("%s (%d × %d)",
|
||||
pika_object_get_name (brush),
|
||||
pika_temp_buf_get_width (brush->priv->mask),
|
||||
pika_temp_buf_get_height (brush->priv->mask));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_dirty (PikaData *data)
|
||||
{
|
||||
PikaBrush *brush = PIKA_BRUSH (data);
|
||||
|
||||
if (brush->priv->mask_cache)
|
||||
pika_brush_cache_clear (brush->priv->mask_cache);
|
||||
|
||||
if (brush->priv->pixmap_cache)
|
||||
pika_brush_cache_clear (brush->priv->pixmap_cache);
|
||||
|
||||
if (brush->priv->boundary_cache)
|
||||
pika_brush_cache_clear (brush->priv->boundary_cache);
|
||||
|
||||
pika_brush_mipmap_clear (brush);
|
||||
|
||||
g_clear_pointer (&brush->priv->blurred_mask, pika_temp_buf_unref);
|
||||
g_clear_pointer (&brush->priv->blurred_pixmap, pika_temp_buf_unref);
|
||||
|
||||
PIKA_DATA_CLASS (parent_class)->dirty (data);
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
pika_brush_get_extension (PikaData *data)
|
||||
{
|
||||
return PIKA_BRUSH_FILE_EXTENSION;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_copy (PikaData *data,
|
||||
PikaData *src_data)
|
||||
{
|
||||
PikaBrush *brush = PIKA_BRUSH (data);
|
||||
PikaBrush *src_brush = PIKA_BRUSH (src_data);
|
||||
|
||||
g_clear_pointer (&brush->priv->mask, pika_temp_buf_unref);
|
||||
if (src_brush->priv->mask)
|
||||
brush->priv->mask = pika_temp_buf_copy (src_brush->priv->mask);
|
||||
|
||||
g_clear_pointer (&brush->priv->pixmap, pika_temp_buf_unref);
|
||||
if (src_brush->priv->pixmap)
|
||||
brush->priv->pixmap = pika_temp_buf_copy (src_brush->priv->pixmap);
|
||||
|
||||
brush->priv->spacing = src_brush->priv->spacing;
|
||||
brush->priv->x_axis = src_brush->priv->x_axis;
|
||||
brush->priv->y_axis = src_brush->priv->y_axis;
|
||||
|
||||
pika_data_dirty (data);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_real_begin_use (PikaBrush *brush)
|
||||
{
|
||||
brush->priv->mask_cache =
|
||||
pika_brush_cache_new ((GDestroyNotify) pika_temp_buf_unref, 'M', 'm');
|
||||
|
||||
brush->priv->pixmap_cache =
|
||||
pika_brush_cache_new ((GDestroyNotify) pika_temp_buf_unref, 'P', 'p');
|
||||
|
||||
brush->priv->boundary_cache =
|
||||
pika_brush_cache_new ((GDestroyNotify) pika_bezier_desc_free, 'B', 'b');
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_real_end_use (PikaBrush *brush)
|
||||
{
|
||||
g_clear_object (&brush->priv->mask_cache);
|
||||
g_clear_object (&brush->priv->pixmap_cache);
|
||||
g_clear_object (&brush->priv->boundary_cache);
|
||||
|
||||
g_clear_pointer (&brush->priv->blurred_mask, pika_temp_buf_unref);
|
||||
g_clear_pointer (&brush->priv->blurred_pixmap, pika_temp_buf_unref);
|
||||
}
|
||||
|
||||
static PikaBrush *
|
||||
pika_brush_real_select_brush (PikaBrush *brush,
|
||||
const PikaCoords *last_coords,
|
||||
const PikaCoords *current_coords)
|
||||
{
|
||||
return brush;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_brush_real_want_null_motion (PikaBrush *brush,
|
||||
const PikaCoords *last_coords,
|
||||
const PikaCoords *current_coords)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
pika_brush_get_checksum (PikaTagged *tagged)
|
||||
{
|
||||
PikaBrush *brush = PIKA_BRUSH (tagged);
|
||||
gchar *checksum_string = NULL;
|
||||
|
||||
if (brush->priv->mask)
|
||||
{
|
||||
GChecksum *checksum = g_checksum_new (G_CHECKSUM_MD5);
|
||||
|
||||
g_checksum_update (checksum,
|
||||
pika_temp_buf_get_data (brush->priv->mask),
|
||||
pika_temp_buf_get_data_size (brush->priv->mask));
|
||||
if (brush->priv->pixmap)
|
||||
g_checksum_update (checksum,
|
||||
pika_temp_buf_get_data (brush->priv->pixmap),
|
||||
pika_temp_buf_get_data_size (brush->priv->pixmap));
|
||||
g_checksum_update (checksum,
|
||||
(const guchar *) &brush->priv->spacing,
|
||||
sizeof (brush->priv->spacing));
|
||||
g_checksum_update (checksum,
|
||||
(const guchar *) &brush->priv->x_axis,
|
||||
sizeof (brush->priv->x_axis));
|
||||
g_checksum_update (checksum,
|
||||
(const guchar *) &brush->priv->y_axis,
|
||||
sizeof (brush->priv->y_axis));
|
||||
|
||||
checksum_string = g_strdup (g_checksum_get_string (checksum));
|
||||
|
||||
g_checksum_free (checksum);
|
||||
}
|
||||
|
||||
return checksum_string;
|
||||
}
|
||||
|
||||
/* public functions */
|
||||
|
||||
PikaData *
|
||||
pika_brush_new (PikaContext *context,
|
||||
const gchar *name)
|
||||
{
|
||||
g_return_val_if_fail (name != NULL, NULL);
|
||||
|
||||
return pika_brush_generated_new (name,
|
||||
PIKA_BRUSH_GENERATED_CIRCLE,
|
||||
5.0, 2, 0.5, 1.0, 0.0);
|
||||
}
|
||||
|
||||
PikaData *
|
||||
pika_brush_get_standard (PikaContext *context)
|
||||
{
|
||||
static PikaData *standard_brush = NULL;
|
||||
|
||||
if (! standard_brush)
|
||||
{
|
||||
g_set_weak_pointer (&standard_brush,
|
||||
pika_brush_new (context, "Standard"));
|
||||
|
||||
pika_data_clean (standard_brush);
|
||||
pika_data_make_internal (standard_brush, "pika-brush-standard");
|
||||
}
|
||||
|
||||
return standard_brush;
|
||||
}
|
||||
|
||||
void
|
||||
pika_brush_begin_use (PikaBrush *brush)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_BRUSH (brush));
|
||||
|
||||
brush->priv->use_count++;
|
||||
|
||||
if (brush->priv->use_count == 1)
|
||||
PIKA_BRUSH_GET_CLASS (brush)->begin_use (brush);
|
||||
}
|
||||
|
||||
void
|
||||
pika_brush_end_use (PikaBrush *brush)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_BRUSH (brush));
|
||||
g_return_if_fail (brush->priv->use_count > 0);
|
||||
|
||||
brush->priv->use_count--;
|
||||
|
||||
if (brush->priv->use_count == 0)
|
||||
PIKA_BRUSH_GET_CLASS (brush)->end_use (brush);
|
||||
}
|
||||
|
||||
PikaBrush *
|
||||
pika_brush_select_brush (PikaBrush *brush,
|
||||
const PikaCoords *last_coords,
|
||||
const PikaCoords *current_coords)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH (brush), NULL);
|
||||
g_return_val_if_fail (last_coords != NULL, NULL);
|
||||
g_return_val_if_fail (current_coords != NULL, NULL);
|
||||
|
||||
return PIKA_BRUSH_GET_CLASS (brush)->select_brush (brush,
|
||||
last_coords,
|
||||
current_coords);
|
||||
}
|
||||
|
||||
gboolean
|
||||
pika_brush_want_null_motion (PikaBrush *brush,
|
||||
const PikaCoords *last_coords,
|
||||
const PikaCoords *current_coords)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH (brush), FALSE);
|
||||
g_return_val_if_fail (last_coords != NULL, FALSE);
|
||||
g_return_val_if_fail (current_coords != NULL, FALSE);
|
||||
|
||||
return PIKA_BRUSH_GET_CLASS (brush)->want_null_motion (brush,
|
||||
last_coords,
|
||||
current_coords);
|
||||
}
|
||||
|
||||
void
|
||||
pika_brush_transform_size (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gint *width,
|
||||
gint *height)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_BRUSH (brush));
|
||||
g_return_if_fail (scale > 0.0);
|
||||
g_return_if_fail (width != NULL);
|
||||
g_return_if_fail (height != NULL);
|
||||
|
||||
if (scale == 1.0 &&
|
||||
aspect_ratio == 0.0 &&
|
||||
fmod (angle, 0.5) == 0.0)
|
||||
{
|
||||
*width = pika_temp_buf_get_width (brush->priv->mask);
|
||||
*height = pika_temp_buf_get_height (brush->priv->mask);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PIKA_BRUSH_GET_CLASS (brush)->transform_size (brush,
|
||||
scale, aspect_ratio, angle, reflect,
|
||||
width, height);
|
||||
}
|
||||
|
||||
const PikaTempBuf *
|
||||
pika_brush_transform_mask (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness)
|
||||
{
|
||||
const PikaTempBuf *mask;
|
||||
gint width;
|
||||
gint height;
|
||||
gdouble effective_hardness = hardness;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH (brush), NULL);
|
||||
g_return_val_if_fail (scale > 0.0, NULL);
|
||||
|
||||
pika_brush_transform_size (brush,
|
||||
scale, aspect_ratio, angle, reflect,
|
||||
&width, &height);
|
||||
|
||||
mask = pika_brush_cache_get (brush->priv->mask_cache,
|
||||
width, height,
|
||||
scale, aspect_ratio, angle, reflect, hardness);
|
||||
|
||||
if (! mask)
|
||||
{
|
||||
#if 0
|
||||
/* This code makes sure that brushes using blur for hardness
|
||||
* (all of them but generated) are blurred once and no more.
|
||||
* It also makes hardnes dynamics not work for these brushes.
|
||||
* This is intentional. Confoliving for each stamp is too expensive.*/
|
||||
if (! brush->priv->blurred_mask &&
|
||||
! PIKA_IS_BRUSH_GENERATED(brush) &&
|
||||
! PIKA_IS_BRUSH_PIPE(brush) && /*Can't cache pipes. Sanely anyway*/
|
||||
hardness < 1.0)
|
||||
{
|
||||
brush->priv->blurred_mask = PIKA_BRUSH_GET_CLASS (brush)->transform_mask (brush,
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
FALSE,
|
||||
hardness);
|
||||
brush->priv->blur_hardness = hardness;
|
||||
}
|
||||
|
||||
if (brush->priv->blurred_mask)
|
||||
{
|
||||
effective_hardness = 1.0; /*Hardness has already been applied*/
|
||||
}
|
||||
#endif
|
||||
|
||||
mask = PIKA_BRUSH_GET_CLASS (brush)->transform_mask (brush,
|
||||
scale,
|
||||
aspect_ratio,
|
||||
angle,
|
||||
reflect,
|
||||
effective_hardness);
|
||||
|
||||
pika_brush_cache_add (brush->priv->mask_cache,
|
||||
(gpointer) mask,
|
||||
width, height,
|
||||
scale, aspect_ratio, angle, reflect, effective_hardness);
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
const PikaTempBuf *
|
||||
pika_brush_transform_pixmap (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness)
|
||||
{
|
||||
const PikaTempBuf *pixmap;
|
||||
gint width;
|
||||
gint height;
|
||||
gdouble effective_hardness = hardness;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH (brush), NULL);
|
||||
g_return_val_if_fail (brush->priv->pixmap != NULL, NULL);
|
||||
g_return_val_if_fail (scale > 0.0, NULL);
|
||||
|
||||
pika_brush_transform_size (brush,
|
||||
scale, aspect_ratio, angle, reflect,
|
||||
&width, &height);
|
||||
|
||||
pixmap = pika_brush_cache_get (brush->priv->pixmap_cache,
|
||||
width, height,
|
||||
scale, aspect_ratio, angle, reflect, hardness);
|
||||
|
||||
if (! pixmap)
|
||||
{
|
||||
#if 0
|
||||
if (! brush->priv->blurred_pixmap &&
|
||||
! PIKA_IS_BRUSH_GENERATED(brush) &&
|
||||
! PIKA_IS_BRUSH_PIPE(brush) /*Can't cache pipes. Sanely anyway*/
|
||||
&& hardness < 1.0)
|
||||
{
|
||||
brush->priv->blurred_pixmap = PIKA_BRUSH_GET_CLASS (brush)->transform_pixmap (brush,
|
||||
1.0,
|
||||
0.0,
|
||||
0.0,
|
||||
FALSE,
|
||||
hardness);
|
||||
brush->priv->blur_hardness = hardness;
|
||||
}
|
||||
|
||||
if (brush->priv->blurred_pixmap) {
|
||||
effective_hardness = 1.0; /*Hardness has already been applied*/
|
||||
}
|
||||
#endif
|
||||
|
||||
pixmap = PIKA_BRUSH_GET_CLASS (brush)->transform_pixmap (brush,
|
||||
scale,
|
||||
aspect_ratio,
|
||||
angle,
|
||||
reflect,
|
||||
effective_hardness);
|
||||
|
||||
pika_brush_cache_add (brush->priv->pixmap_cache,
|
||||
(gpointer) pixmap,
|
||||
width, height,
|
||||
scale, aspect_ratio, angle, reflect, effective_hardness);
|
||||
}
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
const PikaBezierDesc *
|
||||
pika_brush_transform_boundary (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness,
|
||||
gint *width,
|
||||
gint *height)
|
||||
{
|
||||
const PikaBezierDesc *boundary;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH (brush), NULL);
|
||||
g_return_val_if_fail (scale > 0.0, NULL);
|
||||
g_return_val_if_fail (width != NULL, NULL);
|
||||
g_return_val_if_fail (height != NULL, NULL);
|
||||
|
||||
pika_brush_transform_size (brush,
|
||||
scale, aspect_ratio, angle, reflect,
|
||||
width, height);
|
||||
|
||||
boundary = pika_brush_cache_get (brush->priv->boundary_cache,
|
||||
*width, *height,
|
||||
scale, aspect_ratio, angle, reflect, hardness);
|
||||
|
||||
if (! boundary)
|
||||
{
|
||||
boundary = PIKA_BRUSH_GET_CLASS (brush)->transform_boundary (brush,
|
||||
scale,
|
||||
aspect_ratio,
|
||||
angle,
|
||||
reflect,
|
||||
hardness,
|
||||
width,
|
||||
height);
|
||||
|
||||
/* while the brush mask is always at least 1x1 pixels, its
|
||||
* outline can correctly be NULL
|
||||
*
|
||||
* FIXME: make the cache handle NULL things when it is
|
||||
* properly implemented
|
||||
*/
|
||||
if (boundary)
|
||||
pika_brush_cache_add (brush->priv->boundary_cache,
|
||||
(gpointer) boundary,
|
||||
*width, *height,
|
||||
scale, aspect_ratio, angle, reflect, hardness);
|
||||
}
|
||||
|
||||
return boundary;
|
||||
}
|
||||
|
||||
PikaTempBuf *
|
||||
pika_brush_get_mask (PikaBrush *brush)
|
||||
{
|
||||
g_return_val_if_fail (brush != NULL, NULL);
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH (brush), NULL);
|
||||
|
||||
if (brush->priv->blurred_mask)
|
||||
{
|
||||
return brush->priv->blurred_mask;
|
||||
}
|
||||
return brush->priv->mask;
|
||||
}
|
||||
|
||||
PikaTempBuf *
|
||||
pika_brush_get_pixmap (PikaBrush *brush)
|
||||
{
|
||||
g_return_val_if_fail (brush != NULL, NULL);
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH (brush), NULL);
|
||||
|
||||
if(brush->priv->blurred_pixmap)
|
||||
{
|
||||
return brush->priv->blurred_pixmap;
|
||||
}
|
||||
return brush->priv->pixmap;
|
||||
}
|
||||
|
||||
void
|
||||
pika_brush_flush_blur_caches (PikaBrush *brush)
|
||||
{
|
||||
#if 0
|
||||
g_clear_pointer (&brush->priv->blurred_mask, pika_temp_buf_unref);
|
||||
g_clear_pointer (&brush->priv->blurred_pixmap, pika_temp_buf_unref);
|
||||
|
||||
if (brush->priv->mask_cache)
|
||||
pika_brush_cache_clear (brush->priv->mask_cache);
|
||||
|
||||
if (brush->priv->pixmap_cache)
|
||||
pika_brush_cache_clear (brush->priv->pixmap_cache);
|
||||
|
||||
if (brush->priv->boundary_cache)
|
||||
pika_brush_cache_clear (brush->priv->boundary_cache);
|
||||
#endif
|
||||
}
|
||||
|
||||
gdouble
|
||||
pika_brush_get_blur_hardness (PikaBrush *brush)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH (brush), 0);
|
||||
|
||||
return brush->priv->blur_hardness;
|
||||
}
|
||||
|
||||
gint
|
||||
pika_brush_get_width (PikaBrush *brush)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH (brush), 0);
|
||||
|
||||
if (brush->priv->blurred_mask)
|
||||
return pika_temp_buf_get_width (brush->priv->blurred_mask);
|
||||
|
||||
if (brush->priv->blurred_pixmap)
|
||||
return pika_temp_buf_get_width (brush->priv->blurred_pixmap);
|
||||
|
||||
return pika_temp_buf_get_width (brush->priv->mask);
|
||||
}
|
||||
|
||||
gint
|
||||
pika_brush_get_height (PikaBrush *brush)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH (brush), 0);
|
||||
|
||||
if (brush->priv->blurred_mask)
|
||||
return pika_temp_buf_get_height (brush->priv->blurred_mask);
|
||||
|
||||
if (brush->priv->blurred_pixmap)
|
||||
return pika_temp_buf_get_height (brush->priv->blurred_pixmap);
|
||||
|
||||
return pika_temp_buf_get_height (brush->priv->mask);
|
||||
}
|
||||
|
||||
gint
|
||||
pika_brush_get_spacing (PikaBrush *brush)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH (brush), 0);
|
||||
|
||||
return brush->priv->spacing;
|
||||
}
|
||||
|
||||
void
|
||||
pika_brush_set_spacing (PikaBrush *brush,
|
||||
gint spacing)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_BRUSH (brush));
|
||||
|
||||
if (brush->priv->spacing != spacing)
|
||||
{
|
||||
brush->priv->spacing = spacing;
|
||||
|
||||
g_signal_emit (brush, brush_signals[SPACING_CHANGED], 0);
|
||||
g_object_notify (G_OBJECT (brush), "spacing");
|
||||
}
|
||||
}
|
||||
|
||||
static const PikaVector2 fail = { 0.0, 0.0 };
|
||||
|
||||
PikaVector2
|
||||
pika_brush_get_x_axis (PikaBrush *brush)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH (brush), fail);
|
||||
|
||||
return brush->priv->x_axis;
|
||||
}
|
||||
|
||||
PikaVector2
|
||||
pika_brush_get_y_axis (PikaBrush *brush)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH (brush), fail);
|
||||
|
||||
return brush->priv->y_axis;
|
||||
}
|
||||
156
app/core/pikabrush.h
Normal file
156
app/core/pikabrush.h
Normal file
@ -0,0 +1,156 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BRUSH_H__
|
||||
#define __PIKA_BRUSH_H__
|
||||
|
||||
|
||||
#include "pikadata.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_BRUSH (pika_brush_get_type ())
|
||||
#define PIKA_BRUSH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_BRUSH, PikaBrush))
|
||||
#define PIKA_BRUSH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_BRUSH, PikaBrushClass))
|
||||
#define PIKA_IS_BRUSH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_BRUSH))
|
||||
#define PIKA_IS_BRUSH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_BRUSH))
|
||||
#define PIKA_BRUSH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_BRUSH, PikaBrushClass))
|
||||
|
||||
|
||||
typedef struct _PikaBrushPrivate PikaBrushPrivate;
|
||||
typedef struct _PikaBrushClass PikaBrushClass;
|
||||
|
||||
struct _PikaBrush
|
||||
{
|
||||
PikaData parent_instance;
|
||||
|
||||
PikaBrushPrivate *priv;
|
||||
};
|
||||
|
||||
struct _PikaBrushClass
|
||||
{
|
||||
PikaDataClass parent_class;
|
||||
|
||||
/* virtual functions */
|
||||
void (* begin_use) (PikaBrush *brush);
|
||||
void (* end_use) (PikaBrush *brush);
|
||||
PikaBrush * (* select_brush) (PikaBrush *brush,
|
||||
const PikaCoords *last_coords,
|
||||
const PikaCoords *current_coords);
|
||||
gboolean (* want_null_motion) (PikaBrush *brush,
|
||||
const PikaCoords *last_coords,
|
||||
const PikaCoords *current_coords);
|
||||
void (* transform_size) (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gint *width,
|
||||
gint *height);
|
||||
PikaTempBuf * (* transform_mask) (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness);
|
||||
PikaTempBuf * (* transform_pixmap) (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness);
|
||||
PikaBezierDesc * (* transform_boundary) (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness,
|
||||
gint *width,
|
||||
gint *height);
|
||||
|
||||
/* signals */
|
||||
void (* spacing_changed) (PikaBrush *brush);
|
||||
};
|
||||
|
||||
|
||||
GType pika_brush_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaData * pika_brush_new (PikaContext *context,
|
||||
const gchar *name);
|
||||
PikaData * pika_brush_get_standard (PikaContext *context);
|
||||
|
||||
void pika_brush_begin_use (PikaBrush *brush);
|
||||
void pika_brush_end_use (PikaBrush *brush);
|
||||
|
||||
PikaBrush * pika_brush_select_brush (PikaBrush *brush,
|
||||
const PikaCoords *last_coords,
|
||||
const PikaCoords *current_coords);
|
||||
gboolean pika_brush_want_null_motion (PikaBrush *brush,
|
||||
const PikaCoords *last_coords,
|
||||
const PikaCoords *current_coords);
|
||||
|
||||
/* Gets width and height of a transformed mask of the brush, for
|
||||
* provided parameters.
|
||||
*/
|
||||
void pika_brush_transform_size (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gint *width,
|
||||
gint *height);
|
||||
const PikaTempBuf * pika_brush_transform_mask (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness);
|
||||
const PikaTempBuf * pika_brush_transform_pixmap (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness);
|
||||
const PikaBezierDesc * pika_brush_transform_boundary (PikaBrush *brush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness,
|
||||
gint *width,
|
||||
gint *height);
|
||||
|
||||
PikaTempBuf * pika_brush_get_mask (PikaBrush *brush);
|
||||
PikaTempBuf * pika_brush_get_pixmap (PikaBrush *brush);
|
||||
|
||||
gint pika_brush_get_width (PikaBrush *brush);
|
||||
gint pika_brush_get_height (PikaBrush *brush);
|
||||
|
||||
gint pika_brush_get_spacing (PikaBrush *brush);
|
||||
void pika_brush_set_spacing (PikaBrush *brush,
|
||||
gint spacing);
|
||||
|
||||
PikaVector2 pika_brush_get_x_axis (PikaBrush *brush);
|
||||
PikaVector2 pika_brush_get_y_axis (PikaBrush *brush);
|
||||
|
||||
void pika_brush_flush_blur_caches (PikaBrush *brush);
|
||||
gdouble pika_brush_get_blur_hardness (PikaBrush *brush);
|
||||
|
||||
#endif /* __PIKA_BRUSH_H__ */
|
||||
306
app/core/pikabrushcache.c
Normal file
306
app/core/pikabrushcache.c
Normal file
@ -0,0 +1,306 @@
|
||||
/* 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
|
||||
*
|
||||
* pikabrushcache.c
|
||||
* Copyright (C) 2011 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikabrushcache.h"
|
||||
|
||||
#include "pika-log.h"
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
#define MAX_CACHED_DATA 20
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_DATA_DESTROY
|
||||
};
|
||||
|
||||
|
||||
typedef struct _PikaBrushCacheUnit PikaBrushCacheUnit;
|
||||
|
||||
struct _PikaBrushCacheUnit
|
||||
{
|
||||
gpointer data;
|
||||
|
||||
gint width;
|
||||
gint height;
|
||||
gdouble scale;
|
||||
gdouble aspect_ratio;
|
||||
gdouble angle;
|
||||
gboolean reflect;
|
||||
gdouble hardness;
|
||||
};
|
||||
|
||||
|
||||
static void pika_brush_cache_constructed (GObject *object);
|
||||
static void pika_brush_cache_finalize (GObject *object);
|
||||
static void pika_brush_cache_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_brush_cache_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaBrushCache, pika_brush_cache, PIKA_TYPE_OBJECT)
|
||||
|
||||
#define parent_class pika_brush_cache_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_brush_cache_class_init (PikaBrushCacheClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->constructed = pika_brush_cache_constructed;
|
||||
object_class->finalize = pika_brush_cache_finalize;
|
||||
object_class->set_property = pika_brush_cache_set_property;
|
||||
object_class->get_property = pika_brush_cache_get_property;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_DATA_DESTROY,
|
||||
g_param_spec_pointer ("data-destroy",
|
||||
NULL, NULL,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_cache_init (PikaBrushCache *brush)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_cache_constructed (GObject *object)
|
||||
{
|
||||
PikaBrushCache *cache = PIKA_BRUSH_CACHE (object);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->constructed (object);
|
||||
|
||||
pika_assert (cache->data_destroy != NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_cache_finalize (GObject *object)
|
||||
{
|
||||
PikaBrushCache *cache = PIKA_BRUSH_CACHE (object);
|
||||
|
||||
pika_brush_cache_clear (cache);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_cache_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaBrushCache *cache = PIKA_BRUSH_CACHE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_DATA_DESTROY:
|
||||
cache->data_destroy = g_value_get_pointer (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_cache_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaBrushCache *cache = PIKA_BRUSH_CACHE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_DATA_DESTROY:
|
||||
g_value_set_pointer (value, cache->data_destroy);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
PikaBrushCache *
|
||||
pika_brush_cache_new (GDestroyNotify data_destroy,
|
||||
gchar debug_hit,
|
||||
gchar debug_miss)
|
||||
{
|
||||
PikaBrushCache *cache;
|
||||
|
||||
g_return_val_if_fail (data_destroy != NULL, NULL);
|
||||
|
||||
cache = g_object_new (PIKA_TYPE_BRUSH_CACHE,
|
||||
"data-destroy", data_destroy,
|
||||
NULL);
|
||||
|
||||
cache->debug_hit = debug_hit;
|
||||
cache->debug_miss = debug_miss;
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
void
|
||||
pika_brush_cache_clear (PikaBrushCache *cache)
|
||||
{
|
||||
g_return_if_fail (PIKA_IS_BRUSH_CACHE (cache));
|
||||
|
||||
if (cache->cached_units)
|
||||
{
|
||||
GList *iter;
|
||||
|
||||
for (iter = cache->cached_units; iter; iter = g_list_next (iter))
|
||||
{
|
||||
PikaBrushCacheUnit *unit = iter->data;
|
||||
|
||||
cache->data_destroy (unit->data);
|
||||
}
|
||||
|
||||
g_list_free_full (cache->cached_units, g_free);
|
||||
cache->cached_units = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
gconstpointer
|
||||
pika_brush_cache_get (PikaBrushCache *cache,
|
||||
gint width,
|
||||
gint height,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness)
|
||||
{
|
||||
GList *iter;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH_CACHE (cache), NULL);
|
||||
|
||||
for (iter = cache->cached_units; iter; iter = g_list_next (iter))
|
||||
{
|
||||
PikaBrushCacheUnit *unit = iter->data;
|
||||
|
||||
if (unit->data &&
|
||||
unit->width == width &&
|
||||
unit->height == height &&
|
||||
unit->scale == scale &&
|
||||
unit->aspect_ratio == aspect_ratio &&
|
||||
unit->angle == angle &&
|
||||
unit->reflect == reflect &&
|
||||
unit->hardness == hardness)
|
||||
{
|
||||
if (pika_log_flags & PIKA_LOG_BRUSH_CACHE)
|
||||
g_printerr ("%c", cache->debug_hit);
|
||||
|
||||
/* Make the returned cached brush first in the list. */
|
||||
cache->cached_units = g_list_remove_link (cache->cached_units, iter);
|
||||
iter->next = cache->cached_units;
|
||||
if (cache->cached_units)
|
||||
cache->cached_units->prev = iter;
|
||||
cache->cached_units = iter;
|
||||
|
||||
return (gconstpointer) unit->data;
|
||||
}
|
||||
}
|
||||
|
||||
if (pika_log_flags & PIKA_LOG_BRUSH_CACHE)
|
||||
g_printerr ("%c", cache->debug_miss);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
pika_brush_cache_add (PikaBrushCache *cache,
|
||||
gpointer data,
|
||||
gint width,
|
||||
gint height,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness)
|
||||
{
|
||||
GList *iter;
|
||||
PikaBrushCacheUnit *unit;
|
||||
GList *last = NULL;
|
||||
gint length = 0;
|
||||
|
||||
g_return_if_fail (PIKA_IS_BRUSH_CACHE (cache));
|
||||
g_return_if_fail (data != NULL);
|
||||
|
||||
for (iter = cache->cached_units; iter; iter = g_list_next (iter))
|
||||
{
|
||||
unit = iter->data;
|
||||
|
||||
if (data == unit->data)
|
||||
return;
|
||||
|
||||
length++;
|
||||
last = iter;
|
||||
}
|
||||
|
||||
if (length > MAX_CACHED_DATA)
|
||||
{
|
||||
unit = last->data;
|
||||
|
||||
cache->data_destroy (unit->data);
|
||||
cache->cached_units = g_list_delete_link (cache->cached_units, last);
|
||||
g_free (unit);
|
||||
}
|
||||
|
||||
unit = g_new0 (PikaBrushCacheUnit, 1);
|
||||
|
||||
unit->data = data;
|
||||
unit->width = width;
|
||||
unit->height = height;
|
||||
unit->scale = scale;
|
||||
unit->aspect_ratio = aspect_ratio;
|
||||
unit->angle = angle;
|
||||
unit->reflect = reflect;
|
||||
unit->hardness = hardness;
|
||||
|
||||
cache->cached_units = g_list_prepend (cache->cached_units, unit);
|
||||
}
|
||||
87
app/core/pikabrushcache.h
Normal file
87
app/core/pikabrushcache.h
Normal file
@ -0,0 +1,87 @@
|
||||
/* 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
|
||||
*
|
||||
* pikabrushcache.h
|
||||
* Copyright (C) 2011 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BRUSH_CACHE_H__
|
||||
#define __PIKA_BRUSH_CACHE_H__
|
||||
|
||||
|
||||
#include "pikaobject.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_BRUSH_CACHE (pika_brush_cache_get_type ())
|
||||
#define PIKA_BRUSH_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_BRUSH_CACHE, PikaBrushCache))
|
||||
#define PIKA_BRUSH_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_BRUSH_CACHE, PikaBrushCacheClass))
|
||||
#define PIKA_IS_BRUSH_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_BRUSH_CACHE))
|
||||
#define PIKA_IS_BRUSH_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_BRUSH_CACHE))
|
||||
#define PIKA_BRUSH_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_BRUSH_CACHE, PikaBrushCacheClass))
|
||||
|
||||
|
||||
typedef struct _PikaBrushCacheClass PikaBrushCacheClass;
|
||||
|
||||
struct _PikaBrushCache
|
||||
{
|
||||
PikaObject parent_instance;
|
||||
|
||||
GDestroyNotify data_destroy;
|
||||
|
||||
GList *cached_units;
|
||||
|
||||
gchar debug_hit;
|
||||
gchar debug_miss;
|
||||
};
|
||||
|
||||
struct _PikaBrushCacheClass
|
||||
{
|
||||
PikaObjectClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_brush_cache_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaBrushCache * pika_brush_cache_new (GDestroyNotify data_destory,
|
||||
gchar debug_hit,
|
||||
gchar debug_miss);
|
||||
|
||||
void pika_brush_cache_clear (PikaBrushCache *cache);
|
||||
|
||||
gconstpointer pika_brush_cache_get (PikaBrushCache *cache,
|
||||
gint width,
|
||||
gint height,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness);
|
||||
void pika_brush_cache_add (PikaBrushCache *cache,
|
||||
gpointer data,
|
||||
gint width,
|
||||
gint height,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness);
|
||||
|
||||
|
||||
#endif /* __PIKA_BRUSH_CACHE_H__ */
|
||||
304
app/core/pikabrushclipboard.c
Normal file
304
app/core/pikabrushclipboard.c
Normal file
@ -0,0 +1,304 @@
|
||||
/* 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
|
||||
*
|
||||
* pikabrushclipboard.c
|
||||
* Copyright (C) 2006 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika.h"
|
||||
#include "pikabuffer.h"
|
||||
#include "pikabrush-private.h"
|
||||
#include "pikabrushclipboard.h"
|
||||
#include "pikaimage.h"
|
||||
#include "pikapickable.h"
|
||||
#include "pikatempbuf.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
#define BRUSH_MAX_SIZE 1024
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_PIKA,
|
||||
PROP_MASK_ONLY
|
||||
};
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_brush_clipboard_constructed (GObject *object);
|
||||
static void pika_brush_clipboard_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_brush_clipboard_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static PikaData * pika_brush_clipboard_duplicate (PikaData *data);
|
||||
|
||||
static void pika_brush_clipboard_changed (Pika *pika,
|
||||
PikaBrush *brush);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaBrushClipboard, pika_brush_clipboard, PIKA_TYPE_BRUSH)
|
||||
|
||||
#define parent_class pika_brush_clipboard_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_brush_clipboard_class_init (PikaBrushClipboardClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaDataClass *data_class = PIKA_DATA_CLASS (klass);
|
||||
|
||||
object_class->constructed = pika_brush_clipboard_constructed;
|
||||
object_class->set_property = pika_brush_clipboard_set_property;
|
||||
object_class->get_property = pika_brush_clipboard_get_property;
|
||||
|
||||
data_class->duplicate = pika_brush_clipboard_duplicate;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_PIKA,
|
||||
g_param_spec_object ("pika", NULL, NULL,
|
||||
PIKA_TYPE_PIKA,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_MASK_ONLY,
|
||||
g_param_spec_boolean ("mask-only", NULL, NULL,
|
||||
FALSE,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_clipboard_init (PikaBrushClipboard *brush)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_clipboard_constructed (GObject *object)
|
||||
{
|
||||
PikaBrushClipboard *brush = PIKA_BRUSH_CLIPBOARD (object);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->constructed (object);
|
||||
|
||||
pika_assert (PIKA_IS_PIKA (brush->pika));
|
||||
|
||||
g_signal_connect_object (brush->pika, "clipboard-changed",
|
||||
G_CALLBACK (pika_brush_clipboard_changed),
|
||||
brush, 0);
|
||||
|
||||
pika_brush_clipboard_changed (brush->pika, PIKA_BRUSH (brush));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_clipboard_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaBrushClipboard *brush = PIKA_BRUSH_CLIPBOARD (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_PIKA:
|
||||
brush->pika = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
case PROP_MASK_ONLY:
|
||||
brush->mask_only = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_clipboard_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaBrushClipboard *brush = PIKA_BRUSH_CLIPBOARD (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_PIKA:
|
||||
g_value_set_object (value, brush->pika);
|
||||
break;
|
||||
|
||||
case PROP_MASK_ONLY:
|
||||
g_value_set_boolean (value, brush->mask_only);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static PikaData *
|
||||
pika_brush_clipboard_duplicate (PikaData *data)
|
||||
{
|
||||
PikaData *new = g_object_new (PIKA_TYPE_BRUSH, NULL);
|
||||
|
||||
pika_data_copy (new, data);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
PikaData *
|
||||
pika_brush_clipboard_new (Pika *pika,
|
||||
gboolean mask_only)
|
||||
{
|
||||
const gchar *name;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
|
||||
|
||||
if (mask_only)
|
||||
name = _("Clipboard Mask");
|
||||
else
|
||||
name = _("Clipboard Image");
|
||||
|
||||
return g_object_new (PIKA_TYPE_BRUSH_CLIPBOARD,
|
||||
"name", name,
|
||||
"pika", pika,
|
||||
"mask-only", mask_only,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static void
|
||||
pika_brush_clipboard_changed (Pika *pika,
|
||||
PikaBrush *brush)
|
||||
{
|
||||
PikaObject *paste;
|
||||
GeglBuffer *buffer = NULL;
|
||||
gint width;
|
||||
gint height;
|
||||
|
||||
g_clear_pointer (&brush->priv->mask, pika_temp_buf_unref);
|
||||
g_clear_pointer (&brush->priv->pixmap, pika_temp_buf_unref);
|
||||
|
||||
paste = pika_get_clipboard_object (pika);
|
||||
|
||||
if (PIKA_IS_IMAGE (paste))
|
||||
{
|
||||
pika_pickable_flush (PIKA_PICKABLE (paste));
|
||||
buffer = pika_pickable_get_buffer (PIKA_PICKABLE (paste));
|
||||
}
|
||||
else if (PIKA_IS_BUFFER (paste))
|
||||
{
|
||||
buffer = pika_buffer_get_buffer (PIKA_BUFFER (paste));
|
||||
}
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
const Babl *format = gegl_buffer_get_format (buffer);
|
||||
|
||||
width = MIN (gegl_buffer_get_width (buffer), BRUSH_MAX_SIZE);
|
||||
height = MIN (gegl_buffer_get_height (buffer), BRUSH_MAX_SIZE);
|
||||
|
||||
brush->priv->mask = pika_temp_buf_new (width, height,
|
||||
babl_format ("Y u8"));
|
||||
|
||||
if (PIKA_BRUSH_CLIPBOARD (brush)->mask_only)
|
||||
{
|
||||
guchar *p;
|
||||
gint i;
|
||||
|
||||
gegl_buffer_get (buffer,
|
||||
GEGL_RECTANGLE (0, 0, width, height), 1.0,
|
||||
babl_format ("Y u8"),
|
||||
pika_temp_buf_get_data (brush->priv->mask),
|
||||
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||
|
||||
/* invert the mask, it's more intuitive to think
|
||||
* "black on white" than the other way around
|
||||
*/
|
||||
for (i = 0, p = pika_temp_buf_get_data (brush->priv->mask);
|
||||
i < width * height;
|
||||
i++, p++)
|
||||
{
|
||||
*p = 255 - *p;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
brush->priv->pixmap = pika_temp_buf_new (width, height,
|
||||
babl_format ("R'G'B' u8"));
|
||||
|
||||
/* copy the alpha channel into the brush's mask */
|
||||
if (babl_format_has_alpha (format))
|
||||
{
|
||||
gegl_buffer_get (buffer,
|
||||
GEGL_RECTANGLE (0, 0, width, height), 1.0,
|
||||
babl_format ("A u8"),
|
||||
pika_temp_buf_get_data (brush->priv->mask),
|
||||
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset (pika_temp_buf_get_data (brush->priv->mask), 255,
|
||||
width * height);
|
||||
}
|
||||
|
||||
/* copy the color channels into the brush's pixmap */
|
||||
gegl_buffer_get (buffer,
|
||||
GEGL_RECTANGLE (0, 0, width, height), 1.0,
|
||||
babl_format ("R'G'B' u8"),
|
||||
pika_temp_buf_get_data (brush->priv->pixmap),
|
||||
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
width = 17;
|
||||
height = 17;
|
||||
|
||||
brush->priv->mask = pika_temp_buf_new (width, height,
|
||||
babl_format ("Y u8"));
|
||||
pika_temp_buf_data_clear (brush->priv->mask);
|
||||
}
|
||||
|
||||
brush->priv->x_axis.x = width / 2;
|
||||
brush->priv->x_axis.y = 0;
|
||||
brush->priv->y_axis.x = 0;
|
||||
brush->priv->y_axis.y = height / 2;
|
||||
|
||||
pika_data_dirty (PIKA_DATA (brush));
|
||||
}
|
||||
62
app/core/pikabrushclipboard.h
Normal file
62
app/core/pikabrushclipboard.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* 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
|
||||
*
|
||||
* pikabrushclipboard.h
|
||||
* Copyright (C) 2006 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BRUSH_CLIPBOARD_H__
|
||||
#define __PIKA_BRUSH_CLIPBOARD_H__
|
||||
|
||||
|
||||
#include "pikabrush.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_BRUSH_CLIPBOARD (pika_brush_clipboard_get_type ())
|
||||
#define PIKA_BRUSH_CLIPBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_BRUSH_CLIPBOARD, PikaBrushClipboard))
|
||||
#define PIKA_BRUSH_CLIPBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_BRUSH_CLIPBOARD, PikaBrushClipboardClass))
|
||||
#define PIKA_IS_BRUSH_CLIPBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_BRUSH_CLIPBOARD))
|
||||
#define PIKA_IS_BRUSH_CLIPBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_BRUSH_CLIPBOARD))
|
||||
#define PIKA_BRUSH_CLIPBOARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_BRUSH_CLIPBOARD, PikaBrushClipboardClass))
|
||||
|
||||
|
||||
typedef struct _PikaBrushClipboardClass PikaBrushClipboardClass;
|
||||
|
||||
struct _PikaBrushClipboard
|
||||
{
|
||||
PikaBrush parent_instance;
|
||||
|
||||
Pika *pika;
|
||||
gboolean mask_only;
|
||||
};
|
||||
|
||||
struct _PikaBrushClipboardClass
|
||||
{
|
||||
PikaBrushClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_brush_clipboard_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaData * pika_brush_clipboard_new (Pika *pika,
|
||||
gboolean mask_only);
|
||||
|
||||
|
||||
#endif /* __PIKA_BRUSH_CLIPBOARD_H__ */
|
||||
288
app/core/pikabrushgenerated-load.c
Normal file
288
app/core/pikabrushgenerated-load.c
Normal file
@ -0,0 +1,288 @@
|
||||
/* 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
|
||||
*
|
||||
* pika_brush_generated module Copyright 1998 Jay Cox <jaycox@earthlink.net>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pika-utils.h"
|
||||
#include "pikabrushgenerated.h"
|
||||
#include "pikabrushgenerated-load.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
GList *
|
||||
pika_brush_generated_load (PikaContext *context,
|
||||
GFile *file,
|
||||
GInputStream *input,
|
||||
GError **error)
|
||||
{
|
||||
PikaBrush *brush;
|
||||
GDataInputStream *data_input;
|
||||
gchar *string;
|
||||
gsize string_len;
|
||||
gint linenum;
|
||||
gchar *name = NULL;
|
||||
PikaBrushGeneratedShape shape = PIKA_BRUSH_GENERATED_CIRCLE;
|
||||
gboolean have_shape = FALSE;
|
||||
gint spikes = 2;
|
||||
gdouble spacing;
|
||||
gdouble radius;
|
||||
gdouble hardness;
|
||||
gdouble aspect_ratio;
|
||||
gdouble angle;
|
||||
|
||||
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||
g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
data_input = g_data_input_stream_new (input);
|
||||
|
||||
/* make sure the file we are reading is the right type */
|
||||
linenum = 1;
|
||||
string_len = 256;
|
||||
string = pika_data_input_stream_read_line_always (data_input, &string_len,
|
||||
NULL, error);
|
||||
if (! string)
|
||||
goto failed;
|
||||
|
||||
if (! g_str_has_prefix (string, "PIKA-VBR"))
|
||||
{
|
||||
g_set_error (error, PIKA_DATA_ERROR, PIKA_DATA_ERROR_READ,
|
||||
_("Not a PIKA brush file."));
|
||||
g_free (string);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
g_free (string);
|
||||
|
||||
/* make sure we are reading a compatible version */
|
||||
linenum++;
|
||||
string_len = 256;
|
||||
string = pika_data_input_stream_read_line_always (data_input, &string_len,
|
||||
NULL, error);
|
||||
if (! string)
|
||||
goto failed;
|
||||
|
||||
if (! g_str_has_prefix (string, "1.0"))
|
||||
{
|
||||
if (! g_str_has_prefix (string, "1.5"))
|
||||
{
|
||||
g_set_error (error, PIKA_DATA_ERROR, PIKA_DATA_ERROR_READ,
|
||||
_("Unknown PIKA brush version."));
|
||||
g_free (string);
|
||||
goto failed;
|
||||
}
|
||||
else
|
||||
{
|
||||
have_shape = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
g_free (string);
|
||||
|
||||
/* read name */
|
||||
linenum++;
|
||||
string_len = 256;
|
||||
string = pika_data_input_stream_read_line_always (data_input, &string_len,
|
||||
NULL, error);
|
||||
if (! string)
|
||||
goto failed;
|
||||
|
||||
g_strstrip (string);
|
||||
|
||||
/* the empty string is not an allowed name */
|
||||
if (strlen (string) < 1)
|
||||
{
|
||||
name = g_strdup (_("Untitled"));
|
||||
}
|
||||
else
|
||||
{
|
||||
name = pika_any_to_utf8 (string, -1,
|
||||
_("Invalid UTF-8 string in brush file '%s'."),
|
||||
pika_file_get_utf8_name (file));
|
||||
}
|
||||
|
||||
g_free (string);
|
||||
|
||||
if (have_shape)
|
||||
{
|
||||
GEnumClass *enum_class;
|
||||
GEnumValue *shape_val;
|
||||
|
||||
enum_class = g_type_class_peek (PIKA_TYPE_BRUSH_GENERATED_SHAPE);
|
||||
|
||||
/* read shape */
|
||||
linenum++;
|
||||
string_len = 256;
|
||||
string = pika_data_input_stream_read_line_always (data_input, &string_len,
|
||||
NULL, error);
|
||||
if (! string)
|
||||
goto failed;
|
||||
|
||||
g_strstrip (string);
|
||||
shape_val = g_enum_get_value_by_nick (enum_class, string);
|
||||
|
||||
if (! shape_val)
|
||||
{
|
||||
g_set_error (error, PIKA_DATA_ERROR, PIKA_DATA_ERROR_READ,
|
||||
_("Unknown PIKA brush shape."));
|
||||
g_free (string);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
g_free (string);
|
||||
|
||||
shape = shape_val->value;
|
||||
}
|
||||
|
||||
/* read brush spacing */
|
||||
linenum++;
|
||||
string_len = 256;
|
||||
string = pika_data_input_stream_read_line_always (data_input, &string_len,
|
||||
NULL, error);
|
||||
if (! string)
|
||||
goto failed;
|
||||
if (! pika_ascii_strtod (string, NULL, &spacing))
|
||||
{
|
||||
g_set_error (error, PIKA_DATA_ERROR, PIKA_DATA_ERROR_READ,
|
||||
_("Invalid brush spacing."));
|
||||
g_free (string);
|
||||
goto failed;
|
||||
}
|
||||
g_free (string);
|
||||
|
||||
|
||||
/* read brush radius */
|
||||
linenum++;
|
||||
string_len = 256;
|
||||
string = pika_data_input_stream_read_line_always (data_input, &string_len,
|
||||
NULL, error);
|
||||
if (! string)
|
||||
goto failed;
|
||||
if (! pika_ascii_strtod (string, NULL, &radius))
|
||||
{
|
||||
g_set_error (error, PIKA_DATA_ERROR, PIKA_DATA_ERROR_READ,
|
||||
_("Invalid brush radius."));
|
||||
g_free (string);
|
||||
goto failed;
|
||||
}
|
||||
g_free (string);
|
||||
|
||||
if (have_shape)
|
||||
{
|
||||
/* read number of spikes */
|
||||
linenum++;
|
||||
string_len = 256;
|
||||
string = pika_data_input_stream_read_line_always (data_input, &string_len,
|
||||
NULL, error);
|
||||
if (! string)
|
||||
goto failed;
|
||||
if (! pika_ascii_strtoi (string, NULL, 10, &spikes) ||
|
||||
spikes < 2 || spikes > 20)
|
||||
{
|
||||
g_set_error (error, PIKA_DATA_ERROR, PIKA_DATA_ERROR_READ,
|
||||
_("Invalid brush spike count."));
|
||||
g_free (string);
|
||||
goto failed;
|
||||
}
|
||||
g_free (string);
|
||||
}
|
||||
|
||||
/* read brush hardness */
|
||||
linenum++;
|
||||
string_len = 256;
|
||||
string = pika_data_input_stream_read_line_always (data_input, &string_len,
|
||||
NULL, error);
|
||||
if (! string)
|
||||
goto failed;
|
||||
if (! pika_ascii_strtod (string, NULL, &hardness))
|
||||
{
|
||||
g_set_error (error, PIKA_DATA_ERROR, PIKA_DATA_ERROR_READ,
|
||||
_("Invalid brush hardness."));
|
||||
g_free (string);
|
||||
goto failed;
|
||||
}
|
||||
g_free (string);
|
||||
|
||||
/* read brush aspect_ratio */
|
||||
linenum++;
|
||||
string_len = 256;
|
||||
string = pika_data_input_stream_read_line_always (data_input, &string_len,
|
||||
NULL, error);
|
||||
if (! string)
|
||||
goto failed;
|
||||
if (! pika_ascii_strtod (string, NULL, &aspect_ratio))
|
||||
{
|
||||
g_set_error (error, PIKA_DATA_ERROR, PIKA_DATA_ERROR_READ,
|
||||
_("Invalid brush aspect ratio."));
|
||||
g_free (string);
|
||||
goto failed;
|
||||
}
|
||||
g_free (string);
|
||||
|
||||
/* read brush angle */
|
||||
linenum++;
|
||||
string_len = 256;
|
||||
string = pika_data_input_stream_read_line_always (data_input, &string_len,
|
||||
NULL, error);
|
||||
if (! string)
|
||||
goto failed;
|
||||
if (! pika_ascii_strtod (string, NULL, &angle))
|
||||
{
|
||||
g_set_error (error, PIKA_DATA_ERROR, PIKA_DATA_ERROR_READ,
|
||||
_("Invalid brush angle."));
|
||||
g_free (string);
|
||||
goto failed;
|
||||
}
|
||||
g_free (string);
|
||||
|
||||
g_object_unref (data_input);
|
||||
|
||||
brush = PIKA_BRUSH (pika_brush_generated_new (name, shape, radius, spikes,
|
||||
hardness, aspect_ratio, angle));
|
||||
g_free (name);
|
||||
|
||||
pika_brush_set_spacing (brush, spacing);
|
||||
|
||||
return g_list_prepend (NULL, brush);
|
||||
|
||||
failed:
|
||||
|
||||
g_object_unref (data_input);
|
||||
|
||||
if (name)
|
||||
g_free (name);
|
||||
|
||||
g_prefix_error (error, _("In line %d of brush file: "), linenum);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
37
app/core/pikabrushgenerated-load.h
Normal file
37
app/core/pikabrushgenerated-load.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* 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
|
||||
*
|
||||
* brush_generated module Copyright 1998 Jay Cox <jaycox@earthlink.net>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BRUSH_GENERATED_LOAD_H__
|
||||
#define __PIKA_BRUSH_GENERATED_LOAD_H__
|
||||
|
||||
|
||||
#define PIKA_BRUSH_GENERATED_FILE_EXTENSION ".vbr"
|
||||
|
||||
|
||||
GList * pika_brush_generated_load (PikaContext *context,
|
||||
GFile *file,
|
||||
GInputStream *input,
|
||||
GError **error);
|
||||
|
||||
|
||||
#endif /* __PIKA_BRUSH_GENERATED_LOAD_H__ */
|
||||
123
app/core/pikabrushgenerated-save.c
Normal file
123
app/core/pikabrushgenerated-save.c
Normal file
@ -0,0 +1,123 @@
|
||||
/* 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
|
||||
*
|
||||
* pika_brush_generated module Copyright 1998 Jay Cox <jaycox@earthlink.net>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikabrushgenerated.h"
|
||||
#include "pikabrushgenerated-save.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
gboolean
|
||||
pika_brush_generated_save (PikaData *data,
|
||||
GOutputStream *output,
|
||||
GError **error)
|
||||
{
|
||||
PikaBrushGenerated *brush = PIKA_BRUSH_GENERATED (data);
|
||||
const gchar *name = pika_object_get_name (data);
|
||||
GString *string;
|
||||
gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
|
||||
gboolean have_shape = FALSE;
|
||||
|
||||
g_return_val_if_fail (name != NULL && *name != '\0', FALSE);
|
||||
|
||||
/* write magic header */
|
||||
string = g_string_new ("PIKA-VBR\n");
|
||||
|
||||
/* write version */
|
||||
if (brush->shape != PIKA_BRUSH_GENERATED_CIRCLE || brush->spikes > 2)
|
||||
{
|
||||
g_string_append (string, "1.5\n");
|
||||
have_shape = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_string_append (string, "1.0\n");
|
||||
}
|
||||
|
||||
/* write name */
|
||||
g_string_append_printf (string, "%.255s\n", name);
|
||||
|
||||
if (have_shape)
|
||||
{
|
||||
GEnumClass *enum_class;
|
||||
GEnumValue *shape_val;
|
||||
|
||||
enum_class = g_type_class_peek (PIKA_TYPE_BRUSH_GENERATED_SHAPE);
|
||||
|
||||
/* write shape */
|
||||
shape_val = g_enum_get_value (enum_class, brush->shape);
|
||||
g_string_append_printf (string, "%s\n", shape_val->value_nick);
|
||||
}
|
||||
|
||||
/* write brush spacing */
|
||||
g_string_append_printf (string, "%s\n",
|
||||
g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE,
|
||||
pika_brush_get_spacing (PIKA_BRUSH (brush))));
|
||||
|
||||
/* write brush radius */
|
||||
g_string_append_printf (string, "%s\n",
|
||||
g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE,
|
||||
brush->radius));
|
||||
|
||||
if (have_shape)
|
||||
{
|
||||
/* write brush spikes */
|
||||
g_string_append_printf (string, "%d\n", brush->spikes);
|
||||
}
|
||||
|
||||
/* write brush hardness */
|
||||
g_string_append_printf (string, "%s\n",
|
||||
g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE,
|
||||
brush->hardness));
|
||||
|
||||
/* write brush aspect_ratio */
|
||||
g_string_append_printf (string, "%s\n",
|
||||
g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE,
|
||||
brush->aspect_ratio));
|
||||
|
||||
/* write brush angle */
|
||||
g_string_append_printf (string, "%s\n",
|
||||
g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE,
|
||||
brush->angle));
|
||||
|
||||
if (! g_output_stream_write_all (output, string->str, string->len,
|
||||
NULL, NULL, error))
|
||||
{
|
||||
g_string_free (string, TRUE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_string_free (string, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
34
app/core/pikabrushgenerated-save.h
Normal file
34
app/core/pikabrushgenerated-save.h
Normal file
@ -0,0 +1,34 @@
|
||||
/* 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
|
||||
*
|
||||
* brush_generated module Copyright 1998 Jay Cox <jaycox@earthlink.net>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BRUSH_GENERATED_SAVE_H__
|
||||
#define __PIKA_BRUSH_GENERATED_SAVE_H__
|
||||
|
||||
|
||||
/* don't call this function directly, use pika_data_save() instead */
|
||||
gboolean pika_brush_generated_save (PikaData *data,
|
||||
GOutputStream *output,
|
||||
GError **error);
|
||||
|
||||
|
||||
#endif /* __PIKA_BRUSH_GENERATED_SAVE_H__ */
|
||||
879
app/core/pikabrushgenerated.c
Normal file
879
app/core/pikabrushgenerated.c
Normal file
@ -0,0 +1,879 @@
|
||||
/* 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
|
||||
*
|
||||
* pika_brush_generated module Copyright 1998 Jay Cox <jaycox@earthlink.net>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikabrush-private.h"
|
||||
#include "pikabrushgenerated.h"
|
||||
#include "pikabrushgenerated-load.h"
|
||||
#include "pikabrushgenerated-save.h"
|
||||
#include "pikatempbuf.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
#define OVERSAMPLING 4
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_SHAPE,
|
||||
PROP_RADIUS,
|
||||
PROP_SPIKES,
|
||||
PROP_HARDNESS,
|
||||
PROP_ASPECT_RATIO,
|
||||
PROP_ANGLE
|
||||
};
|
||||
|
||||
|
||||
/* local function prototypes */
|
||||
|
||||
static void pika_brush_generated_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void pika_brush_generated_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void pika_brush_generated_dirty (PikaData *data);
|
||||
static const gchar * pika_brush_generated_get_extension (PikaData *data);
|
||||
static void pika_brush_generated_copy (PikaData *data,
|
||||
PikaData *src_data);
|
||||
|
||||
static void pika_brush_generated_transform_size(PikaBrush *gbrush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gint *width,
|
||||
gint *height);
|
||||
static PikaTempBuf * pika_brush_generated_transform_mask(PikaBrush *gbrush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness);
|
||||
|
||||
static PikaTempBuf * pika_brush_generated_calc (PikaBrushGenerated *brush,
|
||||
PikaBrushGeneratedShape shape,
|
||||
gfloat radius,
|
||||
gint spikes,
|
||||
gfloat hardness,
|
||||
gfloat aspect_ratio,
|
||||
gfloat angle,
|
||||
gboolean reflect,
|
||||
PikaVector2 *xaxis,
|
||||
PikaVector2 *yaxis);
|
||||
static void pika_brush_generated_get_size (PikaBrushGenerated *gbrush,
|
||||
PikaBrushGeneratedShape shape,
|
||||
gfloat radius,
|
||||
gint spikes,
|
||||
gfloat hardness,
|
||||
gfloat aspect_ratio,
|
||||
gdouble angle_in_degrees,
|
||||
gboolean reflect,
|
||||
gint *width,
|
||||
gint *height,
|
||||
gdouble *_s,
|
||||
gdouble *_c,
|
||||
PikaVector2 *_x_axis,
|
||||
PikaVector2 *_y_axis);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaBrushGenerated, pika_brush_generated, PIKA_TYPE_BRUSH)
|
||||
|
||||
#define parent_class pika_brush_generated_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_brush_generated_class_init (PikaBrushGeneratedClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaDataClass *data_class = PIKA_DATA_CLASS (klass);
|
||||
PikaBrushClass *brush_class = PIKA_BRUSH_CLASS (klass);
|
||||
|
||||
object_class->set_property = pika_brush_generated_set_property;
|
||||
object_class->get_property = pika_brush_generated_get_property;
|
||||
|
||||
data_class->save = pika_brush_generated_save;
|
||||
data_class->dirty = pika_brush_generated_dirty;
|
||||
data_class->get_extension = pika_brush_generated_get_extension;
|
||||
data_class->copy = pika_brush_generated_copy;
|
||||
|
||||
brush_class->transform_size = pika_brush_generated_transform_size;
|
||||
brush_class->transform_mask = pika_brush_generated_transform_mask;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SHAPE,
|
||||
g_param_spec_enum ("shape", NULL,
|
||||
_("Brush Shape"),
|
||||
PIKA_TYPE_BRUSH_GENERATED_SHAPE,
|
||||
PIKA_BRUSH_GENERATED_CIRCLE,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_RADIUS,
|
||||
g_param_spec_double ("radius", NULL,
|
||||
_("Brush Radius"),
|
||||
0.1, 4000.0, 5.0,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SPIKES,
|
||||
g_param_spec_int ("spikes", NULL,
|
||||
_("Brush Spikes"),
|
||||
2, 20, 2,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_HARDNESS,
|
||||
g_param_spec_double ("hardness", NULL,
|
||||
_("Brush Hardness"),
|
||||
0.0, 1.0, 0.0,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_ASPECT_RATIO,
|
||||
g_param_spec_double ("aspect-ratio",
|
||||
NULL,
|
||||
_("Brush Aspect Ratio"),
|
||||
1.0, 20.0, 1.0,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_ANGLE,
|
||||
g_param_spec_double ("angle", NULL,
|
||||
_("Brush Angle"),
|
||||
0.0, 180.0, 0.0,
|
||||
PIKA_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT));
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_generated_init (PikaBrushGenerated *brush)
|
||||
{
|
||||
brush->shape = PIKA_BRUSH_GENERATED_CIRCLE;
|
||||
brush->radius = 5.0;
|
||||
brush->hardness = 0.0;
|
||||
brush->aspect_ratio = 1.0;
|
||||
brush->angle = 0.0;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_generated_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaBrushGenerated *brush = PIKA_BRUSH_GENERATED (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_SHAPE:
|
||||
pika_brush_generated_set_shape (brush, g_value_get_enum (value));
|
||||
break;
|
||||
case PROP_RADIUS:
|
||||
pika_brush_generated_set_radius (brush, g_value_get_double (value));
|
||||
break;
|
||||
case PROP_SPIKES:
|
||||
pika_brush_generated_set_spikes (brush, g_value_get_int (value));
|
||||
break;
|
||||
case PROP_HARDNESS:
|
||||
pika_brush_generated_set_hardness (brush, g_value_get_double (value));
|
||||
break;
|
||||
case PROP_ASPECT_RATIO:
|
||||
pika_brush_generated_set_aspect_ratio (brush, g_value_get_double (value));
|
||||
break;
|
||||
case PROP_ANGLE:
|
||||
pika_brush_generated_set_angle (brush, g_value_get_double (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_generated_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PikaBrushGenerated *brush = PIKA_BRUSH_GENERATED (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_SHAPE:
|
||||
g_value_set_enum (value, brush->shape);
|
||||
break;
|
||||
case PROP_RADIUS:
|
||||
g_value_set_double (value, brush->radius);
|
||||
break;
|
||||
case PROP_SPIKES:
|
||||
g_value_set_int (value, brush->spikes);
|
||||
break;
|
||||
case PROP_HARDNESS:
|
||||
g_value_set_double (value, brush->hardness);
|
||||
break;
|
||||
case PROP_ASPECT_RATIO:
|
||||
g_value_set_double (value, brush->aspect_ratio);
|
||||
break;
|
||||
case PROP_ANGLE:
|
||||
g_value_set_double (value, brush->angle);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_generated_dirty (PikaData *data)
|
||||
{
|
||||
PikaBrushGenerated *brush = PIKA_BRUSH_GENERATED (data);
|
||||
PikaBrush *gbrush = PIKA_BRUSH (brush);
|
||||
|
||||
g_clear_pointer (&gbrush->priv->mask, pika_temp_buf_unref);
|
||||
|
||||
gbrush->priv->mask = pika_brush_generated_calc (brush,
|
||||
brush->shape,
|
||||
brush->radius,
|
||||
brush->spikes,
|
||||
brush->hardness,
|
||||
brush->aspect_ratio,
|
||||
brush->angle,
|
||||
FALSE,
|
||||
&gbrush->priv->x_axis,
|
||||
&gbrush->priv->y_axis);
|
||||
|
||||
PIKA_DATA_CLASS (parent_class)->dirty (data);
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
pika_brush_generated_get_extension (PikaData *data)
|
||||
{
|
||||
return PIKA_BRUSH_GENERATED_FILE_EXTENSION;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_generated_copy (PikaData *data,
|
||||
PikaData *src_data)
|
||||
{
|
||||
PikaBrushGenerated *brush = PIKA_BRUSH_GENERATED (data);
|
||||
PikaBrushGenerated *src_brush = PIKA_BRUSH_GENERATED (src_data);
|
||||
|
||||
pika_data_freeze (data);
|
||||
|
||||
pika_brush_set_spacing (PIKA_BRUSH (brush),
|
||||
pika_brush_get_spacing (PIKA_BRUSH (src_brush)));
|
||||
|
||||
brush->shape = src_brush->shape;
|
||||
brush->radius = src_brush->radius;
|
||||
brush->spikes = src_brush->spikes;
|
||||
brush->hardness = src_brush->hardness;
|
||||
brush->aspect_ratio = src_brush->aspect_ratio;
|
||||
brush->angle = src_brush->angle;
|
||||
|
||||
pika_data_thaw (data);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_generated_transform_size (PikaBrush *gbrush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gint *width,
|
||||
gint *height)
|
||||
{
|
||||
PikaBrushGenerated *brush = PIKA_BRUSH_GENERATED (gbrush);
|
||||
gdouble ratio;
|
||||
|
||||
ratio = fabs (aspect_ratio) * 19.0 / 20.0 + 1.0;
|
||||
ratio = MIN (ratio, 20);
|
||||
|
||||
/* Since generated brushes are symmetric they don't have aspect
|
||||
* ratios < 1.0. it's the same as rotating by 90 degrees and 1 /
|
||||
* ratio, so we fix the input for this case.
|
||||
*/
|
||||
if (aspect_ratio < 0.0)
|
||||
angle = angle + 0.25;
|
||||
|
||||
angle = fmod (fmod (angle, 1.0) + 1.0, 1.0);
|
||||
angle *= 360;
|
||||
|
||||
pika_brush_generated_get_size (brush,
|
||||
brush->shape,
|
||||
brush->radius * scale,
|
||||
brush->spikes,
|
||||
brush->hardness,
|
||||
ratio,
|
||||
angle,
|
||||
reflect,
|
||||
width, height,
|
||||
NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static PikaTempBuf *
|
||||
pika_brush_generated_transform_mask (PikaBrush *gbrush,
|
||||
gdouble scale,
|
||||
gdouble aspect_ratio,
|
||||
gdouble angle,
|
||||
gboolean reflect,
|
||||
gdouble hardness)
|
||||
{
|
||||
PikaBrushGenerated *brush = PIKA_BRUSH_GENERATED (gbrush);
|
||||
gdouble ratio;
|
||||
|
||||
ratio = fabs (aspect_ratio) * 19.0 / 20.0 + 1.0;
|
||||
ratio = MIN (ratio, 20);
|
||||
|
||||
/* Since generated brushes are symmetric they don't have aspect
|
||||
* ratios < 1.0. it's the same as rotating by 90 degrees and 1 /
|
||||
* ratio, so we fix the input for this case.
|
||||
*/
|
||||
if (aspect_ratio < 0.0)
|
||||
angle = angle + 0.25;
|
||||
|
||||
angle = fmod (fmod (angle, 1.0) + 1.0, 1.0);
|
||||
angle *= 360;
|
||||
|
||||
if (scale == 1.0 &&
|
||||
ratio == brush->aspect_ratio &&
|
||||
angle == brush->angle &&
|
||||
reflect == FALSE &&
|
||||
hardness == brush->hardness)
|
||||
{
|
||||
return pika_temp_buf_copy (pika_brush_get_mask (gbrush));
|
||||
}
|
||||
|
||||
return pika_brush_generated_calc (brush,
|
||||
brush->shape,
|
||||
brush->radius * scale,
|
||||
brush->spikes,
|
||||
hardness,
|
||||
ratio,
|
||||
angle,
|
||||
reflect,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
/* the actual brush rendering functions */
|
||||
|
||||
static gdouble
|
||||
gauss (gdouble f)
|
||||
{
|
||||
/* this aint' a real gauss function */
|
||||
if (f < -0.5)
|
||||
{
|
||||
f = -1.0 - f;
|
||||
return (2.0 * f*f);
|
||||
}
|
||||
|
||||
if (f < 0.5)
|
||||
return (1.0 - 2.0 * f*f);
|
||||
|
||||
f = 1.0 - f;
|
||||
return (2.0 * f*f);
|
||||
}
|
||||
|
||||
/* set up lookup table */
|
||||
static gfloat *
|
||||
pika_brush_generated_calc_lut (gdouble radius,
|
||||
gdouble hardness)
|
||||
{
|
||||
gfloat *lookup;
|
||||
gint length;
|
||||
gint x;
|
||||
gdouble d;
|
||||
gdouble sum;
|
||||
gdouble exponent;
|
||||
gdouble buffer[OVERSAMPLING];
|
||||
|
||||
length = OVERSAMPLING * ceil (1 + sqrt (2 * SQR (ceil (radius + 1.0))));
|
||||
|
||||
lookup = gegl_scratch_new (gfloat, length);
|
||||
sum = 0.0;
|
||||
|
||||
if ((1.0 - hardness) < 0.0000004)
|
||||
exponent = 1000000.0;
|
||||
else
|
||||
exponent = 0.4 / (1.0 - hardness);
|
||||
|
||||
for (x = 0; x < OVERSAMPLING; x++)
|
||||
{
|
||||
d = fabs ((x + 0.5) / OVERSAMPLING - 0.5);
|
||||
|
||||
if (d > radius)
|
||||
buffer[x] = 0.0;
|
||||
else
|
||||
buffer[x] = gauss (pow (d / radius, exponent));
|
||||
|
||||
sum += buffer[x];
|
||||
}
|
||||
|
||||
for (x = 0; d < radius || sum > 0.00001; d += 1.0 / OVERSAMPLING)
|
||||
{
|
||||
sum -= buffer[x % OVERSAMPLING];
|
||||
|
||||
if (d > radius)
|
||||
buffer[x % OVERSAMPLING] = 0.0;
|
||||
else
|
||||
buffer[x % OVERSAMPLING] = gauss (pow (d / radius, exponent));
|
||||
|
||||
sum += buffer[x % OVERSAMPLING];
|
||||
lookup[x++] = sum / OVERSAMPLING;
|
||||
}
|
||||
|
||||
while (x < length)
|
||||
{
|
||||
lookup[x++] = 0.0f;
|
||||
}
|
||||
|
||||
return lookup;
|
||||
}
|
||||
|
||||
static PikaTempBuf *
|
||||
pika_brush_generated_calc (PikaBrushGenerated *brush,
|
||||
PikaBrushGeneratedShape shape,
|
||||
gfloat radius,
|
||||
gint spikes,
|
||||
gfloat hardness,
|
||||
gfloat aspect_ratio,
|
||||
gfloat angle,
|
||||
gboolean reflect,
|
||||
PikaVector2 *xaxis,
|
||||
PikaVector2 *yaxis)
|
||||
{
|
||||
gfloat *centerp;
|
||||
gfloat *lookup;
|
||||
gfloat a;
|
||||
gint x, y;
|
||||
gdouble c, s, cs, ss;
|
||||
PikaVector2 x_axis;
|
||||
PikaVector2 y_axis;
|
||||
PikaTempBuf *mask;
|
||||
gint width;
|
||||
gint height;
|
||||
gint half_width;
|
||||
gint half_height;
|
||||
|
||||
pika_brush_generated_get_size (brush,
|
||||
shape,
|
||||
radius,
|
||||
spikes,
|
||||
hardness,
|
||||
aspect_ratio,
|
||||
angle,
|
||||
reflect,
|
||||
&width, &height,
|
||||
&s, &c, &x_axis, &y_axis);
|
||||
|
||||
mask = pika_temp_buf_new (width, height,
|
||||
babl_format ("Y float"));
|
||||
|
||||
half_width = width / 2;
|
||||
half_height = height / 2;
|
||||
|
||||
centerp = (gfloat *) pika_temp_buf_get_data (mask) +
|
||||
half_height * width + half_width;
|
||||
|
||||
lookup = pika_brush_generated_calc_lut (radius, hardness);
|
||||
|
||||
cs = cos (- 2 * G_PI / spikes);
|
||||
ss = sin (- 2 * G_PI / spikes);
|
||||
|
||||
/* for an even number of spikes compute one half and mirror it */
|
||||
for (y = ((spikes % 2) ? -half_height : 0); y <= half_height; y++)
|
||||
{
|
||||
for (x = -half_width; x <= half_width; x++)
|
||||
{
|
||||
gdouble d = 0;
|
||||
gdouble tx = c * x - s * y;
|
||||
gdouble ty = fabs (s * x + c * y);
|
||||
|
||||
if (spikes > 2)
|
||||
{
|
||||
gdouble angle = atan2 (ty, tx);
|
||||
|
||||
while (angle > G_PI / spikes)
|
||||
{
|
||||
gdouble sx = tx;
|
||||
gdouble sy = ty;
|
||||
|
||||
tx = cs * sx - ss * sy;
|
||||
ty = ss * sx + cs * sy;
|
||||
|
||||
angle -= 2 * G_PI / spikes;
|
||||
}
|
||||
}
|
||||
|
||||
ty *= aspect_ratio;
|
||||
|
||||
switch (shape)
|
||||
{
|
||||
case PIKA_BRUSH_GENERATED_CIRCLE:
|
||||
d = sqrt (SQR (tx) + SQR (ty));
|
||||
break;
|
||||
case PIKA_BRUSH_GENERATED_SQUARE:
|
||||
d = MAX (fabs (tx), fabs (ty));
|
||||
break;
|
||||
case PIKA_BRUSH_GENERATED_DIAMOND:
|
||||
d = fabs (tx) + fabs (ty);
|
||||
break;
|
||||
}
|
||||
|
||||
if (d < radius + 1)
|
||||
a = lookup[(gint) RINT (d * OVERSAMPLING)];
|
||||
else
|
||||
a = 0.0f;
|
||||
|
||||
centerp[y * width + x] = a;
|
||||
|
||||
if (spikes % 2 == 0)
|
||||
centerp[-1 * y * width - x] = a;
|
||||
}
|
||||
}
|
||||
|
||||
gegl_scratch_free (lookup);
|
||||
|
||||
if (xaxis)
|
||||
*xaxis = x_axis;
|
||||
|
||||
if (yaxis)
|
||||
*yaxis = y_axis;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
/* This function is shared between pika_brush_generated_transform_size and
|
||||
* pika_brush_generated_calc, therefore we provide a bunch of optional
|
||||
* pointers for returnvalues.
|
||||
*/
|
||||
static void
|
||||
pika_brush_generated_get_size (PikaBrushGenerated *gbrush,
|
||||
PikaBrushGeneratedShape shape,
|
||||
gfloat radius,
|
||||
gint spikes,
|
||||
gfloat hardness,
|
||||
gfloat aspect_ratio,
|
||||
gdouble angle_in_degrees,
|
||||
gboolean reflect,
|
||||
gint *width,
|
||||
gint *height,
|
||||
gdouble *_s,
|
||||
gdouble *_c,
|
||||
PikaVector2 *_x_axis,
|
||||
PikaVector2 *_y_axis)
|
||||
{
|
||||
gdouble half_width = 0.0;
|
||||
gdouble half_height = 0.0;
|
||||
gint w, h;
|
||||
gdouble c, s;
|
||||
gdouble short_radius;
|
||||
PikaVector2 x_axis;
|
||||
PikaVector2 y_axis;
|
||||
|
||||
/* Since floatongpoint is not really accurate,
|
||||
* we need to round to limit the errors.
|
||||
* Errors in some border cases resulted in
|
||||
* different height and width reported for
|
||||
* the same input value on calling procedure side.
|
||||
* This became problem at the rise of dynamics that
|
||||
* allows for any angle to turn up.
|
||||
**/
|
||||
|
||||
angle_in_degrees = RINT (angle_in_degrees * 1000.0) / 1000.0;
|
||||
|
||||
s = sin (pika_deg_to_rad (angle_in_degrees));
|
||||
c = cos (pika_deg_to_rad (angle_in_degrees));
|
||||
|
||||
if (reflect)
|
||||
c = -c;
|
||||
|
||||
short_radius = radius / aspect_ratio;
|
||||
|
||||
x_axis.x = c * radius;
|
||||
x_axis.y = -1.0 * s * radius;
|
||||
y_axis.x = s * short_radius;
|
||||
y_axis.y = c * short_radius;
|
||||
|
||||
switch (shape)
|
||||
{
|
||||
case PIKA_BRUSH_GENERATED_CIRCLE:
|
||||
half_width = sqrt (x_axis.x * x_axis.x + y_axis.x * y_axis.x);
|
||||
half_height = sqrt (x_axis.y * x_axis.y + y_axis.y * y_axis.y);
|
||||
break;
|
||||
|
||||
case PIKA_BRUSH_GENERATED_SQUARE:
|
||||
half_width = fabs (x_axis.x) + fabs (y_axis.x);
|
||||
half_height = fabs (x_axis.y) + fabs (y_axis.y);
|
||||
break;
|
||||
|
||||
case PIKA_BRUSH_GENERATED_DIAMOND:
|
||||
half_width = MAX (fabs (x_axis.x), fabs (y_axis.x));
|
||||
half_height = MAX (fabs (x_axis.y), fabs (y_axis.y));
|
||||
break;
|
||||
}
|
||||
|
||||
if (spikes > 2)
|
||||
{
|
||||
/* could be optimized by respecting the angle */
|
||||
half_width = half_height = sqrt (radius * radius +
|
||||
short_radius * short_radius);
|
||||
y_axis.x = s * radius;
|
||||
y_axis.y = c * radius;
|
||||
}
|
||||
|
||||
w = MAX (1, ceil (half_width * 2));
|
||||
h = MAX (1, ceil (half_height * 2));
|
||||
|
||||
if (! (w & 0x1)) w++;
|
||||
if (! (h & 0x1)) h++;
|
||||
|
||||
*width = w;
|
||||
*height = h;
|
||||
|
||||
/* These will typically be set then this function is called by
|
||||
* pika_brush_generated_calc, which needs the values in its algorithms.
|
||||
*/
|
||||
if (_s != NULL)
|
||||
*_s = s;
|
||||
|
||||
if (_c != NULL)
|
||||
*_c = c;
|
||||
|
||||
if (_x_axis != NULL)
|
||||
*_x_axis = x_axis;
|
||||
|
||||
if (_y_axis != NULL)
|
||||
*_y_axis = y_axis;
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
PikaData *
|
||||
pika_brush_generated_new (const gchar *name,
|
||||
PikaBrushGeneratedShape shape,
|
||||
gfloat radius,
|
||||
gint spikes,
|
||||
gfloat hardness,
|
||||
gfloat aspect_ratio,
|
||||
gfloat angle)
|
||||
{
|
||||
PikaBrushGenerated *brush;
|
||||
|
||||
g_return_val_if_fail (name != NULL, NULL);
|
||||
g_return_val_if_fail (*name != '\0', NULL);
|
||||
|
||||
brush = g_object_new (PIKA_TYPE_BRUSH_GENERATED,
|
||||
"name", name,
|
||||
"mime-type", "application/x-pika-brush-generated",
|
||||
"spacing", 20.0,
|
||||
"shape", shape,
|
||||
"radius", radius,
|
||||
"spikes", spikes,
|
||||
"hardness", hardness,
|
||||
"aspect-ratio", aspect_ratio,
|
||||
"angle", angle,
|
||||
NULL);
|
||||
|
||||
return PIKA_DATA (brush);
|
||||
}
|
||||
|
||||
PikaBrushGeneratedShape
|
||||
pika_brush_generated_set_shape (PikaBrushGenerated *brush,
|
||||
PikaBrushGeneratedShape shape)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH_GENERATED (brush),
|
||||
PIKA_BRUSH_GENERATED_CIRCLE);
|
||||
|
||||
if (brush->shape != shape)
|
||||
{
|
||||
brush->shape = shape;
|
||||
|
||||
g_object_notify (G_OBJECT (brush), "shape");
|
||||
pika_data_dirty (PIKA_DATA (brush));
|
||||
}
|
||||
|
||||
return brush->shape;
|
||||
}
|
||||
|
||||
gfloat
|
||||
pika_brush_generated_set_radius (PikaBrushGenerated *brush,
|
||||
gfloat radius)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH_GENERATED (brush), -1.0);
|
||||
|
||||
radius = CLAMP (radius, 0.0, 32767.0);
|
||||
|
||||
if (brush->radius != radius)
|
||||
{
|
||||
brush->radius = radius;
|
||||
|
||||
g_object_notify (G_OBJECT (brush), "radius");
|
||||
pika_data_dirty (PIKA_DATA (brush));
|
||||
}
|
||||
|
||||
return brush->radius;
|
||||
}
|
||||
|
||||
gint
|
||||
pika_brush_generated_set_spikes (PikaBrushGenerated *brush,
|
||||
gint spikes)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH_GENERATED (brush), -1);
|
||||
|
||||
spikes = CLAMP (spikes, 2, 20);
|
||||
|
||||
if (brush->spikes != spikes)
|
||||
{
|
||||
brush->spikes = spikes;
|
||||
|
||||
g_object_notify (G_OBJECT (brush), "spikes");
|
||||
pika_data_dirty (PIKA_DATA (brush));
|
||||
}
|
||||
|
||||
return brush->spikes;
|
||||
}
|
||||
|
||||
gfloat
|
||||
pika_brush_generated_set_hardness (PikaBrushGenerated *brush,
|
||||
gfloat hardness)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH_GENERATED (brush), -1.0);
|
||||
|
||||
hardness = CLAMP (hardness, 0.0, 1.0);
|
||||
|
||||
if (brush->hardness != hardness)
|
||||
{
|
||||
brush->hardness = hardness;
|
||||
|
||||
g_object_notify (G_OBJECT (brush), "hardness");
|
||||
pika_data_dirty (PIKA_DATA (brush));
|
||||
}
|
||||
|
||||
return brush->hardness;
|
||||
}
|
||||
|
||||
gfloat
|
||||
pika_brush_generated_set_aspect_ratio (PikaBrushGenerated *brush,
|
||||
gfloat ratio)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH_GENERATED (brush), -1.0);
|
||||
|
||||
ratio = CLAMP (ratio, 1.0, 1000.0);
|
||||
|
||||
if (brush->aspect_ratio != ratio)
|
||||
{
|
||||
brush->aspect_ratio = ratio;
|
||||
|
||||
g_object_notify (G_OBJECT (brush), "aspect-ratio");
|
||||
pika_data_dirty (PIKA_DATA (brush));
|
||||
}
|
||||
|
||||
return brush->aspect_ratio;
|
||||
}
|
||||
|
||||
gfloat
|
||||
pika_brush_generated_set_angle (PikaBrushGenerated *brush,
|
||||
gfloat angle)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH_GENERATED (brush), -1.0);
|
||||
|
||||
if (angle < 0.0)
|
||||
angle = -1.0 * fmod (angle, 180.0);
|
||||
else if (angle > 180.0)
|
||||
angle = fmod (angle, 180.0);
|
||||
|
||||
if (brush->angle != angle)
|
||||
{
|
||||
brush->angle = angle;
|
||||
|
||||
g_object_notify (G_OBJECT (brush), "angle");
|
||||
pika_data_dirty (PIKA_DATA (brush));
|
||||
}
|
||||
|
||||
return brush->angle;
|
||||
}
|
||||
|
||||
PikaBrushGeneratedShape
|
||||
pika_brush_generated_get_shape (PikaBrushGenerated *brush)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH_GENERATED (brush),
|
||||
PIKA_BRUSH_GENERATED_CIRCLE);
|
||||
|
||||
return brush->shape;
|
||||
}
|
||||
|
||||
gfloat
|
||||
pika_brush_generated_get_radius (PikaBrushGenerated *brush)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH_GENERATED (brush), -1.0);
|
||||
|
||||
return brush->radius;
|
||||
}
|
||||
|
||||
gint
|
||||
pika_brush_generated_get_spikes (PikaBrushGenerated *brush)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH_GENERATED (brush), -1);
|
||||
|
||||
return brush->spikes;
|
||||
}
|
||||
|
||||
gfloat
|
||||
pika_brush_generated_get_hardness (PikaBrushGenerated *brush)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH_GENERATED (brush), -1.0);
|
||||
|
||||
return brush->hardness;
|
||||
}
|
||||
|
||||
gfloat
|
||||
pika_brush_generated_get_aspect_ratio (PikaBrushGenerated *brush)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH_GENERATED (brush), -1.0);
|
||||
|
||||
return brush->aspect_ratio;
|
||||
}
|
||||
|
||||
gfloat
|
||||
pika_brush_generated_get_angle (PikaBrushGenerated *brush)
|
||||
{
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH_GENERATED (brush), -1.0);
|
||||
|
||||
return brush->angle;
|
||||
}
|
||||
92
app/core/pikabrushgenerated.h
Normal file
92
app/core/pikabrushgenerated.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* 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
|
||||
*
|
||||
* brush_generated module Copyright 1998 Jay Cox <jaycox@earthlink.net>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BRUSH_GENERATED_H__
|
||||
#define __PIKA_BRUSH_GENERATED_H__
|
||||
|
||||
|
||||
#include "pikabrush.h"
|
||||
|
||||
|
||||
#define PIKA_TYPE_BRUSH_GENERATED (pika_brush_generated_get_type ())
|
||||
#define PIKA_BRUSH_GENERATED(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_BRUSH_GENERATED, PikaBrushGenerated))
|
||||
#define PIKA_BRUSH_GENERATED_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_BRUSH_GENERATED, PikaBrushGeneratedClass))
|
||||
#define PIKA_IS_BRUSH_GENERATED(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_BRUSH_GENERATED))
|
||||
#define PIKA_IS_BRUSH_GENERATED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_BRUSH_GENERATED))
|
||||
#define PIKA_BRUSH_GENERATED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_BRUSH_GENERATED, PikaBrushGeneratedClass))
|
||||
|
||||
|
||||
typedef struct _PikaBrushGeneratedClass PikaBrushGeneratedClass;
|
||||
|
||||
struct _PikaBrushGenerated
|
||||
{
|
||||
PikaBrush parent_instance;
|
||||
|
||||
PikaBrushGeneratedShape shape;
|
||||
gfloat radius;
|
||||
gint spikes; /* 2 - 20 */
|
||||
gfloat hardness; /* 0.0 - 1.0 */
|
||||
gfloat aspect_ratio; /* y/x */
|
||||
gfloat angle; /* in degrees */
|
||||
};
|
||||
|
||||
struct _PikaBrushGeneratedClass
|
||||
{
|
||||
PikaBrushClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
GType pika_brush_generated_get_type (void) G_GNUC_CONST;
|
||||
|
||||
PikaData * pika_brush_generated_new (const gchar *name,
|
||||
PikaBrushGeneratedShape shape,
|
||||
gfloat radius,
|
||||
gint spikes,
|
||||
gfloat hardness,
|
||||
gfloat aspect_ratio,
|
||||
gfloat angle);
|
||||
|
||||
PikaBrushGeneratedShape
|
||||
pika_brush_generated_set_shape (PikaBrushGenerated *brush,
|
||||
PikaBrushGeneratedShape shape);
|
||||
gfloat pika_brush_generated_set_radius (PikaBrushGenerated *brush,
|
||||
gfloat radius);
|
||||
gint pika_brush_generated_set_spikes (PikaBrushGenerated *brush,
|
||||
gint spikes);
|
||||
gfloat pika_brush_generated_set_hardness (PikaBrushGenerated *brush,
|
||||
gfloat hardness);
|
||||
gfloat pika_brush_generated_set_aspect_ratio (PikaBrushGenerated *brush,
|
||||
gfloat ratio);
|
||||
gfloat pika_brush_generated_set_angle (PikaBrushGenerated *brush,
|
||||
gfloat angle);
|
||||
|
||||
PikaBrushGeneratedShape
|
||||
pika_brush_generated_get_shape (PikaBrushGenerated *brush);
|
||||
gfloat pika_brush_generated_get_radius (PikaBrushGenerated *brush);
|
||||
gint pika_brush_generated_get_spikes (PikaBrushGenerated *brush);
|
||||
gfloat pika_brush_generated_get_hardness (PikaBrushGenerated *brush);
|
||||
gfloat pika_brush_generated_get_aspect_ratio (PikaBrushGenerated *brush);
|
||||
gfloat pika_brush_generated_get_angle (PikaBrushGenerated *brush);
|
||||
|
||||
|
||||
#endif /* __PIKA_BRUSH_GENERATED_H__ */
|
||||
167
app/core/pikabrushpipe-load.c
Normal file
167
app/core/pikabrushpipe-load.c
Normal file
@ -0,0 +1,167 @@
|
||||
/* 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
|
||||
* Copyright (C) 1999 Adrian Likins and Tor Lillqvist
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikabrush-load.h"
|
||||
#include "pikabrush-private.h"
|
||||
#include "pikabrushpipe.h"
|
||||
#include "pikabrushpipe-load.h"
|
||||
|
||||
#include "pika-intl.h"
|
||||
|
||||
|
||||
GList *
|
||||
pika_brush_pipe_load (PikaContext *context,
|
||||
GFile *file,
|
||||
GInputStream *input,
|
||||
GError **error)
|
||||
{
|
||||
PikaBrushPipe *pipe = NULL;
|
||||
gint n_brushes = 0;
|
||||
GString *buffer;
|
||||
gchar *paramstring;
|
||||
gchar c;
|
||||
gsize bytes_read;
|
||||
|
||||
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||
g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
/* The file format starts with a painfully simple text header */
|
||||
|
||||
/* get the name */
|
||||
buffer = g_string_new (NULL);
|
||||
while (g_input_stream_read_all (input, &c, 1, &bytes_read, NULL, NULL) &&
|
||||
bytes_read == 1 &&
|
||||
c != '\n' &&
|
||||
buffer->len < 1024)
|
||||
{
|
||||
g_string_append_c (buffer, c);
|
||||
}
|
||||
|
||||
if (buffer->len > 0 && buffer->len < 1024)
|
||||
{
|
||||
gchar *utf8 =
|
||||
pika_any_to_utf8 (buffer->str, buffer->len,
|
||||
_("Invalid UTF-8 string in brush file '%s'."),
|
||||
pika_file_get_utf8_name (file));
|
||||
|
||||
pipe = g_object_new (PIKA_TYPE_BRUSH_PIPE,
|
||||
"name", utf8,
|
||||
"mime-type", "image/x-pika-gih",
|
||||
NULL);
|
||||
|
||||
g_free (utf8);
|
||||
}
|
||||
|
||||
g_string_free (buffer, TRUE);
|
||||
|
||||
if (! pipe)
|
||||
{
|
||||
g_set_error (error, PIKA_DATA_ERROR, PIKA_DATA_ERROR_READ,
|
||||
_("Fatal parse error in brush file '%s': "
|
||||
"File is corrupt."),
|
||||
pika_file_get_utf8_name (file));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get the number of brushes */
|
||||
buffer = g_string_new (NULL);
|
||||
while (g_input_stream_read_all (input, &c, 1, &bytes_read, NULL, NULL) &&
|
||||
bytes_read == 1 &&
|
||||
c != '\n' &&
|
||||
buffer->len < 1024)
|
||||
{
|
||||
g_string_append_c (buffer, c);
|
||||
}
|
||||
|
||||
if (buffer->len > 0 && buffer->len < 1024)
|
||||
{
|
||||
n_brushes = strtol (buffer->str, ¶mstring, 10);
|
||||
}
|
||||
|
||||
if (n_brushes < 1)
|
||||
{
|
||||
g_set_error (error, PIKA_DATA_ERROR, PIKA_DATA_ERROR_READ,
|
||||
_("Fatal parse error in brush file '%s': "
|
||||
"File is corrupt."),
|
||||
pika_file_get_utf8_name (file));
|
||||
g_object_unref (pipe);
|
||||
g_string_free (buffer, TRUE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (*paramstring && g_ascii_isspace (*paramstring))
|
||||
paramstring++;
|
||||
|
||||
pipe->brushes = g_new0 (PikaBrush *, n_brushes);
|
||||
|
||||
while (pipe->n_brushes < n_brushes)
|
||||
{
|
||||
pipe->brushes[pipe->n_brushes] = pika_brush_load_brush (context,
|
||||
file, input,
|
||||
error);
|
||||
|
||||
if (! pipe->brushes[pipe->n_brushes])
|
||||
{
|
||||
g_object_unref (pipe);
|
||||
g_string_free (buffer, TRUE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pipe->n_brushes++;
|
||||
}
|
||||
|
||||
if (! pika_brush_pipe_set_params (pipe, paramstring))
|
||||
{
|
||||
g_set_error (error, PIKA_DATA_ERROR, PIKA_DATA_ERROR_READ,
|
||||
_("Fatal parse error in brush file '%s': "
|
||||
"Inconsistent parameters."),
|
||||
pika_file_get_utf8_name (file));
|
||||
g_object_unref (pipe);
|
||||
g_string_free (buffer, TRUE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_string_free (buffer, TRUE);
|
||||
|
||||
/* Current brush is the first one. */
|
||||
pipe->current = pipe->brushes[0];
|
||||
|
||||
/* just to satisfy the code that relies on this crap */
|
||||
PIKA_BRUSH (pipe)->priv->spacing = pipe->current->priv->spacing;
|
||||
PIKA_BRUSH (pipe)->priv->x_axis = pipe->current->priv->x_axis;
|
||||
PIKA_BRUSH (pipe)->priv->y_axis = pipe->current->priv->y_axis;
|
||||
PIKA_BRUSH (pipe)->priv->mask = pipe->current->priv->mask;
|
||||
PIKA_BRUSH (pipe)->priv->pixmap = pipe->current->priv->pixmap;
|
||||
|
||||
return g_list_prepend (NULL, pipe);
|
||||
}
|
||||
36
app/core/pikabrushpipe-load.h
Normal file
36
app/core/pikabrushpipe-load.h
Normal file
@ -0,0 +1,36 @@
|
||||
/* 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
|
||||
* Copyright (C) 1999 Adrian Likins and Tor Lillqvist
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BRUSH_PIPE_LOAD_H__
|
||||
#define __PIKA_BRUSH_PIPE_LOAD_H__
|
||||
|
||||
|
||||
#define PIKA_BRUSH_PIPE_FILE_EXTENSION ".gih"
|
||||
|
||||
|
||||
GList * pika_brush_pipe_load (PikaContext *context,
|
||||
GFile *file,
|
||||
GInputStream *input,
|
||||
GError **error);
|
||||
|
||||
|
||||
#endif /* __PIKA_BRUSH_PIPE_LOAD_H__ */
|
||||
63
app/core/pikabrushpipe-save.c
Normal file
63
app/core/pikabrushpipe-save.c
Normal file
@ -0,0 +1,63 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikabrushpipe.h"
|
||||
#include "pikabrushpipe-save.h"
|
||||
|
||||
|
||||
gboolean
|
||||
pika_brush_pipe_save (PikaData *data,
|
||||
GOutputStream *output,
|
||||
GError **error)
|
||||
{
|
||||
PikaBrushPipe *pipe = PIKA_BRUSH_PIPE (data);
|
||||
const gchar *name;
|
||||
gint i;
|
||||
|
||||
name = pika_object_get_name (pipe);
|
||||
|
||||
if (! g_output_stream_printf (output, NULL, NULL, error,
|
||||
"%s\n%d %s\n",
|
||||
name, pipe->n_brushes, pipe->params))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < pipe->n_brushes; i++)
|
||||
{
|
||||
PikaBrush *brush = pipe->brushes[i];
|
||||
|
||||
if (brush &&
|
||||
! PIKA_DATA_GET_CLASS (brush)->save (PIKA_DATA (brush),
|
||||
output, error))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
32
app/core/pikabrushpipe-save.h
Normal file
32
app/core/pikabrushpipe-save.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* 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
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PIKA_BRUSH_PIPE_SAVE_H__
|
||||
#define __PIKA_BRUSH_PIPE_SAVE_H__
|
||||
|
||||
|
||||
/* don't call this function directly, use pika_data_save() instead */
|
||||
gboolean pika_brush_pipe_save (PikaData *data,
|
||||
GOutputStream *output,
|
||||
GError **error);
|
||||
|
||||
|
||||
#endif /* __PIKA_BRUSH_PIPE_SAVE_H__ */
|
||||
424
app/core/pikabrushpipe.c
Normal file
424
app/core/pikabrushpipe.c
Normal file
@ -0,0 +1,424 @@
|
||||
/* 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
|
||||
* Copyright (C) 1999 Adrian Likins and Tor Lillqvist
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gegl.h>
|
||||
|
||||
#include "libpikabase/pikaparasiteio.h"
|
||||
#include "libpikamath/pikamath.h"
|
||||
|
||||
#include "core-types.h"
|
||||
|
||||
#include "pikabrush-private.h"
|
||||
#include "pikabrushpipe.h"
|
||||
#include "pikabrushpipe-load.h"
|
||||
#include "pikabrushpipe-save.h"
|
||||
#include "pikatempbuf.h"
|
||||
|
||||
|
||||
static void pika_brush_pipe_finalize (GObject *object);
|
||||
|
||||
static gint64 pika_brush_pipe_get_memsize (PikaObject *object,
|
||||
gint64 *gui_size);
|
||||
|
||||
static gboolean pika_brush_pipe_get_popup_size (PikaViewable *viewable,
|
||||
gint width,
|
||||
gint height,
|
||||
gboolean dot_for_dot,
|
||||
gint *popup_width,
|
||||
gint *popup_height);
|
||||
|
||||
static const gchar * pika_brush_pipe_get_extension (PikaData *data);
|
||||
static void pika_brush_pipe_copy (PikaData *data,
|
||||
PikaData *src_data);
|
||||
|
||||
static void pika_brush_pipe_begin_use (PikaBrush *brush);
|
||||
static void pika_brush_pipe_end_use (PikaBrush *brush);
|
||||
static PikaBrush * pika_brush_pipe_select_brush (PikaBrush *brush,
|
||||
const PikaCoords *last_coords,
|
||||
const PikaCoords *current_coords);
|
||||
static gboolean pika_brush_pipe_want_null_motion (PikaBrush *brush,
|
||||
const PikaCoords *last_coords,
|
||||
const PikaCoords *current_coords);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (PikaBrushPipe, pika_brush_pipe, PIKA_TYPE_BRUSH);
|
||||
|
||||
#define parent_class pika_brush_pipe_parent_class
|
||||
|
||||
|
||||
static void
|
||||
pika_brush_pipe_class_init (PikaBrushPipeClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
PikaObjectClass *pika_object_class = PIKA_OBJECT_CLASS (klass);
|
||||
PikaViewableClass *viewable_class = PIKA_VIEWABLE_CLASS (klass);
|
||||
PikaDataClass *data_class = PIKA_DATA_CLASS (klass);
|
||||
PikaBrushClass *brush_class = PIKA_BRUSH_CLASS (klass);
|
||||
|
||||
object_class->finalize = pika_brush_pipe_finalize;
|
||||
|
||||
pika_object_class->get_memsize = pika_brush_pipe_get_memsize;
|
||||
|
||||
viewable_class->get_popup_size = pika_brush_pipe_get_popup_size;
|
||||
|
||||
data_class->save = pika_brush_pipe_save;
|
||||
data_class->get_extension = pika_brush_pipe_get_extension;
|
||||
data_class->copy = pika_brush_pipe_copy;
|
||||
|
||||
brush_class->begin_use = pika_brush_pipe_begin_use;
|
||||
brush_class->end_use = pika_brush_pipe_end_use;
|
||||
brush_class->select_brush = pika_brush_pipe_select_brush;
|
||||
brush_class->want_null_motion = pika_brush_pipe_want_null_motion;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_pipe_init (PikaBrushPipe *pipe)
|
||||
{
|
||||
pipe->current = NULL;
|
||||
pipe->dimension = 0;
|
||||
pipe->rank = NULL;
|
||||
pipe->stride = NULL;
|
||||
pipe->n_brushes = 0;
|
||||
pipe->brushes = NULL;
|
||||
pipe->select = NULL;
|
||||
pipe->index = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_pipe_finalize (GObject *object)
|
||||
{
|
||||
PikaBrushPipe *pipe = PIKA_BRUSH_PIPE (object);
|
||||
|
||||
g_clear_pointer (&pipe->rank, g_free);
|
||||
g_clear_pointer (&pipe->stride, g_free);
|
||||
g_clear_pointer (&pipe->select, g_free);
|
||||
g_clear_pointer (&pipe->index, g_free);
|
||||
g_clear_pointer (&pipe->params, g_free);
|
||||
|
||||
if (pipe->brushes)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < pipe->n_brushes; i++)
|
||||
if (pipe->brushes[i])
|
||||
g_object_unref (pipe->brushes[i]);
|
||||
|
||||
g_clear_pointer (&pipe->brushes, g_free);
|
||||
}
|
||||
|
||||
PIKA_BRUSH (pipe)->priv->mask = NULL;
|
||||
PIKA_BRUSH (pipe)->priv->pixmap = NULL;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static gint64
|
||||
pika_brush_pipe_get_memsize (PikaObject *object,
|
||||
gint64 *gui_size)
|
||||
{
|
||||
PikaBrushPipe *pipe = PIKA_BRUSH_PIPE (object);
|
||||
gint64 memsize = 0;
|
||||
gint i;
|
||||
|
||||
memsize += pipe->dimension * (sizeof (gint) /* rank */ +
|
||||
sizeof (gint) /* stride */ +
|
||||
sizeof (PipeSelectModes));
|
||||
|
||||
for (i = 0; i < pipe->n_brushes; i++)
|
||||
memsize += pika_object_get_memsize (PIKA_OBJECT (pipe->brushes[i]),
|
||||
gui_size);
|
||||
|
||||
return memsize + PIKA_OBJECT_CLASS (parent_class)->get_memsize (object,
|
||||
gui_size);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_brush_pipe_get_popup_size (PikaViewable *viewable,
|
||||
gint width,
|
||||
gint height,
|
||||
gboolean dot_for_dot,
|
||||
gint *popup_width,
|
||||
gint *popup_height)
|
||||
{
|
||||
return pika_viewable_get_size (viewable, popup_width, popup_height);
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
pika_brush_pipe_get_extension (PikaData *data)
|
||||
{
|
||||
return PIKA_BRUSH_PIPE_FILE_EXTENSION;
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_pipe_copy (PikaData *data,
|
||||
PikaData *src_data)
|
||||
{
|
||||
PikaBrushPipe *pipe = PIKA_BRUSH_PIPE (data);
|
||||
PikaBrushPipe *src_pipe = PIKA_BRUSH_PIPE (src_data);
|
||||
gint i;
|
||||
|
||||
pipe->dimension = src_pipe->dimension;
|
||||
|
||||
g_clear_pointer (&pipe->rank, g_free);
|
||||
pipe->rank = g_memdup2 (src_pipe->rank,
|
||||
pipe->dimension * sizeof (gint));
|
||||
|
||||
g_clear_pointer (&pipe->stride, g_free);
|
||||
pipe->stride = g_memdup2 (src_pipe->stride,
|
||||
pipe->dimension * sizeof (gint));
|
||||
|
||||
g_clear_pointer (&pipe->select, g_free);
|
||||
pipe->select = g_memdup2 (src_pipe->select,
|
||||
pipe->dimension * sizeof (PipeSelectModes));
|
||||
|
||||
g_clear_pointer (&pipe->index, g_free);
|
||||
pipe->index = g_memdup2 (src_pipe->index,
|
||||
pipe->dimension * sizeof (gint));
|
||||
|
||||
for (i = 0; i < pipe->n_brushes; i++)
|
||||
if (pipe->brushes[i])
|
||||
g_object_unref (pipe->brushes[i]);
|
||||
g_clear_pointer (&pipe->brushes, g_free);
|
||||
|
||||
pipe->n_brushes = src_pipe->n_brushes;
|
||||
|
||||
pipe->brushes = g_new0 (PikaBrush *, pipe->n_brushes);
|
||||
for (i = 0; i < pipe->n_brushes; i++)
|
||||
if (src_pipe->brushes[i])
|
||||
{
|
||||
pipe->brushes[i] =
|
||||
PIKA_BRUSH (pika_data_duplicate (PIKA_DATA (src_pipe->brushes[i])));
|
||||
pika_object_set_name (PIKA_OBJECT (pipe->brushes[i]),
|
||||
pika_object_get_name (src_pipe->brushes[i]));
|
||||
}
|
||||
|
||||
g_clear_pointer (&pipe->params, g_free);
|
||||
pipe->params = g_strdup (src_pipe->params);
|
||||
|
||||
pipe->current = pipe->brushes[0];
|
||||
|
||||
PIKA_BRUSH (pipe)->priv->spacing = pipe->current->priv->spacing;
|
||||
PIKA_BRUSH (pipe)->priv->x_axis = pipe->current->priv->x_axis;
|
||||
PIKA_BRUSH (pipe)->priv->y_axis = pipe->current->priv->y_axis;
|
||||
PIKA_BRUSH (pipe)->priv->mask = pipe->current->priv->mask;
|
||||
PIKA_BRUSH (pipe)->priv->pixmap = pipe->current->priv->pixmap;
|
||||
|
||||
pika_data_dirty (data);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_pipe_begin_use (PikaBrush *brush)
|
||||
{
|
||||
PikaBrushPipe *pipe = PIKA_BRUSH_PIPE (brush);
|
||||
gint i;
|
||||
|
||||
PIKA_BRUSH_CLASS (parent_class)->begin_use (brush);
|
||||
|
||||
for (i = 0; i < pipe->n_brushes; i++)
|
||||
if (pipe->brushes[i])
|
||||
pika_brush_begin_use (pipe->brushes[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
pika_brush_pipe_end_use (PikaBrush *brush)
|
||||
{
|
||||
PikaBrushPipe *pipe = PIKA_BRUSH_PIPE (brush);
|
||||
gint i;
|
||||
|
||||
PIKA_BRUSH_CLASS (parent_class)->end_use (brush);
|
||||
|
||||
for (i = 0; i < pipe->n_brushes; i++)
|
||||
if (pipe->brushes[i])
|
||||
pika_brush_end_use (pipe->brushes[i]);
|
||||
}
|
||||
|
||||
static PikaBrush *
|
||||
pika_brush_pipe_select_brush (PikaBrush *brush,
|
||||
const PikaCoords *last_coords,
|
||||
const PikaCoords *current_coords)
|
||||
{
|
||||
PikaBrushPipe *pipe = PIKA_BRUSH_PIPE (brush);
|
||||
gint i, brushix, ix;
|
||||
|
||||
if (pipe->n_brushes == 1)
|
||||
return PIKA_BRUSH (pipe->current);
|
||||
|
||||
brushix = 0;
|
||||
for (i = 0; i < pipe->dimension; i++)
|
||||
{
|
||||
switch (pipe->select[i])
|
||||
{
|
||||
case PIPE_SELECT_INCREMENTAL:
|
||||
ix = (pipe->index[i] + 1) % pipe->rank[i];
|
||||
break;
|
||||
|
||||
case PIPE_SELECT_ANGULAR:
|
||||
/* Coords angle is already nomalized,
|
||||
* offset by 90 degrees is still needed
|
||||
* because hoses were made PS compatible*/
|
||||
ix = (gint) RINT ((1.0 - current_coords->direction + 0.25) * pipe->rank[i]) % pipe->rank[i];
|
||||
break;
|
||||
|
||||
case PIPE_SELECT_VELOCITY:
|
||||
ix = ROUND (current_coords->velocity * pipe->rank[i]);
|
||||
break;
|
||||
|
||||
case PIPE_SELECT_RANDOM:
|
||||
/* This probably isn't the right way */
|
||||
ix = g_random_int_range (0, pipe->rank[i]);
|
||||
break;
|
||||
|
||||
case PIPE_SELECT_PRESSURE:
|
||||
ix = RINT (current_coords->pressure * (pipe->rank[i] - 1));
|
||||
break;
|
||||
|
||||
case PIPE_SELECT_TILT_X:
|
||||
ix = RINT (current_coords->xtilt / 2.0 * pipe->rank[i]) + pipe->rank[i] / 2;
|
||||
break;
|
||||
|
||||
case PIPE_SELECT_TILT_Y:
|
||||
ix = RINT (current_coords->ytilt / 2.0 * pipe->rank[i]) + pipe->rank[i] / 2;
|
||||
break;
|
||||
|
||||
case PIPE_SELECT_CONSTANT:
|
||||
default:
|
||||
ix = pipe->index[i];
|
||||
break;
|
||||
}
|
||||
|
||||
pipe->index[i] = CLAMP (ix, 0, pipe->rank[i] - 1);
|
||||
brushix += pipe->stride[i] * pipe->index[i];
|
||||
}
|
||||
|
||||
/* Make sure is inside bounds */
|
||||
brushix = CLAMP (brushix, 0, pipe->n_brushes - 1);
|
||||
|
||||
pipe->current = pipe->brushes[brushix];
|
||||
|
||||
return PIKA_BRUSH (pipe->current);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pika_brush_pipe_want_null_motion (PikaBrush *brush,
|
||||
const PikaCoords *last_coords,
|
||||
const PikaCoords *current_coords)
|
||||
{
|
||||
PikaBrushPipe *pipe = PIKA_BRUSH_PIPE (brush);
|
||||
gint i;
|
||||
|
||||
if (pipe->n_brushes == 1)
|
||||
return TRUE;
|
||||
|
||||
for (i = 0; i < pipe->dimension; i++)
|
||||
if (pipe->select[i] == PIPE_SELECT_ANGULAR)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
gboolean
|
||||
pika_brush_pipe_set_params (PikaBrushPipe *pipe,
|
||||
const gchar *paramstring)
|
||||
{
|
||||
gint totalcells;
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (PIKA_IS_BRUSH_PIPE (pipe), FALSE);
|
||||
g_return_val_if_fail (pipe->dimension == 0, FALSE); /* only on a new pipe! */
|
||||
|
||||
if (paramstring && *paramstring)
|
||||
{
|
||||
PikaPixPipeParams params;
|
||||
|
||||
pika_pixpipe_params_init (¶ms);
|
||||
pika_pixpipe_params_parse (paramstring, ¶ms);
|
||||
|
||||
pipe->dimension = params.dim;
|
||||
pipe->rank = g_new0 (gint, pipe->dimension);
|
||||
pipe->select = g_new0 (PipeSelectModes, pipe->dimension);
|
||||
pipe->index = g_new0 (gint, pipe->dimension);
|
||||
/* placement is not used at all ?? */
|
||||
|
||||
for (i = 0; i < pipe->dimension; i++)
|
||||
{
|
||||
pipe->rank[i] = MAX (1, params.rank[i]);
|
||||
|
||||
if (strcmp (params.selection[i], "incremental") == 0)
|
||||
pipe->select[i] = PIPE_SELECT_INCREMENTAL;
|
||||
else if (strcmp (params.selection[i], "angular") == 0)
|
||||
pipe->select[i] = PIPE_SELECT_ANGULAR;
|
||||
else if (strcmp (params.selection[i], "velocity") == 0)
|
||||
pipe->select[i] = PIPE_SELECT_VELOCITY;
|
||||
else if (strcmp (params.selection[i], "random") == 0)
|
||||
pipe->select[i] = PIPE_SELECT_RANDOM;
|
||||
else if (strcmp (params.selection[i], "pressure") == 0)
|
||||
pipe->select[i] = PIPE_SELECT_PRESSURE;
|
||||
else if (strcmp (params.selection[i], "xtilt") == 0)
|
||||
pipe->select[i] = PIPE_SELECT_TILT_X;
|
||||
else if (strcmp (params.selection[i], "ytilt") == 0)
|
||||
pipe->select[i] = PIPE_SELECT_TILT_Y;
|
||||
else
|
||||
pipe->select[i] = PIPE_SELECT_CONSTANT;
|
||||
|
||||
pipe->index[i] = 0;
|
||||
}
|
||||
|
||||
pika_pixpipe_params_free (¶ms);
|
||||
|
||||
pipe->params = g_strdup (paramstring);
|
||||
}
|
||||
else
|
||||
{
|
||||
pipe->dimension = 1;
|
||||
pipe->rank = g_new (gint, 1);
|
||||
pipe->rank[0] = pipe->n_brushes;
|
||||
pipe->select = g_new (PipeSelectModes, 1);
|
||||
pipe->select[0] = PIPE_SELECT_INCREMENTAL;
|
||||
pipe->index = g_new (gint, 1);
|
||||
pipe->index[0] = 0;
|
||||
}
|
||||
|
||||
totalcells = 1; /* Not all necessarily present, maybe */
|
||||
for (i = 0; i < pipe->dimension; i++)
|
||||
totalcells *= pipe->rank[i];
|
||||
|
||||
pipe->stride = g_new0 (gint, pipe->dimension);
|
||||
|
||||
for (i = 0; i < pipe->dimension; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
pipe->stride[i] = totalcells / pipe->rank[i];
|
||||
else
|
||||
pipe->stride[i] = pipe->stride[i-1] / pipe->rank[i];
|
||||
}
|
||||
|
||||
if (pipe->stride[pipe->dimension - 1] != 1)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user