Difference between revisions of "Developer manual"

From Inkscape Wiki
Jump to: navigation, search
(C++ Reference)
m (Please use const: typo correction)
 
(4 intermediate revisions by 3 users not shown)
Line 1: Line 1:
= Inkscape Developer's Manual =
+
= Inkscape Developer’s Manual =
  
 
== Introduction ==
 
== Introduction ==
  
 
For those of you just joining us, or who have been with us but are just
 
For those of you just joining us, or who have been with us but are just
now getting the itch to work on Inkscape, I thought I'd give some tips
+
now getting the itch to work on Inkscape, I thought I’d give some tips
 
for how to get started working in the codebase based on our own
 
for how to get started working in the codebase based on our own
 
experiences.
 
experiences.
  
One of the first things most people wonder is "what should I work on".
+
One of the first things most people wonder is “What should I work on?”.
As you may have already noticed, we generally don't "assign" projects.
+
As you may have already noticed, we generally don’t “assign” projects.
We figure there's plenty more work to do than people to do it, so you
+
We figure there’s plenty more work to do than people to do it, so you
may as well work on something that you're either interested in or that
+
may as well work on something that you’re either interested in or that
adds something of benefit to you; that's extra motivation to get your
+
adds something of benefit to you; that’s extra motivation to get your
 
own itches scratched.
 
own itches scratched.
  
If you're really stumped though, we keep a detailed [[Roadmap]] in wiki that
+
If you’re really stumped though, we keep a detailed [[Roadmap]] in wiki that
you're welcome to browse through to look for ideas of things to work
+
you’re welcome to browse through to look for ideas of things to work
 
on.  Tasks that do not have names beside them are open for anyone to
 
on.  Tasks that do not have names beside them are open for anyone to
 
take; if you want to take ownership of a task, just put your name beside
 
take; if you want to take ownership of a task, just put your name beside
 
it.  Feel free to add or reword tasks as needed, although try not to
 
it.  Feel free to add or reword tasks as needed, although try not to
load up the current milestone with tasks that aren't critical for the
+
load up the current milestone with tasks that aren’t critical for the
 
release.  Feel free to work on stuff that is several milestones down the
 
release.  Feel free to work on stuff that is several milestones down the
road; there's rarely any problem with getting stuff done sooner than
+
road; there’s rarely any problem with getting stuff done sooner than
 
planned.  ;-)
 
planned.  ;-)
  
 
We have a process for gaining SVN commit access.  The reason is that
 
We have a process for gaining SVN commit access.  The reason is that
while it is important that we keep access to the codebase open, we don't
+
while it is important that we keep access to the codebase open, we don’t
 
want to be crazy and leave it wide open to any random passer-by.  The
 
want to be crazy and leave it wide open to any random passer-by.  The
 
process is that we require that the person make two contributions
 
process is that we require that the person make two contributions
Line 32: Line 32:
 
to get account access.
 
to get account access.
  
In general you won't need SVN commit access in order to start doing
+
In general you won’t need SVN commit access in order to start doing
 
development, because you can work from an anonymous checkout and create
 
development, because you can work from an anonymous checkout and create
patches.  If you've not done this before, you'll need to learn this
+
patches.  If you’ve not done this before, you’ll need to learn this
 
skill first (basically see docs for `svn diff`).
 
skill first (basically see docs for `svn diff`).
  
When you first start hacking on Inkscape code, I wouldn't recommend
+
When you first start hacking on Inkscape code, I wouldn’t recommend
 
taking an objective of implementing a specific feature, because you will
 
taking an objective of implementing a specific feature, because you will
 
need some time to familiarize yourself with the codebase, and because
 
need some time to familiarize yourself with the codebase, and because
you won't really know what features are going to be straightforward to
+
you won’t really know what features are going to be straightforward to
 
implement and which will be highly challenging.  Of course, if you have
 
implement and which will be highly challenging.  Of course, if you have
 
the time and love adventures, this might be a fun way to go.
 
the time and love adventures, this might be a fun way to go.
  
There are four approaches that I've seen people effectively use in
+
There are four approaches that I’ve seen people effectively use in
 
getting into the codebase:
 
getting into the codebase:
  
 
<ul>
 
<ul>
<li>Write code documentation.  Some people who don't mind adding
+
<li><strong>Write code documentation.</strong> Some people who don’t mind adding
 
comments to code or writing docs find it useful to just go through
 
comments to code or writing docs find it useful to just go through
code they're interested in working on and writing up what it does.
+
code they’re interested in working on and writing up what it does.
 
The codebase is in dire need of better docs, so this approach pays
 
The codebase is in dire need of better docs, so this approach pays
 
dividends well into the future.
 
dividends well into the future.
 
</li>
 
</li>
  
<li>Fix bugs.  Tracing down the cause of reported bugs is an effective
+
<li><strong>Fix bugs.</strong> Tracing down the cause of reported bugs is an effective
 
way to gain understanding of the codebase in small chunks.  Many
 
way to gain understanding of the codebase in small chunks.  Many
 
common bugs can be traced down and fixed in a matter of hours, and
 
common bugs can be traced down and fixed in a matter of hours, and
 
often will identify some bit of code in need of refactoring or
 
often will identify some bit of code in need of refactoring or
 
extension.  Note that some of our older bugs are in the system
 
extension.  Note that some of our older bugs are in the system
because they're hard to fix, so you'll want to work on the more
+
because they’re hard to fix, so you’ll want to work on the more
 
recent ones.
 
recent ones.
 
</li>
 
</li>
  
<li>Chip in on a group effort.  Occasionally we identify a major
+
<li><strong>Chip in on a group effort.</strong> Occasionally we identify a major
 
refactoring effort (such as when we converted from C to C++), that
 
refactoring effort (such as when we converted from C to C++), that
 
we encourage lots of people to help on, in the philosophy that many
 
we encourage lots of people to help on, in the philosophy that many
Line 70: Line 70:
 
not hard for new folks to get involved with; it just takes time.  We
 
not hard for new folks to get involved with; it just takes time.  We
 
generally have one of these kinds of efforts per release.  It
 
generally have one of these kinds of efforts per release.  It
usually isn't glamorous work, but in aggregate moves the codebase
+
usually isn’t glamorous work, but in aggregate moves the codebase
 
forward in a major way.
 
forward in a major way.
 
