Gimp.Drawable.get_offsets/ Python: is this correct?

Looking at the Api-Docs here:

The declaration tells me it needs the layer and the x-offset/ y-offset as input.
How can I input data that I want to retrieve?

Furthermore it says it returns a boolean, not x-offset or y-offset.

To make it more complicated:
If I use the pdb from the python console

procedure = Gimp.get_pdb().lookup_procedure('gimp-drawable-get-offsets'); 
config = procedure.create_config(); 
config.set_property('drawable', drawable); 
result = procedure.run(config); 
success = result.index(0); 
offset_x = result.index(1); 
offset_y = result.index(2)

I get proper offset values.

What’s wrong here?

Version info:
GNU Image Manipulation Program Version 3.0.0-RC2+git
git-describe: f715b54
Build: org.gimp.GIMP.flatpak.nightly rev 0 for linux

Hi Nelo I found this confusing too when I looked at it but I ended up writing a test which explained it to me!
def check_offsets(self, new_image, new_layer):

    offsets = new_layer.get_offsets()

print(" Original", offsets) # (True, offset_x=0, offset_y=0)

    xshift = 20
    yshift = 30
    new_layer.set_offsets(xshift, yshift)

    offsets = new_layer.get_offsets()

print(“New”, offsets) # (True, offset_x=20, offset_y=30)

    assert offsets[1] == xshift
    assert offsets[2] == yshift

    new_layer.set_offsets(0, 0)

    return

I hope that that helps JimDee

I don’t understand why these procedures are in the PDB because it’s a much more complicated/contrived way to call things compared to the GI API (I use the PDB only for plugins).

However the API doc is mostly done from a C user’s perspective so, in the description:

gboolean
gimp_drawable_get_offsets (
  GimpDrawable* drawable,
  gint* offset_x,
  gint* offset_y
)

… the trained eye notices that the gint* are really pointers (*) to integers (gint), so the caller is passing the address of where it wants the results so these are likely outputs[1]. Fortunately the Python API derived from this restores some sanity, so you can just do (because a layer is a drawable):

>>> result=layer.get_offset().

Note that I said “some” sanity because the result now includes both the offsets and the True/False success indicator, so it is packaged as some kind of on-the-fly namedtuple where the first element has no name:

>>> layer.get_offsets()
(True, offset_x=-23, offset_y=68)

So academically you do:

offsets=layer.get_offsets()
if offsets[0]:
    # then you can  use offsets.offset_x and offsets.offset_y

But you can unpack the result directly, and even ignore the True/False in most cases (if what you passed is a drawable, it has offsets, and if that wasn’t a drawable I hope you have a try/except block around that code):

>>> _,offsetX,offsetY=layer.get_offsets()

[1] but of course you also have a GimpDrawable* and it is an input. But in C arguments can only be native types (int/float/pointer) so you cannot pass a full object as an argument, only a pointer to it. So yes it’s ambiguous for object types, but then common sense can also apply. You will also note that you are not calling a gimp_drawable_get_offsets() function but a Gimp.Drawable::get_offsets() method.

Thank you both for clarifying.

It’s the other way around: all PDB procedures are also in libgimp.

The reason why this procedure is in the PDB is because it requires the plug-in to call the core application. On the plug-in side, in fact all you know about a drawable is some identifier. If the plug-in needs say the name of the layer, or type of the layer, or like here the offsets, then it needs to call the core and ask through the PDB (which is our inter-process communication channel). That’s why it’s in the PDB.

Then it’s also in libgimp because all PDB procedures are introspected into a C function which is available in libgimp. Then libgimp may have a few more functions, for things which don’t require IPC communication, e.g. utility functions, or custom GTK widgets.

About this, I looked at it this weekend, before releasing RC3 (after reading your comment here).

So by default, all PDB procedures have indeed a boolean return value. It is actually useful to tell whether or not the procedure succeeded (in some cases, some actions may not be possible).
It is nevertheless possible to bypass this boolean return value in the few cases when it’s unneeded (we have a flag specifically for this in PDB introspection).

Now when looking specifically at gimp_drawable_get_offsets, it’s indeed one of these cases where the boolean success is not that useful because the procedure never fails (well it may if the drawable is not a drawable, but then it’s not a “normal run error”, it’s a bug and the plug-in developer must fix it). But since there are other return values and since C can only have 1 return value, if I add the flag I told about, the signature becomes:

gint
gimp_drawable_get_offsets (GimpDrawable *drawable,
                           gint         *offset_y)

Well that’s ugly. I could hack the PDB with a new/updated flag which would mean “don’t have a boolean success return value but leave all other return values as pointers”, but I don’t know if it’s really worth doing this update before finale 3.0.0. I’m rather tempted to leave things as-is.

IMHO, leave it as is.