508 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			508 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 
								 | 
							
								Creating new PDB procedures
							 | 
						||
| 
								 | 
							
								===========================
							 | 
						||
| 
								 | 
							
								Barak Itkin <lightningismyname@gmail.com>
							 | 
						||
| 
								 | 
							
								version 1.0, August 2010
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								////
							 | 
						||
| 
								 | 
							
								This document is an asciidoc document. It can be read as is, or you can
							 | 
						||
| 
								 | 
							
								print it as a formatted HTML page by running
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    asciidoc README_NEW_PDB_PROC
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This will generate the file README_NEW_PDB_PROC.html.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Note that inline code parts are marked with + signs around them.
							 | 
						||
| 
								 | 
							
								////
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This tutorial will show you the basics of creating a new procedure and
							 | 
						||
| 
								 | 
							
								adding it to PIKA's PDB.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Introduction
							 | 
						||
| 
								 | 
							
								------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								What are PDB procedures?
							 | 
						||
| 
								 | 
							
								~~~~~~~~~~~~~~~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								A *PDB procedure* is a process which is registered in the Procedure
							 | 
						||
| 
								 | 
							
								Data-Base. Procedures registered in the database are available to all
							 | 
						||
| 
								 | 
							
								the PIKA plugins/scripts.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								What should I want to add to the PDB?
							 | 
						||
| 
								 | 
							
								~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Let's say a new feature was added to PIKA, and your plugin/script wants
							 | 
						||
| 
								 | 
							
								to use it. In order to do so, this function should be publicly available
							 | 
						||
| 
								 | 
							
								(most functions are only available to PIKA's core, and in order to
							 | 
						||
| 
								 | 
							
								expose them externally we have to add them to the PDB).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Anything I should know before continuing this tutorial?
							 | 
						||
| 
								 | 
							
								~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Yes. You should know
							 | 
						||
| 
								 | 
							
								https://en.wikipedia.org/wiki/C_%28programming_language%29[C Programming]
							 | 
						||
| 
								 | 
							
								(C is the language in which PIKA is coded), know a bit of
							 | 
						||
| 
								 | 
							
								https://library.gnome.org/devel/glib/stable/[Glib] (the library which
							 | 
						||
| 
								 | 
							
								PIKA uses for many of it's data-structures). In addition, you should
							 | 
						||
| 
								 | 
							
								know enough about the PIKA core for implementing your function (this is
							 | 
						||
| 
								 | 
							
								not a programming tutorial, this is only a technical tutorial) or at
							 | 
						||
| 
								 | 
							
								least have the intuition to understand enough from the code you see, to
							 | 
						||
| 
								 | 
							
								copy paste and modify the parts you need (In fact, this is how I made my
							 | 
						||
| 
								 | 
							
								first addition to the PDB :D However in most cases it's better to know
							 | 
						||
| 
								 | 
							
								what you are doing).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The basics of PDB procedures
							 | 
						||
| 
								 | 
							
								----------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Since adding a function to the PDB can be tedious (you would need to
							 | 
						||
| 
								 | 
							
								modify 3 or more different source files), a scripting framework was
							 | 
						||
| 
								 | 
							
								developed to add functions to the PDB by writing them once. To see how
							 | 
						||
| 
								 | 
							
								function are implemented in the PDB, take a look in
							 | 
						||
| 
								 | 
							
								https://gitlab.gnome.org/GNOME/pika/tree/master/pdb/groups[pdb/groups].
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								You can see many files with the .pdb suffix - these are special template
							 | 
						||
| 
								 | 
							
								files which include the actual source of the PDB functions. Let's take a
							 | 
						||
| 
								 | 
							
								quick look at one of these - text_layer_get_text in
							 | 
						||