</li>
 
</li>
  
<li>Subsystem/module work.  Some people want to get their hands in the
+
<li><strong>Subsystem/module work.</strong> Some people want to get their hands in the
 
details quick, so take the approach of developing new code separate
 
details quick, so take the approach of developing new code separate
 
from the codebase, to be integrated in later.  This generally tends
 
from the codebase, to be integrated in later.  This generally tends
 
to take a larger time commitment than the other approaches, but can be
 
to take a larger time commitment than the other approaches, but can be
 
an effective approach in some circumstances.  We have a SVN module
 
an effective approach in some circumstances.  We have a SVN module
called 'experimental' that you're welcome to house your work until
+
called <code>experimental</code> that you’re welcome to house your work until
it's ready for prime time.
+
it’s ready for prime time.
 
</li>
 
</li>
 
</ul>
 
</ul>
  
Beyond that, you're going to find the documentation for the Inkscape
+
Beyond that, you’re going to find the documentation for the Inkscape
code is pretty scarce.  We've worked on bits and pieces but
+
code is pretty scarce.  We’ve worked on bits and pieces but
 
unfortunately the vast majority of the code is undocumented.  On the
 
unfortunately the vast majority of the code is undocumented.  On the
 
plus side, often you can implement the stuff you care about after
 
plus side, often you can implement the stuff you care about after
 
learning only a limited portion of the codebase.
 
learning only a limited portion of the codebase.
  
I think you'd find Inkscape an enjoyable Open Source project to work on.
+
I think you’d find Inkscape an enjoyable Open Source project to work on.
There's a huge range of interesting and useful skills that can be
+
There’s a huge range of interesting and useful skills that can be
 
learned from it, plus the developers are great guys to participate with.
 
learned from it, plus the developers are great guys to participate with.
 
The project itself runs smoothly and puts a premium on keeping things
 
The project itself runs smoothly and puts a premium on keeping things
 
friendly and low-stress, so heated arguments are rare.  The users have
 
friendly and low-stress, so heated arguments are rare.  The users have
 
been great to work with and very appreciative of even small new features
 
been great to work with and very appreciative of even small new features
and fixes.  Plus, since Inkscape is so visual in nature, it's very cool
+
and fixes.  Plus, since Inkscape is so visual in nature, it’s very cool
 
to see how your little changes make noticeable improvements to the app
 
to see how your little changes make noticeable improvements to the app
 
overall.
 
