Hi Matthew and All,
@Matthew, I've looked at your dbus repo. I might not have understood how you were relating it to this, but to me it looks like you are just using the old plugin interface, rather than anything to do with a new interface.
@All,
Having reviewed what has been said in the thread to date, there is no real substance, so I think its likely that we may be talking about subtly different things. So to start the ball rolling here is an initial description of what I understand as the aims of this work and how I see it possibly being implemented.
As I see it the purpose is to define a new plugin interface to Geany that exposes all the required machinery through a set of GObjects which can be (semi) automatically interfaced to languages other than C, allowing Geany to have plugins written in multiple languages.
This new interface should provide at least the capabilities of the current plugin interface.
The way I see it being implemented, is not to change Geany's existing C structures into GObjects, rather, that the GObjects provide an interface to the existing C implementation and may not even map one to one with the existing structures.
This has several advantages,
1. the interface is somewhat isolated from the Geany implementation, allowing the implementation to evolve without causing a change in the interface seen by plugins. The current plugin interface is so thin that it is easy for changes to Geany to affect the interface. 2. the impact on the core implementation is minimised, so the impact on anything else happening in Geany itself is smaller. 3. The interface can be defined such that it is easy for plugins to use, independent of the underlying implementation
I see the GObjects as simply containing pointers to one or more of the Geany structures and the methods each being just a few calls to existing functions that operate on these structures.
There will still need to be code added to the existing implementation since it needs to create and destroy the GObjects as required and will have to emit signals on them when required. But this is a much less intrusive change compared to re-implementing core in GObjects. In fact it should be only additional code (albeit intertwined in the existing source), so minimising the likelihood of bugs being introduced into the existing Geany functionality.
Since the purpose is to support multiple languages, I think that some support for initialising and sharing interpretors/runtimes also needs to be created. It doesn't help someone to write Python or C# plugins if they have to figure out how to interface the Python interpretor or Mono runtime first. That should be done once for each language and be a loadable part of Geany. This process should also know how to find the plugins in the particular language, like Java ones in jar files, Python ones in directories with __init__.py in them etc. Sharing is needed to reduce the bloat that would occur if each plugin had to have a copy of the interpretor/runtime code
Hope this gives something to think about and throw things at.
Cheers Lex
On 03/16/11 22:25, Lex Trotman wrote:
Hi Matthew and All,
@Matthew, I've looked at your dbus repo. I might not have understood how you were relating it to this, but to me it looks like you are just using the old plugin interface, rather than anything to do with a new interface.
It's very bare still, but there are some things going on which fall into line with the GObject interface. The only real reason it's been referred to is that it 1) provides a GObject wrapper/C API around the current plugin API emitting signals from the right objects, using real properties, etc, 2) (will) provide a shared library that bindings/clients can link to, and 3) provides process isolation. Other than those ideas it's so incomplete/new as to not be too relevant. I'm actually not really planning on working on it until after there's a new GObject interface to Geany, since afterwards, it would be just a matter of inheriting from a few classes and tacking on GDBus stuff.
Unfortunately, there is some context around this which has been discussed around the geany-vala-binding, that a lot of which wasn't on a ML. It's very easy to summarize some of the ideas I've had/heard so far:
- The geany-vala-binding should be sort of a "raw" wrapper around the existing plugin API, providing simple access from Vala code.
- There needs to be a GObject wrapper around a lot of the existing stuff where it makes sense, since a lot of it is sorta OOP in design. This could use Vala to generate all of necessary boiler-plate GObject C code and allow doing things like ABCs and interfaces without gobs of (hand-written) code.
- Signals for the plugins need to be emitted from the appropriate objects. rather than the current central GeanyGObject which is has all the signals. An example would be that the "saved" signal should be on a Document object.
- The API should enforce read/write access on the objects via properties/accessors. The current API just exposes raw struct members, certain ones which, when set would result in strange behaviour in Geany. The current API does have some getters/and setters though they aren't really consistent. For an example of how the Vala binding is wrapping this inconsistent access, see [1]. The point of the DBus binding directly wrapping the Vala binding was to make it a true GObject API, where the Vala binding just provides a window to the existing raw C code (more or less).
- Libpeas[2] should be used as the actual plugin finder/loader. It's a GObject/GLib library designed specifically for finding plugins in different languages, loading their interpreter, and doing stuff like activation/deactivation. It seems Gedit is using this as well as several other popular GNOME-ish programs.
- There is a huge namespace clash with the current plugin API, in order to use sensible prefixes and class names. Nothing in the new interface can be prefixed with Geany, geany or GEANY, which of course would be the sensible prefix for an API. The new interface would have to use something like GeanyLib or LibGeany or whatever, and then in the language bindings the namespace could be whatever (except in Vala where there will still be collisions).
I think that roughly sums up the discussion I've heard so far that may or may not have been on this ML.
Why all the discussion around Vala[3]? It's just *really* nice for generating GObject C APIs, like GOB2 on steroids. It can output C files so that users are not require to have the valac compiler installed, it also can output C header that can be installed like headers are with any other library for use by C code. My personal opinion is that it would be ideal to use Vala for the new GObject interface, at the very least to get something working, and then possibly port it bit by bit into hand-crafted C (though valac's C is pretty clean considering).
@All,
Having reviewed what has been said in the thread to date, there is no real substance, so I think its likely that we may be talking about subtly different things. So to start the ball rolling here is an initial description of what I understand as the aims of this work and how I see it possibly being implemented.
As I see it the purpose is to define a new plugin interface to Geany that exposes all the required machinery through a set of GObjects which can be (semi) automatically interfaced to languages other than C, allowing Geany to have plugins written in multiple languages.
Using GObject-introspection hopefully in most places[4].
This new interface should provide at least the capabilities of the current plugin interface.
Agreed.
The way I see it being implemented, is not to change Geany's existing C structures into GObjects, rather, that the GObjects provide an interface to the existing C implementation and may not even map one to one with the existing structures.
This is in line with the previous discussions, especially the geany-vala-binding providing Vala access for the GObject wrappers to use. I agree that in quite a few cases it won't (or shouldn't) map 1:1 with the old API.
This has several advantages,
- the interface is somewhat isolated from the Geany implementation,
allowing the implementation to evolve without causing a change in the interface seen by plugins. The current plugin interface is so thin that it is easy for changes to Geany to affect the interface. 2. the impact on the core implementation is minimised, so the impact on anything else happening in Geany itself is smaller. 3. The interface can be defined such that it is easy for plugins to use, independent of the underlying implementation
I studied the code in documents.{c,h} a bit just to see what it would take to convert a GeanyDocument into a GObject. My observations were that it would a) require an almost complete re-write of that code, b) completely mess with the existing plugin API as well as tons of stuff in the core that uses GeanyDocument's and c) that it would bloat the code up so much that I don't think it would fit with Geany's "fast and light" philosophy. So your #2 point is really important I think.
I see the GObjects as simply containing pointers to one or more of the Geany structures and the methods each being just a few calls to existing functions that operate on these structures.
Yep, and wrapping them up in GObject properties and signals so Gobject introspection can do its magic in making the higher level language bindings idiomatic (or I guess OOP-ish, since it's roughly the same in most languages I know).
There will still need to be code added to the existing implementation since it needs to create and destroy the GObjects as required and will have to emit signals on them when required. But this is a much less
My initial though was a regular old Geany plugin, using the Vala binding and Vala output C API to provide the "glue" without even touching the existing core code directly. This would at least provide a nice testbed. Then the existing plugin API could just have the odd struct tweaked or function added, etc.
intrusive change compared to re-implementing core in GObjects. In fact it should be only additional code (albeit intertwined in the existing source), so minimising the likelihood of bugs being introduced into the existing Geany functionality.
Very important indeed.
Since the purpose is to support multiple languages, I think that some support for initialising and sharing interpretors/runtimes also needs to be created. It doesn't help someone to write Python or C# plugins if they have to figure out how to interface the Python interpretor or Mono runtime first. That should be done once for each language and be a loadable part of Geany. This process should also know how to find the plugins in the particular language, like Java ones in jar files, Python ones in directories with __init__.py in them etc. Sharing is needed to reduce the bloat that would occur if each plugin had to have a copy of the interpretor/runtime code
This is exactly where LibPeas[2] fits in. I've not found anything that would fit the bill as well as LibPeas would. Also, if we were to add interpreter/runtime loaders to LibPeas, the benefits would populate across to other important projects like Totem, Gedit, Eog, etc. and of course vice versa. Currently LibPeas only has plugin loaders for C (so probably Vala and Genie as well), Python and JS, but surely more can and will be added in the future.
Hope this gives something to think about and throw things at.
Thanks for getting the ball rolling, I'm anxious to hear what others have to say.
[1] http://gitorious.org/geany-vala-binding/geany-vala-binding/blobs/master/gean... [2] http://library.gnome.org/devel/libpeas/0.7/ [3] http://live.gnome.org/Vala/Tutorial [4] http://live.gnome.org/GObjectIntrospection
Cheers, Matthew Brush
On 17 March 2011 17:56, Matthew Brush mbrush@codebrainz.ca wrote:
On 03/16/11 22:25, Lex Trotman wrote:
Hi Matthew and All,
@Matthew, I've looked at your dbus repo. I might not have understood how you were relating it to this, but to me it looks like you are just using the old plugin interface, rather than anything to do with a new interface.
It's very bare still, but there are some things going on which fall into line with the GObject interface. The only real reason it's been referred to is that it 1) provides a GObject wrapper/C API around the current plugin API emitting signals from the right objects, using real properties, etc, 2) (will) provide a shared library that bindings/clients can link to, and 3) provides process isolation. Other than those ideas it's so incomplete/new as to not be too relevant. I'm actually not really planning on working on it until after there's a new GObject interface to Geany, since afterwards, it would be just a matter of inheriting from a few classes and tacking on GDBus stuff.
Makes sense.
Unfortunately, there is some context around this which has been discussed around the geany-vala-binding, that a lot of which wasn't on a ML. It's very easy to summarize some of the ideas I've had/heard so far:
- The geany-vala-binding should be sort of a "raw" wrapper around the existing plugin API, providing simple access from Vala code.
Not sure about wrapping the existing plugin interface, see below
- There needs to be a GObject wrapper around a lot of the existing stuff where it makes sense, since a lot of it is sorta OOP in design. This could use Vala to generate all of necessary boiler-plate GObject C code and allow doing things like ABCs and interfaces without gobs of (hand-written) code.
Well anything to avoid writing GObject code in C has my vote :-). My only comment is that my (limited) look at the Vala docs seems to be lacking in documenting how to wrap existing C interfaces that don't introspect properly. Eg I couldn't find what goes in [CCode...]. Might be just my searching of course :-)
- Signals for the plugins need to be emitted from the appropriate objects. rather than the current central GeanyGObject which is has all the signals. An example would be that the "saved" signal should be on a Document object.
Totally agree, but this is where using the existing plugin interface is deficient, very few signals are provided. But core will have to be changed to emit more. I don't really see that as a problem, adding emits in appropriate places should be no problem, but it does imply that then core can see the GObjects so it can emit on them, again I don't think the existing plugin interface provides much support for making things in the plugin visible to core. Also when to create and delete the GObjects.
- The API should enforce read/write access on the objects via properties/accessors. The current API just exposes raw struct members, certain ones which, when set would result in strange behaviour in Geany. The current API does have some getters/and setters though they aren't really consistent. For an example of how the Vala binding is wrapping this inconsistent access, see [1]. The point of the DBus binding directly wrapping the Vala binding was to make it a true GObject API, where the Vala binding just provides a window to the existing raw C code (more or less).
Yes, I expect that there will need to be a Vala binding of whatever parts of core are needed so that the GObject implementations can use it.
- Libpeas[2] should be used as the actual plugin finder/loader. It's a GObject/GLib library designed specifically for finding plugins in different languages, loading their interpreter, and doing stuff like activation/deactivation. It seems Gedit is using this as well as several other popular GNOME-ish programs.
Looks like it might be helpful, how easy it might be to get it to work alongside the existing plugin manager (so we get one UI) I don't know. Remember we don't want to chop existing plugins off.
- There is a huge namespace clash with the current plugin API, in order to use sensible prefixes and class names. Nothing in the new interface can be prefixed with Geany, geany or GEANY, which of course would be the sensible prefix for an API. The new interface would have to use something like GeanyLib or LibGeany or whatever, and then in the language bindings the namespace could be whatever (except in Vala where there will still be collisions).
Hmmm, yes, geany_interface etc. I'm sure we'll argue our way to some agreement eventually :-)
I think that roughly sums up the discussion I've heard so far that may or may not have been on this ML.
Why all the discussion around Vala[3]? It's just *really* nice for generating GObject C APIs, like GOB2 on steroids. It can output C files so that users are not require to have the valac compiler installed, it also can
Users not needing Vala is very important so this is all good.
output C header that can be installed like headers are with any other library for use by C code. My personal opinion is that it would be ideal to use Vala for the new GObject interface, at the very least to get something working, and then possibly port it bit by bit into hand-crafted C (though valac's C is pretty clean considering).
Lets try not to have premature optimisation :-)
@All,
Having reviewed what has been said in the thread to date, there is no real substance, so I think its likely that we may be talking about subtly different things. So to start the ball rolling here is an initial description of what I understand as the aims of this work and how I see it possibly being implemented.
As I see it the purpose is to define a new plugin interface to Geany that exposes all the required machinery through a set of GObjects which can be (semi) automatically interfaced to languages other than C, allowing Geany to have plugins written in multiple languages.
Using GObject-introspection hopefully in most places[4].
The issue with that IIUC the stable version will be for GTK-3 and since Geany still supports GTK 2.8 its got a *way* to go before it gets to 3 :-)
This new interface should provide at least the capabilities of the current plugin interface.
Agreed.
The way I see it being implemented, is not to change Geany's existing C structures into GObjects, rather, that the GObjects provide an interface to the existing C implementation and may not even map one to one with the existing structures.
This is in line with the previous discussions, especially the geany-vala-binding providing Vala access for the GObject wrappers to use. I agree that in quite a few cases it won't (or shouldn't) map 1:1 with the old API.
This has several advantages,
- the interface is somewhat isolated from the Geany implementation,
allowing the implementation to evolve without causing a change in the interface seen by plugins. The current plugin interface is so thin that it is easy for changes to Geany to affect the interface. 2. the impact on the core implementation is minimised, so the impact on anything else happening in Geany itself is smaller. 3. The interface can be defined such that it is easy for plugins to use, independent of the underlying implementation
I should have added that, yes this may add some overhead, but to put it into perspective, its nothing compared to the amount of code executed in Scintilla, GTK, X-server and graphics driver to re-display the screen so it shouldn't be any problem.
I studied the code in documents.{c,h} a bit just to see what it would take to convert a GeanyDocument into a GObject. My observations were that it would a) require an almost complete re-write of that code, b) completely mess with the existing plugin API as well as tons of stuff in the core that uses GeanyDocument's and c) that it would bloat the code up so much that I don't think it would fit with Geany's "fast and light" philosophy. So your #2 point is really important I think.
Yes, and GeanyDocument is the most obvious object, some of the others may be cross-file.
I see the GObjects as simply containing pointers to one or more of the Geany structures and the methods each being just a few calls to existing functions that operate on these structures.
Yep, and wrapping them up in GObject properties and signals so Gobject introspection can do its magic in making the higher level language bindings idiomatic (or I guess OOP-ish, since it's roughly the same in most languages I know).
Well getters and setters rather than properties, IIUC GTK is heading towards hiding properties or at least making them read-only.
There will still need to be code added to the existing implementation since it needs to create and destroy the GObjects as required and will have to emit signals on them when required. But this is a much less
My initial though was a regular old Geany plugin, using the Vala binding and Vala output C API to provide the "glue" without even touching the existing core code directly. This would at least provide a nice testbed. Then the existing plugin API could just have the odd struct tweaked or function added, etc.
As I said above, I think we will quickly find that this isn't enough. Also just how well does Vala operate through the indirect pointer to function interface provided by the current plugin interface?
intrusive change compared to re-implementing core in GObjects. In fact it should be only additional code (albeit intertwined in the existing source), so minimising the likelihood of bugs being introduced into the existing Geany functionality.
Very important indeed.
Since the purpose is to support multiple languages, I think that some support for initialising and sharing interpretors/runtimes also needs to be created. It doesn't help someone to write Python or C# plugins if they have to figure out how to interface the Python interpretor or Mono runtime first. That should be done once for each language and be a loadable part of Geany. This process should also know how to find the plugins in the particular language, like Java ones in jar files, Python ones in directories with __init__.py in them etc. Sharing is needed to reduce the bloat that would occur if each plugin had to have a copy of the interpretor/runtime code
This is exactly where LibPeas[2] fits in. I've not found anything that would fit the bill as well as LibPeas would. Also, if we were to add interpreter/runtime loaders to LibPeas, the benefits would populate across to other important projects like Totem, Gedit, Eog, etc. and of course vice versa. Currently LibPeas only has plugin loaders for C (so probably Vala and Genie as well), Python and JS, but surely more can and will be added in the future.
Yes, BTW can you specify which Python is used? Distros are now providing both 2 and 3 side by side.
Hope this gives something to think about and throw things at.
Thanks for getting the ball rolling, I'm anxious to hear what others have to say.
Cheers Lex
Le 17/03/2011 09:17, Lex Trotman a écrit :
On 17 March 2011 17:56, Matthew Brush mbrush@codebrainz.ca wrote:
Unfortunately, there is some context around this which has been discussed around the geany-vala-binding, that a lot of which wasn't on a ML. It's very easy to summarize some of the ideas I've had/heard so far:
- The geany-vala-binding should be sort of a "raw" wrapper around the existing plugin API, providing simple access from Vala code.
Not sure about wrapping the existing plugin interface, see below
As Matthew said, this can be useful to write the end-user wrapper without bothering to write the bridge code. The current Vala binding is more or less a 1:1 mapping of the current C API, but can easily be used to write the high-level binding we talk about. Avoids the need of [CCode ..] ;)
- There needs to be a GObject wrapper around a lot of the existing stuff where it makes sense, since a lot of it is sorta OOP in design. This could use Vala to generate all of necessary boiler-plate GObject C code and allow doing things like ABCs and interfaces without gobs of (hand-written) code.
Well anything to avoid writing GObject code in C has my vote :-). My only comment is that my (limited) look at the Vala docs seems to be lacking in documenting how to wrap existing C interfaces that don't introspect properly. Eg I couldn't find what goes in [CCode...]. Might be just my searching of course :-)
Se above ;) But basically you're right: Vala doc on this side is a bit missing.
- Signals for the plugins need to be emitted from the appropriate objects. rather than the current central GeanyGObject which is has all the signals. An example would be that the "saved" signal should be on a Document object.
Totally agree, but this is where using the existing plugin interface is deficient, very few signals are provided. But core will have to be changed to emit more. I don't really see that as a problem, adding emits in appropriate places should be no problem, but it does imply that then core can see the GObjects so it can emit on them, again I don't think the existing plugin interface provides much support for making things in the plugin visible to core. Also when to create and delete the GObjects.
Why? The current API has all its signals in GeanyObject, and it works fine so far. And wrapping signals correctly is "only" a matter of connecting to the GeanyObject signal and emit another back when you received the GanyObject one. Sorta:
geany_object.signal_name.connect(() => this.signal_name.emit())
or whatever fits.
Or are you referring to something else? (maybe I miss something :/)
- Libpeas[2] should be used as the actual plugin finder/loader. It's a GObject/GLib library designed specifically for finding plugins in different languages, loading their interpreter, and doing stuff like activation/deactivation. It seems Gedit is using this as well as several other popular GNOME-ish programs.
Looks like it might be helpful, how easy it might be to get it to work alongside the existing plugin manager (so we get one UI) I don't know. Remember we don't want to chop existing plugins off.
Should be possible (and quite easy) as far as one have access to the plugin dialog internals. Peas has separated UI and core, so it should be possible to build your own UI.
Having reviewed what has been said in the thread to date, there is no real substance, so I think its likely that we may be talking about subtly different things. So to start the ball rolling here is an initial description of what I understand as the aims of this work and how I see it possibly being implemented.
As I see it the purpose is to define a new plugin interface to Geany that exposes all the required machinery through a set of GObjects which can be (semi) automatically interfaced to languages other than C, allowing Geany to have plugins written in multiple languages.
Using GObject-introspection hopefully in most places[4].
The issue with that IIUC the stable version will be for GTK-3 and since Geany still supports GTK 2.8 its got a *way* to go before it gets to 3 :-)
GObject-introspection is part of GObject AFAIK, and GObject hasn't moved to 3.0. So I guess there is no problem on this side ;)
I see the GObjects as simply containing pointers to one or more of the Geany structures and the methods each being just a few calls to existing functions that operate on these structures.
Yep, and wrapping them up in GObject properties and signals so Gobject introspection can do its magic in making the higher level language bindings idiomatic (or I guess OOP-ish, since it's roughly the same in most languages I know).
Well getters and setters rather than properties, IIUC GTK is heading towards hiding properties or at least making them read-only.
Nope, GTK tries to remove all public *fields*, not properties. The fact GTK has almost getters and/or setters for each property is more for being convenient from C code, where getting a property is generally harder than in other languages. In languages having properties, the properties are better IMHO.
There will still need to be code added to the existing implementation since it needs to create and destroy the GObjects as required and will have to emit signals on them when required. But this is a much less
My initial though was a regular old Geany plugin, using the Vala binding and Vala output C API to provide the "glue" without even touching the existing core code directly. This would at least provide a nice testbed. Then the existing plugin API could just have the odd struct tweaked or function added, etc.
As I said above, I think we will quickly find that this isn't enough.
Maybe true.
Also just how well does Vala operate through the indirect pointer to function interface provided by the current plugin interface?
Basically: as well as C. Vala translates to C code, then as far as the result C code works, Vala will work, and since the plugin API hides the indirect pointer complexity, even the binding wouldn't see it.
Cheers, Colomban