Hi,
I'm seeking ideas/advice for how I can implement keybindings for Python plugins[1]. Since `geany_plugin` will be the same for all Python plugins, I don't think I could use the regular way. I wouldn't want every Python plugin's keybindings showing up under the same 'GeanyPy' group.
I tried with a gtk.AccelGroup() on the geany.main_widgets.window from Python/PyGTK, but Geany seems to block most keybindings doing it that way. I really don't know much about this either.
I'm at the design state right now, so if anyone has any ideas for how I should implement this, using either Geany's plugin API, PyGTK directly, or something else I don't know about, I'd much appreciate hearing them.
I'm kinda at a loss here.
[1] https://github.com/codebrainz/geanypy
Cheers, Matthew Brush
On 5 August 2011 13:01, Matthew Brush mbrush@codebrainz.ca wrote:
Hi,
I'm seeking ideas/advice for how I can implement keybindings for Python plugins[1]. Since `geany_plugin` will be the same for all Python plugins, I don't think I could use the regular way. I wouldn't want every Python plugin's keybindings showing up under the same 'GeanyPy' group.
I tried with a gtk.AccelGroup() on the geany.main_widgets.window from Python/PyGTK, but Geany seems to block most keybindings doing it that way. I really don't know much about this either.
Since Geany catches all keyevents you probably have to use Geany facilities since there is no way of attaching to the signal before Geany does.
I'm at the design state right now, so if anyone has any ideas for how I should implement this, using either Geany's plugin API, PyGTK directly, or something else I don't know about, I'd much appreciate hearing them.
I'm kinda at a loss here.
That would be because Geany doesn't have any way of handling sub-plugins so you can't do what you want to do.
What might be better would be for Geany to allow new plugins to be registered at runtime and without loading another module. Then your python wrapper can possibly register the python scripts as plugins but with itself as the callback point. So the scripts would look like plugins and could use normal keybinding support.
This would need extension of plugins.h/c and of course Someone Has To Do It (tm).
Otherwise the only method would be to load a new copy of your wrapper and the python interpretor for each script you wanted to use. (Yuk, but might be the only way at the moment).
Cheers Lex
On 08/04/11 20:29, Lex Trotman wrote:
On 5 August 2011 13:01, Matthew Brushmbrush@codebrainz.ca wrote:
I tried with a gtk.AccelGroup() on the geany.main_widgets.window from Python/PyGTK, but Geany seems to block most keybindings doing it that way. I really don't know much about this either.
Since Geany catches all keyevents you probably have to use Geany facilities since there is no way of attaching to the signal before Geany does.
Well, no *proper* way :)
That would be because Geany doesn't have any way of handling sub-plugins so you can't do what you want to do.
What might be better would be for Geany to allow new plugins to be registered at runtime and without loading another module. Then your python wrapper can possibly register the python scripts as plugins but with itself as the callback point. So the scripts would look like plugins and could use normal keybinding support.
This would need extension of plugins.h/c and of course Someone Has To Do It (tm).
Yep, pretty much, and this is getting deep into LibPeas territory.
Otherwise the only method would be to load a new copy of your wrapper and the python interpretor for each script you wanted to use. (Yuk, but might be the only way at the moment).
In *theory* it might not be so bad, since there's a function Py_IsInitialized() that could check to make sure if a Python interpreter has been started, rather than starting a new one. Since it's all in Geany's (the same) process, this *should* work - without having seperate instances of the Python interperter and the geany python modules for each sub-plugin. But still, each script would needs it's own (boiler-plate) loader C file/.so/.dll in order to be detected by Geany, which does feel a little wrong.
Cheers, Matthew Brush
[...]
Otherwise the only method would be to load a new copy of your wrapper and the python interpretor for each script you wanted to use. (Yuk, but might be the only way at the moment).
In *theory* it might not be so bad, since there's a function Py_IsInitialized() that could check to make sure if a Python interpreter has been started, rather than starting a new one. Since it's all in Geany's (the same) process, this *should* work - without having seperate instances of the Python interperter and the geany python modules for each sub-plugin. But still, each script would needs it's own (boiler-plate) loader C file/.so/.dll in order to be detected by Geany, which does feel a little wrong.
I suppose the dll loader won't let you load multiple copies of the same dll and resolve them all to the same copy? Not that I can see from g_module...
Otherwise I guess it "shouldn't" be too hard to add the extra functionality to Geany but getting stuff from the module is spread around a bit and you would need to be sure the module wasn't unloaded unexpectedly as well.
Cheers Lex
Cheers, Matthew Brush _______________________________________________ Geany-devel mailing list Geany-devel@uvena.de https://lists.uvena.de/cgi-bin/mailman/listinfo/geany-devel
On 08/05/11 20:35, Lex Trotman wrote:
[...]
Otherwise the only method would be to load a new copy of your wrapper and the python interpretor for each script you wanted to use. (Yuk, but might be the only way at the moment).
In *theory* it might not be so bad, since there's a function Py_IsInitialized() that could check to make sure if a Python interpreter has been started, rather than starting a new one. Since it's all in Geany's (the same) process, this *should* work - without having seperate instances of the Python interperter and the geany python modules for each sub-plugin. But still, each script would needs it's own (boiler-plate) loader C file/.so/.dll in order to be detected by Geany, which does feel a little wrong.
I suppose the dll loader won't let you load multiple copies of the same dll and resolve them all to the same copy? Not that I can see from g_module...
I've never seen anything like this, fwiw.
Otherwise I guess it "shouldn't" be too hard to add the extra functionality to Geany but getting stuff from the module is spread around a bit and you would need to be sure the module wasn't unloaded unexpectedly as well.
How can it be unloaded?
Cheers, Matthew Brush
[...]
Otherwise I guess it "shouldn't" be too hard to add the extra functionality to Geany but getting stuff from the module is spread around a bit and you would need to be sure the module wasn't unloaded unexpectedly as well.
How can it be unloaded?
Well I didn't read plugins.c in detail but I suspected that ATM when you deactivate a plugin in the plugin manager it will unload the module, but that would be bad for a shared module.
In fact seems to close and re-open whenever you toggle the activate checkbox, see pm_plugin_toggled() calls plugin_free() which closes the module.
Just means that you need to be careful when you patch it that the Python plugin isn't unloadable without unloading all its dependent plugins.
Cheers Lex
Cheers, Matthew Brush _______________________________________________ Geany-devel mailing list Geany-devel@uvena.de https://lists.uvena.de/cgi-bin/mailman/listinfo/geany-devel
On 08/05/11 21:01, Lex Trotman wrote:
[...]
Otherwise I guess it "shouldn't" be too hard to add the extra functionality to Geany but getting stuff from the module is spread around a bit and you would need to be sure the module wasn't unloaded unexpectedly as well.
How can it be unloaded?
Well I didn't read plugins.c in detail but I suspected that ATM when you deactivate a plugin in the plugin manager it will unload the module, but that would be bad for a shared module.
In fact seems to close and re-open whenever you toggle the activate checkbox, see pm_plugin_toggled() calls plugin_free() which closes the module.
Just means that you need to be careful when you patch it that the Python plugin isn't unloadable without unloading all its dependent plugins.
I think it'll be ok if it's using g_module_make_resident[1], which should ensure that first Python interpreter (libpythonX.X.so) would never get unloaded, and so always be Py_IsInitialized(). Basically, I don't care if you can't reclaim your XX megabytes of RAM until you restart Geany :)
[1] http://www.geany.org/manual/reference/pluginutils_8h.html#ac402e1d165036aaeb...
Cheers, Matthew Brush
On 6 August 2011 14:11, Matthew Brush mbrush@codebrainz.ca wrote:
On 08/05/11 21:01, Lex Trotman wrote:
[...]
Otherwise I guess it "shouldn't" be too hard to add the extra functionality to Geany but getting stuff from the module is spread around a bit and you would need to be sure the module wasn't unloaded unexpectedly as well.
How can it be unloaded?
Well I didn't read plugins.c in detail but I suspected that ATM when you deactivate a plugin in the plugin manager it will unload the module, but that would be bad for a shared module.
In fact seems to close and re-open whenever you toggle the activate checkbox, see pm_plugin_toggled() calls plugin_free() which closes the module.
Just means that you need to be careful when you patch it that the Python plugin isn't unloadable without unloading all its dependent plugins.
I think it'll be ok if it's using g_module_make_resident[1], which should ensure that first Python interpreter (libpythonX.X.so) would never get unloaded, and so always be Py_IsInitialized(). Basically, I don't care if you can't reclaim your XX megabytes of RAM until you restart Geany :)
Sounds fair, I havn't used more than about 2Gb of my 4Gb that I have noticed, despite firefox's best efforts.
BTW what are the restrictions on what Python can be used when Geany calls a Python callback, I guess everything has to be a function that runs to completion. Can it be a closure, can it use yield, can it use threads, can it do async I/O so as not to block Geany?
Cheers Lex
[1] http://www.geany.org/manual/reference/pluginutils_8h.html#ac402e1d165036aaeb...
Cheers, Matthew Brush _______________________________________________ Geany-devel mailing list Geany-devel@uvena.de https://lists.uvena.de/cgi-bin/mailman/listinfo/geany-devel
On 08/05/11 21:32, Lex Trotman wrote:
Sounds fair, I havn't used more than about 2Gb of my 4Gb that I have noticed, despite firefox's best efforts.
BTW what are the restrictions on what Python can be used when Geany calls a Python callback, I guess everything has to be a function that runs to completion. Can it be a closure, can it use yield, can it use threads, can it do async I/O so as not to block Geany?
More or less anything Python itself supports, including Global Interpreter Lock [1]. GeanyPy pretty much only the Python X.X interpreter, and pre-loades the Geany Python package (written in C) which glues Geany's C API to Python's C API.
[1] http://wiki.python.org/moin/GlobalInterpreterLock
Cheers, Matthew Brush
On 6 August 2011 15:05, Matthew Brush mbrush@codebrainz.ca wrote:
On 08/05/11 21:32, Lex Trotman wrote:
Sounds fair, I havn't used more than about 2Gb of my 4Gb that I have noticed, despite firefox's best efforts.
BTW what are the restrictions on what Python can be used when Geany calls a Python callback, I guess everything has to be a function that runs to completion. Can it be a closure, can it use yield, can it use threads, can it do async I/O so as not to block Geany?
More or less anything Python itself supports, including Global Interpreter Lock [1]. GeanyPy pretty much only the Python X.X interpreter, and pre-loades the Geany Python package (written in C) which glues Geany's C API to Python's C API.
Ok, so my Python plugin can start an I/O bound thread in its plugin_init routine and have that thread call a Geany function like updating the status bar when the I/O completes?
Be very careful, both answers are wrong ;-)
And from your next post:
I forgot to mention, for callbacks, I was thinking of using PyGTK/Gobject-introspection on the GeanyObject which has all the signals on it (IIR). So plugins would do:
geany.object.connect('document-open', on_document_open_handler)
Does that allow on_document_open_handler() to be a bound member function?
Cheers Lex
PS I'm not intending to be negative about Geany Python plugins, great idea, but from experience I think you will find some wrinkles in the real world.
On 08/05/11 23:01, Lex Trotman wrote:
On 6 August 2011 15:05, Matthew Brushmbrush@codebrainz.ca wrote:
On 08/05/11 21:32, Lex Trotman wrote:
BTW what are the restrictions on what Python can be used when Geany calls a Python callback, I guess everything has to be a function that runs to completion. Can it be a closure, can it use yield, can it use threads, can it do async I/O so as not to block Geany?
More or less anything Python itself supports, including Global Interpreter Lock [1]. GeanyPy pretty much only the Python X.X interpreter, and pre-loades the Geany Python package (written in C) which glues Geany's C API to Python's C API.
Ok, so my Python plugin can start an I/O bound thread in its plugin_init routine and have that thread call a Geany function like updating the status bar when the I/O completes?
Be very careful, both answers are wrong ;-)
In as much as Python and PyGTK/PyGObject can do this (ie. using GIO and friends, like Geany itself, or the threading module from Python). Geany's GMainLoop is the main loop for Python as well as well, and there's no extra restrictions, AFAIK, on what can be done, beyond those of Python/PyGTK.
And from your next post:
I forgot to mention, for callbacks, I was thinking of using PyGTK/Gobject-introspection on the GeanyObject which has all the signals on it (IIR). So plugins would do:
geany.object.connect('document-open', on_document_open_handler)
Does that allow on_document_open_handler() to be a bound member function?
Using PyGTK, it will be a GCallback from GLib/GObject plus some extra Python cruft.
Cheers, Matthew Brush
On 08/05/11 23:09, Matthew Brush wrote:
On 08/05/11 23:01, Lex Trotman wrote:
On 6 August 2011 15:05, Matthew Brushmbrush@codebrainz.ca wrote:
signals on it (IIR). So plugins would do:
geany.object.connect('document-open', on_document_open_handler)
Does that allow on_document_open_handler() to be a bound member function?
Sorry, yeah, you could do like:
import geany
class MyPlugin(geany.Plugin):
def __init__(self): geany.object.connect('document-open', self.on_document_open)
def on_document_open(self, *args...): do_stuff()
If that's what you meant.
Cheers, Matthew Brush
On 6 August 2011 16:17, Matthew Brush mbrush@codebrainz.ca wrote:
On 08/05/11 23:09, Matthew Brush wrote:
On 08/05/11 23:01, Lex Trotman wrote:
On 6 August 2011 15:05, Matthew Brushmbrush@codebrainz.ca wrote:
signals on it (IIR). So plugins would do:
geany.object.connect('document-open', on_document_open_handler)
Does that allow on_document_open_handler() to be a bound member function?
Sorry, yeah, you could do like:
import geany
class MyPlugin(geany.Plugin):
def __init__(self): geany.object.connect('document-open', self.on_document_open)
def on_document_open(self, *args...): do_stuff()
If that's what you meant.
Exactly, coooool.
Cheers Lex
Cheers, Matthew Brush _______________________________________________ Geany-devel mailing list Geany-devel@uvena.de https://lists.uvena.de/cgi-bin/mailman/listinfo/geany-devel
On 6 August 2011 16:09, Matthew Brush mbrush@codebrainz.ca wrote:
On 08/05/11 23:01, Lex Trotman wrote:
On 6 August 2011 15:05, Matthew Brushmbrush@codebrainz.ca wrote:
On 08/05/11 21:32, Lex Trotman wrote:
BTW what are the restrictions on what Python can be used when Geany calls a Python callback, I guess everything has to be a function that runs to completion. Can it be a closure, can it use yield, can it use threads, can it do async I/O so as not to block Geany?
More or less anything Python itself supports, including Global Interpreter Lock [1]. GeanyPy pretty much only the Python X.X interpreter, and pre-loades the Geany Python package (written in C) which glues Geany's C API to Python's C API.
Ok, so my Python plugin can start an I/O bound thread in its plugin_init routine and have that thread call a Geany function like updating the status bar when the I/O completes?
Be very careful, both answers are wrong ;-)
In as much as Python and PyGTK/PyGObject can do this (ie. using GIO and friends, like Geany itself, or the threading module from Python). Geany's GMainLoop is the main loop for Python as well as well, and there's no extra restrictions, AFAIK, on what can be done, beyond those of Python/PyGTK.
Ok if you do the I/O with GIO not Python. That means structuring everything in callbacks and somehow keeping status between calls.
Can I do (assume appropriate imports and other setup):
class MyPlugin: def __init__(self): geany.object.connect('menu_item_activate', self.menu_item_callback) def menu_item_callback(self): threading.Thread(target=self.do_slow_stuff, args=(self,)) def do_slow_stuff(self): with open("slow_file",r) as f: do_something_with_f
AFAICT basically there is no way of getting back into the Python interpretor to check if any I/O waits in do_something have completed and to continue. As soon as do_something releases the GIL and blocks menu_item_callback will complete and return control to Geany and never return to Python until the next callback.
Same problem even with multiprocessing, no way to find out if the subprocesses have completed (needs a Python thread so, see above).
So long as I don't call back into Geany I can do this using Posix threads in C.
Cheers Lex
On 08/05/11 21:32, Lex Trotman wrote:
On 6 August 2011 14:11, Matthew Brushmbrush@codebrainz.ca wrote:
On 08/05/11 21:01, Lex Trotman wrote:
[...]
Otherwise I guess it "shouldn't" be too hard to add the extra functionality to Geany but getting stuff from the module is spread around a bit and you would need to be sure the module wasn't unloaded unexpectedly as well.
How can it be unloaded?
Well I didn't read plugins.c in detail but I suspected that ATM when you deactivate a plugin in the plugin manager it will unload the module, but that would be bad for a shared module.
In fact seems to close and re-open whenever you toggle the activate checkbox, see pm_plugin_toggled() calls plugin_free() which closes the module.
Just means that you need to be careful when you patch it that the Python plugin isn't unloadable without unloading all its dependent plugins.
I think it'll be ok if it's using g_module_make_resident[1], which should ensure that first Python interpreter (libpythonX.X.so) would never get unloaded, and so always be Py_IsInitialized(). Basically, I don't care if you can't reclaim your XX megabytes of RAM until you restart Geany :)
Sounds fair, I havn't used more than about 2Gb of my 4Gb that I have noticed, despite firefox's best efforts.
BTW what are the restrictions on what Python can be used when Geany calls a Python callback, I guess everything has to be a function that runs to completion. Can it be a closure, can it use yield, can it use threads, can it do async I/O so as not to block Geany?
I forgot to mention, for callbacks, I was thinking of using PyGTK/Gobject-introspection on the GeanyObject which has all the signals on it (IIR). So plugins would do:
geany.object.connect('document-open', on_document_open_handler)
And so on...
Cheers, Matthew Brush
On Thu, 04 Aug 2011 20:01:23 -0700 Matthew Brush mbrush@codebrainz.ca wrote:
I'm seeking ideas/advice for how I can implement keybindings for Python plugins[1]. [...] I'm at the design state right now, so if anyone has any ideas for how I should implement this, using either Geany's plugin API, PyGTK directly, or something else [...]
I'm not sure what you're trying to do, but geanyextrasel attaches itself to main window's key-press and defines it's own keys. Their priority is less than the keybindings of Geany IIRC. Hope that helps.
On 6 August 2011 04:26, Dimitar Zhekov dimitar.zhekov@gmail.com wrote:
On Thu, 04 Aug 2011 20:01:23 -0700 Matthew Brush mbrush@codebrainz.ca wrote:
I'm seeking ideas/advice for how I can implement keybindings for Python plugins[1]. [...] I'm at the design state right now, so if anyone has any ideas for how I should implement this, using either Geany's plugin API, PyGTK directly, or something else [...]
I'm not sure what you're trying to do, but geanyextrasel attaches itself to main window's key-press and defines it's own keys. Their priority is less than the keybindings of Geany IIRC. Hope that helps.
The priority is a result of the fact that Geany binds to the signal first.
But plugins don't need to bind to the key event signal themselves, they can add themselves to Geany keybindings (see for eg addons) and its a nicer user experience if all the keybindings are defined in one place.
Cheers Lex
-- E-gards: Jimmy _______________________________________________ Geany-devel mailing list Geany-devel@uvena.de https://lists.uvena.de/cgi-bin/mailman/listinfo/geany-devel
On 08/05/11 11:26, Dimitar Zhekov wrote:
On Thu, 04 Aug 2011 20:01:23 -0700 Matthew Brushmbrush@codebrainz.ca wrote:
I'm seeking ideas/advice for how I can implement keybindings for Python plugins[1]. [...] I'm at the design state right now, so if anyone has any ideas for how I should implement this, using either Geany's plugin API, PyGTK directly, or something else [...]
I'm not sure what you're trying to do, but geanyextrasel attaches itself to main window's key-press and defines it's own keys. Their priority is less than the keybindings of Geany IIRC. Hope that helps.
Nice!
That's basically what I was trying to do in PyGTK, but I got caught up with having to handle completely arbitrary key combinations where geanyextrasel is looking for a specific modifier mask plus one? other key. It's probably easy to do this, but I haven't got it quite working yet.
I'm not too concerned that Geany's own (and other plugins') callbacks will run before the Python plugins' callbacks, as long as it's documented somewhere (at least until I send some patches to geany core to do what Lex suggested).
Cheers, Matthew Brush