overall.
Line 108: Line 108:
  
 
* List of <s>[http://www.cs.helsinki.fi/u/vkarvone/2004s/cplusplus/errors.html schoolboy errors] (Broken Link)</s>. None of these should appear in [http://en.wikipedia.org/wiki/Free/Libre/Open-Source_Software FLOSS] code.
 
* List of <s>[http://www.cs.helsinki.fi/u/vkarvone/2004s/cplusplus/errors.html schoolboy errors] (Broken Link)</s>. None of these should appear in [http://en.wikipedia.org/wiki/Free/Libre/Open-Source_Software FLOSS] code.
 +
 +
== Please use const ==
 +
 +
Please be very aggressive in adding ''const'' to any code you write. It will help us understand code better and will prevent bugs from creeping in. It is very easy to remove ''const'' later on, but very hard to add it.
 +
 +
''const'' can go on either side of a type. However once you get into references and pointers and such with C++, you generally read those from right-to-left. So it makes the code a little more legible if the ''const'' comes between the variable type and name.
 +
 +
int const foo;
 +
// RTL reading gives "foo is a constant int".
 +
 +
And then:
 +
 +
int const & foo;
 +
// RTL reading gives "foo is a reference to a constant int"
 +
 +
int const * foo;
 +
// RTL reading gives "foo is a pointer to a constant int"
 +
 +
whereas:
 +
 +
int * const foo;
 +
// RTL reading gives "foo is a constant pointer to an int"
 +
 +
Read also:
 +
* [http://www.cprogramming.com/tutorial/const_correctness.html Const Correctness]
 +
* [http://yosefk.com/c++fqa/const.html Const Correctness]
  
 
== Strings ==
 
== Strings ==
 
Please make sure any user-visible strings are localizable.  This requires wrapping them with "_(" and ")", like so:
 
Please make sure any user-visible strings are localizable.  This requires wrapping them with "_(" and ")", like so:
  
  "Select object"
+
  <code>"Select object"</code>
 
becomes
 
becomes
  _("Select object")
+
  <code>_("Select object")</code>
  
 
In case the interpretation of the string may be ambiguous or may differ according to context, you can add a context prefix (that won't be displayed) in order to eliminate the ambiguity.  
 
In case the interpretation of the string may be ambiguous or may differ according to context, you can add a context prefix (that won't be displayed) in order to eliminate the ambiguity.  
  "Ambiguous string"
+
  <code>"Ambiguous string"</code>
 
can then become
 
can then become
  C_("Context", "Ambiguous string")
+
  <code>C_("Context", "Ambiguous string")</code>
  
 
For more complex things, please check the gettext/localization documentation.
 
For more complex things, please check the gettext/localization documentation.
Line 128: Line 154:
 
[[UI improvements]] are enjoyable to work on because they produce visible changes in how Inkscape works.  These improvements are one of the most tangible ways to help improve how Inkscape works; thus, we strongly support new developers wishing to work in these areas.
 
[[UI improvements]] are enjoyable to work on because they produce visible changes in how Inkscape works.  These improvements are one of the most tangible ways to help improve how Inkscape works; thus, we strongly support new developers wishing to work in these areas.
  
It is also very important to us that Inkscape presents an organized, productive, and easily discoverable interface to users, and because of this it is important that new Inkscape UI developers work to ensure changes make Inkscape's UI *more* consistent, *more* flexible, *more* cohesive, and so on.  We don't have firm rules about what can and cannot done, so as to ensure there is plenty of freedom for innovation.  However, we can outline some general principles and guidelines that are important to keep in mind:
+
It is also very important to us that Inkscape presents an organized, productive, and easily discoverable interface to users.  Because of this it is important that new Inkscape UI developers work to ensure changes make Inkscape’s UI *more* consistent, *more* flexible, *more* cohesive, and so on.  We don’t have firm rules about what can and cannot done, in order to ensure plenty of freedom for innovation.  However, we can outline some general principles and guidelines that are important to keep in mind:
  
'''Don't please the artist - BE the artist''' - Many times UI is designed and created by programmers who "understand what the user wants".  But in Inkscape we believe that the best requirements list is the list inside the user's head.  Requirements docs, usability studies, and so on are very indirect ways of transferring this gut-level understanding from user to programmer.  We believe the best way to ensure this information is communicated clearly is for the user to BE the programmer.  Or, alternatively, for the programmer to BECOME a user.
+
<strong>Don’t please the artist—BE the artist.</strong>  Many times UI is designed and created by programmers who “understand what the user wants”.  But in Inkscape we believe that the best requirements list is the list inside the user’s head.  Requirements docs, usability studies, and so on are very indirect ways of transferring this gut-level understanding from user to programmer.  We believe the best way to ensure this information is communicated clearly is for the user to BE the programmer.  Or, alternatively, for the programmer to BECOME a user.
  
This is why we so strongly encourage users to get involved in coding, and why we so strongly encourage programmers to focus on the features that are most important to them personally.  This is also why it is absolutely critical to pay close attention to what users report when using a new feature - often they can tip you off to alternate designs that achieve the same result in a better way.
+
This is why we so strongly encourage users to get involved in coding, and why we so strongly encourage programmers to focus on the features that are most important to them personally.  This is also why it is absolutely critical to pay close attention to what users report when using a new feature—often they can tip you off to alternate designs that achieve the same result in a better way.
  
'''Eliminate limitations''' - Commercial software is often developed to fulfill feature requirement lists from a marketing department.  As such, it's common to see the feature implemented to meet the requirement exactly, and no more.  However, especially with artistic software, art is often found outside what seems reasonable.  So when putting in a new feature, avoid the temptation to limit it to what you expect people to use it for - instead generalize it and open as many parameters as possible for tweaking, and let the artist decide what is reasonable - that is their job.   
+
<strong>Eliminate limitations.</strong> Commercial software is often developed to fulfill feature requirement lists from a marketing department.  As such, it’s common to see the feature implemented to meet the requirement exactly, and no more.  However, especially with artistic software, art is often found outside what seems reasonable.  So when putting in a new feature, avoid the temptation to limit it to what you expect people to use it for—instead generalize it and open as many parameters as possible for tweaking, and let the artist decide what is reasonable.  That’s their job.   
  
As an example, a drawing program might want to support the features, feather and drop shadow.  Obviously, users need these important features.  Commercial software may well implement these as distinct features, each with their own UI controls.  However, these features are just special cases of the more general gaussian blur, and in Inkscape we implemented *that*.  With that in place, artists can not only do feathering and blur, but a whole variety of other effects.
+
As an example, a drawing program might want to support the features “feather” and “drop shadow”.  Obviously, users need these important features.  Commercial software may well implement these as distinct features, each with their own UI controls.  However, these features are just special cases of the more general gaussian blur, and in Inkscape we implemented *that*.  With that in place, artists can do feathering and blur, <em>and</em> a variety of other effects.
  
 
It is interesting to note that, as an open collaborative standard, SVG
 
It is interesting to note that, as an open collaborative standard, SVG
Line 145: Line 171:
 
points over commercial software. Live clones, patterns that can be contain any
 
points over commercial software. Live clones, patterns that can be contain any
 
objects, layers that are essentially groups and can be easily
 
objects, layers that are essentially groups and can be easily
converted to/from groups - all these are examples where the underlying
+
converted to/from groups.  These are all examples where the underlying
 
universality of SVG directly translates into extremely valuable user
 
universality of SVG directly translates into extremely valuable user
 
features.
 
features.
Line 155: Line 181:
 
Generally we find that implementation of an SVG feature goes through three discrete stages:
 
Generally we find that implementation of an SVG feature goes through three discrete stages:
  
1.  Find the appropriate tags and attributes in the SVG spec
+
<ol>
2.  Implement support for rendering files with these tags
+
    <li>Find the appropriate tags and attributes in the SVG spec</li>
3.  Implement support for UI controls to edit the tags
+
    <li>Implement support for rendering files with these tags</li>
 +
    <li>Implement support for UI controls to edit the tags</li>
 +
</ol>
  
(1) is mostly a research project.  Start by reading the SVG spec so you
+
Step 1 is mostly a research project.  Start by reading the SVG spec so you
 
can learn about the tag, the attributes that go with it, and so forth.
 
can learn about the tag, the attributes that go with it, and so forth.
 
It is good practice to set up a page in the Wiki for storing your notes
 
It is good practice to set up a page in the Wiki for storing your notes
as you do this process, so that in case you don't make it to steps 2 and
+
as you do this process, so that in case you don’t make it to steps 2 and
 
3, then maybe someone else can benefit from your research.
 
3, then maybe someone else can benefit from your research.
  
(2) is the fun part.  It helps to be comfortable with Inkscape internals
+
Step 2 is the fun part.  It helps to be comfortable with Inkscape internals
 
for this part.  Depending on the feature, it may require advanced
 
for this part.  Depending on the feature, it may require advanced
 
knowledge of transformation, rendering, document management, and so on.
 
knowledge of transformation, rendering, document management, and so on.
Line 174: Line 202:
 
implementation.
 
implementation.
  
(3) is the most important stage, since it is the point at which the
+
Step 3 is the most important stage. It is the point at which the
 
feature becomes available for users.  This step often requires knowledge
 
feature becomes available for users.  This step often requires knowledge
 
of Gtk+, for creating dialogs, widgets, menus, etc. for allowing the
 
of Gtk+, for creating dialogs, widgets, menus, etc. for allowing the
 
user to edit the characteristics of the feature.  Be sure to listen to
 
user to edit the characteristics of the feature.  Be sure to listen to
feedback from other developers and users - especially if there are
+
feedback from other developers and users—especially if there are
 
different opinions.  It is hard to come up with UI that everyone can
 
different opinions.  It is hard to come up with UI that everyone can
agree on, but it is worth the work to achieve this - the more critique
+
agree on, but it is worth the work to achieve this—the more critique
 
your UI survives, the better loved the feature will be for future users.
 
your UI survives, the better loved the feature will be for future users.
  
Looking through Inkscape's history, these stages are often done by different people.  If you're new to Inkscape, you may find working on stages 1 and 3 easiest, but there are many developers who can answer questions when you're ready to dig into the internals, so don't be afraid to ask questions!
+
Looking through Inkscape’s history, these stages are often done by different people.  If you’re new to Inkscape, you may find working on stages 1 and 3 easiest, but there are many developers who can answer questions when you’re ready to dig into the internals, so don’t be afraid to ask questions!
  
 
== Standards Compliance - Extension Namespaces ==
 
== Standards Compliance - Extension Namespaces ==
Line 193: Line 221:
 
== Global Verbs ==
 
== Global Verbs ==
  
Here's a readers' digest summary of how Inkscape accelerators work:
+
Here’s a readers’ digest summary of how Inkscape accelerators work:
  
A global mapping between key combinations and integer verb IDs
+
A global mapping between key combinations and integer [[verb]] IDs
(sp_verb_t) is maintained in shortcuts.cpp; these are registered using
+
(<code>sp_verb_t</code>) is maintained in <code>shortcuts.cpp</code>; these are registered using
sp_shortcut_set().
+
<code>sp_shortcut_set()</code>.
  
Given an sp_verb_t and an SPView, you can get an SPAction which
+
Given an <code>sp_verb_t</code> and an <code>SPView</code>, you can get an SPAction which
 
represents that action in that view.  These mappings are currently
 
represents that action in that view.  These mappings are currently
hard-coded in verbs.cpp.
+
hard-coded in <code>verbs.cpp</code>.
  
SPActions derive from NRActiveObject, which putatively provides a
+
<code>SPActions</code> derive from <code>NRActiveObject</code>, which putatively provides a
"lightweight" method of doing callbacks, versus GObject signals.  I
+
“lightweight” method of doing callbacks (vs <code>GObject</code> signals).  I
don't completely understand how it works.
+
don’t completely understand how it works.
  
SPActions also contain the label, image, etc, used for buttons and
+
<code>SPActions</code> also contain the label, image, etc, used for buttons and
 
menuitems.
 
menuitems.
  
sp_shortcut_invoke() looks up the SPAction for a keypress and SPView and
+
<code>sp_shortcut_invoke()</code> looks up the <code>SPAction</code> for a keypress and <code>SPView</code> and
invokes it automatically. SPEventContexts call it for keypresses that
+
invokes it automatically. <code>SPEventContexts</code> call it for keypresses that they do not handle themselves.
they do not handle themselves.
+
  
 
== Garbage collection ==
 
== Garbage collection ==
  
As you know, many automatic garbage collectors (like libgc) only
+
As you know, many automatic garbage collectors (like <code>libgc</code>) only
 
free and recycle memory periodically.  This means you may have some
 
free and recycle memory periodically.  This means you may have some
extra slush that could be freed, but hasn't yet.
+
extra slush that could be freed, but hasn’t yet.
  
 
There are other forces at work, though...
 
There are other forces at work, though...
  
 
Pretty much all allocators, whether automatic or not, whether the
 
Pretty much all allocators, whether automatic or not, whether the
system malloc() or some custom allocator like libgc's, work the
+
system <code>malloc()</code> or some custom allocator like <code>libgc</code>’s, work the
 
same way:  they request large blocks of memory from the operating
 
same way:  they request large blocks of memory from the operating
 
system, then divvy those blocks into smaller ones internally to
 
system, then divvy those blocks into smaller ones internally to
Line 233: Line 260:
 
be completely unused before they can actually be freed.
 
be completely unused before they can actually be freed.
  
Let's say for example that an allocator acquires 16 8MB blocks from
+
For example, let’s say an allocator acquires 16 8MB blocks from
 
the OS in response to 32768 4k application allocations...
 
the OS in response to 32768 4k application allocations...
  
In a worst-case scenario, it's possible that the application could
+
In a worst-case scenario, it’s possible that the application could
 
free 32752 of those 4k blocks but the remaining 16 4k just happen
 
free 32752 of those 4k blocks but the remaining 16 4k just happen
 
to be distributed across the 16 8MB blocks requested from the OS.
 
to be distributed across the 16 8MB blocks requested from the OS.
  
If that happens, from the application's point of view it may only
+
If that happens, from the application’s point of view it may only
have 64k allocated, but as far as the OS is concerned, it's still
+
have 64k allocated, but as far as the OS is concerned, it’s still
 
using 128MB!
 
using 128MB!
  
 
Note that this applies to nearly all allocators in common use.
 
Note that this applies to nearly all allocators in common use.
  
While it's unusual for things to get quite that bad, memory
+
While it’s unusual for things to get quite that bad, memory
 
fragmentation is common enough that many popular allocators (for
 
fragmentation is common enough that many popular allocators (for
example Perl's) simply don't bother trying to return memory to the
+
example Perl’s) simply don’t bother trying to return memory to the
 
OS at all (the memory will still get forcibly reclaimed by the OS
 
OS at all (the memory will still get forcibly reclaimed by the OS
 
when the process exits).
 
when the process exits).
  
[ FWIW, libgc's allocator is one of the ones that _does_ make an
+
[ FWIW, <code>libgc</code>’s allocator is one of the ones that _does_ make an
 
effort to release memory to the OS, but it is limited by
 
effort to release memory to the OS, but it is limited by
 
fragmentation like any other ]
 
fragmentation like any other ]
  
 
Also note that for various reasons, the statistics you get from the
 
Also note that for various reasons, the statistics you get from the
OS aren't going to directly reflect the amount of heap-allocated
+
OS aren’t going to directly reflect the amount of heap-allocated
 
memory.  Be careful drawing conclusions from only looking at e.g.
 
memory.  Be careful drawing conclusions from only looking at e.g.
the output of top(1)...
+
the output of <code>top(1)</code>...
  
(the worst thing is that due to the modern practice of
+
(The worst thing is, due to the modern practice of
 
overcommitting memory, the OS may literally lie to an application
 
overcommitting memory, the OS may literally lie to an application
 
about the amount of memory it is being given, hoping the
 
about the amount of memory it is being given, hoping the
application won't really try to use it all)
+
application won’t really try to use it all.)
  
 
The best approach to evaluating memory usage is if you can ask the
 
The best approach to evaluating memory usage is if you can ask the
Line 270: Line 297:
 
the world from the point of view of the application.
 
the world from the point of view of the application.
  
leftover gradients/markers/patterns
+
leftover gradients/markers/patterns will get automatically cleaned up when the objects that use them are deleted.
will get automatically cleaned up when the objects that use them are
+
deleted.
+
  
 
Caveats:
 
Caveats:
Line 280: Line 305:
 
* not all automatically-created objects will necessarily be collected; the code that creates them needs to be updated to set the correct collection policy
 
* not all automatically-created objects will necessarily be collected; the code that creates them needs to be updated to set the correct collection policy
  
* paint objects won't get collected until another editing operation takes place, since NRArenaShape currently holds onto an SPStyle for too long
+
* paint objects won’t get collected until another editing operation takes place, since <code>NRArenaShape</code> currently holds onto an <code>SPStyle</code> for too long
  
 
Technical details:
 
Technical details:
Line 286: Line 311:
 
Assuming its collection policy permits it, an object will be collected
 
Assuming its collection policy permits it, an object will be collected
 
if neither it nor its descendants have any outstanding inter-document
 
if neither it nor its descendants have any outstanding inter-document
URI references (nonzero SPObject::hrefcount).
+
URI references (nonzero <code>SPObject::hrefcount</code>).
  
There are two "policies" for collecting orphans:
+
There are two “policies” for collecting orphans:
  
* "with-parent" - the object will only be collected if one of its ancestors is collected
+
* “with-parent” - the object will only be collected if one of its ancestors is collected
  
* "always" - the object is always collected if unused
+
* “always” - the object is always collected if unused
  
(a third policy might be "never", which would necessarily also prevent
+
(a third policy might be “never”, which would necessarily also prevent
that object's ancestors from ever being collected; I do not plan on
+
that object’s ancestors from ever being collected; I do not plan on
 
implementing it)
 
implementing it)
  
 
The policy in effect is determined by the inkscape:collect attribute.
 
The policy in effect is determined by the inkscape:collect attribute.
  
Be careful with the "always" policy; it really only makes sense for
+
Be careful with the “always” policy; it really only makes sense for
"private" objects that are indirectly created behind the scenes (e.g. by
+
“private” objects that are indirectly created behind the scenes (e.g. by
 
selecting a fill or marker option in the GUI).
 
selecting a fill or marker option in the GUI).
  
SPDocument manages a queue of objects to collect; SPObject handles the machinery for actually queueing them when their hrefcount falls (based on policy), and performing the actual collection (delete).
+
<code>SPDocument</code> manages a queue of objects to collect; <code>SPObject</code> handles the machinery for actually queueing them when their <code>hrefcount</code> falls (based on policy), and performing the actual collection (<code>delete</code>).
SPDocument::collectObjects() performs a collection pass; it's currently only called from sp_document_maybe_done().
+
<code>SPDocument::collectObjects()</code> performs a collection pass. It’s currently only called from <code>sp_document_maybe_done()</code>.
  
 
== Inkscape Experimental SVN ==
 
== Inkscape Experimental SVN ==
  
The 'experimental' module in Inkscape SVN is provided as a kind of "scratchpad" for  
+
The <code>experimental</code> module in Inkscape SVN is provided as a kind of “scratchpad” for  
working up new ideas that aren't quite ready for folding into the main codebase.
+
working up new ideas that aren’t quite ready for folding into the main codebase.
 
This includes architectural sketches, examples, experimental patchsets, tools & utilities, or
 
This includes architectural sketches, examples, experimental patchsets, tools & utilities, or
whatever else strikes the developer's fancy.
+
whatever else strikes the developer’s fancy.
  
Please create a subdirectory within experimental/ for your work. You're welcome to either post
+
Please create a subdirectory within <code>experimental/</code> for your work. You’re welcome to either post
 
the stuff at the top level or create a subdirectory for yourself.  Things linked in at the top level
 
the stuff at the top level or create a subdirectory for yourself.  Things linked in at the top level
 
should be considered fair game for other developers to collaborate on; items posted under
 
should be considered fair game for other developers to collaborate on; items posted under
a developer's username should be considered ask-first.  Same sort of idea as wiki.
+
a developer’s username should be considered ask-first.  Same sort of idea as wiki.
  
 
One of the principles behind this module is the idea of a shared working space.  Other developers
 
One of the principles behind this module is the idea of a shared working space.  Other developers
 
working in experimental can fairly easily see what others are working on in the tree, and perhaps
 
working in experimental can fairly easily see what others are working on in the tree, and perhaps
borrow or contribute ideas back and forth.  Since it is by definition not 'production' code, the  
+
borrow or contribute ideas back and forth.  Since it is by definition not ‘production’ code, the  
work may be incomplete or in a non-compileable state, and thats O-K.
+
work may be incomplete or in a non-compileable state...and that’s okay.
  
 
When an experiment has matured to the point of being actually useful, please move it out of
 
When an experiment has matured to the point of being actually useful, please move it out of
the experimental module to someplace more appropriate.  Or alternatively if the experimental  
+
the experimental module to someplace more appropriate.  Alternatively, if the experimental work has become obsolete or irrelevant, please remove it so we can avoid having the experimental tree get too bulky.
work has become obsolete or irrelevant, please remove it so we can avoid having the
+
experimental tree get too bulky.
+
  
  
Line 346: Line 369:
 
=== "Share" Collateral ===
 
=== "Share" Collateral ===
  
A variety of items are installed in addition to the program itself, and placed into a 'share' directory structured as follows:
+
A variety of items are installed in addition to the program itself, and placed into a <code>share</code> directory structured as follows:
 
                                                                                        
 
                                                                                        
 
     AUTHORS
 
     AUTHORS
Line 365: Line 388:
 
     tutorials/
 
     tutorials/
 
                                                                                        
 
                                                                                        
In the SVN codebase, all of these are placed in inkscape/share/ (except AUTHORS and NEWS which will be copied to share during installation.  The idea is that in theory, this entire tree structure can be copied into place on the user's machine.   
+
In the SVN codebase, all of these are placed in <code>inkscape/share/</code> (except <code>AUTHORS</code> and <code>NEWS</code> which will be copied to share during installation.  The idea is that in theory, this entire tree structure can be copied into place on the user’s machine.   
  
However, we need to provide the user some level of control over the installation.  They may wish to exclude some items, or may wish to augment the default install with some items external to the Inkscape package.  For example, they may wish to incorporate external clipart collections.  One approach would be to install symlinks in the given component directory to the external collection.  For example, if the flags package were to install into /usr/share/flags-svg/, we'd just symlink there.
+
However, we need to provide the user some level of control over the installation.  They may wish to exclude some items, or may wish to augment the default install with some items external to the Inkscape package.  For example, they may wish to incorporate external clipart collections.  One approach would be to install symlinks in the given component directory to the external collection.  For example, if the flags package were to install into <code>/usr/share/flags-svg/</code>, we’d just symlink there.
  
 
=== Code modules ===
 
=== Code modules ===
 
Several parts of the code were written in a modular way, and they have been
 
Several parts of the code were written in a modular way, and they have been
accordingly placed in subdirectories of src/, while the main src directory
+
accordingly placed in subdirectories of <code>src/</code>, while the main src directory
 
still contains the biggest part. To get a first overview of the modules, you
 
still contains the biggest part. To get a first overview of the modules, you
 
might want to have a look at these dependency graphs before you read deeper
 
might want to have a look at these dependency graphs before you read deeper
 
into the source code (outside at the moment):
 
into the source code (outside at the moment):
 
+
<s>
 
[http://www.ark.in-berlin.de/gri-debug.svgz]
 
[http://www.ark.in-berlin.de/gri-debug.svgz]
 
[http://www.ark.in-berlin.de/gri-dialogs.svgz]
 
[http://www.ark.in-berlin.de/gri-dialogs.svgz]
Line 385: Line 408:
 
[http://www.ark.in-berlin.de/gri-livarot.svgz]
 
[http://www.ark.in-berlin.de/gri-livarot.svgz]
 
[http://www.ark.in-berlin.de/gri-widgets.svgz]
 
[http://www.ark.in-berlin.de/gri-widgets.svgz]
[http://www.ark.in-berlin.de/gri-xml.svgz]
+
[http://www.ark.in-berlin.de/gri-xml.svgz]</s> (links broken)
 +
<!-- Was this the equivalent to the current Doxygen graphs? http://jenkins.inkscape.org/job/Inkscape_trunk_doxygen/doxygen/ -->
  
 
These are not all modules! For questions about how to generate these graphs
 
These are not all modules! For questions about how to generate these graphs
 
with graph-includes, please [mailto:rwst@users.sf.net].
 
with graph-includes, please [mailto:rwst@users.sf.net].
  
Question on .svgz files: Is the server sending the right 'Content-Encoding:' header?
+
Question on <code>.svgz</code> files: Is the server sending the right <code>Content-Encoding:</code> header?
 
This matters to Mozilla browsers in standards compliance mode! http://jwatt.org/svg/authoring/#server-configuration
 
This matters to Mozilla browsers in standards compliance mode! http://jwatt.org/svg/authoring/#server-configuration
  

Latest revision as of 20:12, 5 March 2016

Inkscape Developer’s Manual

Introduction

For those of you just joining us, or who have been with us but are just now getting the itch to work on Inkscape, I thought I’d give some tips for how to get started working in the codebase based on our own experiences.

One of the first things most people wonder is “What should I work on?”. As you may have already noticed, we generally don’t “assign” projects. We figure there’s plenty more work to do than people to do it, so you may as well work on something that you’re either interested in or that adds something of benefit to you; that’s extra motivation to get your own itches scratched.

If you’re really stumped though, we keep a detailed Roadmap in wiki that you’re welcome to browse through to look for ideas of things to work on. Tasks that do not have names beside them are open for anyone to take; if you want to take ownership of a task, just put your name beside it. Feel free to add or reword tasks as needed, although try not to load up the current milestone with tasks that aren’t critical for the release. Feel free to work on stuff that is several milestones down the road; there’s rarely any problem with getting stuff done sooner than planned.  ;-)

We have a process for gaining SVN commit access. The reason is that while it is important that we keep access to the codebase open, we don’t want to be crazy and leave it wide open to any random passer-by. The process is that we require that the person make two contributions (patches, documentation, web collateral, etc.) and then make a request to get account access.

In general you won’t need SVN commit access in order to start doing development, because you can work from an anonymous checkout and create patches. If you’ve not done this before, you’ll need to learn this skill first (basically see docs for `svn diff`).

When you first start hacking on Inkscape code, I wouldn’t recommend taking an objective of implementing a specific feature, because you will need some time to familiarize yourself with the codebase, and because you won’t really know what features are going to be straightforward to implement and which will be highly challenging. Of course, if you have the time and love adventures, this might be a fun way to go.

There are four approaches that I’ve seen people effectively use in getting into the codebase:

  • Write code documentation. Some people who don’t mind adding comments to code or writing docs find it useful to just go through code they’re interested in working on and writing up what it does. The codebase is in dire need of better docs, so this approach pays dividends well into the future.
  • Fix bugs. Tracing down the cause of reported bugs is an effective way to gain understanding of the codebase in small chunks. Many common bugs can be traced down and fixed in a matter of hours, and often will identify some bit of code in need of refactoring or extension. Note that some of our older bugs are in the system because they’re hard to fix, so you’ll want to work on the more recent ones.
  • Chip in on a group effort. Occasionally we identify a major refactoring effort (such as when we converted from C to C++), that we encourage lots of people to help on, in the philosophy that many hands makes short work. This work tends to be pretty rote so is not hard for new folks to get involved with; it just takes time. We generally have one of these kinds of efforts per release. It usually isn’t glamorous work, but in aggregate moves the codebase forward in a major way.
  • Subsystem/module work. Some people want to get their hands in the details quick, so take the approach of developing new code separate from the codebase, to be integrated in later. This generally tends to take a larger time commitment than the other approaches, but can be an effective approach in some circumstances. We have a SVN module called experimental that you’re welcome to house your work until it’s ready for prime time.

Beyond that, you’re going to find the documentation for the Inkscape code is pretty scarce. We’ve worked on bits and pieces but unfortunately the vast majority of the code is undocumented. On the plus side, often you can implement the stuff you care about after learning only a limited portion of the codebase.

I think you’d find Inkscape an enjoyable Open Source project to work on. There’s a huge range of interesting and useful skills that can be learned from it, plus the developers are great guys to participate with. The project itself runs smoothly and puts a premium on keeping things friendly and low-stress, so heated arguments are rare. The users have been great to work with and very appreciative of even small new features and fixes. Plus, since Inkscape is so visual in nature, it’s very cool to see how your little changes make noticeable improvements to the app overall.

C++ Reference

  • FAQ (with answers) sheet. We strongly recommend that everyone read this site comprehensively. You should not need to bookmark it, it should be the first of the sites on your autocomplete list for par!

http://www.parashift.com/c++-faq-lite/

It is actually more in-depth than the name FAQ suggests. Many experienced C++ programmers would benefit from it.

Please use const

Please be very aggressive in adding const to any code you write. It will help us understand code better and will prevent bugs from creeping in. It is very easy to remove const later on, but very hard to add it.

const can go on either side of a type. However once you get into references and pointers and such with C++, you generally read those from right-to-left. So it makes the code a little more legible if the const comes between the variable type and name.

int const foo;
// RTL reading gives "foo is a constant int".

And then:

int const & foo;
// RTL reading gives "foo is a reference to a constant int"
int const * foo;
// RTL reading gives "foo is a pointer to a constant int"

whereas:

int * const foo;
// RTL reading gives "foo is a constant pointer to an int"

Read also:

Strings

Please make sure any user-visible strings are localizable. This requires wrapping them with "_(" and ")", like so:

"Select object"

becomes

_("Select object")

In case the interpretation of the string may be ambiguous or may differ according to context, you can add a context prefix (that won't be displayed) in order to eliminate the ambiguity.

"Ambiguous string"

can then become

C_("Context", "Ambiguous string")

For more complex things, please check the gettext/localization documentation. See also http://library.gnome.org/devel/glib/unstable/glib-I18N.html

Implementing User Interface Changes

UI improvements are enjoyable to work on because they produce visible changes in how Inkscape works. These improvements are one of the most tangible ways to help improve how Inkscape works; thus, we strongly support new developers wishing to work in these areas.

It is also very important to us that Inkscape presents an organized, productive, and easily discoverable interface to users. Because of this it is important that new Inkscape UI developers work to ensure changes make Inkscape’s UI *more* consistent, *more* flexible, *more* cohesive, and so on. We don’t have firm rules about what can and cannot done, in order to ensure plenty of freedom for innovation. However, we can outline some general principles and guidelines that are important to keep in mind:

Don’t please the artist—BE the artist. Many times UI is designed and created by programmers who “understand what the user wants”. But in Inkscape we believe that the best requirements list is the list inside the user’s head. Requirements docs, usability studies, and so on are very indirect ways of transferring this gut-level understanding from user to programmer. We believe the best way to ensure this information is communicated clearly is for the user to BE the programmer. Or, alternatively, for the programmer to BECOME a user.

This is why we so strongly encourage users to get involved in coding, and why we so strongly encourage programmers to focus on the features that are most important to them personally. This is also why it is absolutely critical to pay close attention to what users report when using a new feature—often they can tip you off to alternate designs that achieve the same result in a better way.

Eliminate limitations. Commercial software is often developed to fulfill feature requirement lists from a marketing department. As such, it’s common to see the feature implemented to meet the requirement exactly, and no more. However, especially with artistic software, art is often found outside what seems reasonable. So when putting in a new feature, avoid the temptation to limit it to what you expect people to use it for—instead generalize it and open as many parameters as possible for tweaking, and let the artist decide what is reasonable. That’s their job.

As an example, a drawing program might want to support the features “feather” and “drop shadow”. Obviously, users need these important features. Commercial software may well implement these as distinct features, each with their own UI controls. However, these features are just special cases of the more general gaussian blur, and in Inkscape we implemented *that*. With that in place, artists can do feathering and blur, and a variety of other effects.

It is interesting to note that, as an open collaborative standard, SVG necessarily has the same goals as Inkscape: a minimum set of universal, well thought-out building blocks that can accommodate the widest possible range of graphics and applications. Thus, simply by following the SVG philosophy, Inkscape scores quite a few important points over commercial software. Live clones, patterns that can be contain any objects, layers that are essentially groups and can be easily converted to/from groups. These are all examples where the underlying universality of SVG directly translates into extremely valuable user features.

Implementing New SVG Features

The most important way to help Inkscape is to implement a new SVG feature in it. Our hope is to eventually support ALL SVG features, so if you can help check one off the list, it brings us close to the nirvana of 100% SVG compliance.  :-)

Generally we find that implementation of an SVG feature goes through three discrete stages:

  1. Find the appropriate tags and attributes in the SVG spec
  2. Implement support for rendering files with these tags
  3. Implement support for UI controls to edit the tags

Step 1 is mostly a research project. Start by reading the SVG spec so you can learn about the tag, the attributes that go with it, and so forth. It is good practice to set up a page in the Wiki for storing your notes as you do this process, so that in case you don’t make it to steps 2 and 3, then maybe someone else can benefit from your research.

Step 2 is the fun part. It helps to be comfortable with Inkscape internals for this part. Depending on the feature, it may require advanced knowledge of transformation, rendering, document management, and so on. For this part, just hand-edit an SVG file to put the tags in that you found in step #1, and keep plugging away at the code until Inkscape displays things as the specification dictates. It can help to compare your work with Batik, as we use that program as our reference implementation.

Step 3 is the most important stage. It is the point at which the feature becomes available for users. This step often requires knowledge of Gtk+, for creating dialogs, widgets, menus, etc. for allowing the user to edit the characteristics of the feature. Be sure to listen to feedback from other developers and users—especially if there are different opinions. It is hard to come up with UI that everyone can agree on, but it is worth the work to achieve this—the more critique your UI survives, the better loved the feature will be for future users.

Looking through Inkscape’s history, these stages are often done by different people. If you’re new to Inkscape, you may find working on stages 1 and 3 easiest, but there are many developers who can answer questions when you’re ready to dig into the internals, so don’t be afraid to ask questions!

Standards Compliance - Extension Namespaces

  • Only elements and attributes from our extension namespaces that do not affect rendering may be saved in SVG documents.
  • Generally, this means that extension elements and attributes should only be used to provide UI hints.
  • Extension elements and attributes should only be used where an existing facility provided by XML or SVG is not sufficient.

Global Verbs

Here’s a readers’ digest summary of how Inkscape accelerators work:

A global mapping between key combinations and integer verb IDs (sp_verb_t) is maintained in shortcuts.cpp; these are registered using sp_shortcut_set().

Given an sp_verb_t and an SPView, you can get an SPAction which represents that action in that view. These mappings are currently hard-coded in verbs.cpp.

SPActions derive from NRActiveObject, which putatively provides a “lightweight” method of doing callbacks (vs GObject signals). I don’t completely understand how it works.

SPActions also contain the label, image, etc, used for buttons and menuitems.

sp_shortcut_invoke() looks up the SPAction for a keypress and SPView and invokes it automatically. SPEventContexts call it for keypresses that they do not handle themselves.

Garbage collection

As you know, many automatic garbage collectors (like libgc) only free and recycle memory periodically. This means you may have some extra slush that could be freed, but hasn’t yet.

There are other forces at work, though...

Pretty much all allocators, whether automatic or not, whether the system malloc() or some custom allocator like libgc’s, work the same way: they request large blocks of memory from the operating system, then divvy those blocks into smaller ones internally to satisfy application allocation requests.

When an application frees memory, that memory is usually recycled internally rather than returned to the OS immediately. The reason for this is that the large memory blocks acquired from the OS must be completely unused before they can actually be freed.

For example, let’s say an allocator acquires 16 8MB blocks from the OS in response to 32768 4k application allocations...

In a worst-case scenario, it’s possible that the application could free 32752 of those 4k blocks but the remaining 16 4k just happen to be distributed across the 16 8MB blocks requested from the OS.

If that happens, from the application’s point of view it may only have 64k allocated, but as far as the OS is concerned, it’s still using 128MB!

Note that this applies to nearly all allocators in common use.

While it’s unusual for things to get quite that bad, memory fragmentation is common enough that many popular allocators (for example Perl’s) simply don’t bother trying to return memory to the OS at all (the memory will still get forcibly reclaimed by the OS when the process exits).

[ FWIW, libgc’s allocator is one of the ones that _does_ make an effort to release memory to the OS, but it is limited by fragmentation like any other ]

Also note that for various reasons, the statistics you get from the OS aren’t going to directly reflect the amount of heap-allocated memory. Be careful drawing conclusions from only looking at e.g. the output of top(1)...

(The worst thing is, due to the modern practice of overcommitting memory, the OS may literally lie to an application about the amount of memory it is being given, hoping the application won’t really try to use it all.)

The best approach to evaluating memory usage is if you can ask the allocator for information on memory usage directly, as that matches the world from the point of view of the application.

leftover gradients/markers/patterns will get automatically cleaned up when the objects that use them are deleted.

Caveats:

  • this only applies to such objects created with a build of Inkscape which post-dates this commit (June 7 2004)
  • not all automatically-created objects will necessarily be collected; the code that creates them needs to be updated to set the correct collection policy
  • paint objects won’t get collected until another editing operation takes place, since NRArenaShape currently holds onto an SPStyle for too long

Technical details:

Assuming its collection policy permits it, an object will be collected if neither it nor its descendants have any outstanding inter-document URI references (nonzero SPObject::hrefcount).

There are two “policies” for collecting orphans:

  • “with-parent” - the object will only be collected if one of its ancestors is collected
  • “always” - the object is always collected if unused

(a third policy might be “never”, which would necessarily also prevent that object’s ancestors from ever being collected; I do not plan on implementing it)

The policy in effect is determined by the inkscape:collect attribute.

Be careful with the “always” policy; it really only makes sense for “private” objects that are indirectly created behind the scenes (e.g. by selecting a fill or marker option in the GUI).

SPDocument manages a queue of objects to collect; SPObject handles the machinery for actually queueing them when their hrefcount falls (based on policy), and performing the actual collection (delete). SPDocument::collectObjects() performs a collection pass. It’s currently only called from sp_document_maybe_done().

Inkscape Experimental SVN

The experimental module in Inkscape SVN is provided as a kind of “scratchpad” for working up new ideas that aren’t quite ready for folding into the main codebase. This includes architectural sketches, examples, experimental patchsets, tools & utilities, or whatever else strikes the developer’s fancy.

Please create a subdirectory within experimental/ for your work. You’re welcome to either post the stuff at the top level or create a subdirectory for yourself. Things linked in at the top level should be considered fair game for other developers to collaborate on; items posted under a developer’s username should be considered ask-first. Same sort of idea as wiki.

One of the principles behind this module is the idea of a shared working space. Other developers working in experimental can fairly easily see what others are working on in the tree, and perhaps borrow or contribute ideas back and forth. Since it is by definition not ‘production’ code, the work may be incomplete or in a non-compileable state...and that’s okay.

When an experiment has matured to the point of being actually useful, please move it out of the experimental module to someplace more appropriate. Alternatively, if the experimental work has become obsolete or irrelevant, please remove it so we can avoid having the experimental tree get too bulky.


Directory Organization

Distribution / Packaging Files

Files related to generation of distribution packages should go under inkscape/packaging, as follows:

   inkscape/packaging/
                      common/
                      debian/
                      fedora/
                      fink/
                      mandrake/
                      suse/

"Share" Collateral

A variety of items are installed in addition to the program itself, and placed into a share directory structured as follows:

   AUTHORS
   NEWS
   clipart/
   examples/
   extensions/
   fonts/
   gradients/
   icons/
   keyboards/
   markers/
   palettes/
   patterns/
   screens/
       about.svg
   templates/
   tutorials/
                                                                                     

In the SVN codebase, all of these are placed in inkscape/share/ (except AUTHORS and NEWS which will be copied to share during installation. The idea is that in theory, this entire tree structure can be copied into place on the user’s machine.

However, we need to provide the user some level of control over the installation. They may wish to exclude some items, or may wish to augment the default install with some items external to the Inkscape package. For example, they may wish to incorporate external clipart collections. One approach would be to install symlinks in the given component directory to the external collection. For example, if the flags package were to install into /usr/share/flags-svg/, we’d just symlink there.

Code modules

Several parts of the code were written in a modular way, and they have been accordingly placed in subdirectories of src/, while the main src directory still contains the biggest part. To get a first overview of the modules, you might want to have a look at these dependency graphs before you read deeper into the source code (outside at the moment): [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] (links broken)

These are not all modules! For questions about how to generate these graphs with graph-includes, please [11].

Question on .svgz files: Is the server sending the right Content-Encoding: header? This matters to Mozilla browsers in standards compliance mode! http://jwatt.org/svg/authoring/#server-configuration

See Also

Links

Software Quality