diff --git a/README.markdown b/README.markdown
index fd42392..f21c550 100644
--- a/README.markdown
+++ b/README.markdown
@@ -60,12 +60,27 @@ To build GeanyPy you need the following dependencies:
* Python 2.6+ and development files (I don't think Python 3 will work).
* Geany 0.21+ and development files (from SVN)
+
+** For Gtk2 **
+
* PyGTK 2.0 and development files
+** For Gtk3 **
+
+* GObject Introspection is needed [pygtk not needed.]
+
On Debian/Ubuntu, the (non-Geany) dependencies can be installed like this:
- $ apt-get install python python-dev python-gtk2 python-gtk2-dev
+ $ sudo apt-get install python python-dev
+
+** For Gtk2 **
+
+ $ sudo apt-get install python-gtk2 python-gtk2-dev
+
+** For Gtk3 **
+ $ sudo apt-get install python-gi python-gi-dev
+
See Geany's documentation/website for information on compiling it from the
Subversion or Git repositories.
@@ -90,4 +105,4 @@ far. I imagine 2.7 series will also work fine.
Running on Windows
------------------
-See `README.win32` for more information.
+See `README.win32` for more information.
\ No newline at end of file
diff --git a/configure.ac b/configure.ac
index e603255..0b188b9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -22,7 +22,7 @@ LT_INIT([disable-static])
# Check for headers, libraries and packages
AC_CHECK_HEADERS([stdio.h string.h dlfcn.h])
PKG_CHECK_MODULES([GEANY], [geany >= 0.21])
-PKG_CHECK_MODULES([PYGTK], [pygtk-2.0])
+PKG_CHECK_MODULES([PYGOBJECT], [pygobject-3.0])
AX_PYTHON_DEVEL([>= '2.6'])
AX_PYTHON_LIBRARY(,[AC_MSG_ERROR([Cannot determine location of the Python DSO])])
AC_SUBST([PYTHON])
@@ -41,3 +41,5 @@ AC_CONFIG_FILES([
plugins/Makefile
])
AC_OUTPUT
+m4_pattern_allow([AM_PROG_AR])
+AM_PROG_AR
\ No newline at end of file
diff --git a/geany/__init__.py b/geany/__init__.py
index 5412f8c..7ae38f2 100644
--- a/geany/__init__.py
+++ b/geany/__init__.py
@@ -8,6 +8,7 @@
"""
import app
+import bindings
import console
import dialogs
import document
@@ -67,5 +68,8 @@
# GObject to connect signal handlers on and which emits signals.
signals = SignalManager()
+# Initialize the keybindings manager
+bindings.init()
+
import plugin
from plugin import Plugin
diff --git a/geany/console.py b/geany/console.py
index 415e4df..807ed7e 100644
--- a/geany/console.py
+++ b/geany/console.py
@@ -37,6 +37,14 @@
# inside: GtkTextView is not a terminal.
# The use case is: you have a python program, you create this widget,
# and inspect your program interiors.
+try:
+ from gi import pygtkcompat
+except ImportError:
+ pygtkcompat = None
+
+if pygtkcompat is not None:
+ pygtkcompat.enable()
+ pygtkcompat.enable_gtk(version='3.0')
import gtk
import gtk.gdk as gdk
@@ -160,7 +168,7 @@ def raw_input(self, ps=None):
self.thaw_undo()
self.__move_cursor_to(iter)
- self.scroll_to_mark(self.cursor, 0.2)
+ self.scroll_to_mark(self.cursor, 0.2, use_align=False, xalign=0.5, yalign=0.5)
self.in_raw_input = True
@@ -177,7 +185,7 @@ def on_buf_mark_set(self, buffer, iter, mark):
if iter.compare(self.__get_start()) >= 0 and \
iter.compare(self.__get_end()) <= 0:
buffer.move_mark_by_name("cursor", iter)
- self.scroll_to_mark(self.cursor, 0.2)
+ self.scroll_to_mark(self.cursor, 0.2, use_align=False, xalign=0.5, yalign=0.5)
def __insert(self, iter, text):
self.do_insert = True
@@ -286,7 +294,7 @@ def do_key_press_event(self, event, parent_type):
handled = False
if not handled:
- return parent_type.do_key_press_event(self, event)
+ return parent_type.do_key_press_event(self, event.key if hasattr(event, "key") else event)
else:
return True
@@ -296,7 +304,7 @@ def __history(self, dir):
if not new_text is None:
self.__replace_line(new_text)
self.__move_cursor(0)
- self.scroll_to_mark(self.cursor, 0.2)
+ self.scroll_to_mark(self.cursor, 0.2, use_align=False, xalign=0.5, yalign=0.5)
def __get_cursor(self):
return self.buffer.get_iter_at_mark(self.cursor)
@@ -343,7 +351,7 @@ def __delete_at_cursor(self, howmany):
self.__delete(iter, end)
def __get_width(self):
- if not (self.flags() & gtk.REALIZED):
+ if not (self.get_realized()):
return 80
layout = pango.Layout(self.get_pango_context())
letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
@@ -386,7 +394,7 @@ def __print_completions(self, completions):
self.__insert(iter, "%s%s%s" % (self.ps, line_start, line_end))
iter.set_line_offset(len(self.ps) + len(line_start))
self.__move_cursor_to(iter)
- self.scroll_to_mark(self.cursor, 0.2)
+ self.scroll_to_mark(self.cursor, 0.2, use_align=False, xalign=0.5, yalign=0.5)
def __complete(self):
text = self.__get_text(self.__get_start(), self.__get_cursor())
diff --git a/geany/loader.py b/geany/loader.py
index 14b9b73..ae4e504 100644
--- a/geany/loader.py
+++ b/geany/loader.py
@@ -8,165 +8,159 @@
class PluginLoader(object):
- plugins = {}
-
- def __init__(self, plugin_dirs):
-
- self.plugin_dirs = plugin_dirs
-
- self.available_plugins = []
- for plugin in self.iter_plugin_info():
- self.available_plugins.append(plugin)
-
- self.restore_loaded_plugins()
-
-
- def update_loaded_plugins_file(self):
- for path in self.plugin_dirs:
- if os.path.isdir(path):
- try:
- state_file = os.path.join(path, '.loaded_plugins')
- with open(state_file, 'w') as f:
- for plugfn in self.plugins:
- f.write("%s\n" % plugfn)
- except IOError as err:
- if err.errno == 13: #perms
- pass
- else:
- raise
-
-
- def restore_loaded_plugins(self):
- loaded_plugins = []
- for path in reversed(self.plugin_dirs):
- state_file = os.path.join(path, ".loaded_plugins")
- if os.path.exists(state_file):
- for line in open(state_file):
- line = line.strip()
- if line not in loaded_plugins:
- loaded_plugins.append(line)
- for filename in loaded_plugins:
- self.load_plugin(filename)
-
-
- def load_all_plugins(self):
-
- for plugin_info in self.iter_plugin_info():
- if plugin_filename.endswith('test.py'): # hack for testing
- continue
- plug = self.load_plugin(plugin_info.filename)
- if plug:
- print("Loaded plugin: %s" % plugin_info.filename)
- print(" Name: %s v%s" % (plug.name, plug.version))
- print(" Desc: %s" % plug.description)
- print(" Author: %s" % plug.author)
-
-
- def unload_all_plugins(self):
-
- for plugin in self.plugins:
- self.unload_plugin(plugin)
-
-
- def reload_all_plugins(self):
-
- self.unload_all_plugins()
- self.load_all_plugins()
-
-
- def iter_plugin_info(self):
-
- for d in self.plugin_dirs:
- if os.path.isdir(d):
- for current_file in os.listdir(d):
- #check inside folders inside the plugins dir so we can load .py files here as plugins
- current_path=os.path.abspath(os.path.join(d, current_file))
- if os.path.isdir(current_path):
- for plugin_folder_file in os.listdir(current_path):
- if plugin_folder_file.endswith('.py'):
- #loop around results if its fails to load will never reach yield
- for p in self.load_plugin_info(current_path,plugin_folder_file):
- yield p
-
- #not a sub directory so if it ends with .py lets just attempt to load it as a plugin
- if current_file.endswith('.py'):
- #loop around results if its fails to load will never reach yield
- for p in self.load_plugin_info(d,current_file):
- yield p
-
- def load_plugin_info(self,d,f):
- filename = os.path.abspath(os.path.join(d, f))
- if filename.endswith("test.py"):
- pass
- text = open(filename).read()
- module_name = os.path.basename(filename)[:-3]
- try:
- module = imp.load_source(module_name, filename)
- except ImportError as exc:
- print "Error: failed to import settings module ({})".format(exc)
- module=None
- if module:
- for k, v in module.__dict__.iteritems():
- if k == geany.Plugin.__name__:
- continue
- try:
- if issubclass(v, geany.Plugin):
- inf = PluginInfo(
- filename,
- getattr(v, '__plugin_name__'),
- getattr(v, '__plugin_version__', ''),
- getattr(v, '__plugin_description__', ''),
- getattr(v, '__plugin_author__', ''),
- v)
- yield inf
-
- except TypeError:
- continue
-
-
- def load_plugin(self, filename):
-
- for avail in self.available_plugins:
- if avail.filename == filename:
- inst = avail.cls()
- self.plugins[filename] = inst
- self.update_loaded_plugins_file()
- geany.ui_utils.set_statusbar('GeanyPy: plugin activated: %s' %
- inst.name, True)
- return inst
-
-
- def unload_plugin(self, filename):
-
- try:
- plugin = self.plugins[filename]
- name = plugin.name
- plugin.cleanup()
- del self.plugins[filename]
- self.update_loaded_plugins_file()
- geany.ui_utils.set_statusbar('GeanyPy: plugin deactivated: %s' %
- name, True)
- except KeyError:
- print("Unable to unload plugin '%s': it's not loaded" % filename)
-
-
- def reload_plugin(self, filename):
-
- if filename in self.plugins:
- self.unload_plugin(filename)
- self.load_plugin(filename)
-
-
- def plugin_has_help(self, filename):
-
- for plugin_info in self.iter_plugin_info():
- if plugin_info.filename == filename:
- return hasattr(plugin_info.cls, 'show_help')
-
-
- def plugin_has_configure(self, filename):
-
- try:
- return hasattr(self.plugins[filename], 'show_configure')
- except KeyError:
- return None
+ plugins = {}
+
+ def __init__(self, plugin_dirs):
+ self.plugin_dirs = plugin_dirs
+ self.restore_loaded_plugins()
+
+
+ def update_loaded_plugins_file(self):
+ for path in self.plugin_dirs:
+ if os.path.isdir(path):
+ try:
+ state_file = os.path.join(path, '.loaded_plugins')
+ with open(state_file, 'w') as f:
+ for plugfn in self.plugins:
+ f.write("%s\n" % plugfn)
+ except IOError as err:
+ if err.errno == 13: #perms
+ pass
+ else:
+ raise
+
+
+ def restore_loaded_plugins(self):
+ loaded_plugins = []
+ for path in reversed(self.plugin_dirs):
+ state_file = os.path.join(path, ".loaded_plugins")
+ if os.path.exists(state_file):
+ for line in open(state_file):
+ line = line.strip()
+ if line not in loaded_plugins:
+ loaded_plugins.append(line)
+ for filename in loaded_plugins:
+ self.load_plugin(filename)
+
+
+ def load_all_plugins(self):
+
+ for plugin_info in self.iter_plugin_info():
+ if plugin_filename.endswith('test.py'): # hack for testing
+ continue
+ plug = self.load_plugin(plugin_info.filename)
+ if plug:
+ print("Loaded plugin: %s" % plugin_info.filename)
+ print(" Name: %s v%s" % (plug.name, plug.version))
+ print(" Desc: %s" % plug.description)
+ print(" Author: %s" % plug.author)
+
+
+ def unload_all_plugins(self):
+
+ for plugin in self.plugins:
+ self.unload_plugin(plugin)
+
+
+ def reload_all_plugins(self):
+
+ self.unload_all_plugins()
+ self.load_all_plugins()
+
+
+ def iter_plugin_info(self):
+
+ for d in self.plugin_dirs:
+ if os.path.isdir(d):
+ for current_file in os.listdir(d):
+ #check inside folders inside the plugins dir so we can load .py files here as plugins
+ current_path=os.path.abspath(os.path.join(d, current_file))
+ if os.path.isdir(current_path):
+ for plugin_folder_file in os.listdir(current_path):
+ if plugin_folder_file.endswith('.py'):
+ #loop around results if its fails to load will never reach yield
+ for p in self.load_plugin_info(current_path,plugin_folder_file):
+ yield p
+
+ #not a sub directory so if it ends with .py lets just attempt to load it as a plugin
+ if current_file.endswith('.py'):
+ #loop around results if its fails to load will never reach yield
+ for p in self.load_plugin_info(d,current_file):
+ yield p
+
+ def load_plugin_info(self,d,f):
+ filename = os.path.abspath(os.path.join(d, f))
+ if filename.endswith("test.py"):
+ pass
+ text = open(filename).read()
+ module_name = os.path.basename(filename)[:-3]
+ try:
+ module = imp.load_source(module_name, filename)
+ except ImportError as exc:
+ print "Error: failed to import settings module ({})".format(exc)
+ module=None
+ if module:
+ for k, v in module.__dict__.iteritems():
+ if k == geany.Plugin.__name__:
+ continue
+ try:
+ if issubclass(v, geany.Plugin):
+ inf = PluginInfo(
+ filename,
+ getattr(v, '__plugin_name__'),
+ getattr(v, '__plugin_version__', ''),
+ getattr(v, '__plugin_description__', ''),
+ getattr(v, '__plugin_author__', ''),
+ v)
+ yield inf
+
+ except TypeError:
+ continue
+
+
+ def load_plugin(self, filename):
+
+ for avail in self.iter_plugin_info():
+ if avail.filename == filename:
+ inst = avail.cls()
+ self.plugins[filename] = inst
+ self.update_loaded_plugins_file()
+ geany.ui_utils.set_statusbar('GeanyPy: plugin activated: %s' %
+ inst.name, True)
+ return inst
+
+
+ def unload_plugin(self, filename):
+
+ try:
+ plugin = self.plugins[filename]
+ name = plugin.name
+ plugin.cleanup()
+ del self.plugins[filename]
+ self.update_loaded_plugins_file()
+ geany.ui_utils.set_statusbar('GeanyPy: plugin deactivated: %s' %
+ name, True)
+ except KeyError:
+ print("Unable to unload plugin '%s': it's not loaded" % filename)
+
+
+ def reload_plugin(self, filename):
+
+ if filename in self.plugins:
+ self.unload_plugin(filename)
+ self.load_plugin(filename)
+
+
+ def plugin_has_help(self, filename):
+
+ for plugin_info in self.iter_plugin_info():
+ if plugin_info.filename == filename:
+ return hasattr(plugin_info.cls, 'show_help')
+
+
+ def plugin_has_configure(self, filename):
+
+ try:
+ return hasattr(self.plugins[filename], 'show_configure')
+ except KeyError:
+ return None
\ No newline at end of file
diff --git a/geany/manager.py b/geany/manager.py
index 9c7e9a4..2a004c8 100644
--- a/geany/manager.py
+++ b/geany/manager.py
@@ -1,3 +1,12 @@
+try:
+ from gi import pygtkcompat
+except ImportError:
+ pygtkcompat = None
+
+if pygtkcompat is not None:
+ pygtkcompat.enable()
+ pygtkcompat.enable_gtk(version='3.0')
+
import gtk
import gobject
import glib
@@ -7,173 +16,179 @@
class PluginManager(gtk.Dialog):
- def __init__(self, plugin_dirs=[]):
- gtk.Dialog.__init__(self, title="Plugin Manager")
- self.loader = PluginLoader(plugin_dirs)
+ def __init__(self, parent=None, plugin_dirs=[]):
+ super(PluginManager, self).__init__(title="Plugin Manager", parent=parent, flags=gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL)
+ self.loader = PluginLoader(plugin_dirs)
- self.set_default_size(400, 450)
- self.set_has_separator(True)
- icon = self.render_icon(gtk.STOCK_PREFERENCES, gtk.ICON_SIZE_MENU)
- self.set_icon(icon)
+ self.set_default_size(400, 450)
+ icon = self.render_icon(gtk.STOCK_PREFERENCES, gtk.ICON_SIZE_MENU)
+ self.set_icon(icon)
- self.connect("response", lambda w,d: self.hide())
+ self.connect("response", lambda w,d: self.hide())
- vbox = gtk.VBox(False, 12)
- vbox.set_border_width(12)
+ vbox = gtk.VBox(False, 12)
+ vbox.set_border_width(12)
- lbl = gtk.Label("Choose plugins to load or unload:")
- lbl.set_alignment(0.0, 0.5)
- vbox.pack_start(lbl, False, False, 0)
+ lbl = gtk.Label("Choose plugins to load or unload:")
+ lbl.set_alignment(0.0, 0.5)
+ vbox.pack_start(lbl, False, False, 0)
- sw = gtk.ScrolledWindow()
- sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
- vbox.pack_start(sw, True, True, 0)
+ sw = gtk.ScrolledWindow()
+ if hasattr(sw, 'set_hexpand'):
+ sw.set_hexpand(True)
+ sw.set_vexpand(True)
+ sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
+ vbox.pack_start(sw, True, True, 0)
- self.treeview = gtk.TreeView()
- sw.add(self.treeview)
+ self.treeview = gtk.TreeView()
+ sw.add(self.treeview)
- vbox.show_all()
+ vbox.show_all()
- self.get_content_area().add(vbox)
+ self.get_content_area().add(vbox)
- action_area = self.get_action_area()
- action_area.set_spacing(0)
- action_area.set_homogeneous(False)
+ action_area = self.get_action_area()
+ action_area.set_spacing(0)
+ action_area.set_homogeneous(False)
- btn = gtk.Button(stock=gtk.STOCK_CLOSE)
- btn.set_border_width(6)
- btn.connect("clicked", lambda x: self.response(gtk.RESPONSE_CLOSE))
- action_area.pack_start(btn, False, True, 0)
- btn.show()
+ btn = gtk.Button(stock=gtk.STOCK_CLOSE)
+ btn.set_border_width(6)
+ btn.connect("clicked", lambda x: self.response(gtk.RESPONSE_CLOSE))
+ action_area.pack_start(btn, False, True, 0)
+ btn.show()
- self.btn_help = gtk.Button(stock=gtk.STOCK_HELP)
- self.btn_help.set_border_width(6)
- self.btn_help.set_no_show_all(True)
- action_area.pack_start(self.btn_help, False, True, 0)
- action_area.set_child_secondary(self.btn_help, True)
+ self.btn_help = gtk.Button(stock=gtk.STOCK_HELP)
+ self.btn_help.set_border_width(6)
+ self.btn_help.set_no_show_all(True)
+ action_area.pack_start(self.btn_help, False, True, 0)
+ action_area.set_child_secondary(self.btn_help, True)
- self.btn_prefs = gtk.Button(stock=gtk.STOCK_PREFERENCES)
- self.btn_prefs.set_border_width(6)
- self.btn_prefs.set_no_show_all(True)
- action_area.pack_start(self.btn_prefs, False, True, 0)
- action_area.set_child_secondary(self.btn_prefs, True)
+ self.btn_prefs = gtk.Button(stock=gtk.STOCK_PREFERENCES)
+ self.btn_prefs.set_border_width(6)
+ self.btn_prefs.set_no_show_all(True)
+ action_area.pack_start(self.btn_prefs, False, True, 0)
+ action_area.set_child_secondary(self.btn_prefs, True)
- action_area.show()
+ action_area.show()
- self.load_plugins_list()
+ self.load_plugins_list()
- def on_help_button_clicked(self, button, treeview, model):
- path = treeview.get_cursor()[0]
- iter = model.get_iter(path)
- filename = model.get_value(iter, 2)
- for plugin in self.loader.available_plugins:
- if plugin.filename == filename:
- plugin.cls.show_help()
- break
- else:
- print("Plugin does not support help function")
+ def on_help_button_clicked(self, button, treeview, model):
+ path = treeview.get_cursor()[0]
+ iter = model.get_iter(path)
+ filename = model.get_value(iter, 2)
+ for plugin in self.loader.available_plugins:
+ if plugin.filename == filename:
+ plugin.cls.show_help()
+ break
+ else:
+ print("Plugin does not support help function")
- def on_preferences_button_clicked(self, button, treeview, model):
- path = treeview.get_cursor()[0]
- iter = model.get_iter(path)
- filename = model.get_value(iter, 2)
- try:
- self.loader.plugins[filename].show_configure()
- except KeyError:
- print("Plugin is not loaded, can't run configure function")
+ def on_preferences_button_clicked(self, button, treeview, model):
+ path = treeview.get_cursor()[0]
+ iter = model.get_iter(path)
+ filename = model.get_value(iter, 2)
+ try:
+ self.loader.plugins[filename].show_configure()
+ except KeyError:
+ print("Plugin is not loaded, can't run configure function")
- def activate_plugin(self, filename):
- self.loader.load_plugin(filename)
+ def activate_plugin(self, filename):
+ self.loader.load_plugin(filename)
- def deactivate_plugin(self, filename):
- self.loader.unload_plugin(filename)
+ def deactivate_plugin(self, filename):
+ self.loader.unload_plugin(filename)
+
+ def deactivate_all_plugins(self):
+ self.response(gtk.RESPONSE_CLOSE)
+ self.loader.unload_all_plugins()
- def load_plugins_list(self):
- liststore = gtk.ListStore(gobject.TYPE_BOOLEAN, str, str)
+ def load_plugins_list(self):
+ liststore = gtk.ListStore(gobject.TYPE_BOOLEAN, str, str)
- self.btn_help.connect("clicked",
- self.on_help_button_clicked, self.treeview, liststore)
+ self.btn_help.connect("clicked",
+ self.on_help_button_clicked, self.treeview, liststore)
- self.btn_prefs.connect("clicked",
- self.on_preferences_button_clicked, self.treeview, liststore)
+ self.btn_prefs.connect("clicked",
+ self.on_preferences_button_clicked, self.treeview, liststore)
- self.treeview.set_model(liststore)
- self.treeview.set_headers_visible(False)
- self.treeview.set_grid_lines(True)
+ self.treeview.set_model(liststore)
+ self.treeview.set_headers_visible(False)
+ self.treeview.set_grid_lines(True)
- check_renderer = gtk.CellRendererToggle()
- check_renderer.set_radio(False)
- check_renderer.connect('toggled', self.on_plugin_load_toggled, liststore)
- text_renderer = gtk.CellRendererText()
+ check_renderer = gtk.CellRendererToggle()
+ check_renderer.set_radio(False)
+ check_renderer.connect('toggled', self.on_plugin_load_toggled, liststore)
+ text_renderer = gtk.CellRendererText()
- check_column = gtk.TreeViewColumn(None, check_renderer, active=0)
- text_column = gtk.TreeViewColumn(None, text_renderer, markup=1)
+ check_column = gtk.TreeViewColumn(None, check_renderer, active=0)
+ text_column = gtk.TreeViewColumn(None, text_renderer, markup=1)
- self.treeview.append_column(check_column)
- self.treeview.append_column(text_column)
+ self.treeview.append_column(check_column)
+ self.treeview.append_column(text_column)
- self.treeview.connect('row-activated',
- self.on_row_activated, check_renderer, liststore)
- self.treeview.connect('cursor-changed',
- self.on_selected_plugin_changed, liststore)
+ self.treeview.connect('row-activated',
+ self.on_row_activated, check_renderer, liststore)
+ self.treeview.connect('cursor-changed',
+ self.on_selected_plugin_changed, liststore)
- self.load_sorted_plugins_info(liststore)
+ self.load_sorted_plugins_info(liststore)
- def load_sorted_plugins_info(self, list_store):
+ def load_sorted_plugins_info(self, list_store):
- plugin_info_list = list(self.loader.iter_plugin_info())
- #plugin_info_list.sort(key=lambda pi: pi[1])
+ plugin_info_list = list(self.loader.iter_plugin_info())
+ #plugin_info_list.sort(key=lambda pi: pi[1])
- for plugin_info in plugin_info_list:
+ for plugin_info in plugin_info_list:
- lbl = str('%s %s\n%s\n' +
- 'Author: %s\n' +
- 'Filename: %s') % (
- glib.markup_escape_text(plugin_info.name),
- glib.markup_escape_text(plugin_info.version),
- glib.markup_escape_text(plugin_info.description),
- glib.markup_escape_text(plugin_info.author),
- glib.markup_escape_text(plugin_info.filename))
+ lbl = str('%s %s\n%s\n' +
+ 'Author: %s\n' +
+ 'Filename: %s') % (
+ glib.markup_escape_text(plugin_info.name),
+ glib.markup_escape_text(plugin_info.version),
+ glib.markup_escape_text(plugin_info.description),
+ glib.markup_escape_text(plugin_info.author),
+ glib.markup_escape_text(plugin_info.filename))
- loaded = plugin_info.filename in self.loader.plugins
+ loaded = plugin_info.filename in self.loader.plugins
- list_store.append([loaded, lbl, plugin_info.filename])
+ list_store.append([loaded, lbl, plugin_info.filename])
- def on_selected_plugin_changed(self, treeview, model):
+ def on_selected_plugin_changed(self, treeview, model):
- path = treeview.get_cursor()[0]
- iter = model.get_iter(path)
- filename = model.get_value(iter, 2)
- active = model.get_value(iter, 0)
+ path = treeview.get_cursor()[0]
+ iter = model.get_iter(path)
+ filename = model.get_value(iter, 2)
+ active = model.get_value(iter, 0)
- if self.loader.plugin_has_configure(filename):
- self.btn_prefs.set_visible(True)
- else:
- self.btn_prefs.set_visible(False)
+ if self.loader.plugin_has_configure(filename):
+ self.btn_prefs.set_visible(True)
+ else:
+ self.btn_prefs.set_visible(False)
- if self.loader.plugin_has_help(filename):
- self.btn_help.set_visible(True)
- else:
- self.btn_help.set_visible(False)
+ if self.loader.plugin_has_help(filename):
+ self.btn_help.set_visible(True)
+ else:
+ self.btn_help.set_visible(False)
- def on_plugin_load_toggled(self, cell, path, model):
- active = not cell.get_active()
- iter = model.get_iter(path)
- model.set_value(iter, 0, active)
- if active:
- self.activate_plugin(model.get_value(iter, 2))
- else:
- self.deactivate_plugin(model.get_value(iter, 2))
+ def on_plugin_load_toggled(self, cell, path, model):
+ active = not cell.get_active()
+ iter = model.get_iter(path)
+ model.set_value(iter, 0, active)
+ if active:
+ self.activate_plugin(model.get_value(iter, 2))
+ else:
+ self.deactivate_plugin(model.get_value(iter, 2))
- def on_row_activated(self, tvw, path, view_col, cell, model):
- self.on_plugin_load_toggled(cell, path, model)
+ def on_row_activated(self, tvw, path, view_col, cell, model):
+ self.on_plugin_load_toggled(cell, path, model)
diff --git a/geany/signalmanager.py b/geany/signalmanager.py
index 45a434e..16d7910 100644
--- a/geany/signalmanager.py
+++ b/geany/signalmanager.py
@@ -3,56 +3,62 @@
all signals on. The signals are emitted from the C code in signalmanager.c,
where the Geany types get wrapped in PyObject types.
"""
+try:
+ from gi import pygtkcompat
+except ImportError:
+ pygtkcompat = None
+if pygtkcompat is not None:
+ pygtkcompat.enable()
+ pygtkcompat.enable_gtk(version='3.0')
import gobject
class SignalManager(gobject.GObject):
- """
- Manages callback functions for events emitted by Geany's internal GObject.
- """
- __gsignals__ = {
- 'build-start': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- ()),
- 'document-activate': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- (gobject.TYPE_PYOBJECT,)),
- 'document-before-save': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- (gobject.TYPE_PYOBJECT,)),
- 'document-close': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- (gobject.TYPE_PYOBJECT,)),
- 'document-filetype-set': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)),
- 'document-new': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- (gobject.TYPE_PYOBJECT,)),
- 'document-open': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- (gobject.TYPE_PYOBJECT,)),
- 'document-reload': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- (gobject.TYPE_PYOBJECT,)),
- 'document-save': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- (gobject.TYPE_PYOBJECT,)),
- 'editor-notify': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_BOOLEAN,
- (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)),
- 'geany-startup-complete': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- ()),
- 'project-close': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- ()),
- 'project-dialog-confirmed': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- (gobject.TYPE_PYOBJECT,)),
- 'project-dialog-open': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- (gobject.TYPE_PYOBJECT,)),
- 'project-dialog-close': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- (gobject.TYPE_PYOBJECT,)),
- 'project-open': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- (gobject.TYPE_PYOBJECT,)),
- 'project-save': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- (gobject.TYPE_PYOBJECT,)),
- 'update-editor-menu': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
- (gobject.TYPE_STRING, gobject.TYPE_INT,
- gobject.TYPE_PYOBJECT)),
- } # __gsignals__
+ """
+ Manages callback functions for events emitted by Geany's internal GObject.
+ """
+ __gsignals__ = {
+ 'build-start': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ ()),
+ 'document-activate': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ (gobject.TYPE_PYOBJECT,)),
+ 'document-before-save': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ (gobject.TYPE_PYOBJECT,)),
+ 'document-close': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ (gobject.TYPE_PYOBJECT,)),
+ 'document-filetype-set': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)),
+ 'document-new': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ (gobject.TYPE_PYOBJECT,)),
+ 'document-open': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ (gobject.TYPE_PYOBJECT,)),
+ 'document-reload': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ (gobject.TYPE_PYOBJECT,)),
+ 'document-save': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ (gobject.TYPE_PYOBJECT,)),
+ 'editor-notify': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_BOOLEAN,
+ (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)),
+ 'geany-startup-complete': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ ()),
+ 'project-close': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ ()),
+ 'project-dialog-confirmed': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ (gobject.TYPE_PYOBJECT,)),
+ 'project-dialog-open': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ (gobject.TYPE_PYOBJECT,)),
+ 'project-dialog-close': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ (gobject.TYPE_PYOBJECT,)),
+ 'project-open': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ (gobject.TYPE_PYOBJECT,)),
+ 'project-save': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ (gobject.TYPE_PYOBJECT,)),
+ 'update-editor-menu': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
+ (gobject.TYPE_STRING, gobject.TYPE_INT,
+ gobject.TYPE_PYOBJECT)),
+ } # __gsignals__
- def __init__(self):
- self.__gobject_init__()
-
-gobject.type_register(SignalManager)
+ def __init__(self):
+ super(SignalManager, self).__init__()
+gobject.type_register(SignalManager)
\ No newline at end of file
diff --git a/m4/gtk.m4 b/m4/gtk.m4
new file mode 100644
index 0000000..1958be1
--- /dev/null
+++ b/m4/gtk.m4
@@ -0,0 +1,26 @@
+dnl checks for the GTK version to build against (2 or 3)
+dnl defines GP_GTK_PACKAGE (e.g. "gtk+-2.0"), GP_GTK_VERSION (e.g. "2.24") and
+dnl GP_GTK_VERSION_MAJOR (e.g. "2"); and defines the GP_GTK3 AM conditional
+AC_DEFUN([GP_CHECK_GTK_VERSION],
+[
+ AC_REQUIRE([AC_PROG_AWK])
+ AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+
+ _gtk_req=$(${PKG_CONFIG} --print-requires geany | ${AWK} '/^gtk\+-/{print}')
+ GP_GTK_PACKAGE=$(echo ${_gtk_req} | ${AWK} '{print $[]1}')
+ GP_GTK_VERSION=$(echo ${_gtk_req} | ${AWK} '{print $[]3}')
+ GP_GTK_VERSION_MAJOR=$(echo ${GP_GTK_VERSION} | cut -d. -f1)
+ AC_SUBST([GP_GTK_PACKAGE])
+ AC_SUBST([GP_GTK_VERSION])
+ AC_SUBST([GP_GTK_VERSION_MAJOR])
+
+ AM_CONDITIONAL([GP_GTK3], [test "x$GP_GTK_VERSION_MAJOR" = x3])
+
+])
+
+dnl executes $1 if GTK3 is used, and $2 otherwise
+AC_DEFUN([GP_CHECK_GTK3],
+[
+ AC_REQUIRE([GP_CHECK_GTK_VERSION])
+ AS_IF([test ${GP_GTK_VERSION_MAJOR} = 3],[$1],[$2])
+])
\ No newline at end of file
diff --git a/plugins/console.py b/plugins/console.py
index ee26ae3..d6bbfaf 100644
--- a/plugins/console.py
+++ b/plugins/console.py
@@ -1,3 +1,12 @@
+try:
+ from gi import pygtkcompat
+except ImportError:
+ pygtkcompat = None
+
+if pygtkcompat is not None:
+ pygtkcompat.enable()
+ pygtkcompat.enable_gtk(version='3.0')
+
import os
from ConfigParser import SafeConfigParser
import geany
@@ -9,305 +18,304 @@
WIDGET_STATES = [ gtk.STATE_NORMAL, gtk.STATE_ACTIVE, gtk.STATE_PRELIGHT,
- gtk.STATE_SELECTED, gtk.STATE_INSENSITIVE ]
+ gtk.STATE_SELECTED, gtk.STATE_INSENSITIVE ]
class ConsolePlugin(geany.Plugin):
- __plugin_name__ = "Python Console"
- __plugin_description__ = ("Installs a Python console that allows you " +
- "to use the Geany API.")
- __plugin_version__ = "0.01"
- __plugin_author__ = "Matthew Brush "
-
- _font = "Monospace 9"
- _bg = "#FFFFFF"
- _fg = "#000000"
- _banner = ("Geany Python Console\n You can access the Geany Python " +
- "API by importing the `geany' module.\n")
- _use_rl_completer = True
-
- _builder = None
-
- def __init__(self):
- geany.Plugin.__init__(self)
- self.load_config()
- self.install_console()
-
-
- def cleanup(self):
- #self.save_config()
- self.on_save_config_timeout() # do it now
- self.uninstall_console()
-
-
- def load_config(self):
- self.cfg_path = os.path.join(geany.app.configdir, "plugins", "pyconsole.conf")
- self.cfg = SafeConfigParser()
- self.cfg.read(self.cfg_path)
-
-
- def save_config(self):
- gobject.idle_add(self.on_save_config_timeout)
-
-
- def on_save_config_timeout(self, data=None):
- self.cfg.write(open(self.cfg_path, 'w'))
- return False
-
-
- def install_console(self):
-
- # load general settings
- self.banner = self.banner
- self.use_rl_completer = self.use_rl_completer
-
- self.swin = gtk.ScrolledWindow()
- self.swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
- self.console = geany.console.Console(banner = self.banner,
- use_rlcompleter = self.use_rl_completer)
- self.console.connect("populate-popup", self.on_console_populate_popup)
-
- # apply appearance settings
- self.font = self.font
- self.bg = self.bg
- self.fg = self.fg
-
- self.swin.add(self.console)
- geany.main_widgets.message_window_notebook.append_page(self.swin,
- gtk.Label("Python"))
-
- self.swin.show_all()
- self.save_config()
-
- def uninstall_console(self):
- self.swin.destroy()
-
-
- def _get_font(self):
- if self.cfg.has_section('appearances'):
- if self.cfg.has_option('appearances', 'font'):
- return self.cfg.get('appearances', 'font')
- return self._font
- def _set_font(self, font):
- self._font = font
- font_desc = pango.FontDescription(font)
- self.console.modify_font(font_desc)
- if not self.cfg.has_section('appearances'):
- self.cfg.add_section('appearances')
- self.cfg.set('appearances', 'font', self._font)
- self.save_config()
- font = property(_get_font, _set_font)
-
-
- def _get_bg(self):
- if self.cfg.has_section('appearances'):
- if self.cfg.has_option('appearances', 'bg_color'):
- return self.cfg.get('appearances', 'bg_color')
- return self._bg
- def _set_bg(self, bg):
- self._bg = bg
- color = gdk.color_parse(self._bg)
- for state in WIDGET_STATES:
- self.console.modify_bg(state, color)
- self.console.modify_base(state, color)
- if not self.cfg.has_section('appearances'):
- self.cfg.add_section('appearances')
- self.cfg.set('appearances', 'bg_color', self._bg)
- self.save_config()
- bg = property(_get_bg, _set_bg)
-
-
- def _get_fg(self):
- if self.cfg.has_section('appearances'):
- if self.cfg.has_option('appearances', 'fg_color'):
- return self.cfg.get('appearances', 'fg_color')
- return self._fg
- def _set_fg(self, fg):
- self._fg = fg
- color = gdk.color_parse(self._fg)
- for state in WIDGET_STATES:
- self.console.modify_fg(state, color)
- self.console.modify_text(state, color)
- if not self.cfg.has_section('appearances'):
- self.cfg.add_section('appearances')
- self.cfg.set('appearances', 'fg_color', self._fg)
- self.save_config()
- fg = property(_get_fg, _set_fg)
-
-
- def _get_banner(self):
- if self.cfg.has_section('general'):
- if self.cfg.has_option('general', 'banner'):
- return self.cfg.get('general', 'banner')
- return self._banner
- def _set_banner(self, banner):
- self._banner = banner
- if not self.cfg.has_section('general'):
- self.cfg.add_section('general')
- self.cfg.set('general', 'banner', self._banner)
- self.save_config()
- banner = property(_get_banner, _set_banner)
-
-
- def _get_use_rl_completer(self):
- if self.cfg.has_section('general'):
- if self.cfg.has_option('general', 'use_rl_completer'):
- return self.cfg.getboolean('general', 'use_rl_completer')
- return self._use_rl_completer
- def _set_use_rl_completer(self, use_rl_completer):
- self._use_rl_completer = use_rl_completer
- if not self.cfg.has_section('general'):
- self.cfg.add_section('general')
- self.cfg.set('general', 'use_rl_completer',
- str(self._use_rl_completer).lower())
- self.save_config()
- use_rl_completer = property(_get_use_rl_completer, _set_use_rl_completer)
-
-
- def on_console_populate_popup(self, textview, menu, data=None):
- item = gtk.SeparatorMenuItem()
- item.show()
- menu.append(item)
- item = gtk.ImageMenuItem(stock_id=gtk.STOCK_PREFERENCES)
- item.show()
- menu.append(item)
- item.connect("activate", lambda w,d=None: self.show_configure())
-
-
- def on_banner_changed(self, text_buf, data=None):
- self.banner = text_buf.get_text(text_buf.get_start_iter(), text_buf.get_end_iter())
-
- def on_use_rl_completer_toggled(self, chk_btn, data=None):
- self.use_rl_completer = chk_btn.get_active()
-
- def on_font_changed(self, font_btn, data=None):
- self.font = font_btn.get_font_name()
-
- def on_fg_color_changed(self, clr_btn, data=None):
- self.fg = clr_btn.get_color().to_string()
-
- def on_bg_color_changed(self, clr_btn, data=None):
- self.bg = clr_btn.get_color().to_string()
-
-
- def show_configure(self):
- dialog = gtk.Dialog("Configure Python Console",
- geany.main_widgets.window,
- gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
- (gtk.STOCK_CLOSE, gtk.RESPONSE_ACCEPT))
-
- dialog.set_has_separator(True)
-
- content_area = dialog.get_content_area()
- content_area.set_border_width(6)
-
- vbox = gtk.VBox(spacing=6)
- vbox.set_border_width(6)
-
- lbl = gtk.Label()
- lbl.set_use_markup(True)
- lbl.set_markup("General")
-
- fra_general = gtk.Frame("")
- fra_general.set_shadow_type(gtk.SHADOW_NONE)
- fra_general.set_label_widget(lbl)
-
- al_general = gtk.Alignment(0.0, 0.0, 1.0, 1.0)
- al_general.set_padding(0, 0, 12, 0)
- fra_general.add(al_general)
-
- tbl = gtk.Table(3, 2, False)
- tbl.set_row_spacings(6)
- tbl.set_col_spacings(6)
- tbl.set_border_width(6)
-
- lbl = gtk.Label("Banner:")
- lbl.set_alignment(0.0, 0.0)
-
- tvw = gtk.TextView()
- tvw.get_buffer().set_text(self.banner)
- tvw.get_buffer().connect("changed", self.on_banner_changed)
+ __plugin_name__ = "Python Console"
+ __plugin_description__ = ("Installs a Python console that allows you " +
+ "to use the Geany API.")
+ __plugin_version__ = "0.01"
+ __plugin_author__ = "Matthew Brush "
- swin = gtk.ScrolledWindow()
- swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- swin.set_shadow_type(gtk.SHADOW_ETCHED_IN)
- swin.add(tvw)
+ _font = "Monospace 9"
+ _bg = "#FFFFFF"
+ _fg = "#000000"
+ _banner = ("Geany Python Console\n You can access the Geany Python " +
+ "API by importing the `geany' module.\n")
+ _use_rl_completer = True
+
+ _builder = None
+
+ def __init__(self):
+ super(ConsolePlugin, self).__init__()
+ self.load_config()
+ self.install_console()
+
+
+ def cleanup(self):
+ #self.save_config()
+ self.on_save_config_timeout() # do it now
+ self.uninstall_console()
+
+
+ def load_config(self):
+ self.cfg_path = os.path.join(geany.app.configdir, "plugins", "pyconsole.conf")
+ self.cfg = SafeConfigParser()
+ self.cfg.read(self.cfg_path)
+
+
+ def save_config(self):
+ gobject.idle_add(self.on_save_config_timeout)
+
+
+ def on_save_config_timeout(self, data=None):
+ self.cfg.write(open(self.cfg_path, 'w'))
+ return False
+
+
+ def install_console(self):
+
+ # load general settings
+ self.banner = self.banner
+ self.use_rl_completer = self.use_rl_completer
+
+ self.swin = gtk.ScrolledWindow()
+ self.swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
+ self.console = geany.console.Console(banner = self.banner,
+ use_rlcompleter = self.use_rl_completer)
+ self.console.connect("populate-popup", self.on_console_populate_popup)
+
+ # apply appearance settings
+ self.font = self.font
+ self.bg = self.bg
+ self.fg = self.fg
+
+ self.swin.add(self.console)
+ geany.main_widgets.message_window_notebook.append_page(self.swin,
+ gtk.Label("Python"))
+
+ self.swin.show_all()
+ self.save_config()
+
+ def uninstall_console(self):
+ self.swin.destroy()
+
+
+ def _get_font(self):
+ if self.cfg.has_section('appearances'):
+ if self.cfg.has_option('appearances', 'font'):
+ return self.cfg.get('appearances', 'font')
+ return self._font
+ def _set_font(self, font):
+ self._font = font
+ font_desc = pango.FontDescription(font)
+ self.console.modify_font(font_desc)
+ if not self.cfg.has_section('appearances'):
+ self.cfg.add_section('appearances')
+ self.cfg.set('appearances', 'font', self._font)
+ self.save_config()
+ font = property(_get_font, _set_font)
+
+
+ def _get_bg(self):
+ if self.cfg.has_section('appearances'):
+ if self.cfg.has_option('appearances', 'bg_color'):
+ return self.cfg.get('appearances', 'bg_color')
+ return self._bg
+ def _set_bg(self, bg):
+ self._bg = bg
+ color = gdk.color_parse(self._bg)
+ for state in WIDGET_STATES:
+ self.console.modify_bg(state, color)
+ self.console.modify_base(state, color)
+ if not self.cfg.has_section('appearances'):
+ self.cfg.add_section('appearances')
+ self.cfg.set('appearances', 'bg_color', self._bg)
+ self.save_config()
+ bg = property(_get_bg, _set_bg)
+
+
+ def _get_fg(self):
+ if self.cfg.has_section('appearances'):
+ if self.cfg.has_option('appearances', 'fg_color'):
+ return self.cfg.get('appearances', 'fg_color')
+ return self._fg
+ def _set_fg(self, fg):
+ self._fg = fg
+ color = gdk.color_parse(self._fg)
+ for state in WIDGET_STATES:
+ self.console.modify_fg(state, color)
+ self.console.modify_text(state, color)
+ if not self.cfg.has_section('appearances'):
+ self.cfg.add_section('appearances')
+ self.cfg.set('appearances', 'fg_color', self._fg)
+ self.save_config()
+ fg = property(_get_fg, _set_fg)
+
+
+ def _get_banner(self):
+ if self.cfg.has_section('general'):
+ if self.cfg.has_option('general', 'banner'):
+ return self.cfg.get('general', 'banner')
+ return self._banner
+ def _set_banner(self, banner):
+ self._banner = banner
+ if not self.cfg.has_section('general'):
+ self.cfg.add_section('general')
+ self.cfg.set('general', 'banner', self._banner)
+ self.save_config()
+ banner = property(_get_banner, _set_banner)
+
+
+ def _get_use_rl_completer(self):
+ if self.cfg.has_section('general'):
+ if self.cfg.has_option('general', 'use_rl_completer'):
+ return self.cfg.getboolean('general', 'use_rl_completer')
+ return self._use_rl_completer
+ def _set_use_rl_completer(self, use_rl_completer):
+ self._use_rl_completer = use_rl_completer
+ if not self.cfg.has_section('general'):
+ self.cfg.add_section('general')
+ self.cfg.set('general', 'use_rl_completer',
+ str(self._use_rl_completer).lower())
+ self.save_config()
+ use_rl_completer = property(_get_use_rl_completer, _set_use_rl_completer)
+
+
+ def on_console_populate_popup(self, textview, menu, data=None):
+ item = gtk.SeparatorMenuItem()
+ item.show()
+ menu.append(item)
+ item = gtk.ImageMenuItem(stock_id=gtk.STOCK_PREFERENCES)
+ item.show()
+ menu.append(item)
+ item.connect("activate", lambda w,d=None: self.show_configure())
+
+
+ def on_banner_changed(self, text_buf, data=None):
+ self.banner = text_buf.get_text(text_buf.get_start_iter(), text_buf.get_end_iter())
+
+ def on_use_rl_completer_toggled(self, chk_btn, data=None):
+ self.use_rl_completer = chk_btn.get_active()
+
+ def on_font_changed(self, font_btn, data=None):
+ self.font = font_btn.get_font_name()
+
+ def on_fg_color_changed(self, clr_btn, data=None):
+ self.fg = clr_btn.get_color().to_string()
+
+ def on_bg_color_changed(self, clr_btn, data=None):
+ self.bg = clr_btn.get_color().to_string()
+
+
+ def show_configure(self):
+ dialog = gtk.Dialog("Configure Python Console",
+ geany.main_widgets.window,
+ gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+ (gtk.STOCK_CLOSE, gtk.RESPONSE_ACCEPT))
+
+ #dialog.set_has_separator(True)
+
+ content_area = dialog.get_content_area()
+ content_area.set_border_width(6)
+
+ vbox = gtk.VBox(spacing=6)
+ vbox.set_border_width(6)
+
+ lbl = gtk.Label()
+ lbl.set_use_markup(True)
+ lbl.set_markup("General")
+
+ fra_general = gtk.Frame()
+ fra_general.set_shadow_type(gtk.SHADOW_NONE)
+ fra_general.set_label_widget(lbl)
+
+ al_general = gtk.Alignment(0.0, 0.0, 1.0, 1.0)
+ al_general.set_padding(0, 0, 12, 0)
+ fra_general.add(al_general)
+
+ tbl = gtk.Table(3, 2, False)
+ tbl.set_row_spacings(6)
+ tbl.set_col_spacings(6)
+ tbl.set_border_width(6)
+
+ lbl = gtk.Label("Banner:")
+ lbl.set_alignment(0.0, 0.0)
+
+ tvw = gtk.TextView()
+ tvw.get_buffer().set_text(self.banner)
+ tvw.get_buffer().connect("changed", self.on_banner_changed)
- tbl.attach(lbl, 0, 1, 0, 1, gtk.FILL, gtk.FILL, 0, 0)
- tbl.attach(swin, 1, 2, 0, 1, gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL, 0, 0)
+ swin = gtk.ScrolledWindow()
+ swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ swin.set_shadow_type(gtk.SHADOW_ETCHED_IN)
+ swin.add(tvw)
- lbl = gtk.Label("")
- lbl.set_alignment(0.0, 0.5)
+ tbl.attach(lbl, 0, 1, 0, 1, gtk.FILL, gtk.FILL, 0, 0)
+ tbl.attach(swin, 1, 2, 0, 1, gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL, 0, 0)
- check = gtk.CheckButton("Use Readline")
- if self.use_rl_completer:
- check.set_active(True)
- check.connect("toggled", self.on_use_rl_completer_toggled)
+ lbl = gtk.Label("")
+ lbl.set_alignment(0.0, 0.5)
- tbl.attach(lbl, 0, 1, 1, 2, gtk.FILL, gtk.FILL, 0, 0)
- tbl.attach(check, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 0, 0)
+ check = gtk.CheckButton("Use Readline")
+ if self.use_rl_completer:
+ check.set_active(True)
+ check.connect("toggled", self.on_use_rl_completer_toggled)
- lbl = gtk.Label("")
- lbl.set_alignment(0.0, 0.5)
- lbl.set_use_markup(True)
- lbl.set_markup('' +
- 'Note: General settings will be applied when console is reloaded.' +
- '')
- tbl.attach(lbl, 0, 2, 2, 3, gtk.FILL, gtk.FILL, 0, 0)
+ tbl.attach(lbl, 0, 1, 1, 2, gtk.FILL, gtk.FILL, 0, 0)
+ tbl.attach(check, 1, 2, 1, 2, gtk.FILL, gtk.FILL, 0, 0)
- al_general.add(tbl)
+ lbl = gtk.Label("")
+ lbl.set_alignment(0.0, 0.5)
+ lbl.set_use_markup(True)
+ lbl.set_markup('' +
+ 'Note: General settings will be applied when console is reloaded.' +
+ '')
+ tbl.attach(lbl, 0, 2, 2, 3, gtk.FILL, gtk.FILL, 0, 0)
- lbl = gtk.Label()
- lbl.set_use_markup(True)
- lbl.set_markup("Appearances")
+ al_general.add(tbl)
- fra_appearances = gtk.Frame("")
- fra_appearances.set_shadow_type(gtk.SHADOW_NONE)
- fra_appearances.set_label_widget(lbl)
+ lbl = gtk.Label()
+ lbl.set_use_markup(True)
+ lbl.set_markup("Appearances")
- al_appearances = gtk.Alignment(0.0, 0.0, 1.0, 1.0)
- al_appearances.set_padding(0, 0, 12, 0)
- fra_appearances.add(al_appearances)
+ fra_appearances = gtk.Frame()
+ fra_appearances.set_shadow_type(gtk.SHADOW_NONE)
+ fra_appearances.set_label_widget(lbl)
- tbl = gtk.Table(3, 2, False)
- tbl.set_row_spacings(6)
- tbl.set_col_spacings(6)
- tbl.set_border_width(6)
+ al_appearances = gtk.Alignment(0.0, 0.0, 1.0, 1.0)
+ al_appearances.set_padding(0, 0, 12, 0)
+ fra_appearances.add(al_appearances)
- lbl = gtk.Label("Font:")
- lbl.set_alignment(0.0, 0.5)
+ tbl = gtk.Table(3, 2, False)
+ tbl.set_row_spacings(6)
+ tbl.set_col_spacings(6)
+ tbl.set_border_width(6)
- btn = gtk.FontButton(self.font)
- btn.connect("font-set", self.on_font_changed)
+ lbl = gtk.Label("Font:")
+ lbl.set_alignment(0.0, 0.5)
- tbl.attach(lbl, 0, 1, 0, 1, gtk.FILL, gtk.FILL, 0, 0)
- tbl.attach(btn, 1, 2, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL, 0, 0)
+ btn = gtk.FontButton(self.font)
+ btn.connect("font-set", self.on_font_changed)
- lbl = gtk.Label("FG Color:")
- lbl.set_alignment(0.0, 0.5)
+ tbl.attach(lbl, 0, 1, 0, 1, gtk.FILL, gtk.FILL, 0, 0)
+ tbl.attach(btn, 1, 2, 0, 1, gtk.FILL | gtk.EXPAND, gtk.FILL, 0, 0)
- btn = gtk.ColorButton(gdk.color_parse(self.fg))
- btn.connect("color-set", self.on_fg_color_changed)
+ lbl = gtk.Label("FG Color:")
+ lbl.set_alignment(0.0, 0.5)
+ btn = gtk.ColorButton(color=gdk.color_parse(self.fg))
+ btn.connect("color-set", self.on_fg_color_changed)
- tbl.attach(lbl, 0, 1, 1, 2, gtk.FILL, gtk.FILL, 0, 0)
- tbl.attach(btn, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL, 0, 0)
+ tbl.attach(lbl, 0, 1, 1, 2, gtk.FILL, gtk.FILL, 0, 0)
+ tbl.attach(btn, 1, 2, 1, 2, gtk.FILL | gtk.EXPAND, gtk.FILL, 0, 0)
- lbl = gtk.Label("BG Color:")
- lbl.set_alignment(0.0, 0.5)
+ lbl = gtk.Label("BG Color:")
+ lbl.set_alignment(0.0, 0.5)
- btn = gtk.ColorButton(gdk.color_parse(self.bg))
- btn.connect("color-set", self.on_bg_color_changed)
+ btn = gtk.ColorButton(color=gdk.color_parse(self.bg))
+ btn.connect("color-set", self.on_bg_color_changed)
- tbl.attach(lbl, 0, 1, 2, 3, gtk.FILL, gtk.FILL, 0, 0)
- tbl.attach(btn, 1, 2, 2, 3, gtk.FILL | gtk.EXPAND, gtk.FILL, 0, 0)
+ tbl.attach(lbl, 0, 1, 2, 3, gtk.FILL, gtk.FILL, 0, 0)
+ tbl.attach(btn, 1, 2, 2, 3, gtk.FILL | gtk.EXPAND, gtk.FILL, 0, 0)
- al_appearances.add(tbl)
+ al_appearances.add(tbl)
- vbox.pack_start(fra_general, True, True, 0)
- vbox.pack_start(fra_appearances, False, True, 0)
- content_area.pack_start(vbox, True, True, 0)
- content_area.show_all()
+ vbox.pack_start(fra_general, True, True, 0)
+ vbox.pack_start(fra_appearances, False, True, 0)
+ content_area.pack_start(vbox, True, True, 0)
+ content_area.show_all()
- dialog.run()
- dialog.destroy()
+ dialog.run()
+ dialog.destroy()
\ No newline at end of file
diff --git a/plugins/demo.py b/plugins/demo.py
index 77ef0d0..8b8a091 100644
--- a/plugins/demo.py
+++ b/plugins/demo.py
@@ -9,10 +9,10 @@ class DemoPlugin(geany.Plugin):
__plugin_author__ = "Matthew Brush "
def __init__(self):
- geany.Plugin.__init__(self)
+ super(DemoPlugin, self).__init__()
print("Demo plugin initializing")
doc = geany.document.new_file()
doc.editor.scintilla.set_text("Hello from the Demo plugin")
def cleanup(self):
- print("Demo plugin cleaning up")
+ print("Demo plugin cleaning up")
\ No newline at end of file
diff --git a/plugins/hello.py b/plugins/hello.py
index dfa7d27..d6153b8 100644
--- a/plugins/hello.py
+++ b/plugins/hello.py
@@ -1,3 +1,11 @@
+try:
+ from gi import pygtkcompat
+except ImportError:
+ pygtkcompat = None
+
+if pygtkcompat is not None:
+ pygtkcompat.enable()
+ pygtkcompat.enable_gtk(version='3.0')
import gtk
import geany
@@ -18,4 +26,4 @@ def cleanup(self):
self.menu_item.destroy()
def on_hello_item_clicked(widget, data):
- geany.dialogs.show_msgbox("Hello World")
+ geany.dialogs.show_msgbox("Hello World")
\ No newline at end of file
diff --git a/src/Makefile.am b/src/Makefile.am
index 06a258d..d926ea2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,13 +2,14 @@ geanyplugin_LTLIBRARIES = geanypy.la
geanyplugindir = $(libdir)/geany
geanypy_la_LDFLAGS = -module -avoid-version -Wl,--export-dynamic
-geanypy_la_CPPFLAGS = @GEANY_CFLAGS@ @PYGTK_CFLAGS@ @PYTHON_CPPFLAGS@ \
+geanypy_la_CPPFLAGS = @GEANY_CFLAGS@ @PYGOBJECT_CFLAGS@ @PYTHON_CPPFLAGS@ \
-DGEANYPY_PYTHON_DIR="\"$(libdir)/geany/geanypy\"" \
-DGEANYPY_PLUGIN_DIR="\"$(datadir)/geany/geanypy/plugins\"" \
-UHAVE_CONFIG_H
-geanypy_la_LIBADD = @GEANY_LIBS@ @PYGTK_LIBS@ @PYTHON_LDFLAGS@ \
+geanypy_la_LIBADD = @GEANY_LIBS@ @PYGOBJECT_LIBS@ @PYTHON_LDFLAGS@ \
@PYTHON_EXTRA_LIBS@ @PYTHON_EXTRA_LDFLAGS@
geanypy_la_SOURCES = geanypy-app.c \
+ geanypy-bindings.c \
geanypy-dialogs.c \
geanypy-document.c geanypy-document.h \
geanypy-editor.c geanypy-editor.h \
@@ -32,4 +33,4 @@ geanypy_la_SOURCES = geanypy-app.c \
geanypy-search.c \
geanypy-signalmanager.c geanypy-signalmanager.h \
geanypy-templates.c \
- geanypy-uiutils.c geanypy-uiutils.h
+ geanypy-uiutils.c geanypy-uiutils.h
\ No newline at end of file
diff --git a/src/geanypy-bindings.c b/src/geanypy-bindings.c
new file mode 100644
index 0000000..5506faf
--- /dev/null
+++ b/src/geanypy-bindings.c
@@ -0,0 +1,236 @@
+#include "geanypy.h"
+
+
+#define KB_MAX 256
+#define KB_LABEL_MAX 255
+
+typedef struct
+{
+ gchar *kg_name;
+ GeanyKeyGroup *group;
+ GeanyKeyBinding *bindings[KB_MAX] ;
+ PyObject *callbacks[KB_MAX];
+ PyObject *user_data[KB_MAX];
+ gchar labels[KB_MAX][KB_LABEL_MAX];
+ gboolean slots[KB_MAX];
+ gboolean registered[KB_MAX];
+ gboolean initialized;
+} KbManager;
+
+
+static KbManager manager = { NULL };
+
+
+static gchar *name_to_key(const gchar *name)
+{
+ gchar *ptr, *ret = g_strdup(name);
+ for (ptr = ret; *ptr != '\0'; ptr++) {
+ if (!isalnum(*ptr))
+ *ptr = '_';
+ }
+ if (strlen(ret) && !isalpha(ret[0]))
+ ret[0] = '_';
+ return ret;
+}
+
+
+static uint next_key_id(gboolean *found)
+{
+ uint i;
+ for (i = 0; i < KB_MAX; i++)
+ {
+ if (!manager.slots[i])
+ {
+ if (found)
+ *found = TRUE;
+ return i;
+ }
+ }
+ if (found)
+ *found = FALSE;
+ return 0;
+}
+
+
+static void on_keybinding_activate(guint key_id)
+{
+ PyObject *args;
+
+ g_return_if_fail(key_id < KB_MAX);
+
+ if (manager.slots[key_id])
+ {
+ g_return_if_fail(manager.callbacks[key_id]);
+ g_return_if_fail(PyCallable_Check(manager.callbacks[key_id]));
+
+ if (manager.user_data[key_id])
+ args = Py_BuildValue("(iO)", key_id, manager.user_data[key_id]);
+ else
+ args = Py_BuildValue("(i)", key_id);
+
+ if (!args)
+ {
+ g_warning("Unable to build Python arguments.");
+ if (PyErr_Occurred())
+ PyErr_Print();
+ return;
+ }
+
+ (void) PyObject_CallObject(manager.callbacks[key_id], args);
+ Py_DECREF(args);
+ }
+}
+
+
+PyObject * kb_manager_init(PyObject *module)
+{
+
+ if (manager.initialized)
+ Py_RETURN_TRUE;
+
+ manager.kg_name = name_to_key(geany_plugin->info->name /* FIXME: use plugin name */);
+ manager.group = plugin_set_key_group(geany_plugin, manager.kg_name, KB_MAX,
+ (GeanyKeyGroupCallback) on_keybinding_activate);
+
+ if (manager.group)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+
+#if 0
+PyObject * kb_manager_finalize(PyObject *module)
+{
+ uint i;
+ for (i = 0; i < KB_MAX; i++)
+ {
+ Py_XDECREF(manager.callbacks[i]);
+ Py_XDECREF(manager.user_data[i]);
+ g_free(manager.labels[i]);
+ }
+ g_free(manager.kg_name);
+ Py_RETURN_NONE;
+}
+#endif
+
+
+PyObject * kb_manager_register_binding(PyObject *module, PyObject *args)
+{
+ guint id;
+ gboolean found_id;
+ gchar *key_name;
+ const gchar *name, *label;
+ PyObject *pCallback, *pData = NULL;
+
+ if (!PyArg_ParseTuple(args, "ssO|O", &name, &label, &pCallback, &pData))
+ {
+ PyErr_SetString(PyExc_ValueError, "unable to parse arguments");
+ return NULL;
+ }
+
+ found_id = FALSE;
+ id = next_key_id(&found_id);
+ if (!found_id)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "no free keybindings left");
+ return NULL;
+ }
+
+ if (!PyCallable_Check(pCallback))
+ {
+ PyErr_SetString(PyExc_ValueError, "callback function is not callable");
+ return NULL;
+ }
+
+ /* TODO: need to check name, label, callback? */
+
+ snprintf(manager.labels[id], KB_LABEL_MAX, "%s: %s", name, label);
+
+ if (!manager.registered[id])
+ {
+ key_name = g_strdup_printf("%s_%d", manager.kg_name, id);
+ manager.bindings[id] = keybindings_set_item(manager.group,
+ (gsize) id,
+ NULL,
+ 0,
+ 0,
+ key_name,
+ manager.labels[id],
+ NULL);
+ g_free(key_name);
+
+ if (manager.bindings[id])
+ manager.registered[id] = TRUE;
+ else
+ {
+ PyErr_SetString(PyExc_RuntimeError, "unable to register keybinding");
+ return NULL;
+ }
+ }
+
+ Py_INCREF(pCallback);
+ manager.callbacks[id] = pCallback;
+
+ Py_XINCREF(pData);
+ manager.user_data[id] = pData;
+
+ manager.slots[id] = TRUE;
+
+ return PyInt_FromLong((long) id);
+}
+
+
+PyObject * kb_manager_unregister_binding(PyObject *module, PyObject *args)
+{
+ guint id;
+
+ if (!PyArg_ParseTuple(args, "I", &id))
+ {
+ PyErr_SetString(PyExc_ValueError, "expecting a single int argument");
+ return NULL;
+ }
+
+ if (id >= KB_MAX)
+ {
+ gchar *msg = g_strdup_printf("id is out of range (0-%d)", KB_MAX);
+ PyErr_SetString(PyExc_IndexError, msg);
+ g_free(msg);
+ return NULL;
+ }
+
+ if (!manager.slots[id])
+ {
+ PyErr_SetString(PyExc_IndexError, "id is not registered");
+ return NULL;
+ }
+
+ Py_XDECREF(manager.callbacks[id]);
+ Py_XDECREF(manager.user_data[id]);
+ manager.callbacks[id] = NULL;
+ manager.user_data[id] = NULL;
+ manager.slots[id] = FALSE;
+ manager.labels[id][0] = '\0';
+
+ Py_RETURN_NONE;
+}
+
+
+static PyMethodDef KbManagerModule_methods[] = {
+ { "init", (PyCFunction) kb_manager_init, METH_NOARGS,
+ "Initialize the keybindings manager." },
+ { "register_binding", (PyCFunction) kb_manager_register_binding,
+ METH_VARARGS, "Register a callback function for a keybinding event." },
+ { "unregister_binding", (PyCFunction) kb_manager_unregister_binding,
+ METH_VARARGS, "Unregister a callback function by id." },
+ { NULL }
+};
+
+
+PyMODINIT_FUNC initbindings(void)
+{
+ PyObject *m;
+
+ m = Py_InitModule3("bindings", KbManagerModule_methods,
+ "Keybindings management.");
+}
\ No newline at end of file
diff --git a/src/geanypy-encoding.c b/src/geanypy-encoding.c
index 8ffa5fa..a1fc21b 100644
--- a/src/geanypy-encoding.c
+++ b/src/geanypy-encoding.c
@@ -1,94 +1,6 @@
#include "geanypy.h"
-static void
-Encoding_dealloc(Encoding *self)
-{
- g_return_if_fail(self != NULL);
- self->ob_type->tp_free((PyObject *) self);
-}
-
-
-static int
-Encoding_init(Encoding *self)
-{
- g_return_val_if_fail(self != NULL, -1);
- self->encoding = NULL;
- return 0;
-}
-
-
-static PyObject *
-Encoding_get_property(Encoding *self, const gchar *prop_name)
-{
- g_return_val_if_fail(self != NULL, NULL);
- g_return_val_if_fail(prop_name != NULL, NULL);
-
- if (!self->encoding)
- {
- PyErr_SetString(PyExc_RuntimeError,
- "Encoding instance not initialized properly");
- return NULL;
- }
-
- if (g_str_equal(prop_name, "charset") && self->encoding->charset)
- return PyString_FromString(self->encoding->charset);
- else if (g_str_equal(prop_name, "group"))
- return PyInt_FromLong((glong) self->encoding->group);
- else if (g_str_equal(prop_name, "idx"))
- return PyInt_FromLong((glong) self->encoding->idx);
- else if (g_str_equal(prop_name, "name") && self->encoding->name)
- return PyString_FromString(self->encoding->name);
- else if (g_str_equal(prop_name, "order"))
- return PyInt_FromLong((glong) self->encoding->order);
-
- Py_RETURN_NONE;
-}
-GEANYPY_PROPS_READONLY(Encoding);
-
-
-static PyGetSetDef Encoding_getseters[] = {
- GEANYPY_GETSETDEF(Encoding, "charset",
- "String representation of the encoding, ex. 'ISO-8859-3'."),
- GEANYPY_GETSETDEF(Encoding, "group",
- "Internally used member for grouping (see encoding.GROUP_* constants)."),
- GEANYPY_GETSETDEF(Encoding, "idx",
- "The index of the encoding, (see encoding.* constants, not encoding.GROUP_*)."),
- GEANYPY_GETSETDEF(Encoding, "name",
- "Translatable and descriptive name of the encoding, ex 'South European'."),
- GEANYPY_GETSETDEF(Encoding, "order",
- "Internally used member for grouping."),
- { NULL }
-};
-
-
-PyTypeObject EncodingType = {
- PyObject_HEAD_INIT(NULL)
- 0, /* ob_size */
- "geany.encoding.Encoding", /* tp_name */
- sizeof(Encoding), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor) Encoding_dealloc, /* tp_dealloc */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* tp_print - tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- "Wrapper around a GeanyEncoding structure.", /* tp_doc */
- 0, 0, 0, 0, 0, 0, 0, 0, /* tp_traverse - tp_members */
- Encoding_getseters, /* tp_getset */
- 0, 0, 0, 0, 0, /* tp_base - tp_dictoffset */
- (initproc) Encoding_init, /* tp_init */
- 0, 0, /* tp_alloc - tp_new */
-};
-
-
-Encoding *Encoding_create_new_from_geany_encoding(GeanyEncoding *enc)
-{
- Encoding *self;
- self = (Encoding *) PyObject_CallObject((PyObject *) &EncodingType, NULL);
- self->encoding = enc;
- return self;
-}
-
-
static PyObject *
Encodings_convert_to_utf8(PyObject *module, PyObject *args, PyObject *kwargs)
{
@@ -156,17 +68,6 @@ Encodings_get_charset_from_index(PyObject *module, PyObject *args, PyObject *kwa
}
-static const gchar *encoding_groups[] = {
- "GROUP_NONE",
- "GROUP_WEST_EUROPEAN",
- "GROUP_EAST_EUROPEAN",
- "GROUP_EAST_ASIAN",
- "GROUP_ASIAN",
- "GROUP_MIDDLE_EASTERN",
- "GROUP_UNICODE"
-};
-
-
static const gchar *encoding_names[] = {
"ISO_8859_1",
"ISO_8859_2",
@@ -292,19 +193,9 @@ initencoding(void)
int i;
PyObject *m;
- EncodingType.tp_new = PyType_GenericNew;
- if (PyType_Ready(&EncodingType) < 0)
- return;
-
m = Py_InitModule3("encoding", EncodingsModule_methods,
"Encoding conversion functions.");
- Py_INCREF(&EncodingType);
- PyModule_AddObject(m, "Encoding", (PyObject *) &EncodingType);
-
for (i = 0; i < GEANY_ENCODINGS_MAX; i++)
PyModule_AddIntConstant(m, encoding_names[i], (glong) i);
-
- for (i = 0; i < GEANY_ENCODING_GROUPS_MAX; i++)
- PyModule_AddIntConstant(m, encoding_groups[i], (glong) i);
}
diff --git a/src/geanypy-encoding.h b/src/geanypy-encoding.h
index 1c586c1..caea0a1 100644
--- a/src/geanypy-encoding.h
+++ b/src/geanypy-encoding.h
@@ -1,14 +1,4 @@
#ifndef GEANYPY_ENCODING_H__
#define GEANYPY_ENCODING_H__
-PyTypeObject EncodingType;
-
-typedef struct
-{
- PyObject_HEAD
- GeanyEncoding *encoding;
-} Encoding;
-
-Encoding *Encoding_create_new_from_geany_encoding(GeanyEncoding *enc);
-
#endif /* GEANYPY_ENCODING_H__ */
diff --git a/src/geanypy-plugin.c b/src/geanypy-plugin.c
index 48bf98f..c96d52f 100644
--- a/src/geanypy-plugin.c
+++ b/src/geanypy-plugin.c
@@ -43,6 +43,7 @@ static SignalManager *signal_manager = NULL;
/* Forward declarations to prevent compiler warnings. */
PyMODINIT_FUNC initapp(void);
+PyMODINIT_FUNC initbindings(void);
PyMODINIT_FUNC initdialogs(void);
PyMODINIT_FUNC initdocument(void);
PyMODINIT_FUNC initeditor(void);
@@ -81,9 +82,12 @@ GeanyPy_start_interpreter(void)
#endif
Py_Initialize();
-
+ #if GTK_CHECK_VERSION(3, 0, 0)
+ PySys_SetArgv(0, "[]");
+ #endif
/* Import the C modules */
initapp();
+ initbindings();
initdialogs();
initdocument();
initeditor();
@@ -150,7 +154,6 @@ GeanyPy_init_manager(const gchar *dir)
gchar *sys_plugin_dir = NULL;
g_return_if_fail(dir != NULL);
-
module = PyImport_ImportModule("geany.manager");
if (module == NULL)
{
@@ -194,11 +197,11 @@ GeanyPy_init_manager(const gchar *dir)
if (sys_plugin_dir)
{
g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "System plugins: %s", sys_plugin_dir);
- args = Py_BuildValue("([s, s])", sys_plugin_dir, dir);
+ args = Py_BuildValue("(O, [s, s])", pygobject_new(G_OBJECT(geany_data->main_widgets->window)), sys_plugin_dir, dir);
g_free(sys_plugin_dir);
}
else
- args = Py_BuildValue("([s])", dir);
+ args = Py_BuildValue("(O, [s])", pygobject_new(G_OBJECT(geany_data->main_widgets->window)), dir);
manager = PyObject_CallObject(man, args);
if (PyErr_Occurred())
@@ -265,7 +268,7 @@ plugin_init(GeanyData *data)
loader_item = gtk_menu_item_new_with_label(_("Python Plugin Manager"));
gtk_widget_set_sensitive(loader_item, plugin_dir != NULL);
- gtk_menu_append(GTK_MENU(geany->main_widgets->tools_menu), loader_item);
+ gtk_menu_shell_append(GTK_MENU_SHELL(geany->main_widgets->tools_menu), loader_item);
gtk_widget_show(loader_item);
g_signal_connect(loader_item, "activate",
G_CALLBACK(on_python_plugin_loader_activate), NULL);
@@ -274,6 +277,17 @@ plugin_init(GeanyData *data)
G_MODULE_EXPORT void plugin_cleanup(void)
{
+ PyObject* deactivate_all_plugins = PyObject_GetAttrString(manager,
+ "deactivate_all_plugins");
+ if (deactivate_all_plugins != NULL)
+ {
+ PyObject* r = PyObject_CallObject(deactivate_all_plugins, NULL);
+ if (r)
+ Py_DECREF(r);
+ Py_DECREF(deactivate_all_plugins);
+
+ }
+
signal_manager_free(signal_manager);
Py_XDECREF(manager);
GeanyPy_stop_interpreter();
diff --git a/src/geanypy-uiutils.c b/src/geanypy-uiutils.c
index 58f63cb..4d2718e 100644
--- a/src/geanypy-uiutils.c
+++ b/src/geanypy-uiutils.c
@@ -3,7 +3,7 @@
#define GOB_CHECK(pyobj, arg) \
{ \
- if (!pyobj || pyobj == Py_None || !pygobject_check(pyobj, PyGObject_Type)) \
+ if (!pyobj || pyobj == Py_None || !pygobject_check(pyobj, PyGobject_Type)) \
{ \
PyErr_SetString(PyExc_ValueError, \
"argument " #arg " must inherit from a gobject.GObject type"); \
@@ -23,7 +23,7 @@
}
-static PyTypeObject *PyGObject_Type = NULL;
+static PyTypeObject *PyGobject_Type = NULL;
static PyObject *
@@ -123,8 +123,8 @@ UiUtils_combo_box_add_to_history(PyObject *module, PyObject *args, PyObject *kwa
{
GOB_CHECK(py_cbo, 1);
widget = pygobject_get(py_cbo);
- GOB_TYPE_CHECK(widget, GTK_TYPE_COMBO_BOX_ENTRY, 1);
- ui_combo_box_add_to_history(GTK_COMBO_BOX_ENTRY(widget), text, hist_len);
+ GOB_TYPE_CHECK(widget, GTK_TYPE_COMBO_BOX_TEXT, 1);
+ ui_combo_box_add_to_history(GTK_COMBO_BOX_TEXT(widget), text, hist_len);
}
Py_RETURN_NONE;
@@ -418,18 +418,20 @@ static PyMethodDef UiUtilsModule_methods[] = {
PyMODINIT_FUNC initui_utils(void)
{
- PyObject *m;
-
- init_pygobject();
- init_pygtk();
- m = PyImport_ImportModule("gobject");
-
- if (m)
- {
- PyGObject_Type = (PyTypeObject *) PyObject_GetAttrString(m, "GObject");
- Py_XDECREF(m);
- }
-
+ PyObject *m;
+ #if GTK_CHECK_VERSION(3, 0, 0)
+ pygobject_init(-1, -1, -1);
+ m = PyImport_ImportModule("gi._gobject");
+ #else
+ init_pygobject();
+ init_pygtk();
+ m = PyImport_ImportModule("gobject");
+ #endif
+ if (m)
+ {
+ PyGobject_Type = (PyTypeObject *) PyObject_GetAttrString(m, "_PyGObject_API");
+ Py_XDECREF(m);
+ }
InterfacePrefsType.tp_new = PyType_GenericNew;
if (PyType_Ready(&InterfacePrefsType) < 0)
return;
@@ -446,4 +448,4 @@ PyMODINIT_FUNC initui_utils(void)
Py_INCREF(&MainWidgetsType);
PyModule_AddObject(m, "MainWidgets", (PyObject *) &MainWidgetsType);
-}
+}
\ No newline at end of file
diff --git a/src/geanypy.h b/src/geanypy.h
index 0029b70..f198213 100644
--- a/src/geanypy.h
+++ b/src/geanypy.h
@@ -77,12 +77,13 @@ extern "C" {
#include
#include
-#ifndef GEANYPY_WINDOWS
+#ifdef GEANYPY_WINDOWS
/* Used with the results of `pkg-config --cflags pygtk-2.0` */
-# include
-#else
+#include
/* On windows the path of pygtk.h is directly an include dir */
-# include
+#endif
+#if !GTK_CHECK_VERSION(3, 0, 0)
+#include
#endif
#ifndef GTK