devel-docs: Move advanced concepts to gimp-web-devel

See: Infrastructure/gimp-web-devel#9

Also, drop interpreters.txt since we have an example file.
This commit is contained in:
Bruno Lopes 2025-10-17 08:36:03 -03:00
parent d997fd39a6
commit 21044e61f2
No known key found for this signature in database
8 changed files with 0 additions and 1011 deletions

View file

@ -75,7 +75,6 @@ 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.
@ -181,69 +180,3 @@ You should also check out [gimp-module-dependencies.svg](gimp-module-dependencie
**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.

View file

@ -1,89 +0,0 @@
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

View file

@ -1,51 +0,0 @@
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 */

View file

@ -1,210 +0,0 @@
# 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.

View file

@ -1,316 +0,0 @@
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.

View file

@ -1,148 +0,0 @@
=============================================================
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.

View file

@ -1,57 +0,0 @@
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.

View file

@ -1,73 +0,0 @@
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