Adding upstream version 3.0.4.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
23
devel-docs/GIMP3-API-Changes.txt
Normal file
|
@ -0,0 +1,23 @@
|
|||
This file contains a list of changes that can/must be done when
|
||||
we break API/ABI for 3.x.
|
||||
|
||||
|
||||
- Move GIMP_REPEAT_TRUNCATE to the start of the enum and rename it
|
||||
to NONE. Rename the current NONE to EXTEND or something.
|
||||
|
||||
- Add LOTS of padding to all public class structs.
|
||||
|
||||
- Have private pointers in all public instance structs, not just
|
||||
GET_PRIVATE() macros, in order to inspect the private structs
|
||||
easily in the debugger.
|
||||
|
||||
- Remove compat values from all enums.
|
||||
|
||||
- Add user_data to all functions passed to gimp_widgets_init()
|
||||
|
||||
- Preferably make gimp_widgets_init() take a vtable with padding.
|
||||
|
||||
- Change gimp_prop_foo_new() to use the nick as label, or find some
|
||||
other way to use the nick.
|
||||
|
||||
- Pass the plug-in protocol version on the plug-in command line.
|
272
devel-docs/GIMP3-plug-in-porting-guide/API-for-resources.md
Normal file
|
@ -0,0 +1,272 @@
|
|||
# API changes in libgimp and the PDB for resources
|
||||
|
||||
This explains changes to the GIMP API from v2 to v3,
|
||||
concerning resources.
|
||||
|
||||
The audience is plugin authors, and GIMP developers.
|
||||
|
||||
### Resources
|
||||
|
||||
A resource is a chunk of data that can be installed with GIMP
|
||||
and is used by painting tools or for other rendering tasks.
|
||||
Usually known as brush, font, palette, pattern, gradient and so forth.
|
||||
|
||||
### Resources are now first class objects
|
||||
|
||||
GimpResource is now a class in libgimp.
|
||||
|
||||
It has subclasses:
|
||||
|
||||
- Brush
|
||||
- Font
|
||||
- Gradient
|
||||
- Palette
|
||||
- Pattern
|
||||
|
||||
Formerly, the GIMP API had functions operating on resources by name.
|
||||
Now, there are methods on resource objects.
|
||||
Methods take an instance of the object as the first argument,
|
||||
often called "self."
|
||||
|
||||
This means that where you formerly used a string name to refer to a resource object,
|
||||
now you usually should pass an instance of an object.
|
||||
|
||||
### Changes to reference documents
|
||||
|
||||
#### libgimp API reference
|
||||
|
||||
Shows classes Brush, Font, and so forth.
|
||||
The classes have instance methods taking the instance as the first argument.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
gboolean gboolean gimp_brush_delete(gcharray) => gboolean gimp_brush_delete ( GimpBrush*)
|
||||
```
|
||||
|
||||
The classes may also have class methods still taking string names.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
gboolean gimp_brush_id_is_valid (const gchar* id)
|
||||
```
|
||||
|
||||
Is a class method (in the "Functions" section of the class) taking the ID
|
||||
(same as the name) to test whether such a brush is installed in Gimp core.
|
||||
|
||||
#### PDB Browser
|
||||
|
||||
Remember the PDB Browser shows the C API. You must mentally convert
|
||||
to the API in bound languages.
|
||||
|
||||
Shows some procedures that now take type e.g. GimpBrush
|
||||
where formerly they took type gcharray i.e. strings.
|
||||
|
||||
Shows some procedures that take a string name of a brush.
|
||||
These are usually class methods.
|
||||
|
||||
#### Other changes to the API
|
||||
|
||||
Many of the Gimp functions dealing with the context
|
||||
now take or return an instance of a resource.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
gcharray* gimp_context_get_brush (void) => GimpBrush* gimp_context_get_brush (void)
|
||||
```
|
||||
|
||||
A few functions have even more changed signature:
|
||||
|
||||
```
|
||||
gint gimp_palette_get_info (gcharray) =>
|
||||
gint gimp_palette_get_color_count (GimpPalette*)
|
||||
```
|
||||
|
||||
The name and description of this function are changed
|
||||
to accurately describe that the function only returns an integer
|
||||
(formerly, the description said it also returned the name of the palette.)
|
||||
|
||||
### New resource objects
|
||||
|
||||
FUTURE
|
||||
|
||||
Formerly there were no methods in the libgimp API or the PDB for objects:
|
||||
|
||||
- Dynamics
|
||||
- ColorProfile
|
||||
- ToolPreset
|
||||
|
||||
These classes exist primarily so that plugins can let a user choose an instance,
|
||||
and pass the instance on to other procedures.
|
||||
|
||||
### Traits
|
||||
|
||||
Informally, resources can have these traits:
|
||||
|
||||
- Nameable
|
||||
- Creatable/Deleable
|
||||
- Cloneable (Duplicatable)
|
||||
- Editable
|
||||
|
||||
Some resource subclasses don't have all traits.
|
||||
|
||||
### ID's and names
|
||||
|
||||
The ID and name of a resource are currently the same.
|
||||
(Some documents and method names may use either word, inconsistently.)
|
||||
|
||||
You usually use resource instances instead of their IDs.
|
||||
This will insulate your code from changes to GIMP re ID versus name.
|
||||
|
||||
A plugin should not use a resource's ID.
|
||||
A plugin should not show the ID/name to a user.
|
||||
The GIMP app shows the names of resources as a convenience to users,
|
||||
but usually shows resources visually, that is, iconically.
|
||||
An ID is opaque, that is, used internally by GIMP.
|
||||
|
||||
FUTURE: the ID and name of a resource are distinct.
|
||||
Different resource instances may have the same name.
|
||||
Methods returning lists of resources or resource names may return
|
||||
lists having duplicate names.
|
||||
|
||||
### Resource instances are references to underlying data
|
||||
|
||||
A resource instance is a proxy, or reference, to the underlying data.
|
||||
Methods on the instance act on the underlying data.
|
||||
The underlying data is in GIMP's store of resources.
|
||||
|
||||
It is possible for a resource instance to be "invalid"
|
||||
that is, referring to underlying data that does not exist,
|
||||
usually when a user uninstalls the thing.
|
||||
|
||||
### Creating Resources
|
||||
|
||||
Installing a resource is distinct from creating a resource.
|
||||
|
||||
GIMP lets you create some resources.
|
||||
You can't create fonts in GIMP, you can only install them.
|
||||
For those resources that GIMP lets you create,
|
||||
the act of creating it also installs it.
|
||||
|
||||
For resources that you can create in GIMP:
|
||||
|
||||
- some you create using menu items
|
||||
- some you can create using the API
|
||||
|
||||
The API does not let you create a raster brush.
|
||||
|
||||
The API does let you create a parametric brush.
|
||||
For example, in Python:
|
||||
```
|
||||
brush = Gimp.Brush.new("Foo")
|
||||
```
|
||||
creates a new parametric brush.
|
||||
|
||||
Note that the passed name is a proposed name.
|
||||
If the name is already in use,
|
||||
the new brush will have a different name.
|
||||
The brush instance will always be valid.
|
||||
|
||||
### Getting Resources by ID
|
||||
|
||||
Currently, you usually ask the user to interactively choose a resource.
|
||||
|
||||
If you must get a reference to a resource for which you know the ID,
|
||||
you can new() the resource class and set it's ID property.
|
||||
See below.
|
||||
|
||||
FUTURE Resource classes have get_by_id() methods.
|
||||
|
||||
If such a named resource is currently installed,
|
||||
get_by_id() returns a valid instance of the resource class.
|
||||
If such a named resource is not currently installed,
|
||||
the method returns an error.
|
||||
|
||||
### Uninitialized or invalid resource instances
|
||||
|
||||
You can create an instance of a resource class that is invalid.
|
||||
|
||||
For example, in Python:
|
||||
|
||||
```
|
||||
brush = Gimp.Brush()
|
||||
brush.set_property("id", "Foo")
|
||||
```
|
||||
creates an instance that is invalid because there is no underlying data in the GIMP store
|
||||
(assuming a brush named "Foo" is not installed.)
|
||||
|
||||
Ordinarily, you would not use such a construct.
|
||||
Instead, you should use the new() method
|
||||
(for resource classes where it is defined)
|
||||
which creates, installs, and returns a valid instance except in dire circumstances (out of memory.)
|
||||
|
||||
### Invalid resource instances due to uninstalls
|
||||
|
||||
A plugin may have a resource as a parameter.
|
||||
|
||||
An interactive plugin may show a chooser widget to let a user choose a resource.
|
||||
The user's choices may be saved in settings.
|
||||
|
||||
In the same session of GIMP, or in a subsequent session,
|
||||
a user may invoke the plugin again.
|
||||
Then the saved settings are displayed in the plugin's dialog
|
||||
(when the second invocation is also interactive).
|
||||
|
||||
When, in the meantime (between invocations of the plugin)
|
||||
a user has uninstalled the reference resource,
|
||||
the resource, as a reference, is invalid.
|
||||
A well-written plugin should handle this case.
|
||||
|
||||
Resource classes have:
|
||||
|
||||
- is_valid() instance method
|
||||
- id_is_valid(char * name) class method
|
||||
|
||||
Well-written plugins should use these methods to ensure
|
||||
that saved (deserialized) resource instances
|
||||
are valid before subsequently using them.
|
||||
|
||||
|
||||
### Naming and renaming
|
||||
|
||||
As mentioned above, currently names must be unique.
|
||||
|
||||
For some resources, the method rename(char * name) changes the name.
|
||||
The method fails if the new name is already used.
|
||||
|
||||
When the instance is invalid to start with
|
||||
(it has an ID that does not refer to any installed data)
|
||||
renaming it can succeed and then it creates a valid instance.
|
||||
|
||||
### Duplicating
|
||||
|
||||
Duplicating a resource creates and installs the underlying data,
|
||||
under a new, generated name.
|
||||
|
||||
The duplicate() method on an instance returns a new instance.
|
||||
|
||||
### Deleting
|
||||
|
||||
You can delete some resources. This uninstalls them.
|
||||
You can delete some brushes, palettes, and gradients,
|
||||
when they are writeable i.e. editable,
|
||||
which usually means that a user previously created them.
|
||||
You can't delete fonts and patterns.
|
||||
|
||||
You can delete using the delete() instance method
|
||||
|
||||
When you delete a resource, the instance (the proxy in a variable) continues to exist, but is invalid.
|
||||
|
||||
### Resource lists
|
||||
|
||||
Some functions in GIMP return lists of resource names,
|
||||
representing the set of resources installed.
|
||||
|
||||
For example: gimp_brushes_get_list.
|
||||
|
||||
This returns a list of strings, the ID's of the resources.
|
||||
The list will have no duplicates.
|
||||
|
||||
FUTURE: this will return a list of resource instances, and their names may have duplicates.
|
15
devel-docs/GIMP3-plug-in-porting-guide/README.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
Here you'll find documentation useful for porting older GIMP
|
||||
plug-ins, especially Python ones, to the GIMP 3.0 APIs.
|
||||
|
||||
Files:
|
||||
|
||||
- [classes.md:](classes.md)
|
||||
A list of some of the important classes and modules in GIMP 3.0.
|
||||
|
||||
- [pdb-calls.md:](pdb-calls.md)
|
||||
An incomplete list of old PDB functions and their equivalents,
|
||||
using Python classes.
|
||||
|
||||
- [removed_functions.md:](removed_functions.md)
|
||||
Functions that have been removed from GIMP, and their replacements.
|
||||
|
82
devel-docs/GIMP3-plug-in-porting-guide/classes.md
Normal file
|
@ -0,0 +1,82 @@
|
|||
# Useful Modules/Classes in GIMP 3.0+
|
||||
|
||||
Here's a guide to the modules you're likely to need.
|
||||
It's a work in progress: feel free to add to it.
|
||||
|
||||
Online documentation for our libraries can be found at:
|
||||
https://developer.gimp.org/api/3.0/
|
||||
|
||||
You can also get some information in GIMP's Python console with
|
||||
*help(module)* or *help(object)*, and you can get a list of functions
|
||||
with *dir(object)*.
|
||||
|
||||
## Gimp
|
||||
|
||||
The base module: almost everything is under Gimp.
|
||||
|
||||
## Gimp.Image
|
||||
|
||||
The image object.
|
||||
|
||||
Some operations that used to be PDB calls, like
|
||||
```
|
||||
pdb.gimp_selection_layer_alpha(layer)
|
||||
```
|
||||
are now in the Image object, e.g.
|
||||
```
|
||||
img.select_item(Gimp.ChannelOps.REPLACE, layer)
|
||||
```
|
||||
|
||||
## Gimp.Layer
|
||||
|
||||
The layer object.
|
||||
|
||||
```
|
||||
fog = Gimp.Layer.new(image, name,
|
||||
drawable.width(), drawable.height(), type, opacity,
|
||||
Gimp.LayerMode.NORMAL)
|
||||
```
|
||||
|
||||
## Gimp.Selection
|
||||
|
||||
Selection operations that used to be in the PDB, e.g.
|
||||
```
|
||||
pdb.gimp_selection_none(img)
|
||||
```
|
||||
are now in the Gimp.Selection module, e.g.
|
||||
```
|
||||
Gimp.Selection.none(img)
|
||||
```
|
||||
|
||||
## Gimp.ImageType
|
||||
|
||||
A home for image types like RGBA, GRAY, etc:
|
||||
```
|
||||
Gimp.ImageType.RGBA_IMAGE
|
||||
```
|
||||
|
||||
## Gimp.FillType
|
||||
|
||||
e.g. Gimp.FillType.TRANSPARENT, Gimp.FillType.BACKGROUND
|
||||
|
||||
## Gimp.ChannelOps
|
||||
|
||||
The old channel op definitions in the gimpfu module, like
|
||||
```
|
||||
CHANNEL_OP_REPLACE
|
||||
```
|
||||
are now in their own module:
|
||||
|
||||
```
|
||||
Gimp.ChannelOps.REPLACE
|
||||
```
|
||||
|
||||
## Gegl.Color
|
||||
|
||||
In legacy plug-ins you could pass a simple list of integers, like (0, 0, 0).
|
||||
In 3.0+, create a Gegl.Color object:
|
||||
|
||||
```
|
||||
c = Gegl.Color.new("black")
|
||||
c.set_rgba(0.94, 0.71, 0.27, 1.0)
|
||||
```
|
76
devel-docs/GIMP3-plug-in-porting-guide/pdb-calls.md
Normal file
|
@ -0,0 +1,76 @@
|
|||
# PDB equivalence
|
||||
|
||||
A table of old PDB calls, and their equivalents in the GIMP 3.0+ world.
|
||||
|
||||
This document is a work in progress. Feel free to add to it.
|
||||
|
||||
## Undo/Context
|
||||
|
||||
| Removed function | Replacement |
|
||||
| -------------------------------- | ----------------------------
|
||||
| gimp_undo_push_group_start | image.undo_group_start() |
|
||||
| gimp_undo_push_group_end | image.undo_group_end() |
|
||||
| gimp.context_push() | Gimp.context_push() |
|
||||
| gimp.context_push() | Gimp.context_push() |
|
||||
| gimp_context_get_background | Gimp.context_get_background
|
||||
| gimp_context_set_background | Gimp.context_set_background
|
||||
|
||||
## File load/save
|
||||
|
||||
| Removed function | Replacement |
|
||||
| -------------------------------- | ----------------------------
|
||||
| gimp_file_load | Gimp.file_load |
|
||||
| gimp_file_save | Gimp.file_save |
|
||||
|
||||
## Selection operations
|
||||
|
||||
Selection operations are now in the Gimp.Selection class (except
|
||||
a few in the Image class). E.g.
|
||||
|
||||
| Removed function | Replacement |
|
||||
| -------------------------------- | ----------------------------
|
||||
| pdb.gimp_selection_invert(img) | Gimp.Selection.invert(img) |
|
||||
| pdb.gimp_selection_none(img) | Gimp.Selection.none(img) |
|
||||
| pdb.gimp_selection_layer_alpha(layer) | img.select_item(Gimp.ChannelOps.REPLACE, layer) |
|
||||
| gimp_image_select_item | img.select_item(channel_op, layer) |
|
||||
|
||||
## Filling and Masks
|
||||
|
||||
| Removed function | Replacement |
|
||||
| -------------------------------- | ----------------------------
|
||||
| Gimp.drawable_fill() | layer.fill() |
|
||||
| pdb.gimp_edit_fill(FILL_BACKGROUND) | layer.edit_fill(Gimp.FillType.BACKGROUND) |
|
||||
| gimp_layer_add_mask | layer.add_mask
|
||||
| gimp_layer_remove_mask | layer.remove_mask
|
||||
|
||||
## Miscellaneous and Non-PDB Calls
|
||||
|
||||
| Removed function | Replacement |
|
||||
| -------------------------------- | ----------------------------
|
||||
| gimp_displays_flush | Gimp.displays_flush
|
||||
| gimp_image_insert_layer | image.insert_layer
|
||||
|
||||
|
||||
## Plug-ins
|
||||
|
||||
Calling other plug-ins is trickier than before. The old
|
||||
```
|
||||
pdb.script_fu_drop_shadow(img, layer, -3, -3, blur,
|
||||
(0, 0, 0), 80.0, False)
|
||||
```
|
||||
becomes
|
||||
```
|
||||
c = Gegl.Color.new("black")
|
||||
c.set_rgba(0.94, 0.71, 0.27, 1.0)
|
||||
Gimp.get_pdb().run_procedure('script-fu-drop-shadow',
|
||||
[ Gimp.RunMode.NONINTERACTIVE,
|
||||
GObject.Value(Gimp.Image, img),
|
||||
GObject.Value(Gimp.Drawable, layer),
|
||||
GObject.Value(GObject.TYPE_DOUBLE, -3),
|
||||
GObject.Value(GObject.TYPE_DOUBLE, -3),
|
||||
GObject.Value(GObject.TYPE_DOUBLE,blur),
|
||||
c,
|
||||
GObject.Value(GObject.TYPE_DOUBLE, 80.0),
|
||||
GObject.Value(GObject.TYPE_BOOLEAN, False)
|
||||
])
|
||||
```
|
226
devel-docs/GIMP3-plug-in-porting-guide/removed_functions.md
Normal file
|
@ -0,0 +1,226 @@
|
|||
## Removed Functions
|
||||
|
||||
These functions have been removed from GIMP 3. Most of them were deprecated
|
||||
since GIMP 2.10.x or older versions. As we bump the major version, it is time
|
||||
to start with a clean slate.
|
||||
|
||||
Below is a correspondence table with replacement function. The replacement is
|
||||
not necessarily a direct search-and-replace equivalent. Some may have different
|
||||
parameters, and in some case, it may require to think a bit about how things
|
||||
work to reproduce the same functionality. Nevertheless everything which was
|
||||
possible in the previous API is obviously still possible.
|
||||
|
||||
| Removed function | Replacement |
|
||||
| ----------------------------------------------- | ------------------------------------------------- |
|
||||
| `gimp_attach_new_parasite()` | `gimp_attach_parasite()` |
|
||||
| `gimp_brightness_contrast()` | `gimp_drawable_brightness_contrast()` |
|
||||
| `gimp_brushes_get_brush()` | `gimp_context_get_brush()` |
|
||||
| `gimp_brushes_get_brush_data()` | `gimp_brush_get_pixels()` |
|
||||
| `gimp_brushes_get_spacing()` | `gimp_brush_get_spacing()` |
|
||||
| `gimp_brushes_set_spacing()` | `gimp_brush_set_spacing()` |
|
||||
| `gimp_by_color_select()` | `gimp_image_select_color()` |
|
||||
| `gimp_by_color_select_full()` | `gimp_image_select_color()` |
|
||||
| `gimp_channel_menu_new()` | `gimp_channel_combo_box_new()` |
|
||||
| `gimp_checks_get_shades()` | `gimp_checks_get_colors()` |
|
||||
| `gimp_color_balance()` | `gimp_drawable_color_color_balance()` |
|
||||
| `gimp_color_display_convert()` | `gimp_color_display_convert_buffer()` |
|
||||
| `gimp_color_display_convert_surface()` | `gimp_color_display_convert_buffer()` |
|
||||
| `gimp_color_display_stack_convert()` | `gimp_color_display_stack_convert_buffer()` |
|
||||
| `gimp_color_display_stack_convert_surface()` | `gimp_color_display_stack_convert_buffer()` |
|
||||
| `gimp_color_profile_combo_box_add()` | `gimp_color_profile_combo_box_add_file()` |
|
||||
| `gimp_color_profile_combo_box_get_active()` | `gimp_color_profile_combo_box_get_active_file()` |
|
||||
| `gimp_color_profile_combo_box_set_active()` | `gimp_color_profile_combo_box_set_active_file()` |
|
||||
| `gimp_color_profile_store_add()` | `gimp_color_profile_store_add_file()` |
|
||||
| `gimp_colorize()` | `gimp_drawable_colorize_hsl()` |
|
||||
| `gimp_context_get_transform_recursion()` | *N/A* |
|
||||
| `gimp_context_set_transform_recursion()` | *N/A* |
|
||||
| `gimp_curves_explicit()` | `gimp_drawable_curves_explicit()` |
|
||||
| `gimp_curves_spline()` | `gimp_drawable_curves_spline()` |
|
||||
| `gimp_desaturate()` | `gimp_drawable_desaturate()` |
|
||||
| `gimp_desaturate_full()` | `gimp_drawable_desaturate()` |
|
||||
| `gimp_drawable_attach_new_parasite()` | `gimp_item_attach_parasite()` |
|
||||
| `gimp_drawable_bpp()` | `gimp_drawable_get_bpp()` |
|
||||
| `gimp_drawable_delete()` | `gimp_item_delete()` |
|
||||
| `gimp_drawable_get_image()` | `gimp_item_get_image()` |
|
||||
| `gimp_drawable_get_linked()` | *N/A* |
|
||||
| `gimp_drawable_get_name()` | `gimp_item_get_name()` |
|
||||
| `gimp_drawable_get_tattoo()` | `gimp_item_get_tattoo()` |
|
||||
| `gimp_drawable_get_visible()` | `gimp_item_get_visible()` |
|
||||
| `gimp_drawable_height()` | `gimp_drawable_get_height()` |
|
||||
| `gimp_drawable_is_channel()` | `gimp_item_is_channel()` |
|
||||
| `gimp_drawable_is_layer()` | `gimp_item_is_layer()` |
|
||||
| `gimp_drawable_is_layer_mask()` | `gimp_item_is_layer_mask()` |
|
||||
| `gimp_drawable_is_text_layer()` | `gimp_item_is_text_layer()` |
|
||||
| `gimp_drawable_is_valid()` | `gimp_item_is_valid()` |
|
||||
| `gimp_drawable_menu_new()` | `gimp_drawable_combo_box_new()` |
|
||||
| `gimp_drawable_offsets()` | `gimp_drawable_get_offsets()` |
|
||||
| `gimp_drawable_parasite_attach()` | `gimp_item_attach_parasite()` |
|
||||
| `gimp_drawable_parasite_detach()` | `gimp_item_detach_parasite()` |
|
||||
| `gimp_drawable_parasite_find()` | `gimp_item_get_parasite()` |
|
||||
| `gimp_drawable_parasite_list()` | `gimp_item_get_parasite_list()` |
|
||||
| `gimp_drawable_preview_new()` | `gimp_drawable_preview_new_from_drawable()` |
|
||||
| `gimp_drawable_preview_new_from_drawable_id()` | `gimp_drawable_preview_new_from_drawable()` |
|
||||
| `gimp_drawable_set_image()` | *N/A* |
|
||||
| `gimp_drawable_set_linked()` | *N/A* |
|
||||
| `gimp_drawable_set_name()` | `gimp_item_set_name()` |
|
||||
| `gimp_drawable_set_tattoo()` | `gimp_item_set_tattoo()` |
|
||||
| `gimp_drawable_set_visible()` | `gimp_item_set_visible()` |
|
||||
| `gimp_drawable_transform_2d()` | `gimp_item_transform_2d()` |
|
||||
| `gimp_drawable_transform_2d_default()` | `gimp_item_transform_2d()` |
|
||||
| `gimp_drawable_transform_flip()` | `gimp_item_transform_flip()` |
|
||||
| `gimp_drawable_transform_flip_default()` | `gimp_item_transform_flip()` |
|
||||
| `gimp_drawable_transform_flip_simple()` | `gimp_item_transform_flip_simple()` |
|
||||
| `gimp_drawable_transform_matrix()` | `gimp_item_transform_matrix()` |
|
||||
| `gimp_drawable_transform_matrix_default()` | `gimp_item_transform_matrix()` |
|
||||
| `gimp_drawable_transform_perspective()` | `gimp_item_transform_perspective()` |
|
||||
| `gimp_drawable_transform_perspective_default()` | `gimp_item_transform_perspective()` |
|
||||
| `gimp_drawable_transform_rotate()` | `gimp_item_transform_rotate()` |
|
||||
| `gimp_drawable_transform_rotate_default()` | `gimp_item_transform_rotate()` |
|
||||
| `gimp_drawable_transform_rotate_simple()` | `gimp_item_transform_rotate_simple()` |
|
||||
| `gimp_drawable_transform_scale()` | `gimp_item_transform_scale()` |
|
||||
| `gimp_drawable_transform_scale_default()` | `gimp_item_transform_scale()` |
|
||||
| `gimp_drawable_transform_shear()` | `gimp_item_transform_shear()` |
|
||||
| `gimp_drawable_transform_shear_default()` | `gimp_item_transform_shear()` |
|
||||
| `gimp_drawable_width()` | `gimp_drawable_get_width()` |
|
||||
| `gimp_edit_blend()` | `gimp_drawable_edit_gradient_fill()` |
|
||||
| `gimp_edit_bucket_fill()` | `gimp_drawable_edit_bucket_fill()` |
|
||||
| `gimp_edit_bucket_fill_full()` | `gimp_drawable_edit_bucket_fill()` |
|
||||
| `gimp_edit_clear()` | `gimp_drawable_edit_clear()` |
|
||||
| `gimp_edit_fill()` | `gimp_drawable_edit_fill()` |
|
||||
| `gimp_edit_paste_as_new()` | `gimp_edit_paste_as_new_image()` |
|
||||
| `gimp_edit_named_paste_as_new()` | `gimp_edit_named_paste_as_new_image()` |
|
||||
| `gimp_edit_stroke()` | `gimp_drawable_edit_stroke_selection()` |
|
||||
| `gimp_edit_stroke_vectors()` | `gimp_drawable_edit_stroke_item()` |
|
||||
| `gimp_ellipse_select()` | `gimp_image_select_ellipse()` |
|
||||
| `gimp_enum_combo_box_set_stock_prefix()` | `gimp_enum_combo_box_set_icon_prefix()` |
|
||||
| `gimp_enum_stock_box_new()` | `gimp_enum_icon_box_new()` |
|
||||
| `gimp_enum_stock_box_new_with_range()` | `gimp_enum_icon_box_new_with_range()` |
|
||||
| `gimp_enum_stock_box_set_child_padding()` | `gimp_enum_icon_box_set_child_padding()` |
|
||||
| `gimp_enum_store_set_stock_prefix()` | `gimp_enum_store_set_icon_prefix()` |
|
||||
| `gimp_equalize()` | `gimp_drawable_equalize()` |
|
||||
| `gimp_flip()` | `gimp_item_transform_flip_simple()` |
|
||||
| `gimp_floating_sel_relax()` | *N/A* |
|
||||
| `gimp_floating_sel_rigor()` | *N/A* |
|
||||
| `gimp_free_select()` | `gimp_image_select_polygon()` |
|
||||
| `gimp_fuzzy_select()` | `gimp_image_select_contiguous_color()` |
|
||||
| `gimp_fuzzy_select_full()` | `gimp_image_select_contiguous_color()` |
|
||||
| `gimp_gamma()` | `gimp_drawable_get_format()` |
|
||||
| `gimp_get_icon_theme_dir()` | *N/A* |
|
||||
| `gimp_get_path_by_tattoo()` | `gimp_image_get_path_by_tattoo()` |
|
||||
| `gimp_get_theme_dir()` | *N/A* |
|
||||
| `gimp_gradients_get_gradient_data()` | `gimp_gradient_get_uniform_samples()` |
|
||||
| `gimp_gradients_sample_custom()` | `gimp_gradient_get_custom_samples()` |
|
||||
| `gimp_gradients_sample_uniform()` | `gimp_gradient_get_uniform_samples()` |
|
||||
| `gimp_histogram()` | `gimp_drawable_histogram()` |
|
||||
| `gimp_hue_saturation()` | `gimp_drawable_hue_saturation()` |
|
||||
| `gimp_image_add_channel()` | `gimp_image_insert_channel()` |
|
||||
| `gimp_image_add_layer()` | `gimp_image_insert_layer()` |
|
||||
| `gimp_image_add_vectors()` | `gimp_image_insert_path()` |
|
||||
| `gimp_image_attach_new_parasite()` | `gimp_image_attach_parasite()` |
|
||||
| `gimp_image_base_type()` | `gimp_image_get_base_type()` |
|
||||
| `gimp_image_free_shadow()` | `gimp_drawable_free_shadow()` |
|
||||
| `gimp_image_get_channel_position()` | `gimp_image_get_item_position()` |
|
||||
| `gimp_image_get_cmap()` | `gimp_image_get_colormap()` |
|
||||
| `gimp_image_get_layer_position()` | `gimp_image_get_item_position()` |
|
||||
| `gimp_image_get_vectors_position()` | `gimp_image_get_item_position()` |
|
||||
| `gimp_image_height()` | `gimp_image_get_height()` |
|
||||
| `gimp_image_lower_channel()` | `gimp_image_lower_item()` |
|
||||
| `gimp_image_lower_layer()` | `gimp_image_lower_item()` |
|
||||
| `gimp_image_lower_layer_to_bottom()` | `gimp_image_lower_item_to_bottom()` |
|
||||
| `gimp_image_lower_vectors()` | `gimp_image_lower_item()` |
|
||||
| `gimp_image_lower_vectors_to_bottom()` | `gimp_image_lower_item_to_bottom()` |
|
||||
| `gimp_image_menu_new()` | `gimp_image_combo_box_new()` |
|
||||
| `gimp_image_parasite_attach()` | `gimp_image_attach_parasite()` |
|
||||
| `gimp_image_parasite_detach()` | `gimp_image_detach_parasite()` |
|
||||
| `gimp_image_parasite_find()` | `gimp_image_get_parasite()` |
|
||||
| `gimp_image_parasite_list()` | `gimp_image_get_parasite_list()` |
|
||||
| `gimp_image_raise_channel()` | `gimp_image_raise_item()` |
|
||||
| `gimp_image_raise_layer()` | `gimp_image_raise_item()` |
|
||||
| `gimp_image_raise_layer_to_top()` | `gimp_image_raise_item_to_top()` |
|
||||
| `gimp_image_raise_vectors()` | `gimp_image_raise_item()` |
|
||||
| `gimp_image_raise_vectors_to_top()` | `gimp_image_raise_item_to_top()` |
|
||||
| `gimp_image_scale_full()` | `gimp_image_scale()` |
|
||||
| `gimp_image_set_cmap()` | `gimp_image_set_colormap()` |
|
||||
| `gimp_image_width()` | `gimp_image_get_width()` |
|
||||
| `gimp_install_cmap()` | *N/A* |
|
||||
| `gimp_invert()` | `gimp_drawable_invert()` |
|
||||
| `gimp_item_get_linked()` | *N/A* |
|
||||
| `gimp_item_set_linked()` | *N/A* |
|
||||
| `gimp_layer_menu_new()` | `gimp_layer_combo_box_new()` |
|
||||
| `gimp_layer_scale_full()` | `gimp_layer_scale()` |
|
||||
| `gimp_layer_translate()` | `gimp_item_transform_translate()` |
|
||||
| `gimp_levels()` | `gimp_drawable_levels()` |
|
||||
| `gimp_levels_auto()` | `gimp_drawable_levels_stretch()` |
|
||||
| `gimp_levels_stretch()` | `gimp_drawable_levels_stretch()` |
|
||||
| `gimp_min_colors()` | *N/A* |
|
||||
| `gimp_palettes_get_palette()` | `gimp_context_get_palette()` |
|
||||
| `gimp_palettes_get_palette_entry()` | `gimp_palette_entry_get_color()` |
|
||||
| `gimp_parasite_attach()` | `gimp_attach_parasite()` |
|
||||
| `gimp_parasite_data()` | `gimp_parasite_get_data()` |
|
||||
| `gimp_parasite_data_size()` | `gimp_parasite_get_data()` |
|
||||
| `gimp_parasite_detach()` | `gimp_detach_parasite()` |
|
||||
| `gimp_parasite_find()` | `gimp_get_parasite()` |
|
||||
| `gimp_parasite_flags()` | `gimp_parasite_get_flags()` |
|
||||
| `gimp_parasite_list()` | `gimp_get_parasite_list()` |
|
||||
| `gimp_parasite_name()` | `gimp_parasite_get_name()` |
|
||||
| `gimp_path_delete()` | `gimp_image_remove_path()` |
|
||||
| `gimp_path_get_current()` | `gimp_image_get_selected_paths()` |
|
||||
| `gimp_path_get_locked()` | *N/A* |
|
||||
| `gimp_path_get_points()` | `gimp_path_stroke_get_points()` |
|
||||
| `gimp_path_get_point_at_dist()` | `gimp_path_stroke_get_point_at_dist()` |
|
||||
| `gimp_path_get_tattoo()` | `gimp_item_get_tattoo()` |
|
||||
| `gimp_path_import()` | `gimp_image_import_paths_from_file()` |
|
||||
| `gimp_path_list()` | `gimp_image_get_paths()` |
|
||||
| `gimp_path_set_current()` | `gimp_image_set_selected_paths()` |
|
||||
| `gimp_path_set_locked()` | *N/A* |
|
||||
| `gimp_path_set_points()` | `gimp_path_stroke_new_from_points()` |
|
||||
| `gimp_path_set_tattoo()` | `gimp_item_set_tattoo()` |
|
||||
| `gimp_path_stroke_current()` | `gimp_edit_stroke_vectors()` |
|
||||
| `gimp_path_to_selection()` | `gimp_image_select_item()` |
|
||||
| `gimp_patterns_get_pattern()` | `gimp_context_get_pattern()` |
|
||||
| `gimp_patterns_get_pattern_data()` | `gimp_pattern_get_pixels()` |
|
||||
| `gimp_perspective()` | `gimp_item_transform_perspective()` |
|
||||
| `gimp_posterize()` | `gimp_drawable_posterize()` |
|
||||
| `gimp_prop_enum_stock_box_new()` | `gimp_prop_enum_icon_box_new()` |
|
||||
| `gimp_prop_stock_image_new()` | `gimp_prop_icon_image_new()` |
|
||||
| `gimp_prop_unit_menu_new()` | `gimp_prop_unit_combo_box_new()` |
|
||||
| `gimp_rect_select()` | `gimp_image_select_rectangle()` |
|
||||
| `gimp_rotate()` | `gimp_item_transform_rotate()` |
|
||||
| `gimp_round_rect_select()` | `gimp_image_select_round_rectangle()` |
|
||||
| `gimp_scale()` | `gimp_item_transform_scale()` |
|
||||
| `gimp_selection_combine()` | `gimp_image_select_item()` |
|
||||
| `gimp_selection_layer_alpha()` | `gimp_image_select_item()` |
|
||||
| `gimp_selection_load()` | `gimp_image_select_item()` |
|
||||
| `gimp_shear()` | `gimp_item_transform_shear()` |
|
||||
| `gimp_stock_init()` | `gimp_icons_init()` |
|
||||
| `gimp_text()` | `gimp_text_fontname()` |
|
||||
| `gimp_text_get_extents()` | `gimp_text_get_extents_fontname()` |
|
||||
| `gimp_text_layer_get_hinting()` | `gimp_text_layer_get_hint_style()` |
|
||||
| `gimp_text_layer_set_hinting()` | `gimp_text_layer_set_hint_style()` |
|
||||
| `gimp_threshold()` | `gimp_drawable_threshold()` |
|
||||
| `gimp_toggle_button_sensitive_update()` | `g_object_bind_property()` |
|
||||
| `gimp_transform_2d()` | `gimp_item_transform_2d()` |
|
||||
| `gimp_unit_menu_update()` | `#GimpUnitComboBox` |
|
||||
| `gimp_vectors_export_to_file()` | `gimp_image_export_path_to_file()` |
|
||||
| `gimp_vectors_export_to_string()` | `gimp_image_export_path_to_string()` |
|
||||
| `gimp_vectors_get_image()` | `gimp_item_get_image()` |
|
||||
| `gimp_vectors_get_linked()` | *N/A* |
|
||||
| `gimp_vectors_get_name()` | `gimp_item_get_name()` |
|
||||
| `gimp_vectors_get_tattoo()` | `gimp_item_get_tattoo()` |
|
||||
| `gimp_vectors_get_visible()` | `gimp_item_get_visible()` |
|
||||
| `gimp_vectors_import_from_file()` | `gimp_image_import_paths_from_file()` |
|
||||
| `gimp_vectors_import_from_string()` | `gimp_image_import_paths_from_string()` |
|
||||
| `gimp_vectors_is_valid()` | `gimp_item_is_valid()` |
|
||||
| `gimp_vectors_parasite_attach()` | `gimp_item_attach_parasite()` |
|
||||
| `gimp_vectors_parasite_detach()` | `gimp_item_detach_parasite()` |
|
||||
| `gimp_vectors_parasite_find()` | `gimp_item_get_parasite()` |
|
||||
| `gimp_vectors_parasite_list()` | `gimp_item_get_parasite_list()` |
|
||||
| `gimp_vectors_set_linked()` | *N/A* |
|
||||
| `gimp_vectors_set_name()` | `gimp_item_set_name()` |
|
||||
| `gimp_vectors_set_tattoo()` | `gimp_item_set_tattoo()` |
|
||||
| `gimp_vectors_set_visible()` | `gimp_item_set_visible()` |
|
||||
| `gimp_vectors_to_selection()` | `gimp_image_select_item()` |
|
||||
| `gimp_zoom_preview_get_drawable_id()` | `gimp_zoom_preview_get_drawable()` |
|
||||
| `gimp_zoom_preview_new()` | `gimp_zoom_preview_new_from_drawable()` |
|
||||
| `gimp_zoom_preview_new_from_drawable_id()` | `gimp_zoom_preview_new_from_drawable()` |
|
||||
| `gimp_zoom_preview_new_with_model()` | `gimp_zoom_preview_new_with_model_from_drawable()`|
|
342
devel-docs/README.md
Normal file
|
@ -0,0 +1,342 @@
|
|||
---
|
||||
title: Developers documentation
|
||||
---
|
||||
|
||||
This manual holds information that you will find useful if you
|
||||
develop a GIMP plug-in or want to contribute to the GIMP core.
|
||||
|
||||
People only interested into plug-ins can probably read just the
|
||||
[Plug-in development](#plug-in-development) section. If you wish to
|
||||
contribute to all parts of GIMP, the whole documentation is of interest.
|
||||
|
||||
[TOC]
|
||||
|
||||
## Plug-in and Filters development
|
||||
|
||||
All needed information for Plug-in and Filters development is documented on the
|
||||
[Resource Development](https://developer.gimp.org/resource/)
|
||||
section of GIMP Developer website, with exception of the following:
|
||||
|
||||
### Porting from GIMP 2 plug-ins
|
||||
|
||||
Take a look at our [porting guide](GIMP3-plug-in-porting-guide/README.md).
|
||||
|
||||
## Custom data
|
||||
|
||||
This section list all types of data usable to enhance GIMP
|
||||
functionalities. If you are interested to contribute default data to
|
||||
GIMP, be aware that we are looking for a very good base set, not an
|
||||
unfinite number of data for all possible usage (even the less common
|
||||
ones).
|
||||
|
||||
Furthermore we only accept data on Libre licenses:
|
||||
|
||||
* [Free Art License](https://artlibre.org/licence/lal/en/)
|
||||
* [CC0](https://creativecommons.org/publicdomain/zero/1.0/)
|
||||
* [CC BY](https://creativecommons.org/licenses/by/4.0/)
|
||||
* [CC BY-SA](https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
|
||||
Of course you are free to share data usable by GIMP on any license you
|
||||
want on your own. Providing them as third-party GIMP
|
||||
[extensions](#gimp-extensions-gex) is probably the best idea.
|
||||
|
||||
### Brushes
|
||||
|
||||
GIMP currently supports the following brush formats:
|
||||
|
||||
* GIMP Brush (GBR): format to store pixmap brushes
|
||||
* GIMP Brush Pipe (GIH): format to store a series of pixmap brushes
|
||||
* GIMP Generated Brush (VBR): format of "generated" brushes
|
||||
* GIMP Brush Pixmap (GPB): *OBSOLETE* format to store pixel brushes
|
||||
* MyPaint brushes v1 (MYB)
|
||||
* Photoshop ABR Brush
|
||||
* Paint Shop Pro JBR Brush
|
||||
|
||||
We do fully support the GIMP formats obviously, as well as MyPaint
|
||||
brushes, since we use the official `libmypaint` library. We are not sure
|
||||
how well we support other third-party formats, especially if they had
|
||||
recent versions.
|
||||
|
||||
If you are interested in brushes from a developer perspective, you are
|
||||
welcome to read specifications of GIMP formats:
|
||||
[GBR](https://developer.gimp.org/core/standards/gbr/), [GIH](https://developer.gimp.org/core/standards/gih/),
|
||||
[VBR](https://developer.gimp.org/core/standards/vbr/) or the obsolete [GPB](https://developer.gimp.org/core/standards/gpb/).
|
||||
|
||||
If you want to contribute brushes to the official GIMP, be aware we
|
||||
would only accept brushes in non-obsolete GIMP formats. All these
|
||||
formats can be generated by GIMP itself from images.
|
||||
|
||||
If you want to contribute MyPaint brushes, we recommend to propose them
|
||||
to the [MyPaint-brushes](https://github.com/mypaint/mypaint-brushes/)
|
||||
data project, which is also used by GIMP for its default MyPaint brush
|
||||
set.
|
||||
|
||||
Otherwise, you are welcome to provide brush set in any format as
|
||||
third-party [extensions](#gimp-extensions-gex).
|
||||
|
||||
### Dynamics
|
||||
|
||||
GIMP supports the GIMP Paint Dynamics format which can be generated from
|
||||
within GIMP.
|
||||
|
||||
### Patterns
|
||||
|
||||
GIMP supports the GIMP Pattern format (PAT, whose
|
||||
[specification](https://developer.gimp.org/core/standards/pat/) is available for developers).
|
||||
|
||||
This format can be exported by GIMP itself.
|
||||
|
||||
Alternatively GIMP supports patterns from `GdkPixbuf` (**TODO**: get more
|
||||
information?).
|
||||
|
||||
### Palettes
|
||||
|
||||
GIMP supports the GIMP Palette format which can be generated from within
|
||||
GIMP.
|
||||
|
||||
### Gradients
|
||||
|
||||
GIMP supports the GIMP Gradient format (GGR, whose
|
||||
[specification](https://developer.gimp.org/core/standards/ggr/) is available for developers)
|
||||
which can be generated from within GIMP.
|
||||
|
||||
Alternatively GIMP supports the SVG Gradient format.
|
||||
|
||||
### Themes
|
||||
|
||||
GTK3 uses CSS themes. Don't be fooled though. It's not real CSS in that
|
||||
it doesn't have all the features of real web CSS, and since it's for
|
||||
desktop applications, some things are necessarily different. What it
|
||||
means is mostly that it "looks similar" enough that people used to web
|
||||
styling should not be too disorientated.
|
||||
|
||||
You can start by looking at the [official
|
||||
documentation](https://docs.gtk.org/gtk3/migrating-themes.html) for
|
||||
theme migration (from GTK+2 to 3), which gives a good overview, though
|
||||
it's far from being perfect unfortunately.
|
||||
|
||||
Another good idea would be to look at existing well maintained GTK3
|
||||
themes to get inspiration and see how things work.
|
||||
|
||||
Finally you can look at our existing themes, like the [System
|
||||
theme](https://gitlab.gnome.org/GNOME/gimp/-/blob/master/themes/System/gimp.css).
|
||||
Note though that this `System` theme is pretty bare, and that's its goal
|
||||
(try to theme as few as possible over whatever is the current real
|
||||
GTK system theme).
|
||||
|
||||
As a last trick for theme makers, we recommend to work with the
|
||||
GtkInspector tool, which allows you to test CSS rules live in the `CSS`
|
||||
tab. You can run the `GtkInspector` by going to the `File > Debug` menu
|
||||
and selecting `Start GtkInspector` menu item.
|
||||
|
||||
It also allows you to find the name of a widget to use in your CSS
|
||||
rules. To do so:
|
||||
|
||||
* Start the `GtkInspector`;
|
||||
* go on the "Objects" tab;
|
||||
* click the "target" 🞋 icon on the headerbar's top-left, then pick in
|
||||
GIMP interface the widget you are interested to style;
|
||||
* the widget name will be displayed on the top of the information area
|
||||
of the dialog.
|
||||
* Feel free to browse the various sections to see the class hierarchy,
|
||||
CSS nodes and so on.
|
||||
* The second top-left button (just next to the target icon) allows you
|
||||
to switch between the details of the selected widget and the widget
|
||||
hierarchy (container widgets containing other widgets), which is also
|
||||
very useful information.
|
||||
|
||||
Additionally you can quickly switch between the light and dark variant
|
||||
of a same theme by going to "Visual" tab and switching the "Dark
|
||||
Variant" button ON or OFF.
|
||||
|
||||
### Icon themes
|
||||
|
||||
Icon sets (a.k.a. "icon themes") have been separated from themes since
|
||||
GIMP 2.10 so you can have any icon theme with any theme.
|
||||
|
||||
To know about icons, go to [gimp-data/icons](https://gitlab.gnome.org/GNOME/gimp-data/-/blob/main/icons/README.md?ref_type=heads).
|
||||
|
||||
### TODO: Tool presets
|
||||
|
||||
|
||||
## TODO: GIMP extensions (*.gex*)
|
||||
|
||||
|
||||
## Core development
|
||||
|
||||
When writing code, any core developer is expected to follow:
|
||||
|
||||
- GIMP's [coding style](https://developer.gimp.org/core/coding_style/);
|
||||
- the [directory structure](#directory-structure-of-gimp-source-tree)
|
||||
- our [header file inclusion policy](includes.txt)
|
||||
|
||||
[GIMP's developer site](https://developer.gimp.org/) contain various valuable resources.
|
||||
|
||||
Finally the [debugging-tips](https://developer.gimp.org/core/debug/debugging-tips/) file contain many very
|
||||
useful tricks to help you debugging in various common cases.
|
||||
|
||||
### Newcomers
|
||||
|
||||
If this is your first time contributing to GIMP, you might be interested
|
||||
by [build instructions](https://developer.gimp.org/core/setup/).
|
||||
|
||||
You might also like to read these instructions on the process of
|
||||
[submitting patches](https://developer.gimp.org/core/submit-patch/).
|
||||
|
||||
### TODO: Core Contributors
|
||||
|
||||
As a core dev, you can trigger .appimage, .flatpak standalone packages,
|
||||
.exe Windows installer or Microsoft Store/.msixbundle to be generated
|
||||
with the MR code as explained in [gitlab-mr.md](gitlab-mr.md).
|
||||
|
||||
### Directory structure of GIMP source tree
|
||||
|
||||
GIMP source tree can be divided into the main application, libraries, plug-ins,
|
||||
data files and some stuff that don't fit into these categories. Here are the
|
||||
top-level directories:
|
||||
|
||||
| Folder | Description |
|
||||
| --- | --- |
|
||||
| app/ | Source code of the main GIMP application |
|
||||
| app-tools/ | Source code of distributed tools |
|
||||
| build/ | Scripts for creating binary packages |
|
||||
| data/ | Data files: dynamics, gradients, palettes… |
|
||||
| desktop/ | Desktop integration files |
|
||||
| devel-docs/ | Developers documentation |
|
||||
| docs/ | Users documentation |
|
||||
| etc/ | Configuration files installed with GIMP |
|
||||
| extensions/ | Source code of extensions |
|
||||
| gimp-data/ | Raster or image data files |
|
||||
| libgimp/ | Library for plug-ins (core does not link against) |
|
||||
| libgimpbase/ | Basic functions shared by core and plug-ins |
|
||||
| libgimpcolor/ | Color-related functions shared by core and plug-ins |
|
||||
| libgimpconfig/ | Config functions shared by core and plug-ins |
|
||||
| libgimpmath/ | Mathematic operations useful for core and plug-ins |
|
||||
| libgimpmodule/ | Abstracts dynamic loading of modules (used to implement loadable color selectors and display filters) |
|
||||
| libgimpthumb/ | Thumbnail functions shared by core and plug-ins |
|
||||
| libgimpwidgets/ | User interface elements (widgets) and utility functions shared by core and plug-ins |
|
||||
| menus/ | XML/XSL files used to generate menus |
|
||||
| modules/ | Color selectors and display filters loadable at run-time |
|
||||
| pdb/ | Scripts for PDB source code generation |
|
||||
| plug-ins/ | Source code for plug-ins distributed with GIMP |
|
||||
| po/ | Translations of strings used in the core application |
|
||||
| po-libgimp/ | Translations of strings used in libgimp |
|
||||
| po-plug-ins/ | Translations of strings used in C plug-ins |
|
||||
| po-python/ | Translations of strings used in Python plug-ins |
|
||||
| po-script-fu/ | Translations of strings used in Script-Fu scripts |
|
||||
| po-tags/ | Translations of strings used in tags |
|
||||
| po-tips/ | Translations of strings used in tips |
|
||||
| po-windows-installer/ | Translations of strings used in the Windows installer |
|
||||
| themes/ | Official themes |
|
||||
| tools/ | Source code for non-distributed GIMP-related tools |
|
||||
| .gitlab/ | Gitlab-related templates or scripts |
|
||||
|
||||
The source code of the main GIMP application is found in the `app/` directory:
|
||||
|
||||
| Folder | Description |
|
||||
| --- | --- |
|
||||
| app/actions/ | Code of actions (`GimpAction*` defined in `app/widgets/`) (depends: GTK) |
|
||||
| app/config/ | Config files handling: GimpConfig interface and GimpRc object (depends: GObject) |
|
||||
| app/core/ | Core of GIMP **core** (depends: GObject) |
|
||||
| app/dialogs/ | Dialog widgets (depends: GTK) |
|
||||
| app/display/ | Handles displays (e.g. image windows) (depends: GTK) |
|
||||
| app/file/ | File handling routines in **core** (depends: GIO) |
|
||||
| app/file-data/ | GIMP file formats (gbr, gex, gih, pat) support (depends: GIO) |
|
||||
| app/gegl/ | Wrapper code for babl and GEGL API (depends: babl, GEGL) |
|
||||
| app/gui/ | Code that puts the user interface together (depends: GTK) |
|
||||
| app/menus/ | Code for menus (depends: GTK) |
|
||||
| app/operations/ | Custom GEGL operations (depends: GEGL) |
|
||||
| app/paint/ | Paint core that provides different ways to paint strokes (depends: GEGL) |
|
||||
| app/pdb/ | Core side of the Procedural Database, exposes internal functionality |
|
||||
| app/plug-in/ | Plug-in handling in **core** |
|
||||
| app/propgui/ | Property widgets generated from config properties (depends: GTK) |
|
||||
| app/tests/ | Core unit testing framework |
|
||||
| app/text/ | Text handling in **core** |
|
||||
| app/tools/ | User interface part of the tools. Actual tool functionality is in core |
|
||||
| app/vectors/ | Vectors framework in **core** |
|
||||
| app/widgets/ | Collection of widgets used in the application GUI |
|
||||
| app/xcf/ | XCF file handling in **core** |
|
||||
|
||||
#### Auto-generated Files
|
||||
|
||||
Please notice that some files in the source are generated from other
|
||||
sources. All those files have a short notice about being generated
|
||||
somewhere at the top. Among them are the files ending in `pdb.[ch]` in
|
||||
the `libgimp/` directory and the files ending in `cmds.c` in the
|
||||
`app/pdb/` subdirectory. Those are generated from the respective `.pdb`
|
||||
files in `pdb/groups`.
|
||||
|
||||
Other files are:
|
||||
|
||||
* `AUTHORS` from `authors.xml`
|
||||
|
||||
You should also check out [gimp-module-dependencies.svg](gimp-module-dependencies.svg).
|
||||
**TODO**: this SVG file is interesting yet very outdated. It should not
|
||||
be considered as some kind dependency rule and should be updated.
|
||||
|
||||
### Advanced concepts
|
||||
|
||||
#### XCF
|
||||
|
||||
The `XCF` format is the core image format of GIMP, which mirrors
|
||||
features made available in GIMP. More than an image format, you may
|
||||
consider it as a work or project format, as it is not made for finale
|
||||
presentation of an artwork but for the work-in-progress process.
|
||||
|
||||
Developers are welcome to read the [specifications of XCF](https://developer.gimp.org/core/standards/xcf/).
|
||||
|
||||
#### Locks
|
||||
|
||||
Items in an image can be locked in various ways to prevent different
|
||||
types of edits.
|
||||
|
||||
This is further explained in [the specifications of locks](https://developer.gimp.org/core/specifications/locks/).
|
||||
|
||||
#### UI Framework
|
||||
|
||||
GIMP has an evolved GUI framework, with a toolbox, dockables, menus…
|
||||
|
||||
This document describing how the GIMP UI framework functions and how it
|
||||
is [implemented](ui-framework.txt) might be of interest.
|
||||
|
||||
#### Contexts
|
||||
|
||||
GIMP uses a lot a concept of "contexts". We recommend reading more about
|
||||
[how GimpContexts are used in GIMP](contexts.txt).
|
||||
|
||||
#### Undo
|
||||
|
||||
GIMP undo system can be challenging at times. This [quick overview of
|
||||
the undo system](undo.txt) can be of interest as a first introduction.
|
||||
|
||||
#### Parasites
|
||||
|
||||
GIMP has a concept of "parasite" data which basically correspond to
|
||||
persistent or semi-persistent data which can be attached to images or
|
||||
items (layers, channels, paths) within an image. These parasites are
|
||||
saved in the XCF format.
|
||||
|
||||
Parasites can also be attached globally to the GIMP session.
|
||||
|
||||
Parasite contents is format-free and you can use any parasite name,
|
||||
nevertheless GIMP itself uses parasite so you should read the
|
||||
[descriptions of known parasites](parasites.txt).
|
||||
|
||||
#### Metadata
|
||||
|
||||
GIMP supports Exif, IPTC and XMP metadata as well as various image
|
||||
format-specific metadata. The topic is quite huge and complex, if not
|
||||
overwhelming.
|
||||
|
||||
This [old document](https://developer.gimp.org/core/specifications/exif_handling/)
|
||||
might be of interest (or maybe not, it has not been recently reviewed and might
|
||||
be widely outdated; in any case, it is not a complete document at all as we
|
||||
definitely do a lot more nowadays). **TODO**: review this document and delete or
|
||||
update it depending of whether it still makes sense.
|
||||
|
||||
#### Tagging
|
||||
|
||||
Various data in GIMP can be tagged across sessions.
|
||||
|
||||
This document on [how resource tagging in GIMP works](tagging.txt) may
|
||||
be of interest.
|
28
devel-docs/c.vim
Normal file
|
@ -0,0 +1,28 @@
|
|||
" GIMP coding style for vim "
|
||||
|
||||
" To enable these vim rules for GIMP only, add this command to your vimrc:
|
||||
" autocmd BufNewFile,BufRead /path/to/gimp/*.[ch] source /path/to/gimp/devel-docs/c.vim
|
||||
"
|
||||
" Do not use `set exrc` which is a security risk for your system since vim may
|
||||
" be tricked into running shell commands by .vimrc files hidden in malicious
|
||||
" projects (`set secure` won't protect you since it is not taken into account
|
||||
" if the files are owned by you).
|
||||
|
||||
" GNU style
|
||||
setlocal cindent
|
||||
setlocal cinoptions=>4,n-2,{2,^-2,:2,=2,g0,h2,p5,t0,+2,(0,u0,w1,m1
|
||||
setlocal shiftwidth=2
|
||||
setlocal softtabstop=2
|
||||
setlocal textwidth=79
|
||||
setlocal fo-=ro fo+=cql
|
||||
|
||||
" Tabs are always inserted as spaces.
|
||||
set expandtab
|
||||
" But if there are tabs already, show them as 8 columns.
|
||||
setlocal tabstop=8
|
||||
|
||||
" Highlight in red trailing whitespaces and tabs everywhere.
|
||||
highlight TrailingWhitespace ctermbg=LightRed guibg=LightRed
|
||||
match TrailingWhitespace /\s\+$/
|
||||
highlight ForbiddenTabs ctermbg=DarkRed guibg=DarkRed
|
||||
2match ForbiddenTabs /\t/
|
89
devel-docs/contexts.txt
Normal file
|
@ -0,0 +1,89 @@
|
|||
contexts.txt
|
||||
============
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This file describes how GimpContexts are used in GIMP.
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
One important context is the so called "user context",
|
||||
gimp_get_user_context(). This context keeps track on what image the
|
||||
user currently has active, for example. Dock windows have their own
|
||||
context which does not necessarily mirror the user context. A dock
|
||||
window can be set to show information for a specific image. Plug-ins
|
||||
also have their own context.
|
||||
|
||||
|
||||
Communication between contexts
|
||||
------------------------------
|
||||
|
||||
So how do the various contexts synchronize and propagate changes?
|
||||
This is most easily explained by a sequence diagram. Let's say there
|
||||
are two image windows with different images opened in GIMP. Call them
|
||||
A and B. Let's say A is currently active. When the user activates B,
|
||||
this is the sequence of events from the focus event to the layers
|
||||
dockable have been updated with the new image. To understand the
|
||||
diagram, you have to know that the dock window has connected signal
|
||||
handlers to image changes in the user context (through a dialog
|
||||
factory getter), and the layer dockable have connected a signal
|
||||
handler to image changes in the dock window context. The sequence of
|
||||
events is as follows:
|
||||
|
||||
GimpContext GimpContext GimpItemTreeView,
|
||||
GimpDisplayShell user GimpDockWindow dock window GimpLayerTreeView
|
||||
|
||||
| | | | |
|
||||
focus event | | | |
|
||||
------->| | | | |
|
||||
| gimp_context_set_display() | | |
|
||||
|--------------->|----------+ | | |
|
||||
| | | | | |
|
||||
| gimp_context_set_image() | | | |
|
||||
| |<---------+ | | |
|
||||
| | | | |
|
||||
| | "image-changed" | |
|
||||
| |------------->| | |
|
||||
| | | gimp_context_set_image() |
|
||||
| | |------------->| |
|
||||
| | | | "image-changed" /
|
||||
| | | | set_image()
|
||||
| | | |------------>|
|
||||
| | | | |
|
||||
|
||||
In single-window mode, the dockables listen directly to the user
|
||||
context. When switching between single-window and multi-window modes,
|
||||
the dockables are updated with their new context, just as when moving
|
||||
a dockable between different dock windows and thus also different
|
||||
contexts. The sequence diagram for single-window mode is:
|
||||
|
||||
GimpContext GimpItemTreeView
|
||||
GimpDisplayShell user GimpLayerTreeView
|
||||
|
||||
| | |
|
||||
focus event | |
|
||||
------->| | |
|
||||
| gimp_context_set_display() |
|
||||
|--------------->|----------+ |
|
||||
| | | |
|
||||
| gimp_context_set_image() | |
|
||||
| |<---------+ |
|
||||
| | |
|
||||
| | "image-changed" /
|
||||
| | set_image()
|
||||
| |------------->|
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
|
||||
|
||||
Parent/child relationships
|
||||
--------------------------
|
||||
|
||||
TODO
|
393
devel-docs/gimp-module-dependencies.svg
Normal file
|
@ -0,0 +1,393 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.26.3 (20100126.1600)
|
||||
-->
|
||||
<!-- Title: _anonymous_0 Pages: 1 -->
|
||||
<svg width="862pt" height="1008pt"
|
||||
viewBox="0.00 0.00 862.00 1008.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph1" class="graph" transform="scale(1 1) rotate(0) translate(4 1004)">
|
||||
<title>_anonymous_0</title>
|
||||
<polygon fill="white" stroke="white" points="-4,5 -4,-1004 859,-1004 859,5 -4,5"/>
|
||||
<!-- app/plug-in -->
|
||||
<g id="node1" class="node"><title>app/plug-in</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="128" cy="-981" rx="55.8614" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="128" y="-977.9" font-family="Times Roman,serif" font-size="14.00">app/plug-in</text>
|
||||
</g>
|
||||
<!-- app/composite -->
|
||||
<g id="node2" class="node"><title>app/composite</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="176" cy="-907" rx="67.8823" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="176" y="-903.9" font-family="Times Roman,serif" font-size="14.00">app/composite</text>
|
||||
</g>
|
||||
<!-- app/plug-in->app/composite -->
|
||||
<g id="edge2" class="edge"><title>app/plug-in->app/composite</title>
|
||||
<path fill="none" stroke="black" d="M140.112,-962.327C145.585,-953.891 152.16,-943.754 158.178,-934.475"/>
|
||||
<polygon fill="black" stroke="black" points="161.219,-936.219 163.724,-925.925 155.346,-932.41 161.219,-936.219"/>
|
||||
</g>
|
||||
<!-- app/base -->
|
||||
<g id="node4" class="node"><title>app/base</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="285" cy="-833" rx="44.7575" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="285" y="-829.9" font-family="Times Roman,serif" font-size="14.00">app/base</text>
|
||||
</g>
|
||||
<!-- app/composite->app/base -->
|
||||
<g id="edge4" class="edge"><title>app/composite->app/base</title>
|
||||
<path fill="none" stroke="black" d="M202.108,-889.275C217.2,-879.029 236.322,-866.047 252.396,-855.135"/>
|
||||
<polygon fill="black" stroke="black" points="254.66,-857.828 260.968,-849.315 250.728,-852.037 254.66,-857.828"/>
|
||||
</g>
|
||||
<!-- app/config -->
|
||||
<g id="node11" class="node"><title>app/config</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="311" cy="-759" rx="51.8276" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="311" y="-755.9" font-family="Times Roman,serif" font-size="14.00">app/config</text>
|
||||
</g>
|
||||
<!-- app/base->app/config -->
|
||||
<g id="edge10" class="edge"><title>app/base->app/config</title>
|
||||
<path fill="none" stroke="black" d="M291.696,-813.943C294.516,-805.916 297.859,-796.402 300.964,-787.565"/>
|
||||
<polygon fill="black" stroke="black" points="304.314,-788.587 304.327,-777.992 297.71,-786.267 304.314,-788.587"/>
|
||||
</g>
|
||||
<!-- libgimpcolor -->
|
||||
<g id="node6" class="node"><title>libgimpcolor</title>
|
||||
<ellipse fill="#ff7256" stroke="black" cx="418" cy="-167" rx="61.0181" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="418" y="-163.9" font-family="Times Roman,serif" font-size="14.00">libgimpcolor</text>
|
||||
</g>
|
||||
<!-- libgimpmath -->
|
||||
<g id="node7" class="node"><title>libgimpmath</title>
|
||||
<ellipse fill="#ff7256" stroke="black" cx="418" cy="-93" rx="61.0181" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="418" y="-89.9" font-family="Times Roman,serif" font-size="14.00">libgimpmath</text>
|
||||
</g>
|
||||
<!-- libgimpcolor->libgimpmath -->
|
||||
<g id="edge6" class="edge"><title>libgimpcolor->libgimpmath</title>
|
||||
<path fill="none" stroke="black" d="M418,-147.943C418,-140.149 418,-130.954 418,-122.338"/>
|
||||
<polygon fill="black" stroke="black" points="421.5,-122.249 418,-112.249 414.5,-122.249 421.5,-122.249"/>
|
||||
</g>
|
||||
<!-- GLib -->
|
||||
<g id="node9" class="node"><title>GLib</title>
|
||||
<ellipse fill="lightblue" stroke="black" cx="418" cy="-19" rx="31.8198" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="418" y="-15.9" font-family="Times Roman,serif" font-size="14.00">GLib</text>
|
||||
</g>
|
||||
<!-- libgimpmath->GLib -->
|
||||
<g id="edge8" class="edge"><title>libgimpmath->GLib</title>
|
||||
<path fill="none" stroke="black" d="M418,-73.9432C418,-66.1493 418,-56.9538 418,-48.3381"/>
|
||||
<polygon fill="black" stroke="black" points="421.5,-48.2494 418,-38.2495 414.5,-48.2495 421.5,-48.2494"/>
|
||||
</g>
|
||||
<!-- app/core -->
|
||||
<g id="node14" class="node"><title>app/core</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="336" cy="-685" rx="44.0472" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="336" y="-681.9" font-family="Times Roman,serif" font-size="14.00">app/core</text>
|
||||
</g>
|
||||
<!-- app/config->app/core -->
|
||||
<g id="edge26" class="edge"><title>app/config->app/core</title>
|
||||
<path fill="none" stroke="black" d="M317.438,-739.943C320.15,-731.916 323.364,-722.402 326.35,-713.565"/>
|
||||
<polygon fill="black" stroke="black" points="329.699,-714.586 329.584,-703.992 323.067,-712.346 329.699,-714.586"/>
|
||||
</g>
|
||||
<!-- GEGL -->
|
||||
<g id="node13" class="node"><title>GEGL</title>
|
||||
<ellipse fill="lightblue" stroke="black" cx="339" cy="-315" rx="36.977" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="339" y="-311.9" font-family="Times Roman,serif" font-size="14.00">GEGL</text>
|
||||
</g>
|
||||
<!-- app/pdb -->
|
||||
<g id="node15" class="node"><title>app/pdb</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="232" cy="-611" rx="41.9273" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="232" y="-607.9" font-family="Times Roman,serif" font-size="14.00">app/pdb</text>
|
||||
</g>
|
||||
<!-- app/core->app/pdb -->
|
||||
<g id="edge12" class="edge"><title>app/core->app/pdb</title>
|
||||
<path fill="none" stroke="black" d="M312.919,-668.577C298.276,-658.158 279.148,-644.548 263.166,-633.176"/>
|
||||
<polygon fill="black" stroke="black" points="264.836,-630.068 254.659,-627.122 260.777,-635.772 264.836,-630.068"/>
|
||||
</g>
|
||||
<!-- app/gegl -->
|
||||
<g id="node17" class="node"><title>app/gegl</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="336" cy="-611" rx="44.0472" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="336" y="-607.9" font-family="Times Roman,serif" font-size="14.00">app/gegl</text>
|
||||
</g>
|
||||
<!-- app/core->app/gegl -->
|
||||
<g id="edge14" class="edge"><title>app/core->app/gegl</title>
|
||||
<path fill="none" stroke="black" d="M330.012,-665.943C329.288,-658.088 329.08,-648.81 329.387,-640.136"/>
|
||||
<polygon fill="black" stroke="black" points="332.891,-640.19 330.018,-629.992 325.904,-639.756 332.891,-640.19"/>
|
||||
</g>
|
||||
<!-- app/xcf -->
|
||||
<g id="node19" class="node"><title>app/xcf</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="438" cy="-611" rx="39.8075" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="438" y="-607.9" font-family="Times Roman,serif" font-size="14.00">app/xcf</text>
|
||||
</g>
|
||||
<!-- app/core->app/xcf -->
|
||||
<g id="edge16" class="edge"><title>app/core->app/xcf</title>
|
||||
<path fill="none" stroke="black" d="M358.637,-668.577C372.998,-658.158 391.759,-644.548 407.434,-633.176"/>
|
||||
<polygon fill="black" stroke="black" points="409.738,-635.828 415.777,-627.122 405.628,-630.162 409.738,-635.828"/>
|
||||
</g>
|
||||
<!-- app/file -->
|
||||
<g id="node21" class="node"><title>app/file</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="80" cy="-537" rx="41.0122" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="80" y="-533.9" font-family="Times Roman,serif" font-size="14.00">app/file</text>
|
||||
</g>
|
||||
<!-- app/pdb->app/file -->
|
||||
<g id="edge18" class="edge"><title>app/pdb->app/file</title>
|
||||
<path fill="none" stroke="black" d="M203.41,-597.081C179.101,-585.246 144.017,-568.166 117.466,-555.24"/>
|
||||
<polygon fill="black" stroke="black" points="118.985,-552.087 108.462,-550.856 115.921,-558.381 118.985,-552.087"/>
|
||||
</g>
|
||||
<!-- libgimpmodule -->
|
||||
<g id="node23" class="node"><title>libgimpmodule</title>
|
||||
<ellipse fill="#ff7256" stroke="black" cx="413" cy="-537" rx="70.9184" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="413" y="-533.9" font-family="Times Roman,serif" font-size="14.00">libgimpmodule</text>
|
||||
</g>
|
||||
<!-- app/pdb->libgimpmodule -->
|
||||
<g id="edge20" class="edge"><title>app/pdb->libgimpmodule</title>
|
||||
<path fill="none" stroke="black" d="M263.528,-598.11C291.34,-586.739 332.313,-569.988 364.331,-556.898"/>
|
||||
<polygon fill="black" stroke="black" points="366.024,-559.987 373.955,-552.963 363.375,-553.508 366.024,-559.987"/>
|
||||
</g>
|
||||
<!-- app/gegl->app/core -->
|
||||
<g id="edge22" class="edge"><title>app/gegl->app/core</title>
|
||||
<path fill="none" stroke="black" d="M341.982,-629.992C342.709,-637.839 342.92,-647.115 342.615,-655.792"/>
|
||||
<polygon fill="black" stroke="black" points="339.111,-655.746 341.988,-665.943 346.098,-656.178 339.111,-655.746"/>
|
||||
</g>
|
||||
<!-- app/text -->
|
||||
<g id="node26" class="node"><title>app/text</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="282" cy="-537" rx="41.9273" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="282" y="-533.9" font-family="Times Roman,serif" font-size="14.00">app/text</text>
|
||||
</g>
|
||||
<!-- app/xcf->app/text -->
|
||||
<g id="edge24" class="edge"><title>app/xcf->app/text</title>
|
||||
<path fill="none" stroke="black" d="M409.387,-597.427C384.444,-585.595 348.056,-568.334 320.55,-555.287"/>
|
||||
<polygon fill="black" stroke="black" points="321.76,-551.987 311.225,-550.863 318.76,-558.311 321.76,-551.987"/>
|
||||
</g>
|
||||
<!-- app/file->app/plug-in -->
|
||||
<g id="edge32" class="edge"><title>app/file->app/plug-in</title>
|
||||
<path fill="none" stroke="black" d="M80,-556.158C80,-584.37 80,-638.75 80,-685 80,-833 80,-833 80,-833 80,-875.187 84.7969,-886.276 99,-926 102.309,-935.256 106.934,-944.886 111.519,-953.453"/>
|
||||
<polygon fill="black" stroke="black" points="108.498,-955.223 116.415,-962.264 114.617,-951.823 108.498,-955.223"/>
|
||||
</g>
|
||||
<!-- libgimpthumb -->
|
||||
<g id="node34" class="node"><title>libgimpthumb</title>
|
||||
<ellipse fill="#ff7256" stroke="black" cx="67" cy="-389" rx="67.1751" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="67" y="-385.9" font-family="Times Roman,serif" font-size="14.00">libgimpthumb</text>
|
||||
</g>
|
||||
<!-- app/file->libgimpthumb -->
|
||||
<g id="edge34" class="edge"><title>app/file->libgimpthumb</title>
|
||||
<path fill="none" stroke="black" d="M78.3271,-517.955C76.1162,-492.784 72.1982,-448.18 69.5998,-418.598"/>
|
||||
<polygon fill="black" stroke="black" points="73.0694,-418.098 68.7078,-408.442 66.0963,-418.71 73.0694,-418.098"/>
|
||||
</g>
|
||||
<!-- libgimpbase -->
|
||||
<g id="node29" class="node"><title>libgimpbase</title>
|
||||
<ellipse fill="#ff7256" stroke="black" cx="418" cy="-241" rx="58.1882" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="418" y="-237.9" font-family="Times Roman,serif" font-size="14.00">libgimpbase</text>
|
||||
</g>
|
||||
<!-- libgimpmodule->libgimpbase -->
|
||||
<g id="edge36" class="edge"><title>libgimpmodule->libgimpbase</title>
|
||||
<path fill="none" stroke="black" d="M413.328,-517.579C414.183,-466.967 416.483,-330.777 417.503,-270.452"/>
|
||||
<polygon fill="black" stroke="black" points="421.008,-270.166 417.677,-260.108 414.009,-270.048 421.008,-270.166"/>
|
||||
</g>
|
||||
<!-- app/vectors -->
|
||||
<g id="node56" class="node"><title>app/vectors</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="334" cy="-463" rx="55.8614" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="334" y="-459.9" font-family="Times Roman,serif" font-size="14.00">app/vectors</text>
|
||||
</g>
|
||||
<!-- app/text->app/vectors -->
|
||||
<g id="edge76" class="edge"><title>app/text->app/vectors</title>
|
||||
<path fill="none" stroke="black" d="M294.854,-518.708C300.933,-510.057 308.313,-499.554 315.02,-490.01"/>
|
||||
<polygon fill="black" stroke="black" points="318.047,-491.79 320.933,-481.596 312.32,-487.765 318.047,-491.79"/>
|
||||
</g>
|
||||
<!-- Pango -->
|
||||
<g id="node70" class="node"><title>Pango</title>
|
||||
<ellipse fill="lightblue" stroke="black" cx="225" cy="-463" rx="34.8574" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="225" y="-459.9" font-family="Times Roman,serif" font-size="14.00">Pango</text>
|
||||
</g>
|
||||
<!-- app/text->Pango -->
|
||||
<g id="edge78" class="edge"><title>app/text->Pango</title>
|
||||
<path fill="none" stroke="black" d="M267.91,-518.708C260.905,-509.613 252.323,-498.471 244.679,-488.549"/>
|
||||
<polygon fill="black" stroke="black" points="247.41,-486.359 238.535,-480.572 241.865,-490.63 247.41,-486.359"/>
|
||||
</g>
|
||||
<!-- libgimpbase->libgimpcolor -->
|
||||
<g id="edge28" class="edge"><title>libgimpbase->libgimpcolor</title>
|
||||
<path fill="none" stroke="black" d="M418,-221.943C418,-214.149 418,-204.954 418,-196.338"/>
|
||||
<polygon fill="black" stroke="black" points="421.5,-196.249 418,-186.249 414.5,-196.249 421.5,-196.249"/>
|
||||
</g>
|
||||
<!-- libgimpconfig -->
|
||||
<g id="node31" class="node"><title>libgimpconfig</title>
|
||||
<ellipse fill="#ff7256" stroke="black" cx="512" cy="-315" rx="65.9683" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="512" y="-311.9" font-family="Times Roman,serif" font-size="14.00">libgimpconfig</text>
|
||||
</g>
|
||||
<!-- libgimpconfig->libgimpbase -->
|
||||
<g id="edge30" class="edge"><title>libgimpconfig->libgimpbase</title>
|
||||
<path fill="none" stroke="black" d="M489.245,-297.087C477.006,-287.452 461.747,-275.439 448.493,-265.005"/>
|
||||
<polygon fill="black" stroke="black" points="450.568,-262.184 440.545,-258.748 446.238,-267.684 450.568,-262.184"/>
|
||||
</g>
|
||||
<!-- libgimpthumb->libgimpbase -->
|
||||
<g id="edge38" class="edge"><title>libgimpthumb->libgimpbase</title>
|
||||
<path fill="none" stroke="black" d="M72.6671,-369.993C80.1177,-348.474 95.3615,-314.069 121,-296 157.281,-270.43 275.454,-254.627 351.346,-246.855"/>
|
||||
<polygon fill="black" stroke="black" points="352.16,-250.291 361.761,-245.811 351.462,-243.326 352.16,-250.291"/>
|
||||
</g>
|
||||
<!-- Cairo -->
|
||||
<g id="node38" class="node"><title>Cairo</title>
|
||||
<ellipse fill="lightblue" stroke="black" cx="241" cy="-389" rx="33.234" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="241" y="-385.9" font-family="Times Roman,serif" font-size="14.00">Cairo</text>
|
||||
</g>
|
||||
<!-- app/actions -->
|
||||
<g id="node39" class="node"><title>app/actions</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="799" cy="-315" rx="55.1543" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="799" y="-311.9" font-family="Times Roman,serif" font-size="14.00">app/actions</text>
|
||||
</g>
|
||||
<!-- app/dialogs -->
|
||||
<g id="node40" class="node"><title>app/dialogs</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="756" cy="-685" rx="55.8614" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="756" y="-681.9" font-family="Times Roman,serif" font-size="14.00">app/dialogs</text>
|
||||
</g>
|
||||
<!-- app/actions->app/dialogs -->
|
||||
<g id="edge40" class="edge"><title>app/actions->app/dialogs</title>
|
||||
<path fill="none" stroke="black" d="M807.896,-334.161C819.955,-361.932 840,-415.275 840,-463 840,-537 840,-537 840,-537 840,-581.164 827.852,-592.208 805,-630 798.654,-640.495 790.185,-650.846 782.075,-659.688"/>
|
||||
<polygon fill="black" stroke="black" points="779.448,-657.372 775.103,-667.035 784.526,-662.19 779.448,-657.372"/>
|
||||
</g>
|
||||
<!-- app/gui -->
|
||||
<g id="node42" class="node"><title>app/gui</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="756" cy="-611" rx="39.8075" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="756" y="-607.9" font-family="Times Roman,serif" font-size="14.00">app/gui</text>
|
||||
</g>
|
||||
<!-- app/dialogs->app/gui -->
|
||||
<g id="edge42" class="edge"><title>app/dialogs->app/gui</title>
|
||||
<path fill="none" stroke="black" d="M756,-665.943C756,-658.149 756,-648.954 756,-640.338"/>
|
||||
<polygon fill="black" stroke="black" points="759.5,-640.249 756,-630.249 752.5,-640.249 759.5,-640.249"/>
|
||||
</g>
|
||||
<!-- app/display -->
|
||||
<g id="node44" class="node"><title>app/display</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="756" cy="-537" rx="55.8614" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="756" y="-533.9" font-family="Times Roman,serif" font-size="14.00">app/display</text>
|
||||
</g>
|
||||
<!-- app/gui->app/display -->
|
||||
<g id="edge44" class="edge"><title>app/gui->app/display</title>
|
||||
<path fill="none" stroke="black" d="M756,-591.943C756,-584.149 756,-574.954 756,-566.338"/>
|
||||
<polygon fill="black" stroke="black" points="759.5,-566.249 756,-556.249 752.5,-566.249 759.5,-566.249"/>
|
||||
</g>
|
||||
<!-- app/widgets -->
|
||||
<g id="node50" class="node"><title>app/widgets</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="754" cy="-463" rx="57.9828" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="754" y="-459.9" font-family="Times Roman,serif" font-size="14.00">app/widgets</text>
|
||||
</g>
|
||||
<!-- app/display->app/widgets -->
|
||||
<g id="edge50" class="edge"><title>app/display->app/widgets</title>
|
||||
<path fill="none" stroke="black" d="M755.485,-517.943C755.274,-510.149 755.026,-500.954 754.793,-492.338"/>
|
||||
<polygon fill="black" stroke="black" points="758.289,-492.151 754.52,-482.249 751.292,-492.34 758.289,-492.151"/>
|
||||
</g>
|
||||
<!-- libgimpwidgets -->
|
||||
<g id="node46" class="node"><title>libgimpwidgets</title>
|
||||
<ellipse fill="#ff7256" stroke="black" cx="573" cy="-537" rx="70.9184" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="573" y="-533.9" font-family="Times Roman,serif" font-size="14.00">libgimpwidgets</text>
|
||||
</g>
|
||||
<!-- libgimpwidgets->libgimpconfig -->
|
||||
<g id="edge46" class="edge"><title>libgimpwidgets->libgimpconfig</title>
|
||||
<path fill="none" stroke="black" d="M554.592,-518.249C545.949,-508.295 536.384,-495.374 531,-482 512.661,-436.447 510.223,-378.617 510.704,-344.337"/>
|
||||
<polygon fill="black" stroke="black" points="514.209,-344.16 510.947,-334.08 507.211,-343.994 514.209,-344.16"/>
|
||||
</g>
|
||||
<!-- GTK+ -->
|
||||
<g id="node48" class="node"><title>GTK+</title>
|
||||
<ellipse fill="lightblue" stroke="black" cx="577" cy="-463" rx="36.977" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="577" y="-459.9" font-family="Times Roman,serif" font-size="14.00">GTK</text>
|
||||
</g>
|
||||
<!-- libgimpwidgets->GTK+ -->
|
||||
<g id="edge48" class="edge"><title>libgimpwidgets->GTK+</title>
|
||||
<path fill="none" stroke="black" d="M574.03,-517.943C574.451,-510.149 574.948,-500.954 575.414,-492.338"/>
|
||||
<polygon fill="black" stroke="black" points="578.915,-492.424 575.959,-482.249 571.925,-492.046 578.915,-492.424"/>
|
||||
</g>
|
||||
<!-- app/menus -->
|
||||
<g id="node52" class="node"><title>app/menus</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="756" cy="-389" rx="53.2379" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="756" y="-385.9" font-family="Times Roman,serif" font-size="14.00">app/menus</text>
|
||||
</g>
|
||||
<!-- app/widgets->app/menus -->
|
||||
<g id="edge52" class="edge"><title>app/widgets->app/menus</title>
|
||||
<path fill="none" stroke="black" d="M754.515,-443.943C754.726,-436.149 754.974,-426.954 755.207,-418.338"/>
|
||||
<polygon fill="black" stroke="black" points="758.708,-418.34 755.48,-408.249 751.711,-418.151 758.708,-418.34"/>
|
||||
</g>
|
||||
<!-- app/tools -->
|
||||
<g id="node54" class="node"><title>app/tools</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="641" cy="-759" rx="46.1672" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="641" y="-755.9" font-family="Times Roman,serif" font-size="14.00">app/tools</text>
|
||||
</g>
|
||||
<!-- app/widgets->app/tools -->
|
||||
<g id="edge54" class="edge"><title>app/widgets->app/tools</title>
|
||||
<path fill="none" stroke="black" d="M727.313,-480.099C714.423,-489.715 699.864,-502.832 691,-518 651.098,-586.285 642.758,-681.803 641.199,-729.484"/>
|
||||
<polygon fill="black" stroke="black" points="637.694,-729.637 640.946,-739.72 644.692,-729.81 637.694,-729.637"/>
|
||||
</g>
|
||||
<!-- app/menus->app/actions -->
|
||||
<g id="edge66" class="edge"><title>app/menus->app/actions</title>
|
||||
<path fill="none" stroke="black" d="M766.851,-370.327C771.74,-361.913 777.611,-351.809 782.991,-342.55"/>
|
||||
<polygon fill="black" stroke="black" points="786.155,-344.072 788.153,-333.667 780.102,-340.555 786.155,-344.072"/>
|
||||
</g>
|
||||
<!-- app/tools->app/core -->
|
||||
<g id="edge68" class="edge"><title>app/tools->app/core</title>
|
||||
<path fill="none" stroke="black" d="M601.127,-749.326C545.412,-735.808 444.384,-711.296 384.418,-696.747"/>
|
||||
<polygon fill="black" stroke="black" points="384.983,-693.283 374.44,-694.326 383.333,-700.086 384.983,-693.283"/>
|
||||
</g>
|
||||
<!-- app/tools->app/dialogs -->
|
||||
<g id="edge70" class="edge"><title>app/tools->app/dialogs</title>
|
||||
<path fill="none" stroke="black" d="M665.953,-742.943C682.076,-732.569 703.289,-718.918 721.076,-707.473"/>
|
||||
<polygon fill="black" stroke="black" points="722.979,-710.41 729.495,-702.055 719.191,-704.524 722.979,-710.41"/>
|
||||
</g>
|
||||
<!-- app/tools->libgimpwidgets -->
|
||||
<g id="edge72" class="edge"><title>app/tools->libgimpwidgets</title>
|
||||
<path fill="none" stroke="black" d="M638.418,-739.973C633.758,-708.448 622.562,-643.73 603,-592 599.525,-582.81 594.767,-573.258 590.065,-564.744"/>
|
||||
<polygon fill="black" stroke="black" points="593.052,-562.918 585.047,-555.978 586.977,-566.395 593.052,-562.918"/>
|
||||
</g>
|
||||
<!-- app/vectors->Cairo -->
|
||||
<g id="edge56" class="edge"><title>app/vectors->Cairo</title>
|
||||
<path fill="none" stroke="black" d="M311.96,-445.463C298.849,-435.031 282.111,-421.712 268.184,-410.63"/>
|
||||
<polygon fill="black" stroke="black" points="270.362,-407.891 260.358,-404.403 266.004,-413.368 270.362,-407.891"/>
|
||||
</g>
|
||||
<!-- app/paint -->
|
||||
<g id="node58" class="node"><title>app/paint</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="339" cy="-389" rx="46.8775" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="339" y="-385.9" font-family="Times Roman,serif" font-size="14.00">app/paint</text>
|
||||
</g>
|
||||
<!-- app/vectors->app/paint -->
|
||||
<g id="edge58" class="edge"><title>app/vectors->app/paint</title>
|
||||
<path fill="none" stroke="black" d="M335.288,-443.943C335.814,-436.149 336.436,-426.954 337.018,-418.338"/>
|
||||
<polygon fill="black" stroke="black" points="340.517,-418.463 337.699,-408.249 333.533,-417.991 340.517,-418.463"/>
|
||||
</g>
|
||||
<!-- app/paint->GEGL -->
|
||||
<g id="edge60" class="edge"><title>app/paint->GEGL</title>
|
||||
<path fill="none" stroke="black" d="M339,-369.943C339,-362.149 339,-352.954 339,-344.338"/>
|
||||
<polygon fill="black" stroke="black" points="342.5,-344.249 339,-334.249 335.5,-344.249 342.5,-344.249"/>
|
||||
</g>
|
||||
<!-- app/paint->libgimpconfig -->
|
||||
<g id="edge62" class="edge"><title>app/paint->libgimpconfig</title>
|
||||
<path fill="none" stroke="black" d="M371.54,-375.081C398.124,-363.71 436.03,-347.496 465.765,-334.777"/>
|
||||
<polygon fill="black" stroke="black" points="467.29,-337.931 475.108,-330.781 464.537,-331.495 467.29,-337.931"/>
|
||||
</g>
|
||||
<!-- app/paint-funcs -->
|
||||
<g id="node62" class="node"><title>app/paint-funcs</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="201" cy="-315" rx="70.9184" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="201" y="-311.9" font-family="Times Roman,serif" font-size="14.00">app/paint-funcs</text>
|
||||
</g>
|
||||
<!-- app/paint->app/paint-funcs -->
|
||||
<g id="edge64" class="edge"><title>app/paint->app/paint-funcs</title>
|
||||
<path fill="none" stroke="black" d="M310.406,-373.667C290.562,-363.026 263.832,-348.692 241.761,-336.857"/>
|
||||
<polygon fill="black" stroke="black" points="243.401,-333.765 232.934,-332.124 240.092,-339.934 243.401,-333.765"/>
|
||||
</g>
|
||||
<!-- app/paint-funcs->app/composite -->
|
||||
<g id="edge74" class="edge"><title>app/paint-funcs->app/composite</title>
|
||||
<path fill="none" stroke="black" d="M192.538,-334.205C181.067,-362.03 162,-415.437 162,-463 162,-759 162,-759 162,-759 162,-800.375 167.49,-847.969 171.594,-877.768"/>
|
||||
<polygon fill="black" stroke="black" points="168.161,-878.487 173.031,-887.896 175.092,-877.504 168.161,-878.487"/>
|
||||
</g>
|
||||
<!-- libgimp -->
|
||||
<g id="node72" class="node"><title>libgimp</title>
|
||||
<ellipse fill="#ff7256" stroke="black" cx="553" cy="-611" rx="41.2167" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="553" y="-607.9" font-family="Times Roman,serif" font-size="14.00">libgimp</text>
|
||||
</g>
|
||||
<!-- libgimp->libgimpmodule -->
|
||||
<g id="edge80" class="edge"><title>libgimp->libgimpmodule</title>
|
||||
<path fill="none" stroke="black" d="M525.674,-596.556C505.302,-585.788 477.131,-570.898 454.054,-558.7"/>
|
||||
<polygon fill="black" stroke="black" points="455.641,-555.58 445.164,-554.001 452.369,-561.768 455.641,-555.58"/>
|
||||
</g>
|
||||
<!-- libgimp->libgimpwidgets -->
|
||||
<g id="edge82" class="edge"><title>libgimp->libgimpwidgets</title>
|
||||
<path fill="none" stroke="black" d="M558.15,-591.943C560.297,-584.002 562.836,-574.606 565.203,-565.851"/>
|
||||
<polygon fill="black" stroke="black" points="568.637,-566.559 567.867,-555.992 561.879,-564.733 568.637,-566.559"/>
|
||||
</g>
|
||||
<!-- app/tests -->
|
||||
<g id="node75" class="node"><title>app/tests</title>
|
||||
<ellipse fill="lawngreen" stroke="black" cx="756" cy="-759" rx="44.7575" ry="19.0919"/>
|
||||
<text text-anchor="middle" x="756" y="-755.9" font-family="Times Roman,serif" font-size="14.00">app/tests</text>
|
||||
</g>
|
||||
<!-- app/tests->app/dialogs -->
|
||||
<g id="edge84" class="edge"><title>app/tests->app/dialogs</title>
|
||||
<path fill="none" stroke="black" d="M756,-739.943C756,-732.149 756,-722.954 756,-714.338"/>
|
||||
<polygon fill="black" stroke="black" points="759.5,-714.249 756,-704.249 752.5,-714.249 759.5,-714.249"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 24 KiB |
105
devel-docs/gitlab-mr.md
Normal file
|
@ -0,0 +1,105 @@
|
|||
# Merge Request tricks
|
||||
|
||||
By default, a Merge Request pipeline would only build GIMP for
|
||||
Debian with merely testing purposes.
|
||||
|
||||
You might want to actually generate easy-to-install builds, in
|
||||
particular if you want it to be testable for non-developers, or
|
||||
various other reasons.
|
||||
|
||||
So, as a developer, comment: /label ~Package:`AppImage` or `Flatpak` or `Windows Installer` or `Microsoft Store`
|
||||
(this will generate the requested package for new pipelines).
|
||||
|
||||
☣️ We remind that these packages are built on-top of development code
|
||||
(i.e. work-in-progress and potentially unstable codebase likely
|
||||
containing critical bugs) with additional code which can be contributed
|
||||
by anyone (any anonymous person is allowed to propose patches as merge
|
||||
requests not only known team members).
|
||||
Therefore you should always check the merge request changes before
|
||||
running the code and never blindly trust that it is harmless. In any
|
||||
case, run these builds at your own risk. ☢️
|
||||
|
||||
## Reviewing MR branches
|
||||
|
||||
Reviewing merge requests on the Gitlab interface often leads to poor
|
||||
review, because:
|
||||
|
||||
- It doesn't show tabs, trailing whitespaces and other space issues
|
||||
which a well-configured CLI git would usually emphasize with colors.
|
||||
- The commit history is not emphasized, only the final results, but it's
|
||||
very important to check individual commits, as well as usable commit
|
||||
messages.
|
||||
- It's anyway usually much easier to review patches on your usual
|
||||
workflow environment rather than in a hard-to-use web interface.
|
||||
|
||||
There are ways to work on your local environments.
|
||||
|
||||
### Fetching MR branches automatically (read-only)
|
||||
|
||||
This first one is more of a trick, but an incredibly useful one.
|
||||
Unfortunately it is read-only, so it means you can review but not edit
|
||||
the MR yourself. Nevertheless since having to edit a MR should be the
|
||||
exception, not the rule, it's actually not too bad.
|
||||
|
||||
Edit your `.git/config` by adding a second "fetch =" rule to the
|
||||
"origin" remote. It should read:
|
||||
|
||||
```
|
||||
[remote "origin"]
|
||||
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||
fetch = +refs/merge-requests/*/head:refs/remotes/origin/merge-requests/*
|
||||
url = git@ssh.gitlab.gnome.org:GNOME/gimp.git
|
||||
```
|
||||
|
||||
From now on, when you `git pull` or `git fetch` the origin remote, any
|
||||
new or updated merge request will also be fetched. \o/
|
||||
|
||||
### Pushing to a third-party MR branch
|
||||
|
||||
There are cases when you want to push to the MR branch. It should stay
|
||||
rare occasions, but it can be for instance when the contributor seems
|
||||
stuck and doesn't know how to do some things; or maybe one doesn't
|
||||
understand instructions; sometimes also some contributors disappear
|
||||
after pushing their patch and never answer to review anymore.
|
||||
|
||||
When this happen, you could merge the commit and fix it immediately
|
||||
after (but it's never good to leave the repo in a bad state, even for
|
||||
just a few minutes). You could also apply, fix and push the fixed
|
||||
commits directly, but then the MR has to be closed and it doesn't look
|
||||
like it was applied (which is not the end of the world, but it's still
|
||||
nicer to show proper status on which patches were accepted or not).
|
||||
Moreover you would not be able to pass the CI build.
|
||||
|
||||
So we will fetch the remote yet without naming the remote:
|
||||
|
||||
- Click the "Check out branch" button below the merge request
|
||||
description. Gitlab gives you instructions but we will only use the
|
||||
first step ("Fetch and check out the branch for this merge request").
|
||||
For instance if contributor `xyz` created the branch `fix-bug-123` on
|
||||
their own remote, you would run:
|
||||
|
||||
```
|
||||
git fetch "git@ssh.gitlab.gnome.org:xyz/gimp.git" 'fix-bug-123'
|
||||
git checkout -b 'xyz/fix-bug-123' FETCH_HEAD
|
||||
```
|
||||
|
||||
- Now that you are in a local branch with their code, make your fix, add
|
||||
a local commit.
|
||||
|
||||
- Finally push to the contributor's own remote with the call:
|
||||
|
||||
```
|
||||
git push git@ssh.gitlab.gnome.org:xyz/gimp.git xyz/fix-bug-123:fix-bug-123
|
||||
```
|
||||
|
||||
This assumes that the contributor checked the option "*Allow commits
|
||||
from members who can merge to the target branch.*" (which we ask
|
||||
contributors to check, and it's set by default)
|
||||
|
||||
- Now check the MR page. It will normally be updated with your new
|
||||
commit(s) and a new pipeline should be triggered.
|
||||
|
||||
- Finally if you don't need the local branch anymore, you may delete it
|
||||
locally. The nice thing is that since you didn't name the remote, it
|
||||
doesn't pollute your git output and all data will be simply disposed
|
||||
of the next time `git gc` runs (implicitly or explicitly).
|
51
devel-docs/includes.txt
Normal file
|
@ -0,0 +1,51 @@
|
|||
includes.txt
|
||||
============
|
||||
|
||||
The include policy for the files in app/ is as follows:
|
||||
|
||||
Each subdirectory has a <module>-types.h file which defines the type
|
||||
space known to this module. All .c files in the directory include this
|
||||
(and only this) <module>-types.h file. <foo>-types.h files from other
|
||||
modules are included from the <module>-types.h file only. This way
|
||||
<module>-types.h becomes the only place where the namespace known to a
|
||||
module is defined.
|
||||
|
||||
|
||||
***** .h files *****
|
||||
|
||||
No .h file includes anything, with two exceptions:
|
||||
|
||||
- objects include their immediate parent class
|
||||
- if the header uses stuff like time_t (or off_t), it includes
|
||||
<time.h> (or <sys/types.h>). This only applies to system stuff!
|
||||
|
||||
|
||||
***** .c files *****
|
||||
|
||||
The include order of all .c files of a module is as follows:
|
||||
|
||||
/* example of a .c file from app/core */
|
||||
|
||||
#include "config.h" /* always and first */
|
||||
|
||||
#include <glib.h> /* *only* needed if the file needs stuff */
|
||||
/* like G_OS_WIN32 for conditional inclusion */
|
||||
/* of system headers */
|
||||
|
||||
#include <system headers> /* like <stdio.h> */
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "libgimpfoo/gimpfoo.h" /* as needed, e.g. "libgimpbase/gimpbase.h" */
|
||||
#include "libgimpbar/gimpbar.h"
|
||||
|
||||
#include "core-types.h" /* and _no_ other foo-types.h file */
|
||||
|
||||
#include "base/foo.h" /* files from modules below this one */
|
||||
#include "base/bar.h"
|
||||
|
||||
#include "gimp.h" /* files from this module */
|
||||
#include "gimpimage.h"
|
||||
#include "gimpwhatever.h"
|
||||
|
||||
#include "gimp-intl.h" /* if needed, *must* be the last include */
|
210
devel-docs/interpreters.txt
Normal file
|
@ -0,0 +1,210 @@
|
|||
# Interpreters for GIMP plugins
|
||||
|
||||
|
||||
|
||||
## About this document
|
||||
|
||||
This describes how GIMP invokes interpreters for GIMP plugin files.
|
||||
|
||||
This doesn't discuss the architecture of GIMP's interpreters,
|
||||
or how to write an interpreted plugin.
|
||||
|
||||
The audience is mainly GIMP developers.
|
||||
This may also interest users who want to use different interpreters.
|
||||
|
||||
|
||||
## Brief summary
|
||||
|
||||
On Linux (except for Lua) and MacOS, a shebang in a GIMP plugin
|
||||
text file is enough to indicate what interpreter to start.
|
||||
On Windows (and Linux for Lua), you also need an .interp file installed with GIMP.
|
||||
|
||||
It can get complicated;
|
||||
there are many combinations of environment variables, shebangs, file suffixes, and .interp files that can work.
|
||||
|
||||
*To insure a GIMP interpreted plugin works across platforms,
|
||||
it should have a shebang.*
|
||||
|
||||
*Except that ScriptFu plugin files installed to /scripts do not need a shebang
|
||||
since the ScriptFu extension reads them.*
|
||||
|
||||
## Partial history of interpreters in GIMP
|
||||
|
||||
Rarely are interpreters added to GIMP.
|
||||
GIMP 2 offers Perl, Scheme, and Python2 interpreters.
|
||||
GIMP 3 offers Python3, lua, javascript, and the gimp-script-fu-interpreter interpreters.
|
||||
|
||||
|
||||
## Background
|
||||
|
||||
An interpreter usually reads a text file.
|
||||
A user often launches an interpreter and passes a text file.
|
||||
But users can also double-click on a text file to launch the corresponding interpreter.
|
||||
|
||||
Similarly, GIMP launches an interpreter on GIMP plugin text files.
|
||||
GIMP must figure out the "corresponding" interpreter.
|
||||
|
||||
The general mechanism for launching interpreters from their text files is built into the operating system.
|
||||
On Linux and MacOS, the mechanism is called a shebang or sh-bang.
|
||||
On Windows, the mechanism "associates" file extensions with programs.
|
||||
|
||||
GIMP uses similar mechanisms to launch interpreters.
|
||||
See the code in /app/plug-ins/gimpinterpreterdb.c .
|
||||
*The exception is the ScriptFu extension.
|
||||
GIMP starts it when GIMP starts and it reads its ".scm" plugin files from the /scripts directory without benefit
|
||||
of the shebang mechanism.*
|
||||
|
||||
GIMP uses the mechanism when it queries plugin files at startup.
|
||||
Subsequently, GIMP knows the interpreter to launch,
|
||||
for example when a user clicks on a menu item implemented by an interpreter.
|
||||
A user should not click on a GIMP plugin file in a file browser;
|
||||
only one of the GIMP apps should launch interpreted GIMP plugin files.
|
||||
|
||||
|
||||
## Platform differences
|
||||
|
||||
On Linux (except for Lua) and MacOS, you simply need a shebang in a plugin text file.
|
||||
|
||||
On Windows (and Linux, at least for Lua), you must also define an .interp file.
|
||||
The .interp files are part of GIMP's installation on Windows (and Linux for Lua)
|
||||
(in both installer and Microsoft Store versions).
|
||||
The .interp files are built when the Windows installer is built.
|
||||
See the source file: /build/windows/installer/base_gimp3264.iss .
|
||||
|
||||
A user can optionally create .interp files on Linux and MacOS.
|
||||
But they are not usually part of a Linux installation.
|
||||
Sophisticated users can edit .interp files to change which interpreters GIMP launches.
|
||||
|
||||
|
||||
## shebangs
|
||||
|
||||
A shebang is text in the first line of a text file to be interpreted.
|
||||
A shebang starts with "#!",
|
||||
followed by the name or path of an interpreter,
|
||||
or followed by "/usr/bin/env", a space, and the name or path of an interpreter.
|
||||
|
||||
!!! Shebangs for GIMP plugins always use UNIX notation, i.e. forward slashes in path strings.
|
||||
Even on Windows, the shebangs are in UNIX notation.
|
||||
|
||||
Recommended examples for GIMP 3 (see repo directory /extensions/goat-exercises):
|
||||
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/env lua
|
||||
#!/usr/bin/env gjs
|
||||
#!/usr/bin/env gimp-script-fu-interpreter-3.0
|
||||
|
||||
Other examples:
|
||||
|
||||
#!python
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/env python
|
||||
|
||||
Whether the other examples actually work depends on:
|
||||
|
||||
- the platform
|
||||
- the user's environment, namely search PATH's
|
||||
- any .interp files
|
||||
|
||||
|
||||
## .interp files
|
||||
|
||||
Again, .interp files are necessary on Windows (and Linux, at least for Lua).
|
||||
They tell GIMP which executable interpreter to launch for a GIMP plugin text file.
|
||||
|
||||
You usually have one .interp file for each interpreter.
|
||||
For example:
|
||||
- python.interp
|
||||
- lua.interp
|
||||
- gimp-script-fu-interpreter.interp
|
||||
|
||||
The repo file /data/interpreters/default.interp is a non-functioning template
|
||||
for a <foo>.interp file.
|
||||
|
||||
.interp files are installed on Windows to, for example:
|
||||
|
||||
C:\Users\foo\AppData\Programs\GIMP 3.0\lib\gimp\3.0\interpreters
|
||||
|
||||
|
||||
interp files have three kinds of lines:
|
||||
- "program" in the form lhs=rhs
|
||||
- "extension" in the "binfmt" format
|
||||
- "magic" in the "binfmt" format
|
||||
|
||||
### "program" lines in an .interp file
|
||||
|
||||
These lines associate a shebang with a path to an executable.
|
||||
|
||||
These are in the form: "lhs=rhs"
|
||||
where lhs/rhs denotes "left hand side" and "right hand side."
|
||||
|
||||
The lhs matches the full text of a shebang after the "#!"
|
||||
For example, the lhs can be "/usr/bin/env python", having a space.
|
||||
Since a shebang is always in UNIX notation, any slashes are forward.
|
||||
|
||||
The rhs specifies a path to an interpreter.
|
||||
The rhs on the Windows platform is in Windows notation, using back slashes.
|
||||
For example, the rhs can be "C:\Users\foo\AppData\Programs\GIMP 3.0\bin\python"
|
||||
|
||||
|
||||
### "extension" lines in an .interp file
|
||||
|
||||
These lines associate a three-letter (sic) file extension (suffix) with a path to an executable.
|
||||
|
||||
These lines are in binfmt format.
|
||||
See https://en.wikipedia.org/wiki/Binfmt_misc.
|
||||
|
||||
Informally the format is: ":name:type:offset:magic: mask:interpreter:flags"
|
||||
!!! Note the field delimiter is usually ":" but can be another character.
|
||||
GIMP parses the binfmt using the first character as the delimiter.
|
||||
The first field is a name or identifier and has little significance.
|
||||
The second field is an "E".
|
||||
The third, fifth, and seventh fields are usually empty.
|
||||
The fourth field is an up-to-three letter suffix.
|
||||
The sixth field "interpreter" is a name or path to an executable interpreter.
|
||||
|
||||
If the sixth field is a Windows path that has a ":"
|
||||
then the fields must be delimited with another character, say a ",".
|
||||
|
||||
Examples:
|
||||
|
||||
:python:E::py::python3:
|
||||
:luajit:E::lua::luajit:
|
||||
,python,E,,py,,C:\Users\foo\AppData\GIMP 3.0\bin\python3,
|
||||
|
||||
Note the examples are not necessarily working examples.
|
||||
They might not work if the name or path is not found,
|
||||
for example if luajit was not installed to the Windows system directory of executables.
|
||||
|
||||
Note one example shows a path in Windows notation,
|
||||
having a ":", back slashes, and a space in the path.
|
||||
|
||||
|
||||
### "magic" lines in an .interp file
|
||||
|
||||
These lines associate "magic" bytes (inside a binary file) with a path to an executable.
|
||||
|
||||
These lines are in binfmt format.
|
||||
The second field is an "M".
|
||||
|
||||
We won't discuss these further, since they are little used.
|
||||
Binary files on Windows might not have "magic" bytes.
|
||||
Usually interpreters read text files, and rarely binary files.
|
||||
|
||||
|
||||
## Building .interp files for windows
|
||||
|
||||
If a GIMP developer adds an interpreter to the GIMP package,
|
||||
they must modify GIMP's build for Windows
|
||||
to ensure proper .interp files are installed.
|
||||
|
||||
See the repo file: /build/windows/installer/base_gimp3264.iss .
|
||||
|
||||
For the convenience of users, we usually install an .interp file having many lines.
|
||||
Only one "program" line is needed if users only install canonical plugin text files
|
||||
having a recommended shebang
|
||||
using the actual filename of the target interpreter.
|
||||
But since users may install non-canonical plugin text files by copying files,
|
||||
for convenience we have more lines in the .interp file.
|
||||
An extra "extension" line allows plugin text files without any shebang but a proper extension.
|
||||
An extra "program" line allows plugin text files
|
||||
having shebangs with alternate names for an interpreter.
|
13
devel-docs/meson.build
Normal file
|
@ -0,0 +1,13 @@
|
|||
devel_docs_build_root = meson.current_build_dir()
|
||||
|
||||
scan_args_common = [
|
||||
'--deprecated-guards=GIMP_DISABLE_DEPRECATED',
|
||||
]
|
||||
|
||||
mkdb_args_common = [
|
||||
'--name-space=gimp',
|
||||
]
|
||||
|
||||
if gi_docgen.found() and have_gobject_introspection
|
||||
subdir('reference')
|
||||
endif
|
32
devel-docs/os-support.txt
Normal file
|
@ -0,0 +1,32 @@
|
|||
## GIMP's Operating System Support
|
||||
|
||||
GIMP is available on a wide range of operating systems.
|
||||
As a general rule, we should stop supporting a platform as soon as the
|
||||
publisher stops supporting it, or if it is nearly not used anymore.
|
||||
|
||||
There is no accurate rule though, and it also mostly depends on what the
|
||||
developers maintaining GIMP for this platform will decide.
|
||||
|
||||
### GNU/Linux, *BSD…
|
||||
|
||||
Until GIMP 3.0 release, Debian 12 "bookworm" stable will be our baseline target.
|
||||
I.e. that we can bump a minimum dependency version only if it is in Debian
|
||||
bookworm.
|
||||
|
||||
After GIMP 3.0 release, we might get back to depend on Debian Testing.
|
||||
|
||||
### macOS
|
||||
|
||||
Compatibility with MacOS 11 and over.
|
||||
|
||||
Hardware:
|
||||
* x86_64 (Intel)
|
||||
* ARM 64-bit (Apple Silicon)
|
||||
|
||||
### Windows
|
||||
|
||||
Windows 10 and over.
|
||||
|
||||
Hardware:
|
||||
* x86 32 and 64-bit
|
||||
* ARM 64-bit
|
316
devel-docs/parasites.txt
Normal file
|
@ -0,0 +1,316 @@
|
|||
|
||||
PARASITE REGISTRY
|
||||
=================
|
||||
|
||||
This document describes parasites in GIMP.
|
||||
|
||||
|
||||
Table of contents
|
||||
-----------------
|
||||
Parasite registry
|
||||
Table of contents
|
||||
Audience
|
||||
|
||||
1. Namespace
|
||||
|
||||
2. Known prefixes
|
||||
|
||||
3. Known global parasites
|
||||
|
||||
4. Known image parasites
|
||||
|
||||
5. Known layer/drawable parasites
|
||||
|
||||
6. Parasite format
|
||||
|
||||
|
||||
Audience
|
||||
--------
|
||||
This document is designed for the convenience of GIMP developers.
|
||||
It does not need to concern users.
|
||||
|
||||
>>>> If your plug-in or script writes parasites, please
|
||||
>>>> amend this file in the Git repository or submit patches to
|
||||
>>>> gimp-developer-list@gnome.org
|
||||
|
||||
|
||||
1. NAMESPACE
|
||||
============
|
||||
|
||||
Plug-in-specific data should be prefixed by the plug-in function name and
|
||||
a slash, i.e. private data of plug_in_displace should be named like:
|
||||
|
||||
plug_in_displace/data1
|
||||
plug_in_displace/data2
|
||||
etc.
|
||||
|
||||
Global data follows no strict rules.
|
||||
|
||||
|
||||
2. KNOWN PREFIXES
|
||||
=================
|
||||
|
||||
"tiff" : The standard GIMP TIFF plugin
|
||||
"jpeg" : The standard GIMP JPEG plugin
|
||||
"png" : The standard GIMP PNG plugin
|
||||
"dcm" : The standard GIMP DICOM plugin
|
||||
"gimp" : For common and standard parasites
|
||||
|
||||
|
||||
3. KNOWN GLOBAL PARASITES
|
||||
=========================
|
||||
|
||||
"jpeg-save-defaults" (GLOBAL, PERSISTENT)
|
||||
Default save parameters used by the JPEG plug-in.
|
||||
|
||||
"png-save-defaults" (GLOBAL, PERSISTENT)
|
||||
Default save parameters used by the PNG plug-in.
|
||||
|
||||
"<plug-in>/_fu_data" (GLOBAL, IMAGE, DRAWABLE, PERSISTENT)
|
||||
The Gimp::Fu module (Perl) might store the arguments of the
|
||||
last plug-in invocation. It is usually attached to images,
|
||||
but might also be found globally. The data format is either
|
||||
pure character data (Data::Dumper) or a serialized data
|
||||
stream created by Storable::nfreeze.
|
||||
|
||||
"exif-orientation-rotate" (GLOBAL, PERSISTENT)
|
||||
Whether a load plug-in should automatically rotate the image
|
||||
according to the orientation specified in the EXIF data. This
|
||||
has values "yes" or "no". If the parasite is not set, the
|
||||
plug-in should ask the user what to do. This parasite may be
|
||||
removed in a future version (assuming always yes).
|
||||
|
||||
|
||||
4. KNOWN IMAGE PARASITES
|
||||
========================
|
||||
|
||||
"gimp-comment" (IMAGE, PERSISTENT)
|
||||
Standard GIF-style image comments. This parasite should be
|
||||
human-readable text in UTF-8 encoding. A trailing \0 might
|
||||
be included and is not part of the comment. Note that image
|
||||
comments may also be present in the "gimp-metadata" parasite.
|
||||
|
||||
"gimp-brush-name" (IMAGE, PERSISTENT)
|
||||
A string in UTF-8 encoding specifying the name of a GIMP brush.
|
||||
Currently, the gbr plug-in uses this parasite when loading and
|
||||
saving .gbr files. A trailing \0 might be included and is not
|
||||
part of the name.
|
||||
|
||||
"gimp-brush-pipe-name" (IMAGE, PERSISTENT)
|
||||
A string in UTF-8 encoding specifying the name of a GIMP brush
|
||||
pipe. Currently, the gih plug-in uses this parasite when loading and
|
||||
saving .gih files. A trailing \0 might be included and is not
|
||||
part of the name.
|
||||
|
||||
"gimp-brush-pipe-parameters" (IMAGE, PERSISTENT)
|
||||
This is all very preliminary:
|
||||
|
||||
A string, containing parameters describing how an brush pipe
|
||||
should be used. The contents is a space-separated list of
|
||||
keywords and values. The keyword and value are separated by a
|
||||
colon.
|
||||
|
||||
This parasite is currently attached to an image by the psp
|
||||
plug-in when it loads a .tub file (Paint Shop Pro picture
|
||||
tube). It is used (first attached with values asked from the
|
||||
user, if nonexistent) by the gpb plug-in when it saves a .gih
|
||||
file. The .gih file contains the same text in it.
|
||||
|
||||
The keywords are:
|
||||
ncells: the number of brushes in the brush pipe
|
||||
step: the default spacing for the pipe
|
||||
dim: the dimension of the pipe. The number of cells
|
||||
in the pipe should be equal to the product
|
||||
of the ranks of each dimension.
|
||||
cols: number of columns in each layer of the image,
|
||||
to be used when editing the pipe as a GIMP image
|
||||
rows: ditto for rows. Note that the number of columns and rows
|
||||
not necessarily are identical to the ranks of the
|
||||
dimensions of a pipe, but in the case of two-
|
||||
and three-dimensional pipes, it probably is.
|
||||
rank0, rank1, ...: (one for each dimension): the index range
|
||||
for that dimension
|
||||
placement: "default", "constant" or "random". "constant" means
|
||||
use the spacing in the first brush in the pipe.
|
||||
"random" means perturb that with some suitable
|
||||
random number function. (Hmm, would it be overdoing it
|
||||
if the pipe also could specify what random function
|
||||
and its parameters...?)
|
||||
sel0, sel1, ...: "default", "random", "incremental", "angular",
|
||||
"pressure", "velocity", and whatever else suitable we might
|
||||
think of ;-) Determines how one index from each dimension is
|
||||
selected (until we have pinpointed the brush to use).
|
||||
|
||||
"gimp-image-grid" (IMAGE, PERSISTENT)
|
||||
The GimpGrid object serialized to a string. Saved as parasite
|
||||
to keep the XCF files backwards compatible. Although gimp-1.2
|
||||
does not know how to handle the image grid, it keeps the grid
|
||||
information intact.
|
||||
|
||||
"gimp-pattern-name" (IMAGE, PERSISTENT)
|
||||
A string in UTF-8 encoding specifying the name of a GIMP pattern.
|
||||
Currently, the pat plug-in uses this parasite when loading and
|
||||
saving .pat files. A trailing \0 might be included and is not
|
||||
part of the name.
|
||||
|
||||
"tiff-save-options" (IMAGE)
|
||||
The TiffSaveVals structure from the TIFF plugin.
|
||||
|
||||
"jpeg-save-options" (IMAGE)
|
||||
The JpegSaveVals structure from the JPEG plugin.
|
||||
|
||||
"jpeg-exif-data" (IMAGE) (deprecated)
|
||||
The ExifData structure serialized into a uchar* blob from
|
||||
libexif. This is deprecated in favor of "exif-data".
|
||||
|
||||
"jpeg-original-settings" (IMAGE, PERSISTENT)
|
||||
The settings found in the original JPEG image: quality (IJG),
|
||||
color space, component subsampling and quantization tables.
|
||||
These can be reused when saving the image in order to minimize
|
||||
quantization losses and keep the same size/quality ratio.
|
||||
|
||||
"gamma" (IMAGE, PERSISTENT)
|
||||
The original gamma this image was created/saved. For JPEG; this is
|
||||
always one, for PNG it's usually taken from the image data. GIMP
|
||||
might use and modify this. The format is an ascii string with the
|
||||
gamma exponent as a flotingpoint value.
|
||||
|
||||
Example: for sRGB images this might contain "0.45454545"
|
||||
|
||||
"chromaticity" (IMAGE, PERSISTENT)
|
||||
This parasite contains 8 floatingpoint values (ascii, separated by
|
||||
whitespace) specifying the x and y coordinates of the whitepoint, the
|
||||
red, green and blue primaries, in this order.
|
||||
|
||||
Example: for sRGB images this might contain
|
||||
"0.3127 0.329 0.64 0.33 0.3 0.6 0.15 0.06"
|
||||
wx wy rx ry gx gy bx by
|
||||
|
||||
"rendering-intent" (IMAGE, PERSISTENT)
|
||||
This specifies the rendering intent of the image. It's a value
|
||||
between 0 and 3, again in ascii:
|
||||
|
||||
0 - perceptual (e.g. for photographs)
|
||||
1 - relative colorimetric (e.g. for logos)
|
||||
2 - saturation-preserving (e.g. for business charts)
|
||||
3 - absolute colorimetric
|
||||
|
||||
"hot-spot" (IMAGE, PERSISTENT)
|
||||
Use this parasite to store an image's "hot spot". Currently
|
||||
used by the XBM plugin to store mouse cursor hot spots.
|
||||
|
||||
Example: a hot spot at coordinates (5,5) is stored as "5 5"
|
||||
|
||||
"exif-data" (IMAGE, PERSISTENT)
|
||||
The ExifData structure serialized into a character array by
|
||||
libexif (using exif_data_save_data). If a "gimp-metadata"
|
||||
parasite is present, it should take precedence over this one.
|
||||
|
||||
"gimp-metadata" (IMAGE, PERSISTENT)
|
||||
The metadata associated with the image, serialized as one XMP
|
||||
packet. This metadata includes the contents of any XMP, EXIF
|
||||
and IPTC blocks from the original image, as well as
|
||||
user-specified values such as image comment, copyright,
|
||||
license, etc.
|
||||
|
||||
"icc-profile" (IMAGE, PERSISTENT | UNDOABLE)
|
||||
This contains an ICC profile describing the color space the
|
||||
image was produced in. TIFF images stored in PhotoShop do
|
||||
oftentimes contain embedded profiles. An experimental color
|
||||
manager exists to use this parasite, and it will be used
|
||||
for interchange between TIFF and PNG (identical profiles)
|
||||
|
||||
"icc-profile-name" (IMAGE, PERSISTENT | UNDOABLE)
|
||||
The profile name is a convenient name for referring to the
|
||||
profile. It is for example used in the PNG file format. The
|
||||
name must be stored in UTF-8 encoding. If a file format uses
|
||||
a different character encoding, it must be converted to UTF-8
|
||||
for use as a parasite.
|
||||
|
||||
"decompose-data" (IMAGE, NONPERSISTENT)
|
||||
Starting with GIMP 2.4, this is added to images produced by
|
||||
the decompose plug-in, and contains information necessary to
|
||||
recompose the original source RGB layer from the resulting
|
||||
grayscale layers. It is ascii; a typical example would be
|
||||
"source=2 type=RGBA 4 5 6 7". This means that layer 2 was
|
||||
decomposed in RGBA mode, giving rise to layers 4, 5, 6, and 7.
|
||||
|
||||
"print-settings" (IMAGE, NONPERSISTENT)
|
||||
This parasite is stored by the Print plug-in and holds settings
|
||||
done in the Print dialog. It also has a version field so that
|
||||
changes to the parasite can be done. GIMP 2.4 used version 0.3.
|
||||
The format is GKeyFile. A lot of the contents are identical to
|
||||
what is stored in ~/.gimp-2.x/print-settings but the parasite
|
||||
has some additional image-related fields.
|
||||
|
||||
"print-page-setup" (IMAGE, NONPERSISTENT)
|
||||
This parasite is stored by the Print plug-in and holds settings
|
||||
done in the Page Setup dialog. The format is GKeyFile as created
|
||||
from GtkPageSetup. The content is identical to what is stored in
|
||||
~/.gimp-2.x/print-page-setup.
|
||||
|
||||
"dcm/XXXX-XXXX-AA" (IMAGE, PERSISTENT)
|
||||
These parasites are stored by the Dicom plug-in and hold the DICOM
|
||||
element information for that image. The format is raw binary data
|
||||
as read from the original image.
|
||||
where: XXXX is a 4-digit ascii encoded hexadecimal number
|
||||
AA is a two character ascii value representing the Dicom
|
||||
element's Value Representation (VR)
|
||||
|
||||
|
||||
5. KNOWN LAYER/DRAWABLE PARASITES
|
||||
=================================
|
||||
|
||||
"gimp-text-layer" (LAYER, PERSISTENT)
|
||||
The associated GimpText object serialized to a string. For
|
||||
convenience the string is terminated by a trailing '\0'.
|
||||
The idea of using a parasite for text layers is to keep the XCF
|
||||
files backward compatible. Although gimp-1.2 doesn't know how
|
||||
to handle the text layer, it keeps the parasite intact.
|
||||
|
||||
"gfig" (LAYER, PERSISTENT)
|
||||
As of GIMP 2.2, the gfig plug-in creates its own layers, and
|
||||
stores a representation of the figure as a layer parasite.
|
||||
The parasite contains a GFig save file, in an ascii format.
|
||||
If gfig is started while the active layer contains a "gfig"
|
||||
parasite, the contents of the parasite are loaded at startup.
|
||||
|
||||
|
||||
6. PARASITE FORMAT
|
||||
==================
|
||||
|
||||
The parasite data format is not rigidly specified. For non-persistent
|
||||
parasites you are entirely free, as the parasite data does not survive the
|
||||
current gimp session. If you need persistent data, you basically have to
|
||||
choose between the following alternatives (also, having some standard for
|
||||
non-persistent data might be fine as well):
|
||||
|
||||
- Cook your own binary data format
|
||||
|
||||
You can invent your own data format. This means that you will either
|
||||
loose totally (consider endian-ness or version-ness issues) or you will
|
||||
get yourself into deep trouble to get it "right" in all cases.
|
||||
|
||||
- Use character (string) data
|
||||
|
||||
Obvious to Perl people but less so to C programmers: just sprintf your
|
||||
data into a string (e.g. "SIZE 100x200 XRES 300 YRES 300") and store
|
||||
that in the parasite, and later sscanf it again. This often solves most
|
||||
of the problems you might encounter, makes for easier debugging and
|
||||
more robustness (consider the case when you add more entries to your
|
||||
persistent data: older plug-ins might be able to read the relevant
|
||||
parts and your application can detect missing fields easily). The
|
||||
drawback is that your data is likely to be larger than a compact binary
|
||||
representation would be. Not much a problem for most applications,
|
||||
though.
|
||||
|
||||
You could also use one parasite per field you store, i.e. foo-size,
|
||||
foo-offset-x, foo-offset-y etc...
|
||||
|
||||
- Use the libgimpconfig serialize functions
|
||||
|
||||
This is a special case of the previous one, using the convenience
|
||||
functions provided by libgimpconfig. If you are not concerned about
|
||||
the size of the string representation of your data, you can use
|
||||
gimp_config_serialize_to_string() and other functions to easily
|
||||
convert your data to/from a character string.
|
119
devel-docs/reference/gimp-ui/gimp-ui-3.0.toml.in
Normal file
|
@ -0,0 +1,119 @@
|
|||
[library]
|
||||
namespace = "GimpUi"
|
||||
version = "@GIMP_VERSION@"
|
||||
browse_url = "https://gitlab.gnome.org/GNOME/gimp/"
|
||||
repository_url = "https://gitlab.gnome.org/GNOME/gimp.git"
|
||||
website_url = "https://www.gimp.org"
|
||||
authors = "GIMP contributors"
|
||||
logo_url = "@GIMP_LOGO@"
|
||||
license = "GPL-3.0-or-later"
|
||||
description = "GIMP UI library"
|
||||
dependencies = [
|
||||
'Babl-0.1',
|
||||
'Gimp-3.0',
|
||||
'GLib-2.0',
|
||||
'GObject-2.0',
|
||||
'GdkPixbuf-2.0',
|
||||
'Gegl-0.4',
|
||||
'Gio-2.0',
|
||||
'Gtk-3.0',
|
||||
'cairo-1.0',
|
||||
]
|
||||
devhelp = true
|
||||
search_index = true
|
||||
|
||||
# These links are mostly used for the dependency lists in index page.
|
||||
|
||||
[dependencies."Babl-0.1"]
|
||||
name = "Babl"
|
||||
description = "Pixel encoding and color space conversion engine"
|
||||
docs_url = "https://gegl.org/babl"
|
||||
|
||||
[dependencies."Gimp-3.0"]
|
||||
name = "Gimp"
|
||||
description = "GIMP Library"
|
||||
docs_url = "https://developer.gimp.org/api/3.0/libgimp/"
|
||||
|
||||
[dependencies."GLib-2.0"]
|
||||
name = "GLib"
|
||||
description = "C Utility Library"
|
||||
docs_url = "https://developer.gnome.org/glib/stable"
|
||||
|
||||
[dependencies."GObject-2.0"]
|
||||
name = "GObject"
|
||||
description = "The base type system library"
|
||||
docs_url = "https://developer.gnome.org/gobject/stable"
|
||||
|
||||
[dependencies."GdkPixbuf-2.0"]
|
||||
name = "GdkPixbuf"
|
||||
description = "Image loading and scaling"
|
||||
docs_url = "https://docs.gtk.org/gdk-pixbuf/"
|
||||
|
||||
[dependencies."Gegl-0.4"]
|
||||
name = "Gegl"
|
||||
description = "Generic Graphics Library"
|
||||
docs_url = "https://gegl.org/"
|
||||
|
||||
[dependencies."Gio-2.0"]
|
||||
name = "Gio"
|
||||
description = "GObject interfaces and objects"
|
||||
docs_url = "https://developer.gnome.org/gio/stable"
|
||||
|
||||
[dependencies."Gtk-3.0"]
|
||||
name = "Gtk"
|
||||
description = "The GTK toolkit"
|
||||
docs_url = "https://developer.gnome.org/gtk3/stable"
|
||||
|
||||
[dependencies."cairo-1.0"]
|
||||
name = "cairo"
|
||||
description = "A 2D graphics library with support for multiple output devices"
|
||||
docs_url = "https://www.cairographics.org/manual/"
|
||||
|
||||
[theme]
|
||||
name = "basic"
|
||||
show_index_summary = true
|
||||
show_class_hierarchy = true
|
||||
|
||||
[source-location]
|
||||
base_url = "https://gitlab.gnome.org/GNOME/gimp/-/blob/master/"
|
||||
|
||||
[extra]
|
||||
content_files = [
|
||||
'widget-gallery.md',
|
||||
]
|
||||
content_images = [
|
||||
'images/browser.png',
|
||||
'images/busy-box.png',
|
||||
'images/button.png',
|
||||
'images/chain-button.png',
|
||||
'images/color-area.png',
|
||||
'images/color-button.png',
|
||||
'images/color-hex-entry.png',
|
||||
'images/color-notebook.png',
|
||||
'images/color-profile-combo-box.png',
|
||||
'images/color-profile-view.png',
|
||||
'images/color-scale.png',
|
||||
'images/color-scales.png',
|
||||
'images/color-select.png',
|
||||
'images/color-selection.png',
|
||||
'images/dialog.png',
|
||||
'images/enum-combo-box.png',
|
||||
'images/enum-label.png',
|
||||
'images/file-entry.png',
|
||||
'images/frame.png',
|
||||
'images/hint-box.png',
|
||||
'images/int-combo-box.png',
|
||||
'images/memsize-entry.png',
|
||||
'images/number-pair-entry.png',
|
||||
'images/offset-area.png',
|
||||
'images/page-selector.png',
|
||||
'images/path-editor.png',
|
||||
'images/pick-button.png',
|
||||
'images/preview-area.png',
|
||||
'images/ruler.png',
|
||||
'images/string-combo-box.png',
|
||||
'images/unit-combo-box.png',
|
||||
]
|
||||
# The urlmap is used as base links when an API docs refer to a type or
|
||||
# function from another library.
|
||||
urlmap_file = "urlmap.js"
|
BIN
devel-docs/reference/gimp-ui/images/browser.png
Normal file
After Width: | Height: | Size: 9.7 KiB |
BIN
devel-docs/reference/gimp-ui/images/busy-box.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
devel-docs/reference/gimp-ui/images/button.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
devel-docs/reference/gimp-ui/images/chain-button.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
devel-docs/reference/gimp-ui/images/color-area.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
devel-docs/reference/gimp-ui/images/color-button.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
devel-docs/reference/gimp-ui/images/color-hex-entry.png
Normal file
After Width: | Height: | Size: 3 KiB |
BIN
devel-docs/reference/gimp-ui/images/color-notebook.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
devel-docs/reference/gimp-ui/images/color-profile-combo-box.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
devel-docs/reference/gimp-ui/images/color-profile-view.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
devel-docs/reference/gimp-ui/images/color-scale.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
devel-docs/reference/gimp-ui/images/color-scales.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
devel-docs/reference/gimp-ui/images/color-select.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
devel-docs/reference/gimp-ui/images/color-selection.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
devel-docs/reference/gimp-ui/images/dialog.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
BIN
devel-docs/reference/gimp-ui/images/enum-combo-box.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
devel-docs/reference/gimp-ui/images/enum-label.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
devel-docs/reference/gimp-ui/images/file-entry.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
devel-docs/reference/gimp-ui/images/frame.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
devel-docs/reference/gimp-ui/images/hint-box.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
devel-docs/reference/gimp-ui/images/int-combo-box.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
devel-docs/reference/gimp-ui/images/memsize-entry.png
Normal file
After Width: | Height: | Size: 5 KiB |
BIN
devel-docs/reference/gimp-ui/images/number-pair-entry.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
devel-docs/reference/gimp-ui/images/offset-area.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
devel-docs/reference/gimp-ui/images/page-selector.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
devel-docs/reference/gimp-ui/images/path-editor.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
devel-docs/reference/gimp-ui/images/pick-button.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
devel-docs/reference/gimp-ui/images/preview-area.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
devel-docs/reference/gimp-ui/images/ruler.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
devel-docs/reference/gimp-ui/images/string-combo-box.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
devel-docs/reference/gimp-ui/images/unit-combo-box.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
39
devel-docs/reference/gimp-ui/meson.build
Normal file
|
@ -0,0 +1,39 @@
|
|||
# Extra markdown files
|
||||
gimp_ui_doc_content_files = [
|
||||
'widget-gallery.md',
|
||||
]
|
||||
|
||||
gimp_ui_doc_toml = configure_file(
|
||||
input: 'gimp-ui-3.0.toml.in',
|
||||
output: '@BASENAME@',
|
||||
configuration: {
|
||||
'GIMP_VERSION': gimp_version,
|
||||
'GIMP_LOGO': '../images/gimp-devel-logo.png',
|
||||
},
|
||||
)
|
||||
|
||||
gimp_ui_docs = custom_target('gimp-ui-docs',
|
||||
input: libgimpui_gir[0],
|
||||
output: 'libgimpui-@0@'.format(gimp_api_version),
|
||||
command: [
|
||||
gi_docgen,
|
||||
'generate',
|
||||
'--quiet',
|
||||
'--fatal-warnings',
|
||||
'--config', gimp_ui_doc_toml,
|
||||
'--output-dir=@OUTPUT@',
|
||||
'--no-namespace-dir',
|
||||
'--content-dir=@0@'.format(meson.current_source_dir()),
|
||||
'--add-include-path=@0@'.format(meson.project_build_root() / 'libgimp'),
|
||||
'--add-include-path=@0@'.format(get_option('prefix') / 'share' / 'gir-1.0'),
|
||||
'@INPUT@',
|
||||
],
|
||||
depends: libgimp_gir[0],
|
||||
depend_files: [
|
||||
gimp_ui_doc_toml,
|
||||
gimp_ui_doc_content_files,
|
||||
],
|
||||
build_by_default: true,
|
||||
install: true,
|
||||
install_dir: get_option('datadir') / 'doc' / 'gimp-@0@'.format(gimp_app_version),
|
||||
)
|
12
devel-docs/reference/gimp-ui/urlmap.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
// A map between namespaces and base URLs for their online gi-docgen documentation
|
||||
baseURLs = [
|
||||
[ 'Babl', 'https://developer.gimp.org/api/babl/' ],
|
||||
[ 'Gegl', 'https://developer.gimp.org/api/gegl/' ],
|
||||
[ 'GLib', 'https://docs.gtk.org/glib/' ],
|
||||
[ 'GObject', 'https://docs.gtk.org/gobject/' ],
|
||||
[ 'Gdk', 'https://docs.gtk.org/gdk3/' ],
|
||||
[ 'GdkPixbuf', 'https://docs.gtk.org/gdk-pixbuf/' ],
|
||||
[ 'Gio', 'https://docs.gtk.org/gio/' ],
|
||||
[ 'Gtk', 'https://docs.gtk.org/gtk3/' ],
|
||||
[ 'Gimp', 'https://developer.gimp.org/api/3.0/libgimp/' ],
|
||||
]
|
36
devel-docs/reference/gimp-ui/widget-gallery.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
Title: Widget gallery
|
||||
|
||||
Widget gallery
|
||||
==============
|
||||
|
||||
[](class.Browser.html)
|
||||
[](class.Button.html)
|
||||
[](class.BusyBox.html)
|
||||
[](class.ChainButton.html)
|
||||
[](class.ColorArea.html)
|
||||
[](class.ColorButton.html)
|
||||
[](class.ColorHexEntry.html)
|
||||
[](class.ColorNotebook.html)
|
||||
[](class.ColorScale.html)
|
||||
[](class.ColorScales.html)
|
||||
[](class.ColorSelect.html)
|
||||
[](class.ColorSelection.html)
|
||||
[](class.ColorProfileComboBox.html)
|
||||
[](class.ColorProfileView.html)
|
||||
[](class.Dialog.html)
|
||||
[](class.EnumComboBox.html)
|
||||
[](class.EnumLabel.html)
|
||||
[](class.FileEntry.html)
|
||||
[](class.Frame.html)
|
||||
[](class.HintBox.html)
|
||||
[](class.IntComboBox.html)
|
||||
[](class.MemsizeEntry.html)
|
||||
[](class.NumberPairEntry.html)
|
||||
[](class.OffsetArea.html)
|
||||
[](class.PageSelector.html)
|
||||
[](class.PathEditor.html)
|
||||
[](class.PickButton.html)
|
||||
[](class.PreviewArea.html)
|
||||
[](class.Ruler.html)
|
||||
[](class.StringComboBox.html)
|
||||
[](class.UnitComboBox.html)
|
80
devel-docs/reference/gimp/gimp-3.0.toml.in
Normal file
|
@ -0,0 +1,80 @@
|
|||
[library]
|
||||
namespace = "Gimp"
|
||||
version = "@GIMP_VERSION@"
|
||||
browse_url = "https://gitlab.gnome.org/GNOME/gimp/"
|
||||
repository_url = "https://gitlab.gnome.org/GNOME/gimp.git"
|
||||
website_url = "https://www.gimp.org"
|
||||
authors = "GIMP contributors"
|
||||
logo_url = "@GIMP_LOGO_PATH@"
|
||||
license = "GPL-3.0-or-later"
|
||||
description = "GIMP library"
|
||||
dependencies = [
|
||||
'Babl-0.1',
|
||||
'GLib-2.0',
|
||||
'GObject-2.0',
|
||||
'GdkPixbuf-2.0',
|
||||
'Gegl-0.4',
|
||||
'Gio-2.0',
|
||||
'Gtk-3.0',
|
||||
'cairo-1.0',
|
||||
]
|
||||
devhelp = true
|
||||
search_index = true
|
||||
|
||||
[dependencies."Babl-0.1"]
|
||||
name = "Babl"
|
||||
description = "Pixel encoding and color space conversion engine"
|
||||
docs_url = "https://gegl.org/babl"
|
||||
|
||||
[dependencies."GLib-2.0"]
|
||||
name = "GLib"
|
||||
description = "C Utility Library"
|
||||
docs_url = "https://developer.gnome.org/glib/stable"
|
||||
|
||||
[dependencies."GObject-2.0"]
|
||||
name = "GObject"
|
||||
description = "The base type system library"
|
||||
docs_url = "https://developer.gnome.org/gobject/stable"
|
||||
|
||||
[dependencies."GdkPixbuf-2.0"]
|
||||
name = "GdkPixbuf"
|
||||
description = "Image loading and scaling"
|
||||
docs_url = "https://docs.gtk.org/gdk-pixbuf/"
|
||||
|
||||
[dependencies."Gegl-0.4"]
|
||||
name = "Gegl"
|
||||
description = "Generic Graphics Library"
|
||||
docs_url = "https://gegl.org/"
|
||||
|
||||
[dependencies."Gio-2.0"]
|
||||
name = "Gio"
|
||||
description = "GObject interfaces and objects"
|
||||
docs_url = "https://developer.gnome.org/gio/stable"
|
||||
|
||||
[dependencies."Gtk-3.0"]
|
||||
name = "Gtk"
|
||||
description = "The GTK toolkit"
|
||||
docs_url = "https://developer.gnome.org/gtk3/stable"
|
||||
|
||||
[dependencies."cairo-1.0"]
|
||||
name = "cairo"
|
||||
description = "A 2D graphics library with support for multiple output devices"
|
||||
docs_url = "https://www.cairographics.org/manual/"
|
||||
|
||||
[dependencies."Pango-1.0"]
|
||||
name = "Pango"
|
||||
description = "Internationalized text layout and rendering"
|
||||
docs_url = "https://docs.gtk.org/Pango/"
|
||||
|
||||
[theme]
|
||||
name = "basic"
|
||||
show_index_summary = true
|
||||
show_class_hierarchy = true
|
||||
|
||||
[source-location]
|
||||
base_url = "https://gitlab.gnome.org/GNOME/gimp/-/blob/master/"
|
||||
|
||||
[extra]
|
||||
content_files = [
|
||||
]
|
||||
urlmap_file = "urlmap.js"
|
36
devel-docs/reference/gimp/meson.build
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Extra markdown files
|
||||
gimp_doc_content_files = [
|
||||
]
|
||||
|
||||
gimp_doc_toml = configure_file(
|
||||
input: 'gimp-3.0.toml.in',
|
||||
output: '@BASENAME@',
|
||||
configuration: {
|
||||
'GIMP_VERSION': gimp_version,
|
||||
'GIMP_LOGO_PATH': '../images/gimp-devel-logo.png',
|
||||
},
|
||||
)
|
||||
|
||||
gimp_docs = custom_target('gimp-docs',
|
||||
input: libgimp_gir[0],
|
||||
output: 'libgimp-@0@'.format(gimp_api_version),
|
||||
command: [
|
||||
gi_docgen,
|
||||
'generate',
|
||||
'--quiet',
|
||||
'--fatal-warnings',
|
||||
'--config', gimp_doc_toml,
|
||||
'--output-dir=@OUTPUT@',
|
||||
'--no-namespace-dir',
|
||||
'--content-dir=@0@'.format(meson.current_source_dir()),
|
||||
'--add-include-path=@0@'.format(get_option('prefix') / 'share' / 'gir-1.0'),
|
||||
'@INPUT@',
|
||||
],
|
||||
depend_files: [
|
||||
gimp_doc_toml,
|
||||
gimp_doc_content_files,
|
||||
],
|
||||
build_by_default: true,
|
||||
install: true,
|
||||
install_dir: get_option('datadir') / 'doc' / 'gimp-@0@'.format(gimp_app_version),
|
||||
)
|
12
devel-docs/reference/gimp/urlmap.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
// A map between namespaces and base URLs for their online gi-docgen documentation
|
||||
baseURLs = [
|
||||
[ 'Babl', 'https://developer.gimp.org/api/babl/' ],
|
||||
[ 'Gegl', 'https://developer.gimp.org/api/gegl/' ],
|
||||
[ 'GLib', 'https://docs.gtk.org/glib/' ],
|
||||
[ 'GObject', 'https://docs.gtk.org/gobject/' ],
|
||||
[ 'Gdk', 'https://docs.gtk.org/gdk3/' ],
|
||||
[ 'GdkPixbuf', 'https://docs.gtk.org/gdk-pixbuf/' ],
|
||||
[ 'Gio', 'https://docs.gtk.org/gio/' ],
|
||||
[ 'Gtk', 'https://docs.gtk.org/gtk3/' ],
|
||||
[ 'Pango', 'https://docs.gtk.org/Pango/' ],
|
||||
]
|
2
devel-docs/reference/meson.build
Normal file
|
@ -0,0 +1,2 @@
|
|||
subdir('gimp')
|
||||
subdir('gimp-ui')
|
148
devel-docs/tagging.txt
Normal file
|
@ -0,0 +1,148 @@
|
|||
=============================================================
|
||||
How does resource tagging in Gimp work?
|
||||
=============================================================
|
||||
|
||||
|
||||
GimpTagged
|
||||
|
||||
Tagging is not limited to a concrete class hierarchy, but any class
|
||||
implementing the GimpTagged interface can be tagged. In addition to
|
||||
methods for adding/removing/enumerating tags it also requires
|
||||
GimpTagged objects to identify themselves:
|
||||
|
||||
* gimp_tagged_get_identifier: used to get a unique identifier of a
|
||||
GimpTagged object. For objects which are stored in a file it will
|
||||
usually be a filename.
|
||||
|
||||
* gimp_tagged_get_checksum: the identifier mentioned above has the problem
|
||||
that it can change during sessions (for example, user moves or renames
|
||||
a resource file). Therefore, there needs to be a way to get another
|
||||
identifier from the data of the tagged object, so that tags stored between
|
||||
session can be remapped properly.
|
||||
|
||||
|
||||
GimpTag
|
||||
|
||||
Tags are represented by a GimpTag object. There are no limitations for
|
||||
tag names except that they cannot contain a selected set of terminal
|
||||
punctuation characters (used to separate tags), leading or trailing
|
||||
whitespace and cannot begin with a reserved prefix for internal tags
|
||||
('gimp:'). These conditions are enforced when creating a tag object from a
|
||||
tag string. The only reason for tag creation to fail is if there are
|
||||
no characters left after trying to fix a tag according to the
|
||||
rules above. Tag names are displayed as the user typed them (case
|
||||
sensitive), but tag comparison is done case-insensitively.
|
||||
|
||||
Tags are immutable, i.e. when a tag is created with one name string, it
|
||||
cannot be changed, but a new tag has to be created instead.
|
||||
|
||||
There are methods provided for convenient use with glib, a comparison
|
||||
function which can be used to sort tag lists and functions for storing
|
||||
tags in a GHashTable.
|
||||
|
||||
|
||||
GimpTagCache
|
||||
|
||||
Between sessions, tags assigned to objects are stored in a cache
|
||||
file. The cache file is a simple XML file, which lists all resources and
|
||||
tags which are added to them. Resources which have no tags assigned
|
||||
are listed here too, so that when we check the cache we know that they
|
||||
have no tags assigned instead of trying to find out if the resource file
|
||||
has been renamed.
|
||||
|
||||
When the session ends, a list of all resources and their tags
|
||||
is constructed. Resources which were not loaded during this session,
|
||||
but had tags assigned are also added to the list (they are saved
|
||||
because they could be useful in the next session, for example, when
|
||||
a temporarily disconnected network directory is reconnected). The list
|
||||
is then written to a tag cache file in the user's home directory.
|
||||
|
||||
When the session starts, the previously saved resource and tag mapping has to
|
||||
be loaded and assigned to GimpTagged objects. First the tag cache is
|
||||
loaded from file, and then containers are added (GimpContainer objects
|
||||
which contain items implementing the GimpTagged interface). After that,
|
||||
loaded resources are assigned tags:
|
||||
|
||||
If a resource identifier matches an identifier in the cache,
|
||||
corresponding tags are assigned to the GimpTagged object.
|
||||
Else, if the identifier is not found in the tag cache,
|
||||
an attempt is made to check if the resource file has been
|
||||
moved/renamed. In such case the checksum is used to match the
|
||||
GimpTagged object with all of the records in the tag cache.
|
||||
If a match is found,
|
||||
the identifier is updated in the tag cache.
|
||||
Otherwise,
|
||||
the loaded GimpTagged object is considered to be a newly
|
||||
added resource.
|
||||
|
||||
|
||||
GimpFilteredContainer
|
||||
|
||||
A GimpFilteredContainer is a "view" (representation) of a
|
||||
GimpContainer. It is related to tagging in that it can be used to
|
||||
filter a GimpContainer to contain only GimpTagged objects which have
|
||||
certain tags assigned. It is automatically updated with any changes in
|
||||
the GimpContainer it wraps. However, items should not be added or removed
|
||||
from this container manually as changes do not affect the original
|
||||
container and would be lost when the GimpFilteredContainer is
|
||||
updated. Instead, the contents should be changed by setting a tag list
|
||||
which would be used to filter GimpTagged objects containing all of the
|
||||
given GimpTags.
|
||||
|
||||
GimpFilteredContainer can use any GimpContainer as a source
|
||||
container. Therefore, it is possible to use the decorator design pattern
|
||||
to implement additional container views, such as a view combining items
|
||||
from multiple containers.
|
||||
|
||||
|
||||
GimpTagEntry widget
|
||||
|
||||
The GimpTagEntry widget extends GtkEntry and is used to either assign or
|
||||
query tags depending on the selected mode. The widget support various
|
||||
usability features:
|
||||
|
||||
* Jellybeans: When a tag is entered and confirmed by either separator,
|
||||
pressing return or otherwise, it becomes a jellybean, i.e. a single
|
||||
unit, not a bunch of characters. Navigating in a GimpTagEntry,
|
||||
deleting tags, etc. can be performed much faster. However, while a tag
|
||||
is just being entered (not yet confirmed), all actions operate on
|
||||
characters as usual.
|
||||
|
||||
* Custom auto completion is implemented in the GimpTagEntry widget which
|
||||
allows to complete tags in the middle of a tag list, doesn't offer
|
||||
already completed tags, tab cycles all possible completions, etc.
|
||||
|
||||
* If the GimpTagEntry is empty and unused it displays a description for
|
||||
the user regarding its purpose.
|
||||
|
||||
When operating in tag assignment mode, tags are assigned only when
|
||||
the user hits the return key.
|
||||
|
||||
When operating in tag query mode, the given GimpFilteredContainer is
|
||||
filtered as the user types. The GimpTagEntry also remembers recently used
|
||||
configurations, which can be cycled using up and down arrow keys.
|
||||
|
||||
|
||||
GimpComboTagEntry widget
|
||||
|
||||
The GimpComboTagEntry widget extends GimpTagEntry and adds the ability to pick
|
||||
tags from a menu-like list (using the GimpTagPopup widget).
|
||||
|
||||
|
||||
GimpTagPopup widget
|
||||
|
||||
The GimpTagPopup widget is used as a tag list menu from the GimpComboTagEntry
|
||||
widget. It is not designed to be used with any other widget.
|
||||
|
||||
GimpTagPopup has many visual and behavioral similarities to GtkMenu.
|
||||
In particular, it uses menu-like scrolling.
|
||||
|
||||
GimpTagPopup implements various usability features, some of which are:
|
||||
|
||||
* Tags which would result in an empty selection of resources are made
|
||||
insensitive.
|
||||
|
||||
* Closing either with the keyboard or by clicking outside the popup area.
|
||||
|
||||
* Underlining of highlighted (hovered) tags.
|
||||
|
57
devel-docs/ui-framework.txt
Normal file
|
@ -0,0 +1,57 @@
|
|||
GIMP UI Framework
|
||||
=================
|
||||
|
||||
This document describes how the GIMP UI framework functions and is
|
||||
implemented. Here, "UI framework" refers to the system that saves the
|
||||
UI layout between GIMP sessions, i.e. how docks, dockable dialogs etc
|
||||
are setup.
|
||||
|
||||
|
||||
Key Classes
|
||||
-----------
|
||||
|
||||
GimpDockable - Represents a dockable dialog.
|
||||
GimpDockbook - A GtkNotebook of GimpDockables
|
||||
GimpDock - A columns of GimpDockbooks
|
||||
GimpToolbox - Subclasses GimpDock, contains the toolbox.
|
||||
Dockables are added at the bottom
|
||||
GimpMenuDock - Subclasses GimpDock, contains dockables, should
|
||||
probably be merged with GimpDock. The name
|
||||
contains "menu" from the time when it hosted the
|
||||
Image Selection Menu that is now in the
|
||||
GimpDockWindow
|
||||
GimpDockColumns - A set of GimpDocks arranged side by side.
|
||||
GimpDockWindow - A toplevel window containing a GimpDockColumns.
|
||||
GimpImageWindow - A toplevel window containing images and one
|
||||
GimpDockColumns to the left and to the right.
|
||||
GimpDialogFactory - A factory to create and position toplevel windows
|
||||
GimpSessionInfo - Contains session info for one toplevel
|
||||
GimpUIConfigurer - Configures the UI when switching between
|
||||
single-window and multi-window mode
|
||||
|
||||
|
||||
GimpDialogFactory
|
||||
-----------------
|
||||
|
||||
The GimpDialogFactory can be considered to solve two distinct
|
||||
problems:
|
||||
|
||||
1. Create widgets from text, in particular from text in sessionrc
|
||||
2. Session manage toplevel windows so their position is remembered
|
||||
across GIMP sessions
|
||||
|
||||
One possible design adjustment would be to have GimpWidgetFactory that
|
||||
takes care of 1), and then have GimpDialogFactory inherit from
|
||||
GtkWidgetFactory and implementing 2). GimpWidgetFactory could possibly
|
||||
use GtkBuilder.
|
||||
|
||||
|
||||
sessionrc
|
||||
---------
|
||||
When GIMP starts, the sessionrc file is parsed. This step puts
|
||||
GimpSessionInfo:s into GimpDialogFactories. Later when dialogs are
|
||||
created, the dialog factory looks up existing session info entries. If
|
||||
one exists, it uses the session info to set e.g. the position of the
|
||||
created dialog. If it doesn't exist, it creates a new session info
|
||||
object for the dialog. When GIMP exists, the current session infos are
|
||||
then written back to sessionrc.
|
73
devel-docs/undo.txt
Normal file
|
@ -0,0 +1,73 @@
|
|||
A quick overview of the undo system
|
||||
-----------------------------------
|
||||
|
||||
Actions on the image by the user are pushed onto an undo stack. Each
|
||||
action object includes all the information needed to undo or redo an
|
||||
operation, plus an UndoType. The type can be converted to text to
|
||||
show to the user. Actions may be run forwards (UndoState == REDO) or
|
||||
backwards (UndoState == UNDO). As the action is run, it swaps the
|
||||
image's current state and the recorded state. A run action is moved
|
||||
from the undo stack to the redo stack (or vice-versa if UndoState ==
|
||||
REDO). Pushing something onto the undo stack causes the redo stack to
|
||||
be cleared, since the actions on the redo stack may depend on the
|
||||
image being in a particular state (eg consider: layer add, rename,
|
||||
undo rename, layer delete. If the redo stack weren't cleared on undo,
|
||||
then there would still be a "rename" operation on the redo stack which
|
||||
could be run on a non-existent layer. Bad news.)
|
||||
|
||||
Undo groups
|
||||
-----------
|
||||
In order to group many basic operations together into a more useful
|
||||
whole, code can push group start and end markers. A group is treated
|
||||
as a single action for the purposes of the undo and redo user
|
||||
commands. It is legal to nest groups, in which case the outermost
|
||||
group is the only user-visible one.
|
||||
|
||||
Groups boundaries used to be implemented by pushing a NULL pointer on
|
||||
the undo (or redo) stack. Now they are a special action which has the
|
||||
"group_boundary" bit set. This allows the group boundaries to include
|
||||
the undo type associated with the whole group. The individual actions
|
||||
need to preserve their own undo type since the undo_free_* functions
|
||||
sometimes need to know which action is being freed.
|
||||
|
||||
Undo events
|
||||
-----------
|
||||
Images emit UNDO_EVENT signals, to say that the user has performed an
|
||||
undo or redo action on that image. This allows interested parties to
|
||||
track image mutation actions. So far, only the undo history dialog
|
||||
uses this feature. The other way to discover the undo status of an
|
||||
image is to use the iterator functions undo_map_over_undo_stack() and
|
||||
undo_map_over_redo_stack(). These call your function on each action
|
||||
(or group) on the stack. There is also undo_get_undo_name() and
|
||||
undo_get_redo_name() to peek at the top items on each stack. This
|
||||
could be used (eg) to change the undo/redo menu strings to something
|
||||
more meaningful, but currently lack synchronisation.
|
||||
|
||||
Dirtying images
|
||||
---------------
|
||||
NOTE about the gimage->dirty counter:
|
||||
If 0, then the image is clean (ie, copy on disk is the same as the one
|
||||
in memory).
|
||||
If positive, then that's the number of dirtying operations done
|
||||
on the image since the last save.
|
||||
If negative, then user has hit undo and gone back in time prior
|
||||
to the saved copy. Hitting redo will eventually come back to
|
||||
the saved copy.
|
||||
The image is dirty (ie, needs saving) if counter is non-zero.
|
||||
If the counter is around 10000, this is due to undo-ing back
|
||||
before a saved version, then mutating the image (thus destroying
|
||||
the redo stack). Once this has happened, it's impossible to get
|
||||
the image back to the state on disk, since the redo info has been
|
||||
freed. See undo.c for the gorey details.
|
||||
|
||||
NEVER CALL gimp_image_dirty() directly!
|
||||
|
||||
If your code has just dirtied the image, push an undo instead.
|
||||
Failing that, push the trivial undo which tells the user the
|
||||
command is not undoable: undo_push_cantundo() (But really, it would
|
||||
be best to push a proper undo). If you just dirty the image
|
||||
without pushing an undo then the dirty count is increased, but
|
||||
popping that many undo actions won't lead to a clean image.
|
||||
|
||||
Austin
|
||||
|