| 
								 | 
							
								https://gitlab.gnome.org/GNOME/pika/tree/master/pdb/groups/text_layer.pdb[pdb/groups/text_layer.pdb].
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[source,perl]
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								sub text_layer_get_text {
							 | 
						||
| 
								 | 
							
								    $blurb = 'Get the text from a text layer as string.';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    $help = <<'HELP';
							 | 
						||
| 
								 | 
							
								This procedure returns the text from a text layer as a string.
							 | 
						||
| 
								 | 
							
								HELP
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    &marcus_pdb_misc('2008', '2.6');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @inargs = (
							 | 
						||
| 
								 | 
							
								        { name => 'layer', type => 'layer',
							 | 
						||
| 
								 | 
							
								          desc => 'The text layer' }
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @outargs = (
							 | 
						||
| 
								 | 
							
								        { name => 'text', type => 'string',
							 | 
						||
| 
								 | 
							
								          desc => 'The text from the specified text layer.' }
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    %invoke = (
							 | 
						||
| 
								 | 
							
								        code => <<'CODE'
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  if (pika_pdb_layer_is_text_layer (layer, FALSE, error))
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      g_object_get (pika_text_layer_get_text (PIKA_TEXT_LAYER (layer)),
							 | 
						||
| 
								 | 
							
								                    "text", &text,
							 | 
						||
| 
								 | 
							
								                    NULL);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      success = FALSE;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								CODE
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								As you can see, all the function is wrapped inside the following wrapper:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[source,perl]
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								sub text_layer_get_text {
							 | 
						||
| 
								 | 
							
								  ...
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								That's the first line, declaring the name of the new PDB function (it
							 | 
						||
| 
								 | 
							
								will be renamed to +pika_text_layer_get_text+ automatically), and
							 | 
						||
| 
								 | 
							
								opening the braces for it's content.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Description of the procedure
							 | 
						||
| 
								 | 
							
								~~~~~~~~~~~~~~~~~~~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								At the beginning of the PDB function, you'll find lines similar to these:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[source,perl]
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								    $blurb = 'Get the text from a text layer as string.';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    $help = <<'HELP';
							 | 
						||
| 
								 | 
							
								This procedure returns the text from a text layer as a string.
							 | 
						||
| 
								 | 
							
								HELP
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Every procedure has a blurb string and a help string. A blurb is a short
							 | 
						||
| 
								 | 
							
								string summarizing what the function does, and the help is a longer
							 | 
						||
| 
								 | 
							
								string  in which you describe your function in more depth.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								A one line string can be specified by simply putting it between braces
							 | 
						||
| 
								 | 
							
								(like the blurb string). A longer string, which can possibly spread over
							 | 
						||
| 
								 | 
							
								several lines, must be written in a special way:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[source,perl]
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								<<'HELP';
							 | 
						||
| 
								 | 
							
								This procedure returns the text from a text layer as a string.
							 | 
						||
| 
								 | 
							
								HELP
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The +<<'*HELP*'+ practically mean that the content of the string will be
							 | 
						||
| 
								 | 
							
								specified in the next lines and it will continue until reaching a line
							 | 
						||
| 
								 | 
							
								which has the content +HELP+ in it (without any spaces before/after it,
							 | 
						||
| 
								 | 
							
								and without anything else in that line).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Now, the next line is:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[source,perl]
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								     &marcus_pdb_misc('2008', '2.6');
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If you contribute a function to the PIKA PDB, you credit yourself in the
							 | 
						||
| 
								 | 
							
								source code. The above line is for an author which contributed many
							 | 
						||
| 
								 | 
							
								functions and he now has a simple macro to credit him. For us regular
							 | 
						||
| 
								 | 
							
								users, if we want to specify the credit to ourself we should replace the
							 | 
						||
| 
								 | 
							
								above line with the following lines:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[source,perl]
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								    $author = 'Elvis Presley <the_king@rock.com>';
							 | 
						||
| 
								 | 
							
								    $copyright = 'Elvis Presley';
							 | 
						||
| 
								 | 
							
								    $date = '2010';
							 | 
						||
| 
								 | 
							
								    $since = '2.8';
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Replace the values of +$author+ and +$copyright+ with your own name and
							 | 
						||
| 
								 | 
							
								email, replace the value of +$date+ with the date in which you wrote the
							 | 
						||
| 
								 | 
							
								function (most functions only specify the year, so try to keep with this
							 | 
						||
| 
								 | 
							
								standard instead of adding a full date). And finally, replace the value
							 | 
						||
| 
								 | 
							
								of +$since+ with the version of PIKA which will be the first to include
							 | 
						||
| 
								 | 
							
								this function. For example, if PIKA 2.6 was released, and 2.8 wasn't
							 | 
						||
| 
								 | 
							
								released yet. then new functionality will be added in 2.8 (new
							 | 
						||
| 
								 | 
							
								functionality is only added inside new major version releases) and you
							 | 
						||
| 
								 | 
							
								should specify 2.8.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								In and Out Arguments
							 | 
						||
| 
								 | 
							
								~~~~~~~~~~~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								After the header of the function which contains it's description, you'll
							 | 
						||
| 
								 | 
							
								find these lines:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[source,perl]
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								    @inargs = (
							 | 
						||
| 
								 | 
							
								        { name => 'layer', type => 'layer',
							 | 
						||
| 
								 | 
							
								          desc => 'The text layer' }
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @outargs = (
							 | 
						||
| 
								 | 
							
								        { name => 'text', type => 'string',
							 | 
						||
| 
								 | 
							
								          desc => 'The text from the specified text layer.' }
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Here we specify the input arguments of this procedure, together with the
							 | 
						||
| 
								 | 
							
								returned arguments. As you can see, each argument has a name, a type and
							 | 
						||
| 
								 | 
							
								a description. The name will be used later in our code and it should be
							 | 
						||
| 
								 | 
							
								meaningful and be a valid name for a variable in C.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The type is one of the types listed in
							 | 
						||
| 
								 | 
							
								https://gitlab.gnome.org/GNOME/pika/tree/master/pdb/pdb.pl[pdb/pdb.pl]
							 | 
						||
| 
								 | 
							
								inside the +%arg_types+ array. In
							 | 
						||
| 
								 | 
							
								https://gitlab.gnome.org/GNOME/pika/tree/master/pdb/pdb.pl[pdb/pdb.pl]
							 | 
						||
| 
								 | 
							
								you can see the corresponding C type for each of the types we specify.
							 | 
						||
| 
								 | 
							
								For example, +layer+ type (inside the .pdb file) becomes a variable with
							 | 
						||
| 
								 | 
							
								the C type of +PikaLayer *+, and +string+ becomes +gchar *+.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If I want to add another input variable to the function, it'll look like this:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[source,perl]
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								    @inargs = (
							 | 
						||
| 
								 | 
							
								        { name => 'layer', type => 'layer',
							 | 
						||
| 
								 | 
							
								          desc => 'The text layer' },
							 | 
						||
| 
								 | 
							
								        { name => 'temp', type => 'int32',
							 | 
						||
| 
								 | 
							
								          desc => 'My silly number' }
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @outargs = (
							 | 
						||
| 
								 | 
							
								        { name => 'text', type => 'string',
							 | 
						||
| 
								 | 
							
								          desc => 'The text from the specified text layer.' }
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Don't forget to add comma between arguments!
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								The actual code
							 | 
						||
| 
								 | 
							
								~~~~~~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								After specifying the arguments we will specify the actual code of the
							 | 
						||
| 
								 | 
							
								function inside the following wrapper:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[source,perl]
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								    %invoke = (
							 | 
						||
| 
								 | 
							
								        code => <<'CODE'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								     ...
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								CODE
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Now finally, let's take a look at the actual code:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[source,c]
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								  if (pika_pdb_layer_is_text_layer (layer, FALSE, error))
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      g_object_get (pika_text_layer_get_text (PIKA_TEXT_LAYER (layer)),
							 | 
						||
| 
								 | 
							
								                    "text", &text,
							 | 
						||
| 
								 | 
							
								                    NULL);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      success = FALSE;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								This is a simple code in C - nothing fancy. However, this code uses
							 | 
						||
| 
								 | 
							
								functions from inside PIKA's core (hacking on the PIKA core will be the
							 | 
						||
| 
								 | 
							
								content for a different guide). The variables +text+ and +layer+, inside
							 | 
						||
| 
								 | 
							
								the C code, correspond to the variables we specified in the input/output
							 | 
						||
| 
								 | 
							
								arguments (since they have exactly the same name):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[source,c]
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								    @inargs = (
							 | 
						||
| 
								 | 
							
								        { name => 'layer', type => 'layer',
							 | 
						||
| 
								 | 
							
								          desc => 'The text layer' }
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    @outargs = (
							 | 
						||
| 
								 | 
							
								        { name => 'text', type => 'string',
							 | 
						||
| 
								 | 
							
								          desc => 'The text from the specified text layer.' }
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If for some reason, our function can fail (for example, in the code
							 | 
						||
| 
								 | 
							
								above the second line checks if the passed parameter is indeed a text
							 | 
						||
| 
								 | 
							
								layer and not just any layer) then we should add an indication that it
							 | 
						||
| 
								 | 
							
								failed by setting the variable +success+ to have the value +FALSE+.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Now, we need to do two more things to finish our function: add it to
							 | 
						||
| 
								 | 
							
								the function list, and configure the includes correctly.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Registering the function inside the PDB file
							 | 
						||
| 
								 | 
							
								~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								At the end of the PDB file, you should find the following segments:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[source,perl]
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								@headers = qw("libpikabase/pikabase.h"
							 | 
						||
| 
								 | 
							
								              "core/pikacontext.h"
							 | 
						||
| 
								 | 
							
								              "text/pikatext.h"
							 | 
						||
| 
								 | 
							
								              "text/pikatextlayer.h"
							 | 
						||
| 
								 | 
							
								              "pikapdb-utils.h"
							 | 
						||
| 
								 | 
							
								              "pikapdberror.h"
							 | 
						||
| 
								 | 
							
								              "pika-intl.h");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@procs = qw(text_layer_new
							 | 
						||
| 
								 | 
							
								            text_layer_get_text
							 | 
						||
| 
								 | 
							
								            text_layer_set_text
							 | 
						||
| 
								 | 
							
								  ...
							 | 
						||
| 
								 | 
							
								);
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Inside the +@headers+ there is a list of various header files from the
							 | 
						||
| 
								 | 
							
								pika source. If your code requires a header which is not specified, add
							 | 
						||
| 
								 | 
							
								it there.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Inside the +@procs+ there is a list of the procedures which are exported
							 | 
						||
| 
								 | 
							
								by the file. *Make sure you add your procedure to the list!*
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Advanced details
							 | 
						||
| 
								 | 
							
								----------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								enum arguments
							 | 
						||
| 
								 | 
							
								~~~~~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								In some cases you would like to have arguments which have a value from
							 | 
						||
| 
								 | 
							
								an enum (enumeration). Instead of just declaring these as integer values
							 | 
						||
| 
								 | 
							
								and telling in your description which value corresponds to which number,
							 | 
						||
| 
								 | 
							
								this can be done automatically for you if the desired enum is one of the
							 | 
						||
| 
								 | 
							
								enums which are already used by PIKA.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								To make it clearer, let's take a look at +layer_get_mode+ in
							 | 
						||
| 
								 | 
							
								https://gitlab.gnome.org/GNOME/pika/tree/master/pdb/groups/layer.pdb[pdb/groups/layer.pdb]:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[source,perl]
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								    @outargs = (
							 | 
						||
| 
								 | 
							
									{ name => 'mode', type => 'enum PikaLayerModeEffects',
							 | 
						||
| 
								 | 
							
									  desc => 'The layer combination mode' }
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								If we take a look at the same procedure as it shows up in the procedure
							 | 
						||
| 
								 | 
							
								browser (+pika_layer_get_mode+), we will see the following return values:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[options="header",cols="1,1,11"]
							 | 
						||
| 
								 | 
							
								|=======================================================================
							 | 
						||
| 
								 | 
							
								|Name	|Type	|Description
							 | 
						||
| 
								 | 
							
								|mode	|INT32	|
							 | 
						||
| 
								 | 
							
								The layer combination mode { NORMAL-MODE (0), DISSOLVE-MODE (1),
							 | 
						||
| 
								 | 
							
								BEHIND-MODE (2), MULTIPLY-MODE (3), SCREEN-MODE (4), OVERLAY-MODE (5),
							 | 
						||
| 
								 | 
							
								DIFFERENCE-MODE (6), ADDITION-MODE (7), SUBTRACT-MODE (8),
							 | 
						||
| 
								 | 
							
								DARKEN-ONLY-MODE (9), LIGHTEN-ONLY-MODE (10), HUE-MODE (11),
							 | 
						||
| 
								 | 
							
								SATURATION-MODE (12), COLOR-MODE (13), VALUE-MODE (14),
							 | 
						||
| 
								 | 
							
								DIVIDE-MODE (15), DODGE-MODE (16), BURN-MODE (17), HARDLIGHT-MODE (18),
							 | 
						||
| 
								 | 
							
								SOFTLIGHT-MODE (19), GRAIN-EXTRACT-MODE (20), GRAIN-MERGE-MODE (21),
							 | 
						||
| 
								 | 
							
								COLOR-ERASE-MODE (22), ERASE-MODE (23), REPLACE-MODE (24),
							 | 
						||
| 
								 | 
							
								ANTI-ERASE-MODE (25) }
							 | 
						||
| 
								 | 
							
								|=======================================================================
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								As you can see, all the values of the enum  were listed (the source file
							 | 
						||
| 
								 | 
							
								containing this enum is
							 | 
						||
| 
								 | 
							
								https://gitlab.gnome.org/GNOME/pika/tree/master/app/base/base-enums.h[app/base/base-enums.h])
							 | 
						||
| 
								 | 
							
								in it's description, and the type for this argument was declared as an
							 | 
						||
| 
								 | 
							
								integer value (reminder: enumeration values in C are actually mapped to
							 | 
						||
| 
								 | 
							
								numbers, unlike languages such as Java where enumeration values are
							 | 
						||
| 
								 | 
							
								indeed a new type in the language).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Limiting the range of numerical arguments
							 | 
						||
| 
								 | 
							
								~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								In some cases you would like to limit the range of numerical values
							 | 
						||
| 
								 | 
							
								passed as parameters for your PDB function. For example, the width of
							 | 
						||
| 
								 | 
							
								newly created images should be limited to be at least 1 (since images
							 | 
						||
| 
								 | 
							
								with 0 width don't make sense...) and it also should be limited to some
							 | 
						||
| 
								 | 
							
								maximal width (so that it won't be bigger than the maximal size PIKA
							 | 
						||
| 
								 | 
							
								supports).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								We can add this sort of range limitations inside the declaration of the
							 | 
						||
| 
								 | 
							
								function, and by that we can make sure it won't be called with values
							 | 
						||
| 
								 | 
							
								out of range (PIKA will make sure the values are inside the specified
							 | 
						||
| 
								 | 
							
								range before it calls our function). To see an example, let's take look
							 | 
						||
| 
								 | 
							
								at the procedure image_new from
							 | 
						||
| 
								 | 
							
								https://gitlab.gnome.org/GNOME/pika/tree/master/pdb/groups/image.pdb[pdb/groups/image.pdb]:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[source,perl]
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								    @inargs = (
							 | 
						||
| 
								 | 
							
								    { name => 'width', type => '1 <= int32 <= PIKA_MAX_IMAGE_SIZE',
							 | 
						||
| 
								 | 
							
								      desc => 'The width of the image' },
							 | 
						||
| 
								 | 
							
								    { name => 'height', type => '1 <= int32 <= PIKA_MAX_IMAGE_SIZE',
							 | 
						||
| 
								 | 
							
								      desc => 'The height of the image' },
							 | 
						||
| 
								 | 
							
								    { name => 'type', type => 'enum PikaImageBaseType',
							 | 
						||
| 
								 | 
							
								      desc => 'The type of image' }
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								As you can see, inside the +*type*+ field of the first two parameters,
							 | 
						||
| 
								 | 
							
								we added a limitation on the range of the parameter. The lower
							 | 
						||
| 
								 | 
							
								limitation is a simple number, and the upper limitation is a constant
							 | 
						||
| 
								 | 
							
								macro (+PIKA_MAX_IMAGE_SIZE+) defined in
							 | 
						||
| 
								 | 
							
								https://gitlab.gnome.org/GNOME/pika/tree/master/libpikabase/pikalimits.h[libpikabase/pikalimits.h].
							 | 
						||
| 
								 | 
							
								In order to make sure this constand will indeed be defined when parsing
							 | 
						||
| 
								 | 
							
								this function, the file
							 | 
						||
| 
								 | 
							
								https://gitlab.gnome.org/GNOME/pika/tree/master/libpikabase/pikabase.h[libpikabase/pikabase.h]
							 | 
						||
| 
								 | 
							
								(which includes
							 | 
						||
| 
								 | 
							
								https://gitlab.gnome.org/GNOME/pika/tree/master/libpikabase/pikalimits.h[libpikabase/pikalimits.h])
							 | 
						||
| 
								 | 
							
								was added to the +@headers+ section of the pdb file.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Now, if you take a look at the code part of this function you won't see
							 | 
						||
| 
								 | 
							
								any check that the value is indeed inside the specified range. As we
							 | 
						||
| 
								 | 
							
								said, PIKA takes care of this automatically for us so we don't need to
							 | 
						||
| 
								 | 
							
								add the check ourselves. Inside the procedure browser, this procedure
							 | 
						||
| 
								 | 
							
								would show up like this:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[options="header",cols="1,1,11"]
							 | 
						||
| 
								 | 
							
								|=======================================================================
							 | 
						||
| 
								 | 
							
								|Name	|Type	|Description
							 | 
						||
| 
								 | 
							
								|width	|INT32	|The width of the image (1 \<= width \<= 262144)
							 | 
						||
| 
								 | 
							
								|height	|INT32	|The height of the image (1 \<= height \<= 262144)
							 | 
						||
| 
								 | 
							
								|type	|INT32	|The type of image { RGB (0), GRAY (1), INDEXED (2) }
							 | 
						||
| 
								 | 
							
								|=======================================================================
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Array arguments
							 | 
						||
| 
								 | 
							
								~~~~~~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								In some cases you will want a function which returns an array or a
							 | 
						||
| 
								 | 
							
								function which receives an array. Array arguments are specified in a
							 | 
						||
| 
								 | 
							
								special way which is a bit different than the other arguments. To see
							 | 
						||
| 
								 | 
							
								how array arguments are specified, let's take a look at the +@outargs+
							 | 
						||
| 
								 | 
							
								of +vectors_stroke_get_points+ from
							 | 
						||
| 
								 | 
							
								https://gitlab.gnome.org/GNOME/pika/tree/master/pdb/groups/vectors.pdb[pdb/groups/vectors.pdb]:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[source,perl]
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								    @outargs = (
							 | 
						||
| 
								 | 
							
								        { name => 'type', type => 'enum PikaVectorsStrokeType',
							 | 
						||
| 
								 | 
							
								          desc => 'type of the stroke (always PIKA_VECTORS_STROKE_TYPE_BEZIER for now).' },
							 | 
						||
| 
								 | 
							
								        { name => 'controlpoints', type => 'floatarray',
							 | 
						||
| 
								 | 
							
								          desc => 'List of the control points for the stroke (x0, y0, x1, y1, ...).',
							 | 
						||
| 
								 | 
							
								          array => { name => 'num_points',
							 | 
						||
| 
								 | 
							
								                     desc => 'The number of floats returned.' } },
							 | 
						||
| 
								 | 
							
								        { name => 'closed', type => 'boolean',
							 | 
						||
| 
								 | 
							
								          desc => 'Whether the stroke is closed or not.' }
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								As you can see, the second argument which is of type +floatarray+ is
							 | 
						||
| 
								 | 
							
								specified in a different way than the other arguments; In addition to
							 | 
						||
| 
								 | 
							
								+name+, +type+ and +desc+, it also has an +*array*+  part. This part
							 | 
						||
| 
								 | 
							
								will declare another parameter for this function which will hold the
							 | 
						||
| 
								 | 
							
								length of the array (Reminder: in C you need the length of an array
							 | 
						||
| 
								 | 
							
								since unlike languages such as python, the length of an array isn't kept
							 | 
						||
| 
								 | 
							
								by default).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								As a result of this declaration, two arguments will be created (in this
							 | 
						||
| 
								 | 
							
								order):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								--
							 | 
						||
| 
								 | 
							
								. +*num_points*+ - a parameter of type +gint32+ which will hold the
							 | 
						||
| 
								 | 
							
								length of the array.
							 | 
						||
| 
								 | 
							
								. +*controlpoints*+ - a parameter of type +gdouble*+ which will point to
							 | 
						||
| 
								 | 
							
								the first element in the array.
							 | 
						||
| 
								 | 
							
								--
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Like all the other arguments which are declared in the +@outargs+ and
							 | 
						||
| 
								 | 
							
								+@intargs+ parts, their name  value will be the name of the variable in
							 | 
						||
| 
								 | 
							
								the code part. If you'll look at the code part of this function,
							 | 
						||
| 
								 | 
							
								you'll be able to find these lines:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								[source,c]
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								          num_points = points_array->len;
							 | 
						||
| 
								 | 
							
								          controlpoints = g_new (gdouble, num_points * 2);
							 | 
						||
| 
								 | 
							
								----
							 | 
						||
| 
								 | 
							
								As you can see from the code above, the +controlpoints+ argument starts
							 | 
						||
| 
								 | 
							
								just as a pointer to a double (array) - you have to do the allocation of
							 | 
						||
| 
								 | 
							
								the array yourself. However, if we would specify an array as an input
							 | 
						||
| 
								 | 
							
								argument, then the pointer will point to its beginning.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Summary
							 | 
						||
| 
								 | 
							
								-------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Hey! Now what - how do I see my function?
							 | 
						||
| 
								 | 
							
								~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Compile PIKA again from the source, and pass the flag --with-pdbgen to
							 | 
						||
| 
								 | 
							
								the configure script (or to the autogen script if using the autogen
							 | 
						||
| 
								 | 
							
								script).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Conclusions
							 | 
						||
| 
								 | 
							
								~~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								Now that you know how a PDB function looks like, you should be able to
							 | 
						||
| 
								 | 
							
								add new ones of your own if PIKA needs them (ask on the development list
							 | 
						||
| 
								 | 
							
								before working on a new function like this, since you need to see if the
							 | 
						||
| 
								 | 
							
								developers agree that it's needed!).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Don't forget to include the functions inside the right files! Under
							 | 
						||
| 
								 | 
							
								https://gitlab.gnome.org/GNOME/pika/tree/master/pdb/groups[pdb/groups]
							 | 
						||
| 
								 | 
							
								you can see many files (fonts.pdb, brush.pdb, layer.pdb, etc.) - *make
							 | 
						||
| 
								 | 
							
								sure you add your function in the place which logically suites it!*
							 |